def test_get_watershed_masks_with_area_threshold(): rmg = RasterModelGrid((7, 7), 200) z = np.array([ -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999., 26., 0., 26., 30., 34., -9999., -9999., 28., 1., 28., 5., 32., -9999., -9999., 30., 3., 30., 10., 34., -9999., -9999., 32., 11., 32., 15., 38., -9999., -9999., 34., 32., 34., 36., 40., -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999. ]) rmg.at_node['topographic__elevation'] = z rmg.set_closed_boundaries_at_grid_edges(True, True, True, False) # Route flow. fr = FlowRouter(rmg) fr.run_one_step() # Get the masks of watersheds greater than or equal to 80,000 # square-meters. critical_area = 80000 mask = get_watershed_masks_with_area_threshold(rmg, critical_area) # Assert that mask null nodes have a drainage area below critical area. null_nodes = np.where(mask == -1)[0] A = rmg.at_node['drainage_area'][null_nodes] below_critical_area_nodes = A < critical_area trues = np.ones(len(A), dtype=bool) np.testing.assert_equal(below_critical_area_nodes, trues)
def __init__(self, input_file=None, params=None): """Initialize the StochasticDischargeHortonianModel.""" # Call ErosionModel's init super(StochasticDischargeHortonianModel, self).__init__(input_file=input_file, params=params) # Instantiate components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) self.rain_generator = \ PrecipitationDistribution(delta_t=self.params['dt'], total_time=self.params['run_duration'], **self.params) # Add a field for discharge if 'surface_water__discharge' not in self.grid.at_node: self.grid.add_zeros('node', 'surface_water__discharge') self.discharge = self.grid.at_node['surface_water__discharge'] # Get the infiltration-capacity parameter self.infilt = self.params['infiltration_capacity'] # Run flow routing and lake filler (only once, because we are not # not changing topography) self.flow_router.run_one_step() self.lake_filler.map_depressions()
def test_track_source(): """Unit tests for track_source(). """ grid = RasterModelGrid((5, 5), spacing=(1., 1.)) grid.at_node['topographic__elevation'] = np.array([5., 5., 5., 5., 5., 5., 4., 5., 1., 5., 0., 3., 5., 3., 0., 5., 4., 5., 2., 5., 5., 5., 5., 5., 5.]) grid.status_at_node[10] = 0 grid.status_at_node[14] = 0 fr = FlowRouter(grid) fr.route_flow() r = grid.at_node['flow__receiver_node'] assert_equal(r[6], 10) assert_equal(r[7], 8) assert_equal(r[18], 14) hsd_ids = np.empty(grid.number_of_nodes, dtype=int) hsd_ids[:] = 1 hsd_ids[2:5] = 0 hsd_ids[7:10] = 0 (hsd_upstr, flow_accum) = track_source(grid, hsd_ids) assert_equal(hsd_upstr[8], [1, 0, 0]) assert_equal(hsd_upstr[14], [1, 1, 1, 1, 0, 0, 1]) assert_equal(flow_accum[14], 7)
def __init__(self, modern_dem_name, outlet_id, chi_mask_dem_name=None, from_file=None): """Initialize MetricCalculator with names of postglacial and modern DEMs.""" if from_file is None: # Read and remember the modern DEM (whether data or model) (self.grid, self.z) = self.read_topography(modern_dem_name) #print self.grid.x_of_node self.grid.set_watershed_boundary_condition_outlet_id(outlet_id, self.z, nodata_value=-9999) # Instantiate and run a FlowRouter and lake filler, so we get # drainage area for cumulative-area statistic, and also fields for chi. fr = FlowRouter(self.grid) dfr = DepressionFinderAndRouter(self.grid) fr.route_flow() dfr.map_depressions() # Remember modern drainage area grid self.area = self.grid.at_node['drainage_area'] # Instantiate a ChiFinder for chi-index self.chi_finder = ChiFinder(self.grid, min_drainage_area=10000., reference_concavity=0.5) core_nodes = np.zeros(self.area.shape, dtype=bool) core_nodes[self.grid.core_nodes] = True # Read and remember the MASK, if provided if chi_mask_dem_name is None: self.mask = (self.area>1e5) self.till_mask = np.zeros(self.mask.shape, dtype=bool) self.till_mask[self.grid.core_nodes] = 1 else: (self.mask_grid, zmask) = self.read_topography(chi_mask_dem_name) mask = (zmask>0)*1 self.mask = (self.area>1e5)*(mask==1) mask_bool = (zmask>0) self.till_mask = np.zeros(self.mask.shape, dtype=bool) self.till_mask[mask_bool*core_nodes] = 1 # # Create dictionary to contain metrics self.metric = {} else: with open(from_file, 'r') as f: metrics = load(f) self.modern_dem_name = metrics.pop('Topo file') self.metric = metrics fn_split = from_file.split('.') fn_split[-1] = 'chi' fn_split.append('txt') chi_filename = '.'.join(fn_split) self.density_chi = np.loadtxt(chi_filename)
def test_get_watershed_nodes(): grid = RasterModelGrid((7, 7), 1) z = np.array([ -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999., 26., 0., 30., 32., 34., -9999., -9999., 28., 1., 25., 28., 32., -9999., -9999., 30., 3., 3., 11., 34., -9999., -9999., 32., 11., 25., 18., 38., -9999., -9999., 34., 32., 34., 36., 40., -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999. ]) grid.at_node['topographic__elevation'] = z outlet_id = 2 grid.set_watershed_boundary_condition_outlet_id(outlet_id, z, nodata_value=-9999.) fr = FlowRouter(grid) fr.run_one_step() ws_nodes = get_watershed_nodes(grid, outlet_id) # Given the watershed boundary conditions, the number of watershed nodes # should be equal to the number of core nodes plus 1 for the outlet node. np.testing.assert_equal(len(ws_nodes), grid.number_of_core_nodes + 1)
def __init__(self, input_file=None, params=None): """Initialize the LinearDiffusionModel.""" # Call ErosionModel's init super(DrainageAreaModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params)
def plot_and_calc_concavities_final_run(directory='.'): """ Plots S-A for final topo saved in folder "directory". Returns (k_s, concavity) for lin regression on log log trend. Concavity is defined as positive. """ mg2 = deepcopy(mg) z2 = mg2.add_zeros('node', 'topographic__elevation', noclobber=False) fr2 = FlowRouter(mg2) # search for topo saves, to establish the num files, codes etc: prefixed_z = [ filename for filename in os.listdir(directory) if filename.startswith('topographic__elevation') ] # grab the unique ID, so we can differentiate plots (if desired) unique_ID = prefixed_z[0][-14:-4] # work on first save to establish num digits _format = 0 while True: char = prefixed_z[-1][-16 - _format] try: num = int(char) except ValueError: # was a str break else: _format += 1 # load the final topo: z2[:] = np.loadtxt(directory + '/' + prefixed_z[-1]) # create a new flow map: fr2.run_one_step() profile_IDs = channel_nodes(mg2, mg2.at_node['topographic__steepest_slope'], mg2.at_node['drainage_area'], mg2.at_node['flow__receiver_node']) ch_dists = get_distances_upstream( mg2, len(mg2.at_node['topographic__steepest_slope']), profile_IDs, mg2.at_node['flow__link_to_receiver_node']) slopes = mg2.at_node['topographic__steepest_slope'][profile_IDs[0]] areas = mg2.at_node['drainage_area'][profile_IDs[0]] logslopes = np.log(slopes) logareas = np.log(areas) goodvals = np.logical_and(np.isfinite(logslopes), np.isfinite(logareas)) concavity, log_k_s, _, _, _ = linregress(logareas[goodvals], logslopes[goodvals]) k_s = np.exp(log_k_s) loglog(areas, slopes, 'x') loglog(areas, k_s * areas**concavity, '-') xlabel('Drainage area (m**2)') ylabel('Slope (m/m)') return k_s, -concavity
def __init__(self, input_file=None, params=None): """Initialize the StreamPowerThresholdModel.""" # Call ErosionModel's init super(StreamPowerThresholdModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.params['K_sp'], threshold_sp=self.params['threshold_sp'])
def __init__(self, input_file=None, params=None): """Initialize the LinearDiffusionModel.""" # Call ErosionModel's init super(EffectiveDrainageAreaModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) # Add a field for effective drainage area self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = self.params['saturation_area_scale']
def test_find_unique_upstream_hsd_ids_and_fractions(): """Unit tests find_unique_upstream_hsd_ids_and_fractions(). """ grid = RasterModelGrid((5, 5), spacing=(1., 1.)) grid.at_node['topographic__elevation'] = np.array([ 5., 5., 5., 5., 5., 5., 4., 5., 1., 5., 0., 3., 5., 3., 0., 5., 4., 5., 2., 5., 5., 5., 5., 5., 5. ]) grid.status_at_node[10] = 0 grid.status_at_node[14] = 0 fr = FlowRouter(grid) fr.route_flow() hsd_ids = np.empty(grid.number_of_nodes, dtype=int) hsd_ids[:] = 1 hsd_ids[2:5] = 0 hsd_ids[7:10] = 0 (hsd_upstr, flow_accum) = track_source(grid, hsd_ids) (uniq_ids, coeff) = find_unique_upstream_hsd_ids_and_fractions(hsd_upstr) np.testing.assert_almost_equal(np.sort(np.array(coeff[8])), np.array([0.33333333, 0.66666667]))
class DrainageAreaModel(_ErosionModel): """ A DrainageAreaModel simply computes drainage area on a raster-grid DEM. """ def __init__(self, input_file=None, params=None): """Initialize the LinearDiffusionModel.""" # Call ErosionModel's init super(DrainageAreaModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ self.flow_router.run_one_step() # for debug from landlab.io import write_esri_ascii import numpy write_esri_ascii('test_dr_area_before_temp.txt', self.grid, names='drainage_area', clobber=True) loga = self.grid.add_zeros('node', 'loga') loga[:] = numpy.log10(self.grid.at_node['drainage_area'] + 1) write_esri_ascii('test_logdr_area_before_temp.txt', self.grid, names='loga', clobber=True) write_esri_ascii('test_sink_flag_before_temp.txt', self.grid, names='flow__sink_flag', clobber=True) self.lake_filler.map_depressions()
def __init__(self, input_file=None, params=None): """Initialize the HybridAlluviumModel.""" # Call ErosionModel's init super(HybridAlluviumModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) #make area_field and/or discharge_field depending on discharge_method if self.params['discharge_method'] is not None: if self.params['discharge_method'] == 'area_field': area_field = self.grid.at_node['drainage_area'] discharge_field = None elif self.params['discharge_method'] == 'discharge_field': discharge_field = self.grid.at_node['surface_water__discharge'] area_field = None else: raise (KeyError) else: area_field = None discharge_field = None # Instantiate a HybridAlluvium component self.eroder = Space(self.grid, K_sed=self.params['K_sed'], K_br=self.params['K_br'], F_f=self.params['F_f'], phi=self.params['phi'], H_star=self.params['H_star'], v_s=self.params['v_s'], m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], sp_crit_sed=self.params['sp_crit_sed'], sp_crit_br=self.params['sp_crit_br'], method=self.params['method'], discharge_method=self.params['discharge_method'], area_field=area_field, discharge_field=discharge_field)
def test_find_unique_upstream_hsd_ids_and_fractions(): """Unit tests find_unique_upstream_hsd_ids_and_fractions(). """ grid = RasterModelGrid((5, 5), spacing=(1., 1.)) grid.at_node['topographic__elevation'] = np.array([5., 5., 5., 5., 5., 5., 4., 5., 1., 5., 0., 3., 5., 3., 0., 5., 4., 5., 2., 5., 5., 5., 5., 5., 5.]) grid.status_at_node[10] = 0 grid.status_at_node[14] = 0 fr = FlowRouter(grid) fr.route_flow() hsd_ids = np.empty(grid.number_of_nodes, dtype=int) hsd_ids[:] = 1 hsd_ids[2:5] = 0 hsd_ids[7:10] = 0 (hsd_upstr, flow_accum) = track_source(grid, hsd_ids) (uniq_ids, coeff) = find_unique_upstream_hsd_ids_and_fractions(hsd_upstr) np.testing.assert_almost_equal( np.sort(np.array(coeff[8])), np.array([0.33333333, 0.66666667]))
class EffectiveDrainageAreaModel(_ErosionModel): """ A DrainageAreaModel simply computes drainage area on a raster-grid DEM. """ def __init__(self, input_file=None, params=None): """Initialize the LinearDiffusionModel.""" # Call ErosionModel's init super(EffectiveDrainageAreaModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) # Add a field for effective drainage area self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = self.params['saturation_area_scale'] def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Run flow routing and lake filler self.flow_router.run_one_step() self.lake_filler.map_depressions() # Calculate effective area area = self.grid.at_node['drainage_area'] slope = self.grid.at_node['topographic__steepest_slope'] cores = self.grid.core_nodes self.eff_area[cores] = ( area[cores] * np.exp(-self.sat_param * slope[cores] / area[cores])) # Lower outlet self.z[self.outlet_node] -= self.outlet_lowering_rate * dt print(('lowering outlet to ', self.z[self.outlet_node]))
def test_get_watershed_outlet(): grid = RasterModelGrid((7, 7), 1) z = np.array([ -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999., 26., 0., 30., 32., 34., -9999., -9999., 28., 1., 25., 28., 32., -9999., -9999., 30., 3., 3., 11., 34., -9999., -9999., 32., 11., 25., 18., 38., -9999., -9999., 34., 32., 34., 36., 40., -9999., -9999., -9999., -9999., -9999., -9999., -9999., -9999. ]) grid.at_node['topographic__elevation'] = z imposed_outlet = 2 grid.set_watershed_boundary_condition_outlet_id(imposed_outlet, z, nodata_value=-9999.) fr = FlowRouter(grid) fr.run_one_step() test_node = 32 determined_outlet = get_watershed_outlet(grid, test_node) np.testing.assert_equal(determined_outlet, imposed_outlet) # Create a pit. pit_node = 38 grid.at_node['topographic__elevation'][pit_node] -= 32 fr.run_one_step() pit_outlet = get_watershed_outlet(grid, test_node) np.testing.assert_equal(pit_outlet, pit_node)
def __init__(self, input_file=None, params=None): """Initialize the StreamPowerVarThresholdModel.""" # Call ErosionModel's init super(StreamPowerVarThresholdModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros('node', 'erosion__threshold') self.threshold[:] = self.params['threshold_sp'] # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.params['K_sp'], threshold_sp=self.threshold) # Get the parameter for rate of threshold increase with erosion depth self.thresh_change_per_depth = self.params['thresh_change_per_depth']
class StreamPowerThresholdModel(_ErosionModel): """ A StreamPowerThresholdModel computes erosion using a form of the unit stream power model that represents a threshold using an exponential term. """ def __init__(self, input_file=None, params=None): """Initialize the StreamPowerThresholdModel.""" # Call ErosionModel's init super(StreamPowerThresholdModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.params['K_sp'], threshold_sp=self.params['threshold_sp']) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Route flow self.flow_router.run_one_step() self.lake_filler.map_depressions() # Get IDs of flooded nodes, if any flooded = np.where(self.lake_filler.flood_status == 3)[0] # Do some erosion (but not on the flooded nodes) self.eroder.run_one_step(dt, flooded_nodes=flooded)
def test_track_source(): """Unit tests for track_source(). """ grid = RasterModelGrid((5, 5), spacing=(1., 1.)) grid.at_node['topographic__elevation'] = np.array([ 5., 5., 5., 5., 5., 5., 4., 5., 1., 5., 0., 3., 5., 3., 0., 5., 4., 5., 2., 5., 5., 5., 5., 5., 5. ]) grid.status_at_node[10] = 0 grid.status_at_node[14] = 0 fr = FlowRouter(grid) fr.route_flow() r = grid.at_node['flow__receiver_node'] assert r[6] == 10 assert r[7] == 8 assert r[18] == 14 hsd_ids = np.empty(grid.number_of_nodes, dtype=int) hsd_ids[:] = 1 hsd_ids[2:5] = 0 hsd_ids[7:10] = 0 (hsd_upstr, flow_accum) = track_source(grid, hsd_ids) assert hsd_upstr[8] == [1, 0, 0] assert hsd_upstr[14] == [1, 1, 1, 1, 0, 0, 1] assert flow_accum[14] == 7
gridlist = [] # add initial noise to produce convergent flow from the initial conditions np.random.seed(91) # so our figures are reproducible mg_noise = np.random.rand(mg.number_of_nodes)/1000. # set up the input fields zr = mg.add_zeros('node', 'topographic__elevation') zr += mg_noise # Landlab sets fixed elevation boundary conditions by default. This is # what we want, so we will not modify these here. # instantiate the components: frr = FlowRouter(mg) # water__unit_flux_in gets automatically ingested spr = StreamPowerEroder(mg, K_sp=K_sp, m_sp=m_sp, n_sp=n_sp, threshold_sp=0, use_Q=None) lake = DepressionFinderAndRouter(mg) # Hillslopes dfn = LinearDiffuser(mg, linear_diffusivity=K_hs) zr_last = -9999 keep_running = np.mean(np.abs(zr - zr_last)) >= end_thresh ti = 0 while keep_running: zr_last = zr.copy() zr[mg.core_nodes] += uplift_rate*dt dfn.run_one_step(dt) # hillslopes always diffusive, even when dry frr.run_one_step()
# make velocity profile and because the grid is discretized into pixels, we need to count how much # deformation has occurred over a timestep and move a pixel after the # accumulated deformation is larger than than the pixel length v_profile = profile * vmax accum_disp = profile * float(dxy) # This is an array for counting how many pixels need to be moved nshift = np.zeros(np.size(yLocation)) n_buff = 0 # optional extra buffer zone incase you only want to move a subset. ################################################################################ ## Last, we instantiate landlab components that will evolve the landscape ##### ################################################################################ fr = FlowRouter(rmg) # standard D8 flow routing algorithm sp = FastscapeEroder(rmg, K_sp='K_sp', m_sp=m, n_sp=n, threshold_sp=0) # river eroder lin_diffuse = LinearDiffuser(rmg, linear_diffusivity='D') #linear diffuser fill = DepressionFinderAndRouter(rmg) #lake filling algorithm nts = int(num_frames) ds = xr.Dataset( data_vars={ 'topographic__elevation': ( ('time', 'y', 'x'), # tuple of dimensions np.empty((nts, rmg.shape[0], rmg.shape[1])), # n-d array of data { 'units': 'meters' }) }, # dictionary with data attributes
2] = ice_topo_f[0:lat.shape[0] - 1, :] # top centre extend_t[0:lat.shape[0] - 1, lon.shape[0] * 2:lon.shape[0] * 3] = ice_topo_f[0:lat.shape[0] - 1, :] # Top right extend_t[lat.shape[0] - 1:lat.shape[0] * 2 - 2, 0:lon.shape[0] * 3] = np.fliplr( np.flipud(extend_t[0:lat.shape[0] - 1, 0:lon.shape[0] * 3])) # pad bottom # Create raster grid for flow calculation and add data fg = RasterModelGrid((extend_t.shape[0], extend_t.shape[1]), spacing=(1, 1)) _ = fg.add_field('node', 'topographic__elevation', extend_t) fg.set_closed_boundaries_at_grid_edges(False, False, False, False) # Calculate flow fields fr = FlowRouter(fg) fg = fr.route_flow() # Preview the flow field with this plotting func. # drainage_plot(fg, title='Grid 2 using FlowDirectorD8') # Fill in Lakes/depressions fg.at_node['flow__sink_flag'][ fg.core_nodes].sum() # how many depressions do we have? hf = SinkFiller(fg, apply_slope=True) hf.run_one_step() fr.run_one_step() # drainage_plot(fg, title='Grid 2 using FlowDirectorD8') # Output is a single vector flow_rec = fg.at_node['flow__receiver_node']
modeled_time = [] storm_events = [] a = 1 if a == 1: m = 0.3 n = 0.7 k_tau = 8.357150818380437e-15 tc0 = (k_tau * (0.)**a) tc1 = (k_tau * (10.)**a) tc5 = (k_tau * (25.)**a) tc10 = (k_tau * (50.)**a) fr = FlowRouter(rmg, method='D4') fr1 = FlowRouter(rmg1, method='D4') fr5 = FlowRouter(rmg5, method='D4') fr10 = FlowRouter(rmg10, method='D4') dle = StreamPowerEroder(rmg, K_sp=(1e-10), threshold_sp=float(tc0), use_Q='water__discharge', m_sp=m, n_sp=n) #(3.4e-11) dle1 = StreamPowerEroder(rmg1, K_sp=(1e-10), threshold_sp=float(tc1), use_Q='water__discharge', m_sp=m, n_sp=n) #(3.4e-11)
g = 9.81 #m/s2 drag_cube = 0.8 #Carling channel_width = 10 #m threshold_drainage_area = 500 #unclear on what these units are mg.add_zeros('node','water_depth') mg.add_zeros('node','water_velocity') mg.add_zeros('node','corrected_shear_stress') mg.add_zeros('node', 'erodibility') mg.add_zeros('node', 'incision_rate') mg.add_zeros('node', 'num_blocks') #hopefully will contain array of sizes at a given node, one entry for each block mg.add_zeros('node', 'f_covered') mg['node']['erodibility'][:] = k spatial_step = mg.empty(centering='node') #instantiate components fr = Flow(mg, input_file) lf = LakeFill(mg, input_file) sp = Fsc(mg, input_file) hd = Diff(mg, input_file) tracking_mat = np.zeros((100000, 4), dtype=np.float64) #colums: 0) which node, 1) side length 2) vol 3) sub/emergence tracking_mat[:, :] = np.nan for_slicing = 0 #in case no blocks ever get put in side_length = 4 #m, block side length tau_c_br = 10 #Pa, for now a1 = 6.5 a2 = 2.5 d = 0.1 #z0 tol = 0.01 #m water thickness error allowable
## Import what is needed from landlab import RasterModelGrid from landlab.components import LinearDiffuser, FlowRouter from landlab.components import FastscapeEroder from landlab.plot import imshow_grid from matplotlib import pyplot as plt ## Make a grid that is 100 by 100 with dx=dy=100. m rmg1 = RasterModelGrid((100, 100), 100.) ## Add elevation field to the grid. z1 = rmg1.add_ones('node', 'topographic__elevation') ## Instantiate process components ld1 = LinearDiffuser(rmg1, linear_diffusivity=0.1) fr1 = FlowRouter(rmg1, method='D8') fse1 = FastscapeEroder(rmg1, K_sp=1e-5, m_sp=0.5, n_sp=1.) ## Set some variables rock_up_rate = 1e-3 #m/yr dt = 1000 # yr rock_up_len = dt * rock_up_rate # m ## Time loop where evolution happens for i in range(500): z1[rmg1.core_nodes] += rock_up_len #uplift only the core nodes ld1.run_one_step(dt) #linear diffusion happens. fr1.run_one_step() #flow routing happens, time step not needed fse1.run_one_step(dt) #fluvial incision happens ## optional print statement print('i', i)
z[outlet]=0 #set boundary conditions of model grid (open only (fixed value) on south center pixel) for edge in (mg.nodes_at_left_edge,mg.nodes_at_right_edge,mg.nodes_at_top_edge,mg.nodes_at_bottom_edge): mg.status_at_node[edge] = CLOSED_BOUNDARY #set southcenter pixel to FIXED VALUE mg.status_at_node[outlet]=1 #PROCESS SET-UP #initialize linear diffuser component lin_diffuse = LinearDiffuser(mg, linear_diffusivity=lin_dif) #iniitalize erosion by run-off fr = FlowRouter(mg) sp = FastscapeEroder(mg,K_sp=K_sp, m_sp=m_sp, n_sp=n_sp) for i in range(nt): fr.run_one_step() sp.run_one_step(dt) lin_diffuse.run_one_step(dt) z[mg.core_nodes] += uplift_rate * dt # add the uplift # color_list=np.linspace(1,0.3,nt) if i % 20 == 0: print(i*dt)
mg.at_node['topographic__elevation'] += np.random.rand(mg.at_node.size)/10000 print('No pre-existing topography. Creating own random noise topo.') #Create boundary conditions of the model grid (either closed or fixed-head) for edge in (mg.nodes_at_left_edge,mg.nodes_at_right_edge, mg.nodes_at_top_edge): mg.status_at_node[edge] = CLOSED_BOUNDARY for edge in (mg.nodes_at_bottom_edge): mg.status_at_node[edge] = FIXED_VALUE_BOUNDARY #Initialize Fastscape fc = FastscapeEroder(mg, K_sp = ksp , m_sp = msp, n_sp = nsp, rainfall_intensity = 1) fr = FlowRouter(mg) lm = DepressionFinderAndRouter(mg) for i in range(nSteps): fr.run_one_step(dt=1) lm.map_depressions() fc.run_one_step(dt=1) mg.at_node['topographic__elevation'][mg.core_nodes] += 0.0002 z = mg.at_node['topographic__elevation'] plt.figure() imshow_grid(mg,z) plt.savefig('test.png') plt.close()
# In this case the difference components are: # * `FlowRouter` which determines the drainage area at each point. In this # case we are using `D8` to determine downslope neighbors. # * `FastscapeEroder` which calculates the incision rate based on a power-law # function of discharge and slope. This uses the Braun and Willet algorithm, # reference <a href="http://www.sciencedirect.com/science/article/pii/S0169555X12004618">here</a>) # * `LinearDiffusers` which calculates erosion and deposition of material # using a sediment transport rate which is proportional to the slope. Here we # do not allow diffusion to deposit, but you can change that. # * Note that in the case of `FastscapeEroder`, the values are noted when the # class is instantiated. In the case of the `LinearDiffuser`, the value is # assigned to a variable and that variable is sent to the class. There are # multiple ways to do things, depending on your coding style and what makes # sense to you. fr = FlowRouter(mg, method='D8') sp = FastscapeEroder(mg, K_sp=0.00005, m_sp=0.5, n_sp=1.0, threshold_sp=0., rainfall_intensity=1.) k_d = 0.5 lin_diffuse = LinearDiffuser(mg, linear_diffusivity=k_d) # * The calculations are all done in the time loop below. for i in range(nt): fr.run_one_step() # route flow sp.run_one_step(dt) # fluvial incision
def test_edge_draining(): """ This tests when the lake attempts to drain from an edge, where an issue is suspected. """ # Create a 7x7 test grid with a well defined hole in it, AT THE EDGE. mg = RasterModelGrid((7, 7), (1., 1.)) z = mg.node_x.copy() guard_sides = np.concatenate((np.arange(7, 14), np.arange(35, 42))) edges = np.concatenate((np.arange(7), np.arange(42, 49))) hole_here = np.array(([15, 16, 22, 23, 29, 30])) z[guard_sides] = z[13] z[edges] = -2. # force flow outwards from the tops of the guards z[hole_here] = -1. A_new = np.array( [ [ [ 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., 15., 5., 4., 3., 2., 1., 0., 0., 10., 4., 3., 2., 1., 0., 0., 1., 4., 3., 2., 1., 0., 0., 1., 1., 1., 1., 1., 0., 0., 1., 1., 1., 1., 1., 0., ] ] ] ).flatten() depr_outlet_target = np.array( [ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, 14, 14, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, ] ).flatten() mg.add_field("node", "topographic__elevation", z, units="-") fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() assert mg.at_node["drainage_area"] == approx(A_new) assert lf.depression_outlet_map == approx(depr_outlet_target)
class HybridAlluviumModel(_ErosionModel): """ A HybridAlluviumModel computes erosion of sediment and bedrock using dual mass conservation on the bed and in the water column. It applies exponential entrainment rules to account for bed cover. """ def __init__(self, input_file=None, params=None): """Initialize the HybridAlluviumModel.""" # Call ErosionModel's init super(HybridAlluviumModel, self).__init__(input_file=input_file, params=params) # Instantiate a FlowRouter and DepressionFinderAndRouter components self.flow_router = FlowRouter(self.grid, **self.params) self.lake_filler = DepressionFinderAndRouter(self.grid, **self.params) #make area_field and/or discharge_field depending on discharge_method if self.params['discharge_method'] is not None: if self.params['discharge_method'] == 'area_field': area_field = self.grid.at_node['drainage_area'] discharge_field = None elif self.params['discharge_method'] == 'discharge_field': discharge_field = self.grid.at_node['surface_water__discharge'] area_field = None else: raise (KeyError) else: area_field = None discharge_field = None # Instantiate a HybridAlluvium component self.eroder = Space(self.grid, K_sed=self.params['K_sed'], K_br=self.params['K_br'], F_f=self.params['F_f'], phi=self.params['phi'], H_star=self.params['H_star'], v_s=self.params['v_s'], m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], sp_crit_sed=self.params['sp_crit_sed'], sp_crit_br=self.params['sp_crit_br'], method=self.params['method'], discharge_method=self.params['discharge_method'], area_field=area_field, discharge_field=discharge_field) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Route flow self.flow_router.run_one_step() self.lake_filler.map_depressions() # Get IDs of flooded nodes, if any flooded = np.where(self.lake_filler.flood_status == 3)[0] # Do some erosion (but not on the flooded nodes) self.eroder.run_one_step(dt, flooded_nodes=flooded)
def test_composite_pits(): """ A test to ensure the component correctly handles cases where there are multiple pits, inset into each other. """ mg = RasterModelGrid(10, 10, 1.) z = mg.add_field("node", "topographic__elevation", mg.node_x.copy()) # a sloping plane # np.random.seed(seed=0) # z += np.random.rand(100)/10000. # punch one big hole z.reshape((10, 10))[3:8, 3:8] = 0. # dig a couple of inset holes z[57] = -1. z[44] = -2. z[54] = -10. # make an outlet z[71] = 0.9 fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() flow_sinks_target = np.zeros(100, dtype=bool) flow_sinks_target[mg.boundary_nodes] = True # no internal sinks now: assert_array_equal(mg.at_node["flow__sink_flag"], flow_sinks_target) # test conservation of mass: assert mg.at_node["drainage_area"].reshape((10, 10))[1:-1, 1].sum() == approx( 8. ** 2 ) # ^all the core nodes # test the actual flow field: # nA = np.array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., # 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 1., 1., 1., 4., 2., 2., 8., 4., 1., 0., # 1., 1., 1., 8., 3., 15., 3., 2., 1., 0., # 1., 1., 1., 13., 25., 6., 3., 2., 1., 0., # 1., 1., 1., 45., 3., 3., 5., 2., 1., 0., # 50., 50., 49., 3., 2., 2., 2., 4., 1., 0., # 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., # 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]) nA = np.array( [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 1., 1., 1., 4., 2., 2., 6., 4., 1., 0., 1., 1., 1., 6., 3., 12., 3., 2., 1., 0., 1., 1., 1., 8., 20., 4., 3., 2., 1., 0., 1., 1., 1., 35., 5., 4., 3., 2., 1., 0., 50., 50., 49., 13., 10., 8., 6., 4., 1., 0., 1., 1., 1., 1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., ] ) assert_array_equal(mg.at_node["drainage_area"], nA) # the lake code map: lc = np.array( [ XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, 57, 57, 57, 57, 57, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, ] ) # test the remaining properties: assert lf.lake_outlets.size == 1 assert lf.lake_outlets[0] == 72 outlets_in_map = np.unique(lf.depression_outlet_map) assert outlets_in_map.size == 2 assert outlets_in_map[1] == 72 assert lf.number_of_lakes == 1 assert lf.lake_codes[0] == 57 assert_array_equal(lf.lake_map, lc) assert lf.lake_areas[0] == approx(25.) assert lf.lake_volumes[0] == approx(63.)
from landlab.components import FlowRouter, FastscapeEroder, SteepnessFinder import numpy as np from landlab import RasterModelGrid, CLOSED_BOUNDARY from landlab.plot.imshow import imshow_grid_at_node import matplotlib.pyplot as plt mg = RasterModelGrid((200, 200), 100.) z = mg.add_zeros('node', 'topographic__elevation') z += np.random.rand(mg.number_of_nodes) mg.status_at_node[mg.nodes_at_left_edge] = CLOSED_BOUNDARY mg.status_at_node[mg.nodes_at_right_edge] = CLOSED_BOUNDARY fr = FlowRouter(mg) sp = FastscapeEroder(mg, K_sp=1.e-5) sf = SteepnessFinder(mg, min_drainage_area=1.e5) dt = 20000. for i in xrange(100): print(i) fr.route_flow() sp.run_one_timestep(dt) mg.at_node['topographic__elevation'][mg.core_nodes] += 1. sf.calculate_steepnesses() edges = mg.ones('node', dtype=bool) edges.reshape(mg.shape)[2:-2, 2:-2] = False steepness_mask = np.logical_or(sf.hillslope_mask, edges)
Ksp = np.array(dfList) # Set uplift rate uplift_rate = 0.0001 # [m/yr] m_sp = 0.5 n_sp = 1. ### Initialize components # Set initial surface_water__discharge rmg['node']['surface_water__discharge'] = np.zeros(rmg.number_of_nodes) Q = rmg.at_node['surface_water__discharge'] ### Initialize components # Flow router using D8 Flow Director (default FD) fr = FlowRouter(rmg) # Stream Power Eroder (erosion by water) sp = StreamPowerEroder(rmg, K_sp=Ksp, m_sp=m_sp, n_sp=n_sp, threshold_sp=0, use_Q=Q) # Set up LEM def run_LEM(years): # Create list for saving rainfall rainOutput = []
def test_degenerate_drainage(): """ This "hourglass" configuration should be one of the hardest to correctly re-route. """ mg = RasterModelGrid(9, 5) z_init = mg.node_x.copy() * 0.0001 + 1. lake_pits = np.array([7, 11, 12, 13, 17, 27, 31, 32, 33, 37]) z_init[lake_pits] = -1. z_init[22] = 0. # the common spill pt for both lakes z_init[21] = 0.1 # an adverse bump in the spillway z_init[20] = -0.2 # the spillway z = mg.add_field("node", "topographic__elevation", z_init) fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() # correct_A = np.array([ 0., 0., 0., 0., 0., # 0., 1., 3., 1., 0., # 0., 5., 1., 2., 0., # 0., 1., 10., 1., 0., # 21., 21., 1., 1., 0., # 0., 1., 9., 1., 0., # 0., 3., 1., 2., 0., # 0., 1., 1., 1., 0., # 0., 0., 0., 0., 0.]) correct_A = np.array( [ 0., 0., 0., 0., 0., 0., 1., 3., 1., 0., 0., 2., 4., 2., 0., 0., 1., 10., 1., 0., 21., 21., 1., 1., 0., 0., 1., 9., 1., 0., 0., 2., 2., 2., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0., ] ) thelake = np.concatenate((lake_pits, [22])).sort() assert mg.at_node["drainage_area"] == approx(correct_A)
k[:] = k_unerodible #for hard rock mg['node']['K_values'] = k elif hard_layer_on_or_off == 0: k[:] = k_erodible #soft rock else: print 'WARNING: MUST SELECT 0 OR 1 IN LAYERED PARAM' #set up its boundary conditions (left, top, right, bottom is inactive) mg.set_closed_boundaries_at_grid_edges(False, True, False, True) # Display initialization message print('Running ...') #instantiate the components: pr = PrecipitationDistribution(input_file) fr = Flow(mg) sp = Fsc(mg, input_file) hd = Diff(mg, input_file) ####################RUN track_uplift = 0 #track cumulative uplift to know top of hard layer last_trunc = runtime for (interval_duration, rainfall_rate) in pr.yield_storm_interstorm_duration_intensity(): if rainfall_rate != 0.: # note diffusion also only happens when it's raining... _ = fr.route_flow() _ = sp.erode(mg, interval_duration, K_if_used='K_values') _ = hd.diffuse(interval_duration) track_uplift += uplift_rate * interval_duration #top of beginning surface mg.at_node['topographic__elevation'][mg.core_nodes] += uplift_rate * interval_duration this_trunc = pr.elapsed_time // t_plot
def get_ordered_cells_for_soil_moisture(grid, outlet_id=None): """ Runs Landlab's FlowRouter and DepressionFinderAndRouter to route flow. Also orders the cells in the descending order of channel length (upstream cell order). Parameters: ========== grid: grid object RasterModelGrid outlet_id: int (Optional) Outlet id to be set Returns: ======= ordered_cells: np.array(dtype=int) cells ordered in descending order of channel length grid: grid object updated RasterModelGrid """ if outlet_id == None: outlet_id = np.argmin(grid.at_node['topographic__elevation']) outlet = grid.set_watershed_boundary_condition_outlet_id(outlet_id, grid.at_node['topographic__elevation'], nodata_value=-9999.,) grid.set_closed_boundaries_at_grid_edges(True, True, True, True) flw_r = FlowRouter(grid) flw_r.run_one_step() df = DepressionFinderAndRouter(grid) df.map_depressions() r = grid.at_node['flow__receiver_node'][grid.node_at_core_cell] R = np.zeros(grid.number_of_nodes, dtype=int) R[grid.node_at_core_cell] = r channel_length = np.zeros(grid.number_of_nodes, dtype=int) # Compute channel lengths for each node in the wtrshd (node_at_core_cell) for node in grid.node_at_core_cell: node_c = node.copy() while R[node_c] != node_c: channel_length[node] += 1 node_c = R[node_c] grid.at_node['channel_length'] = channel_length # Sorting nodes in the ascending order of channel length # NOTE: length of ordered_nodes = grid.number_of_core_cells ordered_nodes = grid.node_at_core_cell[ np.argsort(channel_length[grid.node_at_core_cell])] # Sorting nodes in the descending order of channel length ordered_nodes = ordered_nodes[::-1] dd = 1 # switch 2 for while loop count_loops = 0 # No. of loops while runs while dd: dd = 0 count_loops += 1 sorted_order = list(ordered_nodes) alr_counted_ = [] for node_ in sorted_order: donors = [] donors = list(grid.node_at_core_cell[np.where(r==node_)[0]]) if len(donors) != 0: for k in range(0, len(donors)): if donors[k] not in alr_counted_: sorted_order.insert(donors[k], sorted_order.pop(sorted_order.index(node_))) dd = 1 alr_counted_.append(node_) ordered_nodes = np.array(sorted_order) ordered_cells = grid.cell_at_node[ordered_nodes] return ordered_cells, grid
def test_three_pits(): """ A test to ensure the component correctly handles cases where there are multiple pits. """ mg = RasterModelGrid(10, 10, 1.) z = mg.add_field("node", "topographic__elevation", mg.node_x.copy()) # a sloping plane # np.random.seed(seed=0) # z += np.random.rand(100)/10000. # punch some holes z[33] = 1. z[43] = 1. z[37] = 4. z[74:76] = 1. fr = FlowRouter(mg) lf = DepressionFinderAndRouter(mg) fr.route_flow() lf.map_depressions() flow_sinks_target = np.zeros(100, dtype=bool) flow_sinks_target[mg.boundary_nodes] = True # no internal sinks now: assert_array_equal(mg.at_node["flow__sink_flag"], flow_sinks_target) # test conservation of mass: assert mg.at_node["drainage_area"].reshape((10, 10))[1:-1, 1].sum() == approx( 8. ** 2 ) # ^all the core nodes # test the actual flow field: nA = np.array( [ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 8., 8., 7., 6., 5., 4., 3., 2., 1., 0., 2., 2., 1., 1., 2., 1., 1., 1., 1., 0., 26., 26., 25., 15., 11., 10., 9., 8., 1., 0., 2., 2., 1., 9., 2., 1., 1., 1., 1., 0., 2., 2., 1., 1., 5., 4., 3., 2., 1., 0., 2., 2., 1., 1., 1., 1., 3., 2., 1., 0., 20., 20., 19., 18., 17., 12., 3., 2., 1., 0., 2., 2., 1., 1., 1., 1., 3., 2., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., ] ) assert_array_equal(mg.at_node["drainage_area"], nA) # test a couple more properties: lc = np.empty(100, dtype=int) lc.fill(XX) lc[33] = 33 lc[43] = 33 lc[37] = 37 lc[74:76] = 74 assert_array_equal(lf.lake_map, lc) assert_array_equal(lf.lake_codes, [33, 37, 74]) assert lf.number_of_lakes == 3 assert lf.lake_areas == approx([2., 1., 2.]) assert lf.lake_volumes == approx([2., 2., 4.])