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 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 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 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
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()
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]))
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)
## Landscape Evolution ## # Now that we have performed the tectonic deformation, lets apply our # landscape evolution and watch the landscape change as a result. # Uplift the landscape rmg['node']['topographic__elevation'][rmg.core_nodes] += uplift_rate * dt # set the lower boundary as fixed elevation rmg['node']['topographic__elevation'][rmg.node_y == 0] = 0 # Diffuse the landscape simulating hillslope sediment transport lin_diffuse.run_one_step(dt) # Accumulate and route flow, fill any lakes, and erode under the rivers fr.run_one_step() # route flow DepressionFinderAndRouter.map_depressions(fill) # fill lakes sp.run_one_step(dt) # fastscape stream power eroder ## Calculate the geomorphic metric ## # In the paper, we use a geomorphic metric, BR, to quantify the # reorientation of the channels as time goes on. The code to calculate this # value is below but turned off as it can slow the model. Set the # 'calculate_BR' variable to 'True' if you want to calculate it. if calculate_BR: aspects = rmg.calc_aspect_at_node() # measure pixel aspect # classify and count the number of pixels with certain directions
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) ## Plotting the topography plt.figure(1) imshow_grid(rmg1, 'topographic__elevation') #need to run for about 4000 time steps, or 4,000,000 years to reach SS
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.set_watershed_boundary_condition(z,remove_disconnected=True) fig=plt.figure(figsize=(8,6)) fig.suptitle('Kd='+str(lin_dif)+' Ks='+str(K_sp)+' U='+str(uplift_rate)+'\n\n') ax1=fig.add_subplot(221) ax2=fig.add_subplot(222,sharex=ax1,sharey=ax1)
#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() np.save('iniTopo',z)
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)
#### Instantiate process components ld1 = LinearDiffuser(rmg1, linear_diffusivity=0.3) ### parameters defined fr1 = FlowRouter(rmg1, method='D8') #slp1 = FlowRouter(slps,method='D8') fse1 = FastscapeEroder(rmg1, K_sp = 1e-5, m_sp=0.5, n_sp=1.) ### parameters defined ## Set some variables rock_up_rate = 1e-4 # m/yr # uplift rate ### parameter defined dt = 1000 # yr rock_up_len = dt*rock_up_rate # m ## Time loop where evolution happens for i in range(50000): 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, as this is not time sensitive fse1.run_one_step(dt) #fluvial incision happens ## optional print statement # print('i', i) ## Plotting the topography plt.figure(1) imshow_grid(rmg1, 'topographic__elevation', grid_units = ['m','m'], var_name='Elevation (m)') plt.savefig('diffusive_%i.png' %seed_n) plt.close() #need to run for about 4000 time steps, or 4,000,000 years to reach SS ################### Waterhsed 2 ############################################## ###### Instantiate process 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() lake.map_depressions() spr.run_one_step(dt, flooded_nodes=lake.lake_at_node) keep_running = np.mean(np.abs(zr - zr_last)) >= end_thresh ti += dt print ti/1000., 'kyr elapsed; ', np.mean(zr-zr_last) / dt * 1E6, \ 'um/yr surface uplift' print "Convergence reached! Landscape is at steady state." A = mg.at_node['drainage_area']#[not_edge] A = A.reshape(ncells_side, ncells_side) S = mg.at_node['topographic__steepest_slope'] S = S.reshape(ncells_side, ncells_side) np.savetxt('Synthetic_data/z.txt', zr, fmt='%.2f') np.savetxt('Synthetic_data/A.txt', A, fmt='%d')
class StochasticDischargeHortonianModel(_ErosionModel): """ A StochasticDischargeHortonianModel generates a random sequency of runoff events across a topographic surface, calculating the resulting water discharge at each node. """ 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 reset_random_seed(self): """Re-set the random number generation sequence.""" try: seed = self.params['random_seed'] except KeyError: seed = 0 self.rain_generator.seed_generator(seedval=seed) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Calculate discharge field area = self.grid.at_node['drainage_area'] if self.infilt > 0.0: runoff = self.rain_rate - (self.infilt * (1.0 - np.exp(-self.rain_rate / self.infilt))) else: runoff = self.rain_rate self.discharge[:] = runoff * area def run_for(self, dt, runtime): """ Run model without interruption for a specified time period. """ self.rain_generator.delta_t = dt self.rain_generator.run_time = runtime for (tr, p) in self.rain_generator.yield_storm_interstorm_duration_intensity(): self.rain_rate = p self.run_one_step(tr) def write_storm_sequence_to_file(self, filename=None): """ Write event duration and intensity to a formatted text file. """ # Re-seed the random number generator, so we get the same sequence. self.reset_random_seed() # Generate a set of event parameters. This is needed because the # PrecipitationDistribution component automatically generates a # parameter set on initialization. Therefore, to get to the same # starting point that we used in the sequence-through-time, we need # to regenerate these. self.rain_generator.get_precipitation_event_duration() self.rain_generator.get_interstorm_event_duration() self.rain_generator.get_storm_depth() self.rain_generator.get_storm_intensity() # Open a file for writing if filename is None: filename = 'event_sequence.txt' stormfile = open(filename, 'w') # Set the generator's time step and run time to the full duration of # the run. This ensures that we get a sequence that is as long as the # model run, and does not split events by time step (unlike the actual # model run) self.rain_generator.delta_t = self.params['run_duration'] self.rain_generator.run_time = self.params['run_duration'] tt = 0.0 for (tr, p) in self.rain_generator.yield_storm_interstorm_duration_intensity(): runoff = p - self.infilt * (1.0 - np.exp(-p / self.infilt)) stormfile.write(str(tt) + ',' + str(p) + ',' + str(runoff) + '\n') tt += tr stormfile.write(str(tt) + ',' + str(p) + ',' + str(runoff) + '\n') # Close the file stormfile.close()
class StreamPowerVarThresholdModel(_ErosionModel): """ A StreamPowerVarThresholdModel computes erosion using a form of the unit stream power model that represents a threshold using an exponential term. The threshold value itself depends on incision depth below an initial reference surface. This is meant to mimic coarsening of sediment in the channel with progressive incision, similar to the model of Gran et al. (2013) """ 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'] 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] # Set the erosion threshold. # # Note that a minus sign is used because cum ero depth is negative for # erosion, positive for deposition. # The second line handles the case where there is growth, in which case # we want the threshold to stay at its initial value rather than # getting smaller. cum_ero = self.grid.at_node['cumulative_erosion__depth'] cum_ero[:] = (self.z - self.grid.at_node['initial_topographic__elevation']) self.threshold[:] = (self.params['threshold_sp'] - (self.thresh_change_per_depth * cum_ero)) self.threshold[self.threshold < self.params['threshold_sp']] = \ self.params['threshold_sp'] # Do some erosion (but not on the flooded nodes) self.eroder.run_one_step(dt, flooded_nodes=flooded)
def draw_profile_evolution(start, stop, step, format, directory='.', force_same_nodes=False, plot_field_downstream=None, different_runs_different_plots=True): """Plot a set of long profiles, loaded from saved data. "format" is the number of numbers in the file string. e.g., "00150" is 5. "012345" is 6. "plot_field_downstream" is the string of a field at which values should also be plotted, on a second figure. """ mg2 = deepcopy(mg) z2 = mg2.add_zeros('node', 'topographic__elevation', noclobber=False) fr2 = FlowRouter(mg2) first = True for i in xrange(start, stop, step): num_zeros = format - len(str(i)) numberstr = '0' * num_zeros + str(i) + '_' # search for this string as a topo: prefixed = [ filename for filename in os.listdir(directory) if filename.startswith('topographic__elevation_' + numberstr) ] # grab the unique ID, so we can differentiate plots (if desired) unique_ID = prefixed[0][-14:-4] print('Plotting the profile with unique ID: ' + unique_ID) try: z2[:] = np.loadtxt(directory + '/' + prefixed[0]) except IndexError: raise IndexError( "it's likely you've mis-set directory, or end is out of range") if plot_field_downstream is not None: prefixedvals = [ filename for filename in os.listdir(directory) if filename.startswith(plot_field_downstream + '_' + numberstr) ] field_vals = np.loadtxt(directory + '/' + prefixedvals[0]) fr2.run_one_step() if force_same_nodes: if first: if different_runs_different_plots: draw_profile(mg2, figure_name=('profile_' + unique_ID)) else: draw_profile(mg2) first = False if plot_field_downstream is not None: if different_runs_different_plots: figure('field_values_downstream_' + unique_ID) else: figure('field_values_downstream') plot(ch_dists[0], field_vals[profile_IDs[0]]) else: if different_runs_different_plots: figure('profile_' + unique_ID) else: figure('profile') plot(ch_dists[0], mg2.at_node['topographic__elevation'][profile_IDs[0]]) if plot_field_downstream is not None: if different_runs_different_plots: figure('field_values_downstream_' + unique_ID) else: figure('field_values_downstream') plot(ch_dists[0], field_vals[profile_IDs[0]]) else: if different_runs_different_plots: draw_profile(mg2, figure_name=('profile_' + unique_ID)) else: draw_profile(mg2) if plot_field_downstream is not None: 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']) if different_runs_different_plots: figure('field_values_downstream_' + unique_ID) else: figure('field_values_downstream') plot(ch_dists[0], field_vals[profile_IDs[0]]) if plot_field_downstream is not None: if different_runs_different_plots: figure('field_values_downstream_' + unique_ID) else: figure('field_values_downstream') xlabel('Distance downstream (m)') ylabel('Field value')
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
model_run_time = durations_s[i] + (interstorm_durs[i] * 3600.) storm_events.append( [durations[i], intensities[i], durations[i] * intensities[i]]) dt = float(durations_s[i]) uplift_dt = float(durations_s[i] + (interstorm_durs[i] * 3600.)) * 3.17098e-8 rainfall_ms = intensities[i] * 2.777777777778e-7 fr = FlowRouter(rmg, method='D4', runoff_rate=float(rainfall_ms)) fr1 = FlowRouter(rmg1, method='D4', runoff_rate=float(rainfall_ms)) fr5 = FlowRouter(rmg5, method='D4', runoff_rate=float(rainfall_ms)) fr10 = FlowRouter(rmg10, method='D4', runoff_rate=float(rainfall_ms)) fr.run_one_step() fr1.run_one_step() fr5.run_one_step() fr10.run_one_step() last_z = copy.deepcopy(z) last_z1 = copy.deepcopy(z1) last_z5 = copy.deepcopy(z5) last_z10 = copy.deepcopy(z10) rmg, z, _ = dle.erode(rmg, dt=dt) rmg1, z1, e1 = dle1.erode(rmg1, dt=dt) rmg5, z5, e5 = dle5.erode(rmg5, dt=dt) rmg10, z10, e10 = dle10.erode(rmg10, dt=dt) total_incision_depth += last_z - z