def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicHyRt.""" # Call ErosionModel's init super(BasicHyRt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) contact_zone__width = (self._length_factor * self.params['contact_zone__width']) # L self.K_rock_sp = self.get_parameter_from_exponent('K_rock_sp') self.K_till_sp = self.get_parameter_from_exponent('K_till_sp') linear_diffusivity = ( (self._length_factor**2) * self.get_parameter_from_exponent('linear_diffusivity')) v_sc = self.get_parameter_from_exponent( 'v_sc') # normalized settling velocity. Unitless. # Set up rock-till self.setup_rock_and_till(self.params['rock_till_file__name'], rock_erody_br=self.K_rock_sp, till_erody_br=self.K_till_sp, rock_thresh_br=0.0, till_thresh_br=0.0, contact_width=contact_zone__width) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Handle solver option try: solver = self.params['solver'] except: solver = 'original' # Instantiate an ErosionDeposition ("hybrid") component self.eroder = ErosionDeposition(self.grid, K='K_br', F_f=self.params['F_f'], phi=self.params['phi'], v_s=v_sc, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], method='simple_stream_power', discharge_method='drainage_area', area_field='drainage_area', solver=solver) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def test_assertion_error(): """Test that the correct assertion error will be raised.""" mg = RasterModelGrid(10, 10) z = mg.add_zeros('topographic__elevation', at='node') z += 200 + mg.x_of_node + mg.y_of_node + np.random.randn(mg.size('node')) mg.set_closed_boundaries_at_grid_edges(bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True) mg.set_watershed_boundary_condition_outlet_id(0, z, -9999) fa = FlowAccumulator(mg, flow_director='D8', depression_finder=DepressionFinderAndRouter) sp = FastscapeEroder(mg, K_sp=.0001, m_sp=.5, n_sp=1) ld = LinearDiffuser(mg, linear_diffusivity=0.0001) dt = 100 for i in range(200): fa.run_one_step() flooded = np.where(fa.depression_finder.flood_status==3)[0] sp.run_one_step(dt=dt, flooded_nodes=flooded) ld.run_one_step(dt=dt) mg.at_node['topographic__elevation'][0] -= 0.001 # Uplift assert_raises(AssertionError, analyze_channel_network_and_plot, mg, threshold = 100, starting_nodes = [0], number_of_channels=2)
def test_assertion_error(): """Test that the correct assertion error will be raised.""" mg = RasterModelGrid(10, 10) z = mg.add_zeros('topographic__elevation', at='node') z += 200 + mg.x_of_node + mg.y_of_node + np.random.randn(mg.size('node')) mg.set_closed_boundaries_at_grid_edges(bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True) mg.set_watershed_boundary_condition_outlet_id(0, z, -9999) fa = FlowAccumulator(mg, depression_finder=DepressionFinderAndRouter) sp = FastscapeEroder(mg, K_sp=.0001, m_sp=.5, n_sp=1) ld = LinearDiffuser(mg, linear_diffusivity=0.0001) dt = 100 for i in range(200): fa.run_one_step() flooded = np.where(fa.depression_finder.flood_status == 3)[0] sp.run_one_step(dt=dt, flooded_nodes=flooded) ld.run_one_step(dt=dt) mg.at_node['topographic__elevation'][0] -= 0.001 # Uplift assert_raises(AssertionError, analyze_channel_network_and_plot, mg, threshold=100, starting_nodes=[0], number_of_channels=2)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """ Initialize the BasicDdHy """ # Call ErosionModel's init super(BasicDdHy, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) # Get Parameters and convert units if necessary: self.K_sp = self.get_parameter_from_exponent('K_sp') linear_diffusivity = ( (self._length_factor**2) # L2/T * self.get_parameter_from_exponent('linear_diffusivity')) v_s = self.get_parameter_from_exponent('v_sc') # unitless self.sp_crit = ( self._length_factor # L/T * self.get_parameter_from_exponent('erosion__threshold')) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros('node', 'erosion__threshold') self.threshold[:] = self.sp_crit #starting value # Handle solver option try: solver = self.params['solver'] except: solver = 'original' # Instantiate an ErosionDeposition component self.eroder = ErosionDeposition(self.grid, K=self.K_sp, F_f=self.params['F_f'], phi=self.params['phi'], v_s=v_s, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], sp_crit='erosion__threshold', method='threshold_stream_power', discharge_method='drainage_area', area_field='drainage_area', solver=solver) # Get the parameter for rate of threshold increase with erosion depth self.thresh_change_per_depth = self.params['thresh_change_per_depth'] # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def test_assertion_error(): """Test that the correct assertion error will be raised.""" mg = RasterModelGrid((10, 10)) z = mg.add_zeros("topographic__elevation", at="node") z += 200 + mg.x_of_node + mg.y_of_node + np.random.randn(mg.size("node")) mg.set_closed_boundaries_at_grid_edges( bottom_is_closed=True, left_is_closed=True, right_is_closed=True, top_is_closed=True, ) mg.set_watershed_boundary_condition_outlet_id(0, z, -9999) fa = FlowAccumulator(mg, flow_director="D8", depression_finder=DepressionFinderAndRouter) sp = FastscapeEroder(mg, K_sp=0.0001, m_sp=0.5, n_sp=1, erode_flooded_nodes=True) ld = LinearDiffuser(mg, linear_diffusivity=0.0001) dt = 100 for i in range(200): fa.run_one_step() sp.run_one_step(dt=dt) ld.run_one_step(dt=dt) mg.at_node["topographic__elevation"][0] -= 0.001 # Uplift with pytest.raises(ValueError): ChannelProfiler(mg, outlet_nodes=[0], number_of_watersheds=2)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicVsRt.""" # Call ErosionModel's init super(BasicVsRt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) contact_zone__width = (self._length_factor) * self.params[ 'contact_zone__width'] # has units length self.K_rock_sp = self.get_parameter_from_exponent('K_rock_sp') self.K_till_sp = self.get_parameter_from_exponent('K_till_sp') linear_diffusivity = ( self._length_factor** 2.) * self.get_parameter_from_exponent('linear_diffusivity') recharge_rate = (self._length_factor) * self.params[ 'recharge_rate'] # has units length per time soil_thickness = (self._length_factor) * self.params[ 'initial_soil_thickness'] # has units length K_hydraulic_conductivity = (self._length_factor) * self.params[ 'K_hydraulic_conductivity'] # has units length per time # Set up rock-till self.setup_rock_and_till(self.params['rock_till_file__name'], self.K_rock_sp, self.K_till_sp, contact_zone__width) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Add a field for effective drainage area if 'effective_drainage_area' in self.grid.at_node: self.eff_area = self.grid.at_node['effective_drainage_area'] else: self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = (K_hydraulic_conductivity * soil_thickness * self.grid.dx) / (recharge_rate) # Instantiate a FastscapeEroder component self.eroder = StreamPowerEroder(self.grid, K_sp=self.erody, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], use_Q=self.eff_area) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicVs.""" # Call ErosionModel's init super(BasicVs, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) # Get Parameters: K_sp = self.get_parameter_from_exponent('K_sp', raise_error=False) K_ss = self.get_parameter_from_exponent('K_ss', raise_error=False) linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') # has units length^2/time recharge_rate = (self._length_factor)*self.params['recharge_rate'] # has units length per time soil_thickness = (self._length_factor)*self.params['initial_soil_thickness'] # has units length K_hydraulic_conductivity = (self._length_factor)*self.params['K_hydraulic_conductivity'] # has units length per time # check that a stream power and a shear stress parameter have not both been given if K_sp != None and K_ss != None: raise ValueError('A parameter for both K_sp and K_ss has been' 'provided. Only one of these may be provided') elif K_sp != None or K_ss != None: if K_sp != None: self.K = K_sp else: self.K = (self._length_factor**(1./3.))*K_ss # K_ss has units Lengtg^(1/3) per Time else: raise ValueError('A value for K_sp or K_ss must be provided.') # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # Add a field for effective drainage area if 'effective_drainage_area' in self.grid.at_node: self.eff_area = self.grid.at_node['effective_drainage_area'] else: self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = (K_hydraulic_conductivity*soil_thickness*self.grid.dx)/(recharge_rate) # Instantiate a FastscapeEroder component self.eroder = StreamPowerEroder(self.grid, use_Q=self.eff_area, K_sp=self.K, m_sp=self.params['m_sp'], n_sp=self.params['n_sp']) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the LinDifSPThresholdModel.""" # Call ErosionModel's init super(BasicTh, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) # Get Parameters and convert units if necessary: K_sp = self.get_parameter_from_exponent('K_sp', raise_error=False) K_ss = self.get_parameter_from_exponent('K_ss', raise_error=False) linear_diffusivity = ( self._length_factor**2.) * self.get_parameter_from_exponent( 'linear_diffusivity') # has units length^2/time # threshold has units of Length per Time which is what # StreamPowerSmoothThresholdEroder expects threshold = self._length_factor * self.get_parameter_from_exponent( 'erosion__threshold') # has units length/time # check that a stream power and a shear stress parameter have not both been given if K_sp != None and K_ss != None: raise ValueError('A parameter for both K_sp and K_ss has been' 'provided. Only one of these may be provided') elif K_sp != None or K_ss != None: if K_sp != None: self.K = K_sp else: self.K = (self._length_factor**( 1. / 3.)) * K_ss # K_ss has units Lengtg^(1/3) per Time else: raise ValueError('A value for K_sp or K_ss must be provided.') # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.K, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], threshold_sp=threshold) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the VSADepthDepThresholdModel.""" # Call ErosionModel's init super(BasicDdVs, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) self.K_sp = self.get_parameter_from_exponent('K_sp') linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') # has units length^2/time recharge_rate = (self._length_factor)*self.params['recharge_rate'] # has units length per time soil_thickness = (self._length_factor)*self.params['initial_soil_thickness'] # has units length K_hydraulic_conductivity = (self._length_factor)*self.params['K_hydraulic_conductivity'] # has units length per time self.threshold_value = self._length_factor*self.get_parameter_from_exponent('erosion__threshold') # has units length/time # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # Add a field for effective drainage area if 'effective_drainage_area' in self.grid.at_node: self.eff_area = self.grid.at_node['effective_drainage_area'] else: self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = (K_hydraulic_conductivity*soil_thickness*self.grid.dx)/(recharge_rate) # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros('node', 'erosion__threshold') self.threshold[:] = self.threshold_value # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder(self.grid, use_Q=self.eff_area, K_sp=self.K_sp, m_sp=self.params['m_sp'], n_sp=self.params['n_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'] # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the Basic model.""" # Call ErosionModel's init super(Basic, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) # Get Parameters: K_sp = self.get_parameter_from_exponent('K_sp', raise_error=False) K_ss = self.get_parameter_from_exponent('K_ss', raise_error=False) linear_diffusivity = ( self._length_factor**2.) * self.get_parameter_from_exponent( 'linear_diffusivity') # has units length^2/time # check that a stream power and a shear stress parameter have not both been given if K_sp != None and K_ss != None: raise ValueError('A parameter for both K_sp and K_ss has been' 'provided. Only one of these may be provided') elif K_sp != None or K_ss != None: if K_sp != None: self.K = K_sp else: self.K = (self._length_factor**( 1. / 3.)) * K_ss # K_ss has units Lengtg^(1/3) per Time else: raise ValueError('A value for K_sp or K_ss must be provided.') # run the sink filler, only on initiation. sink_filler = SinkFiller(self.grid, apply_slope=True, fill_slope=1e-3) sink_filler.run_one_step() # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Instantiate a FastscapeEroder component self.eroder = FastscapeEroder(self.grid, K_sp=self.K, m_sp=self.params['m_sp'], n_sp=self.params['n_sp']) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the StochasticRainThresholdModel.""" # Call ErosionModel's init super(BasicThSt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) K_stoch_sp = self.get_parameter_from_exponent('K_stochastic_sp') linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') # has units length^2/time # threshold has units of Length per Time which is what # StreamPowerSmoothThresholdEroder expects threshold = self._length_factor*self.get_parameter_from_exponent('erosion__threshold') # has units length/time # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # instantiate rain generator self.instantiate_rain_generator() # 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 infiltration_capacity = (self._length_factor)*self.params['infiltration_capacity']# has units length per time self.infilt = infiltration_capacity # Keep a reference to drainage area self.area = self.grid.at_node['drainage_area'] # Run flow routing and lake filler self.flow_router.run_one_step() # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder(self.grid, K_sp=K_stoch_sp, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], threshold_sp=threshold, use_Q=self.discharge) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity)
def test_depression_finder_bad_instance(): mg = RasterModelGrid((5, 5), spacing=(1, 1)) z = mg.add_field("topographic__elevation", mg.node_x + mg.node_y, at="node") ld = LinearDiffuser(mg, linear_diffusivity=1.) with pytest.raises(ValueError): fa = FlowAccumulator(mg, flow_director="D8", depression_finder=ld)
def test_stream_power_save_output(tmpdir): mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.set_status_at_node_on_edges( right=mg.BC_NODE_IS_CLOSED, top=mg.BC_NODE_IS_CLOSED, left=mg.BC_NODE_IS_CLOSED, bottom=mg.BC_NODE_IS_FIXED_VALUE, ) 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) 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, RasterModelGrid) assert set(mg1.at_node.keys()) == set(keys) assert_equal(mg1.status_at_node, mg.status_at_node)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicDdRt.""" # Call ErosionModel's init super(BasicDdRt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) contact_zone__width = (self._length_factor)*self.params['contact_zone__width'] # has units length self.K_rock_sp = self.get_parameter_from_exponent('K_rock_sp') self.K_till_sp = self.get_parameter_from_exponent('K_till_sp') linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') self.threshold_value = self._length_factor*self.get_parameter_from_exponent('erosion__threshold') # has units length/time # Set up rock-till self.setup_rock_and_till(self.params['rock_till_file__name'], self.K_rock_sp, self.K_till_sp, contact_zone__width) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros('node', 'erosion__threshold') self.threshold[:] = self.threshold_value # Instantiate a StreamPowerSmoothThresholdEroder component self.eroder = StreamPowerSmoothThresholdEroder(self.grid, K_sp=self.erody, m_sp=self.params['m_sp'], n_sp=self.params['n_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'] # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicThRt.""" # Call ErosionModel's init super(BasicThRt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) contact_zone__width = (self._length_factor)*self.params['contact_zone__width'] # has units length self.K_rock_sp = self.get_parameter_from_exponent('K_rock_sp') self.K_till_sp = self.get_parameter_from_exponent('K_till_sp') rock_erosion__threshold = self.get_parameter_from_exponent('rock_erosion__threshold') till_erosion__threshold = self.get_parameter_from_exponent('till_erosion__threshold') linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') # Set up rock-till self.setup_rock_and_till(self.params['rock_till_file__name'], self.K_rock_sp, self.K_till_sp, rock_erosion__threshold, till_erosion__threshold, contact_zone__width) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # Instantiate a StreamPowerSmoothThresholdEroder component self.eroder = StreamPowerSmoothThresholdEroder(self.grid, K_sp=self.erody, threshold_sp=self.threshold, m_sp=self.params['m_sp'], n_sp=self.params['n_sp']) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity)
def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicCv model.""" # Call ErosionModel's init super(BasicCv, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) K_sp = self.get_parameter_from_exponent('K_sp') linear_diffusivity = ( self._length_factor** 2.) * self.get_parameter_from_exponent('linear_diffusivity') self.climate_factor = self.params['climate_factor'] self.climate_constant_date = self.params['climate_constant_date'] time = [0, self.climate_constant_date, self.params['run_duration']] K = [K_sp * self.climate_factor, K_sp, K_sp] self.K_through_time = interp1d(time, K) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Instantiate a FastscapeEroder component self.eroder = FastscapeEroder(self.grid, K_sp=K[0], m_sp=self.params['m_sp'], n_sp=self.params['n_sp']) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity)
def test_stream_power_run_model_subdivide(): mg = RasterModelGrid((3, 3), xy_spacing=10.0) mg.set_status_at_node_on_edges( right=mg.BC_NODE_IS_CLOSED, top=mg.BC_NODE_IS_CLOSED, left=mg.BC_NODE_IS_CLOSED, bottom=mg.BC_NODE_IS_FIXED_VALUE, ) z = mg.add_ones("node", "topographic__elevation") z[1] = 1e-15 zb = 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) 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) mdl = StreamPowerModel( mg, hydrology_model=hm, diffusion_model=ld, erosion_model=sp, regolith_model=rm, total_morphological_time=1e8, maximum_morphological_dt=2e7, ) mdl.run_step(1e5, dt_m_max=2e4) assert z[4] < 1.0 assert_equal(z[4] - zb[4], 1.0) assert_equal(mdl.num_substeps, 5)
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 if this_trunc != last_trunc: # time to plot a new profile! print ('Time %d' % (t_plot * this_trunc))
class BasicThSt(_StochasticErosionModel): """ A BasicThSt computes erosion using (1) unit stream power with a threshold, (2) linear nhillslope diffusion, and (3) generation of a random sequence of runoff events across a topographic surface. Examples -------- >>> from erosion_model import StochasticRainThresholdModel >>> my_pars = {} >>> my_pars['dt'] = 1.0 >>> my_pars['run_duration'] = 1.0 >>> my_pars['infiltration_capacity'] = 1.0 >>> my_pars['K_sp'] = 1.0 >>> my_pars['threshold_sp'] = 1.0 >>> my_pars['linear_diffusivity'] = 0.01 >>> my_pars['mean_storm_duration'] = 0.002 >>> my_pars['mean_interstorm_duration'] = 0.008 >>> my_pars['mean_storm_depth'] = 0.025 >>> srt = StochasticRainThresholdModel(params=my_pars) Warning: no DEM specified; creating 4x5 raster grid """ def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the StochasticRainThresholdModel.""" # Call ErosionModel's init super(BasicThSt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) K_stoch_sp = self.get_parameter_from_exponent('K_stochastic_sp') linear_diffusivity = (self._length_factor**2.)*self.get_parameter_from_exponent('linear_diffusivity') # has units length^2/time # threshold has units of Length per Time which is what # StreamPowerSmoothThresholdEroder expects threshold = self._length_factor*self.get_parameter_from_exponent('erosion__threshold') # has units length/time # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator(self.grid, flow_director='D8', depression_finder = DepressionFinderAndRouter) # instantiate rain generator self.instantiate_rain_generator() # 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 infiltration_capacity = (self._length_factor)*self.params['infiltration_capacity']# has units length per time self.infilt = infiltration_capacity # Keep a reference to drainage area self.area = self.grid.at_node['drainage_area'] # Run flow routing and lake filler self.flow_router.run_one_step() # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder(self.grid, K_sp=K_stoch_sp, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], threshold_sp=threshold, use_Q=self.discharge) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity = linear_diffusivity) def calc_runoff_and_discharge(self): """Calculate runoff rate and discharge; return runoff.""" if self.rain_rate > 0.0 and self.infilt > 0.0: runoff = self.rain_rate - (self.infilt * (1.0 - np.exp(-self.rain_rate / self.infilt))) if runoff < 0: runoff = 0 else: runoff = self.rain_rate self.discharge[:] = runoff * self.area return runoff def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Route flow self.flow_router.run_one_step() # Get IDs of flooded nodes, if any flooded = np.where(self.flow_router.depression_finder.flood_status==3)[0] # Handle water erosion self.handle_water_erosion(dt, flooded) # Do some soil creep self.diffuser.run_one_step(dt) # calculate model time self.model_time += dt # Lower outlet self.update_outlet(dt) # Check walltime self.check_walltime()
def __init__(self, clock, grid, m_sp=0.5, n_sp=1.0, water_erodibility=0.0001, regolith_transport_parameter=0.1, water_erosion_rule__threshold=0.01, water_erosion_rule__thresh_depth_derivative=0.0, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility : float, optional Water erodibility (:math:`K`). Default is 0.0001. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. water_erosion_rule__threshold : float, optional Erosion rule threshold when no erosion has occured (:math:`\omega_c`). Default is 0.01. water_erosion_rule__thresh_depth_derivative : float, optional Rate of increase of water erosion threshold as increased incision occurs (:math:`b`). Default is 0.0. **kwargs : Keyword arguments to pass to :py:class:`ErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicDd : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicDd**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random >>> from terrainbento import Clock, BasicDd >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") Construct the model. >>> model = BasicDd(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super().__init__(clock, grid, **kwargs) # verify correct fields are present. self._verify_fields(self._required_fields) # Get Parameters and convert units if necessary: self.m = m_sp self.n = n_sp self.K = water_erodibility if float(self.n) != 1.0: raise ValueError("Model only supports n equals 1.") # threshold has units of Length per Time which is what # StreamPowerSmoothThresholdEroder expects self.threshold_value = water_erosion_rule__threshold # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros("node", "water_erosion_rule__threshold") self.threshold[:] = self.threshold_value # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, m_sp=self.m, n_sp=self.n, K_sp=self.K, threshold_sp=self.threshold, discharge_field="surface_water__discharge", erode_flooded_nodes=self._erode_flooded_nodes, ) # Get the parameter for rate of threshold increase with erosion depth self.thresh_change_per_depth = ( water_erosion_rule__thresh_depth_derivative) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=regolith_transport_parameter)
class BasicDd(ErosionModel): r"""**BasicDd** model program. This model program evolves a topographic surface, :math:`\eta`, with the following governing equation: .. math:: \frac{\partial \eta}{\partial t} = -\left(KQ^{m}S^{n} - \omega_{ct}\left(1-e^{-KQ^{m}S^{n}/\omega_{ct}}\right)\right) + D\nabla^2 \eta where :math:`Q` is the local stream discharge and :math:`S` is the local slope, :math:`m` and :math:`n` are the discharge and slope exponent parameters, :math:`K` is the erodibility by water, :math:`D` is the regolith transport efficiency, and :math:`\omega_{ct}` is the critical stream power needed for erosion to occur. :math:`\omega_{ct}` changes through time as it increases with cumulative incision depth: .. math:: \omega_{ct}\left(x,y,t\right) = \mathrm{max}\left(\omega_c + b D_I\left(x, y, t\right), \omega_c \right) where :math:`\omega_c` is the threshold when no incision has taken place, :math:`b` is the rate at which the threshold increases with incision depth, and :math:`D_I` is the cumulative incision depth at location :math:`\left(x,y\right)` and time :math:`t`. Refer to `Barnhart et al. (2019) <https://doi.org/10.5194/gmd-12-1267-2019>`_ Table 5 for full list of parameter symbols, names, and dimensions. The following at-node fields must be specified in the grid: - ``topographic__elevation`` """ _required_fields = ["topographic__elevation"] def __init__(self, clock, grid, m_sp=0.5, n_sp=1.0, water_erodibility=0.0001, regolith_transport_parameter=0.1, water_erosion_rule__threshold=0.01, water_erosion_rule__thresh_depth_derivative=0.0, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility : float, optional Water erodibility (:math:`K`). Default is 0.0001. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. water_erosion_rule__threshold : float, optional Erosion rule threshold when no erosion has occured (:math:`\omega_c`). Default is 0.01. water_erosion_rule__thresh_depth_derivative : float, optional Rate of increase of water erosion threshold as increased incision occurs (:math:`b`). Default is 0.0. **kwargs : Keyword arguments to pass to :py:class:`ErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicDd : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicDd**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random >>> from terrainbento import Clock, BasicDd >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") Construct the model. >>> model = BasicDd(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super().__init__(clock, grid, **kwargs) # verify correct fields are present. self._verify_fields(self._required_fields) # Get Parameters and convert units if necessary: self.m = m_sp self.n = n_sp self.K = water_erodibility if float(self.n) != 1.0: raise ValueError("Model only supports n equals 1.") # threshold has units of Length per Time which is what # StreamPowerSmoothThresholdEroder expects self.threshold_value = water_erosion_rule__threshold # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros("node", "water_erosion_rule__threshold") self.threshold[:] = self.threshold_value # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, m_sp=self.m, n_sp=self.n, K_sp=self.K, threshold_sp=self.threshold, discharge_field="surface_water__discharge", erode_flooded_nodes=self._erode_flooded_nodes, ) # Get the parameter for rate of threshold increase with erosion depth self.thresh_change_per_depth = ( water_erosion_rule__thresh_depth_derivative) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=regolith_transport_parameter) def update_erosion_threshold_values(self): r"""Update the erosion threshold at each node based on cumulative incision so far using: .. math:: \omega_{ct}\left(x,y,t\right) = \mathrm{max}\left(\omega_c + \\ b D_I\left(x, y, t\right), \omega_c \right) where :math:`\omega_c` is the threshold when no incision has taken place, :math:`b` is the rate at which the threshold increases with incision depth, and :math:`D_I` is the cumulative incision depth at location :math:`\left(x,y\right)` and time :math:`t`. """ # 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_elevation_change"] cum_ero[:] = (self.z - self.grid.at_node["initial_topographic__elevation"]) self.threshold[:] = self.threshold_value - ( self.thresh_change_per_depth * cum_ero) self.threshold[ self.threshold < self.threshold_value] = self.threshold_value def run_one_step(self, step): """Advance model **BasicDd** for one time-step of duration step. The **run_one_step** method does the following: 1. Creates rain and runoff, then directs and accumulates flow. 2. Assesses the location, if any, of flooded nodes where erosion should not occur. 3. Assesses if a :py:mod:`PrecipChanger` is an active boundary handler and if so, uses it to modify the erodibility by water. 4. Calculates detachment-limited, threshold-modified erosion by water. 5. Calculates topographic change by linear diffusion. 6. Finalizes the step using the :py:mod:`ErosionModel` base class function **finalize__run_one_step**. This function updates all boundary handlers handlers by ``step`` and increments model time by ``step``. Parameters ---------- step : float Increment of time for which the model is run. """ # create and move water self.create_and_move_water(step) # Calculate the new threshold values given cumulative erosion self.update_erosion_threshold_values() # Do some erosion (but not on the flooded nodes) # (if we're varying K through time, update that first) if "PrecipChanger" in self.boundary_handlers: self.eroder.K = (self.K * self.boundary_handlers["PrecipChanger"]. get_erodibility_adjustment_factor()) self.eroder.run_one_step(step) # Do some soil creep self.diffuser.run_one_step(step) # Finalize the run_one_step_method self.finalize__run_one_step(step)
# 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 coords={ 'x': ( ('x'), # tuple of dimensions
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 elapsed_time = 0. keep_running = True counter = 0 # simple incremented counter to let us see the model advance
threshold_sp = 0, rainfall_intensity = 1) fr = FlowRouter(mg) lm = DepressionFinderAndRouter(mg) expw = ExponentialWeatherer(mg, max_soil_production_rate = maxSoilProductionRate, soil_production_decay_depth = soilProductionDepth) dld = DepthDependentDiffuser(mg, linear_diffusivity = linDiff, soil_transport_decay_depth = soilTransportDepth) ld = LinearDiffuser(mg, linear_diffusivity = linDiff) print("finished with the initialization of the erosion components") print("---------------------") ##---------------------------------Main Loop------------------------------------# t0 = time.time() elapsed_time = 0 print("starting with main loop.") print("---------------------") #Create incremental counter for controlling progress of mainloop counter = 0 #Create Limits for DHDT plot. Move this somewhere else later.. DHDTLowLim = upliftRate - (upliftRate * 1) DHDTHighLim = upliftRate + (upliftRate * 1)
class BasicDdHy(_ErosionModel): """ A BasicDdHy computes erosion using 1) the hybrid alluvium component with a threshold that varies with cumulative incision depth, the linear diffusion component. """ def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """ Initialize the BasicDdHy """ # Call ErosionModel's init super(BasicDdHy, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) # Get Parameters and convert units if necessary: self.K_sp = self.get_parameter_from_exponent('K_sp') linear_diffusivity = ( (self._length_factor**2) # L2/T * self.get_parameter_from_exponent('linear_diffusivity')) v_s = self.get_parameter_from_exponent('v_sc') # unitless self.sp_crit = ( self._length_factor # L/T * self.get_parameter_from_exponent('erosion__threshold')) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Create a field for the (initial) erosion threshold self.threshold = self.grid.add_zeros('node', 'erosion__threshold') self.threshold[:] = self.sp_crit #starting value # Handle solver option try: solver = self.params['solver'] except: solver = 'original' # Instantiate an ErosionDeposition component self.eroder = ErosionDeposition(self.grid, K=self.K_sp, F_f=self.params['F_f'], phi=self.params['phi'], v_s=v_s, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], sp_crit='erosion__threshold', method='threshold_stream_power', discharge_method='drainage_area', area_field='drainage_area', solver=solver) # Get the parameter for rate of threshold increase with erosion depth self.thresh_change_per_depth = self.params['thresh_change_per_depth'] # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Route flow self.flow_router.run_one_step() # Get IDs of flooded nodes, if any flooded = np.where( self.flow_router.depression_finder.flood_status == 3)[0] # Calculate cumulative erosion and update threshold cum_ero = self.grid.at_node['cumulative_erosion__depth'] cum_ero[:] = (self.z - self.grid.at_node['initial_topographic__elevation']) self.threshold[:] = (self.sp_crit - (self.thresh_change_per_depth * cum_ero)) self.threshold[self.threshold < self.sp_crit] = self.sp_crit # Do some erosion (but not on the flooded nodes) # (if we're varying K through time, update that first) if self.opt_var_precip: self.eroder.K = ( self.K_sp * self.pc.get_erodibility_adjustment_factor(self.model_time)) self.eroder.run_one_step(dt, flooded_nodes=flooded) # Do some soil creep self.diffuser.run_one_step(dt) # calculate model time self.model_time += dt # Lower outlet self.update_outlet(dt) # Check walltime self.check_walltime()
elev[:] = b + 0.1 * hg * np.random.rand(len(elev)) base = grid.add_zeros('node', 'aquifer_base__elevation') wt = grid.add_zeros('node', 'water_table__elevation') wt[:] = elev.copy() #initialize landlab components gdp = GroundwaterDupuitPercolator(grid, porosity=n, hydraulic_conductivity=ksat, \ regularization_f=0.01, recharge_rate=0.0, \ courant_coefficient=0.9, vn_coefficient = 0.9) pd = PrecipitationDistribution(grid, mean_storm_duration=tr, mean_interstorm_duration=tb, mean_storm_depth=ds, total_t=Th) pd.seed_generator(seedval=1235) ld = LinearDiffuser(grid, linear_diffusivity=D) #initialize other models hm = HydrologyEventStreamPower( grid, precip_generator=pd, groundwater_model=gdp, ) #use surface_water_area_norm__discharge (Q/sqrt(A)) for Theodoratos definitions sp = FastscapeEroder(grid, K_sp=Ksp, m_sp=1, n_sp=1, discharge_field="surface_water_area_norm__discharge") rm = RegolithConstantThickness(grid, equilibrium_depth=b, uplift_rate=U)
class BasicRtVs(ErosionModel): """ A BasicVsRt computes erosion using linear diffusion, basic stream power with 2 lithologies, and Q ~ A exp( -b S / A). """ def __init__(self, input_file=None, params=None, BaselevelHandlerClass=None): """Initialize the BasicVsRt.""" # Call ErosionModel's init super(BasicVsRt, self).__init__(input_file=input_file, params=params, BaselevelHandlerClass=BaselevelHandlerClass) contact_zone__width = (self._length_factor) * self.params[ 'contact_zone__width'] # has units length self.K_rock_sp = self.get_parameter_from_exponent('K_rock_sp') self.K_till_sp = self.get_parameter_from_exponent('K_till_sp') linear_diffusivity = ( self._length_factor** 2.) * self.get_parameter_from_exponent('linear_diffusivity') recharge_rate = (self._length_factor) * self.params[ 'recharge_rate'] # has units length per time soil_thickness = (self._length_factor) * self.params[ 'initial_soil_thickness'] # has units length K_hydraulic_conductivity = (self._length_factor) * self.params[ 'K_hydraulic_conductivity'] # has units length per time # Set up rock-till self.setup_rock_and_till(self.params['rock_till_file__name'], self.K_rock_sp, self.K_till_sp, contact_zone__width) # Instantiate a FlowAccumulator with DepressionFinderAndRouter using D8 method self.flow_router = FlowAccumulator( self.grid, flow_director='D8', depression_finder=DepressionFinderAndRouter) # Add a field for effective drainage area if 'effective_drainage_area' in self.grid.at_node: self.eff_area = self.grid.at_node['effective_drainage_area'] else: self.eff_area = self.grid.add_zeros('node', 'effective_drainage_area') # Get the effective-area parameter self.sat_param = (K_hydraulic_conductivity * soil_thickness * self.grid.dx) / (recharge_rate) # Instantiate a FastscapeEroder component self.eroder = StreamPowerEroder(self.grid, K_sp=self.erody, m_sp=self.params['m_sp'], n_sp=self.params['n_sp'], use_Q=self.eff_area) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser(self.grid, linear_diffusivity=linear_diffusivity) def calc_effective_drainage_area(self): """Calculate and store effective drainage area. Effective drainage area is defined as: $A_{eff} = A \exp ( \alpha S / A) = A R_r$ where $S$ is downslope-positive steepest gradient, $A$ is drainage area, $R_r$ is the runoff ratio, and $\alpha$ is the saturation parameter. """ 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]))) def setup_rock_and_till(self, file_name, rock_erody, till_erody, contact_width): """Set up lithology handling for two layers with different erodibility. Parameters ---------- file_name : string Name of arc-ascii format file containing elevation of contact position at each grid node (or NODATA) Read elevation of rock-till contact from an esri-ascii format file containing the basal elevation value at each node, create a field for erodibility. Some considerations here: 1. We could represent the contact between two layers either as a depth below present land surface, or as an altitude. Using a depth would allow for vertical motion, because for a fixed surface, the depth remains constant while the altitude changes. But the depth must be updated every time the surface is eroded or aggrades. Using an altitude avoids having to update the contact position every time the surface erodes or aggrades, but any tectonic motion would need to be applied to the contact position as well. Here we'll use the altitude approach because this model was originally written for an application with lots of erosion expected but no tectonics. """ from landlab.io import read_esri_ascii # Read input data on rock-till contact elevation read_esri_ascii(file_name, grid=self.grid, name='rock_till_contact__elevation', halo=1) # Get a reference to the rock-till field self.rock_till_contact = self.grid.at_node[ 'rock_till_contact__elevation'] # Create field for erodibility if 'substrate__erodibility' in self.grid.at_node: self.erody = self.grid.at_node['substrate__erodibility'] else: self.erody = self.grid.add_zeros('node', 'substrate__erodibility') # Create array for erodibility weighting function self.erody_wt = np.zeros(self.grid.number_of_nodes) # Read the erodibility value of rock and till self.rock_erody = rock_erody self.till_erody = till_erody # Read and remember the contact zone characteristic width self.contact_width = contact_width def update_erodibility_field(self): """Update erodibility at each node based on elevation relative to contact elevation. To promote smoothness in the solution, the erodibility at a given point (x,y) is set as follows: 1. Take the difference between elevation, z(x,y), and contact elevation, b(x,y): D(x,y) = z(x,y) - b(x,y). This number could be positive (if land surface is above the contact), negative (if we're well within the rock), or zero (meaning the rock-till contact is right at the surface). 2. Define a smoothing function as: $F(D) = 1 / (1 + exp(-D/D*))$ This sigmoidal function has the property that F(0) = 0.5, F(D >> D*) = 1, and F(-D << -D*) = 0. Here, D* describes the characteristic width of the "contact zone", where the effective erodibility is a mixture of the two. If the surface is well above this contact zone, then F = 1. If it's well below the contact zone, then F = 0. 3. Set the erodibility using F: $K = F K_till + (1-F) K_rock$ So, as F => 1, K => K_till, and as F => 0, K => K_rock. In between, we have a weighted average. Translating these symbols into variable names: z = self.elev b = self.rock_till_contact D* = self.contact_width F = self.erody_wt K_till = self.till_erody K_rock = self.rock_erody """ # Update the erodibility weighting function (this is "F") core = self.grid.core_nodes if self.contact_width > 0.0: self.erody_wt[core] = ( 1.0 / (1.0 + np.exp(-(self.z[core] - self.rock_till_contact[core]) / self.contact_width))) else: self.erody_wt[core] = 0.0 self.erody_wt[np.where(self.z > self.rock_till_contact)[0]] = 1.0 # (if we're varying K through time, update that first) if self.opt_var_precip: erode_factor = self.pc.get_erodibility_adjustment_factor( self.model_time) self.till_erody = self.K_till_sp * erode_factor self.rock_erody = self.K_rock_sp * erode_factor # Calculate the effective erodibilities using weighted averaging self.erody[:] = (self.erody_wt * self.till_erody + (1.0 - self.erody_wt) * self.rock_erody) def run_one_step(self, dt): """ Advance model for one time-step of duration dt. """ # Route flow self.flow_router.run_one_step() # Update effective runoff ratio self.calc_effective_drainage_area() # Zero out effective area in flooded nodes self.eff_area[self.flow_router.depression_finder.flood_status == 3] = 0.0 # Update the erodibility field self.update_erodibility_field() # Do some erosion (but not on the flooded nodes) self.eroder.run_one_step(dt) # Do some soil creep self.diffuser.run_one_step(dt) # calculate model time self.model_time += dt # Lower outlet self.update_outlet(dt) # Check walltime self.check_walltime()
mg = RasterModelGrid((Nr, Nc), dx) # Initializing the elevation values _ = mg.add_zeros('node', 'topographic__elevation') z = np.zeros((Nr, Nc)) mg.at_node['topographic__elevation'] = z.reshape(Nr * Nc) # Imposing fixed elevation boundary conditions for edge in (mg.nodes_at_left_edge, mg.nodes_at_right_edge): mg.status_at_node[edge] = FIXED_VALUE_BOUNDARY for edge in (mg.nodes_at_bottom_edge, mg.nodes_at_top_edge): mg.status_at_node[edge] = FIXED_VALUE_BOUNDARY # Selecting D_infinity as the flow direction method fc = FlowAccumulator(mg, flow_director='FlowDirectorDINF') fd = LinearDiffuser(mg, linear_diffusivity=D) fc.run_one_step() # Minimum time-steps for simulation to run min_try = 500 # Other important variables for the simulation i = -1 t = 0 dt = 1. diff_list = [] steady_state = False while steady_state is False: # Selecting 'dt' for high accuracy (user dependent)
class BasicThVs(ErosionModel): r"""**BasicThVs** model program. This model program combines models :py:class:`BasicTh` and :py:class:`BasicVs`. It evolves a topographic surface described by : math:`\eta` with the following governing equations: .. math:: \frac{\partial \eta}{\partial t} = -\left(K A_{eff}^{m}S^{n} - \omega_{c}\left(1-e^{-KA_{eff}^{m}S^{n}/\omega_{c}}\right)\right) + D\nabla^2 \eta A_{eff} = A \exp \left( -\frac{-\alpha S}{A}\right) \alpha = \frac{K_{sat} H dx}{R_m} where :math:`Q` is the local stream discharge, :math:`S` is the local slope, :math:`m` and :math:`n` are the discharge and slope exponent parameters, :math:`K` is the erodibility by water, :math:`\omega_c` is the critical stream power needed for erosion to occur, and :math:`D` is the regolith transport parameter. :math:`\alpha` is the saturation area scale used for transforming area into effective area :math:`A_{eff}`. It is given as a function of the saturated hydraulic conductivity :math:`K_{sat}`, the soil thickness :math:`H`, the grid spacing :math:`dx`, and the recharge rate, :math:`R_m`. Refer to `Barnhart et al. (2019) <https://doi.org/10.5194/gmd-12-1267-2019>`_ Table 5 for full list of parameter symbols, names, and dimensions. The following at-node fields must be specified in the grid: - ``topographic__elevation`` - ``soil__depth`` """ _required_fields = ["topographic__elevation", "soil__depth"] def __init__(self, clock, grid, m_sp=0.5, n_sp=1.0, water_erodibility=0.0001, regolith_transport_parameter=0.1, hydraulic_conductivity=0.1, water_erosion_rule__threshold=0.01, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility : float, optional Water erodibility (:math:`K`). Default is 0.0001. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. water_erosion_rule__threshold : float, optional Erosion rule threshold when no erosion has occured (:math:`\omega_c`). Default is 0.01. hydraulic_conductivity : float, optional Hydraulic conductivity (:math:`K_{sat}`). Default is 0.1. **kwargs : Keyword arguments to pass to :py:class:`ErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicThVs : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicThVs**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random >>> from terrainbento import Clock, BasicThVs >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") >>> _ = random(grid, "soil__depth") Construct the model. >>> model = BasicThVs(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super().__init__(clock, grid, **kwargs) # ensure Precipitator and RunoffGenerator are vanilla self._ensure_precip_runoff_are_vanilla(vsa_precip=True) # verify correct fields are present. self._verify_fields(self._required_fields) self.m = m_sp self.n = n_sp self.K = water_erodibility if float(self.n) != 1.0: raise ValueError("Model only supports n = 1.") # Get the effective-area parameter self._Kdx = hydraulic_conductivity * self.grid.dx # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.K, m_sp=self.m, n_sp=self.n, threshold_sp=water_erosion_rule__threshold, discharge_field="surface_water__discharge", erode_flooded_nodes=self._erode_flooded_nodes, ) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=regolith_transport_parameter) def _calc_effective_drainage_area(self): """Calculate and store effective drainage area.""" area = self.grid.at_node["drainage_area"] slope = self.grid.at_node["topographic__steepest_slope"] cores = self.grid.core_nodes sat_param = (self._Kdx * self.grid.at_node["soil__depth"] / self.grid.at_node["rainfall__flux"]) eff_area = area[cores] * (np.exp( -sat_param[cores] * slope[cores] / area[cores])) self.grid.at_node["surface_water__discharge"][cores] = eff_area def run_one_step(self, step): """Advance model **BasicThVs** for one time-step of duration step. The **run_one_step** method does the following: 1. Directs flow, accumulates drainage area, and calculates effective drainage area. 2. Assesses the location, if any, of flooded nodes where erosion should not occur. 3. Assesses if a :py:mod:`PrecipChanger` is an active boundary handler and if so, uses it to modify the erodibility by water. 4. Calculates detachment-limited erosion by water. 5. Calculates topographic change by linear diffusion. 6. Finalizes the step using the :py:mod:`ErosionModel` base class function **finalize__run_one_step**. This function updates all boundary handlers handlers by ``step`` and increments model time by ``step``. Parameters ---------- step : float Increment of time for which the model is run. """ # create and move water self.create_and_move_water(step) # Update effective runoff ratio self._calc_effective_drainage_area() # Zero out effective area in flooded nodes if self._erode_flooded_nodes: flooded_nodes = [] else: flood_status = self.grid.at_node["flood_status_code"] flooded_nodes = np.nonzero(flood_status == _FLOODED)[0] self.grid.at_node["surface_water__discharge"][flooded_nodes] = 0.0 # Do some erosion (but not on the flooded nodes) # (if we're varying K through time, update that first) if "PrecipChanger" in self.boundary_handlers: self.eroder.K = (self.K * self.boundary_handlers["PrecipChanger"]. get_erodibility_adjustment_factor()) self.eroder.run_one_step(step) # Do some soil creep self.diffuser.run_one_step(step) # Finalize the run_one_step_method self.finalize__run_one_step(step)
# 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() 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'
## Linear diffusion and channels on a raster ## 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
surface='topographic__elevation', flow_director='D8') lmb = LakeMapperBarnes( grid, method='D8', fill_flat=False, surface="topographic__elevation", fill_surface="topographic__elevation", redirect_flow_steepest_descent=False, reaccumulate_flow=False, track_lakes=False, ignore_overfill=True, ) dfr = DepressionFinderAndRouter(grid) ld = LinearDiffuser(grid, D) sp = FastscapeEroder(grid, K_sp=Ksp, m_sp=0.5, n_sp=1.0, threshold_sp=E0) for i in range(N): dfr._find_pits() if dfr._number_of_pits > 0: lmb.run_one_step() z[grid.core_nodes] += U * dt ld.run_one_step(dt) fa.run_one_step() sp.run_one_step(dt) print('completed loop %d' % i)
class BasicRtVs(TwoLithologyErosionModel): r"""**BasicRtVs** model program. This model program combines the :py:class:`BasicRt` and :py:class:`BasicVs` programs by allowing for two lithologies, an "upper" layer and a "lower" layer, and using discharge proportional to effective drainage area based on variable source area hydrology. Given a spatially varying contact zone elevation, :math:`\eta_C(x,y))`, model **BasicRtVs** evolves a topographic surface described by :math:`\eta` with the following governing equations: .. math:: \frac{\partial \eta}{\partial t} = - K(\eta,\eta_C) A_{eff}^{m}S^{n} + D\nabla^2 \eta K(\eta, \eta_C ) = w K_1 + (1 - w) K_2 w = \frac{1}{1+\exp \left( -\frac{(\eta -\eta_C )}{W_c}\right)} A_{eff} = A \exp \left( -\frac{-\alpha S}{A}\right) \alpha = \frac{K_{sat} dx }{R_m} where :math:`Q` is the local stream discharge, :math:`S` is the local slope, :math:`m` and :math:`n` are the discharge and slope exponent parameters, :math:`W_c` is the contact-zone width, :math:`K_1` and :math:`K_2` are the erodabilities of the upper and lower lithologies, and :math:`D` is the regolith transport parameter. :math:`\alpha` is the saturation area scale used for transforming area into effective area and it is given as a function of the saturated hydraulic conductivity :math:`K_{sat}`, the soil thickness :math:`H`, the grid spacing :math:`dx`, and the recharge rate, :math:`R_m`. :math:`w` is a weight used to calculate the effective erodibility :math:`K(\eta, \eta_C)` based on the depth to the contact zone and the width of the contact zone. The weight :math:`w` promotes smoothness in the solution of erodibility at a given point. When the surface elevation is at the contact elevation, the erodibility is the average of :math:`K_1` and :math:`K_2`; above and below the contact, the erodibility approaches the value of :math:`K_1` and :math:`K_2` at a rate related to the contact zone width. Thus, to make a very sharp transition, use a small value for the contact zone width. Refer to `Barnhart et al. (2019) <https://doi.org/10.5194/gmd-12-1267-2019>`_ Table 5 for full list of parameter symbols, names, and dimensions. The following at-node fields must be specified in the grid: - ``topographic__elevation`` - ``lithology_contact__elevation`` - ``soil__depth`` """ _required_fields = [ "topographic__elevation", "lithology_contact__elevation", "soil__depth", ] def __init__(self, clock, grid, hydraulic_conductivity=0.1, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility_upper : float, optional Water erodibility of the upper layer (:math:`K_{1}`). Default is 0.001. water_erodibility_lower : float, optional Water erodibility of the upper layer (:math:`K_{2}`). Default is 0.0001. contact_zone__width : float, optional Thickness of the contact zone (:math:`W_c`). Default is 1. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. hydraulic_conductivity : float, optional Hydraulic conductivity (:math:`K_{sat}`). Default is 0.1. **kwargs : Keyword arguments to pass to :py:class:`TwoLithologyErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicRtVs : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicRtVs**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random, constant >>> from terrainbento import Clock, BasicRtVs >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") >>> _ = random(grid, "soil__depth") >>> _ = constant(grid, "lithology_contact__elevation", value=-10.) Construct the model. >>> model = BasicRtVs(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super(BasicRtVs, self).__init__(clock, grid, **kwargs) # ensure Precipitator and RunoffGenerator are vanilla self._ensure_precip_runoff_are_vanilla() # verify correct fields are present. self._verify_fields(self._required_fields) # Set up rock-till boundary and associated grid fields. self._setup_rock_and_till() # Get the effective-area parameter self._Kdx = hydraulic_conductivity * self.grid.dx # Instantiate a FastscapeEroder component self.eroder = FastscapeEroder( self.grid, K_sp=self.erody, m_sp=self.m, n_sp=self.n, discharge_name="surface_water__discharge", ) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=self.regolith_transport_parameter ) def _calc_effective_drainage_area(self): r"""Calculate and store effective drainage area. Effective drainage area is defined as: .. math:: A_{eff} = A \exp ( \alpha S / A) = A R_r where :math:`S` is downslope-positive steepest gradient, :math:`A` is drainage area, :math:`R_r` is the runoff ratio, and :math:`\alpha` is the saturation parameter. """ area = self.grid.at_node["drainage_area"] slope = self.grid.at_node["topographic__steepest_slope"] cores = self.grid.core_nodes sat_param = ( self._Kdx * self.grid.at_node["soil__depth"] / self.grid.at_node["rainfall__flux"] ) eff_area = area[cores] * ( np.exp(-sat_param[cores] * slope[cores] / area[cores]) ) self.grid.at_node["surface_water__discharge"][cores] = eff_area def run_one_step(self, step): """Advance model **BasicRtVs** for one time-step of duration step. The **run_one_step** method does the following: 1. Directs flow, accumulates drainage area, and calculates effective drainage area. 2. Assesses the location, if any, of flooded nodes where erosion should not occur. 3. Assesses if a :py:mod:`PrecipChanger` is an active boundary handler and if so, uses it to modify the erodibility by water. 4. Updates the spatially variable erodibility value based on the relative distance between the topographic surface and the lithology contact. 5. Calculates detachment-limited erosion by water. 6. Calculates topographic change by linear diffusion. 7. Finalizes the step using the :py:mod:`ErosionModel` base class function **finalize__run_one_step**. This function updates all boundary handlers handlers by ``step`` and increments model time by ``step``. Parameters ---------- step : float Increment of time for which the model is run. """ # create and move water self.create_and_move_water(step) # Update effective runoff ratio self._calc_effective_drainage_area() # Get IDs of flooded nodes, if any if self.flow_accumulator.depression_finder is None: flooded = [] else: flooded = np.where( self.flow_accumulator.depression_finder.flood_status == 3 )[0] # Zero out effective area in flooded nodes self.grid.at_node["surface_water__discharge"][flooded] = 0.0 # Update the erodibility field self._update_erodibility_field() # Do some erosion (but not on the flooded nodes) self.eroder.run_one_step(step) # Do some soil creep self.diffuser.run_one_step(step) # Finalize the run_one_step_method self.finalize__run_one_step(step)
def __init__(self, clock, grid, m_sp=0.5, n_sp=1.0, water_erodibility=0.0001, regolith_transport_parameter=0.1, hydraulic_conductivity=0.1, water_erosion_rule__threshold=0.01, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility : float, optional Water erodibility (:math:`K`). Default is 0.0001. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. water_erosion_rule__threshold : float, optional Erosion rule threshold when no erosion has occured (:math:`\omega_c`). Default is 0.01. hydraulic_conductivity : float, optional Hydraulic conductivity (:math:`K_{sat}`). Default is 0.1. **kwargs : Keyword arguments to pass to :py:class:`ErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicThVs : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicThVs**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random >>> from terrainbento import Clock, BasicThVs >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") >>> _ = random(grid, "soil__depth") Construct the model. >>> model = BasicThVs(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super().__init__(clock, grid, **kwargs) # ensure Precipitator and RunoffGenerator are vanilla self._ensure_precip_runoff_are_vanilla(vsa_precip=True) # verify correct fields are present. self._verify_fields(self._required_fields) self.m = m_sp self.n = n_sp self.K = water_erodibility if float(self.n) != 1.0: raise ValueError("Model only supports n = 1.") # Get the effective-area parameter self._Kdx = hydraulic_conductivity * self.grid.dx # Instantiate a FastscapeEroder component self.eroder = StreamPowerSmoothThresholdEroder( self.grid, K_sp=self.K, m_sp=self.m, n_sp=self.n, threshold_sp=water_erosion_rule__threshold, discharge_field="surface_water__discharge", erode_flooded_nodes=self._erode_flooded_nodes, ) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=regolith_transport_parameter)
def __init__(self, clock, grid, hydraulic_conductivity=0.1, **kwargs): """ Parameters ---------- clock : terrainbento Clock instance grid : landlab model grid instance The grid must have all required fields. m_sp : float, optional Drainage area exponent (:math:`m`). Default is 0.5. n_sp : float, optional Slope exponent (:math:`n`). Default is 1.0. water_erodibility_upper : float, optional Water erodibility of the upper layer (:math:`K_{1}`). Default is 0.001. water_erodibility_lower : float, optional Water erodibility of the upper layer (:math:`K_{2}`). Default is 0.0001. contact_zone__width : float, optional Thickness of the contact zone (:math:`W_c`). Default is 1. regolith_transport_parameter : float, optional Regolith transport efficiency (:math:`D`). Default is 0.1. hydraulic_conductivity : float, optional Hydraulic conductivity (:math:`K_{sat}`). Default is 0.1. **kwargs : Keyword arguments to pass to :py:class:`TwoLithologyErosionModel`. Importantly these arguments specify the precipitator and the runoff generator that control the generation of surface water discharge (:math:`Q`). Returns ------- BasicRtVs : model object Examples -------- This is a minimal example to demonstrate how to construct an instance of model **BasicRtVs**. For more detailed examples, including steady-state test examples, see the terrainbento tutorials. To begin, import the model class. >>> from landlab import RasterModelGrid >>> from landlab.values import random, constant >>> from terrainbento import Clock, BasicRtVs >>> clock = Clock(start=0, stop=100, step=1) >>> grid = RasterModelGrid((5,5)) >>> _ = random(grid, "topographic__elevation") >>> _ = random(grid, "soil__depth") >>> _ = constant(grid, "lithology_contact__elevation", value=-10.) Construct the model. >>> model = BasicRtVs(clock, grid) Running the model with ``model.run()`` would create output, so here we will just run it one step. >>> model.run_one_step(1.) >>> model.model_time 1.0 """ # Call ErosionModel"s init super(BasicRtVs, self).__init__(clock, grid, **kwargs) # ensure Precipitator and RunoffGenerator are vanilla self._ensure_precip_runoff_are_vanilla() # verify correct fields are present. self._verify_fields(self._required_fields) # Set up rock-till boundary and associated grid fields. self._setup_rock_and_till() # Get the effective-area parameter self._Kdx = hydraulic_conductivity * self.grid.dx # Instantiate a FastscapeEroder component self.eroder = FastscapeEroder( self.grid, K_sp=self.erody, m_sp=self.m, n_sp=self.n, discharge_name="surface_water__discharge", ) # Instantiate a LinearDiffuser component self.diffuser = LinearDiffuser( self.grid, linear_diffusivity=self.regolith_transport_parameter )