def test_eet_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) grid.add_zeros("lithosphere__overlying_pressure_increment", at="node") for val in (10e3, 1e3): assert Flexure(grid, eet=val).eet == pytest.approx(val) with pytest.raises(ValueError): assert Flexure(grid, eet=-10e3)
def initialize(self, param_filename): # Read parameters from input file params = load_params(param_filename) self.elastic_thickness = params['elastic_thickness'] self.youngs_modulus = params['youngs_modulus'] self.rho_m = params['mantle_density'] self.grav_accel = params['gravitational_acceleration'] self.water_surf_elev = params['water_surface_elevation'] self.water_density = params['lake_water_density'] self.tolerance = params['lake_elev_tolerance'] # Read DEM print('Reading DEM file...') (self.grid, self.dem) = read_esri_ascii(params['dem_filename']) print('done.') # Store a copy that we'll modify self.flexed_dem = self.dem.copy() # Create and initialize Flexure component self.flexer = Flexure(self.grid, eet=self.elastic_thickness, youngs=self.youngs_modulus, method="flexure", rho_mantle=self.rho_m, gravity=self.grav_accel) self.load = self.grid.at_node[ 'lithosphere__overlying_pressure_increment'] self.deflection = self.grid.at_node[ 'lithosphere_surface__elevation_increment'] self.initialized = True
def test_method_names(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) grid.add_zeros("lithosphere__overlying_pressure_increment", at="node") assert Flexure(grid, method="airy").method == "airy" assert Flexure(grid, method="flexure").method == "flexure" with pytest.raises(ValueError): Flexure(grid, method="bad-name")
def test_update(): n = 11 n_mid = (n - 1) // 2 i_mid = np.ravel_multi_index((n_mid, n_mid), (n, n)) load_0 = 1e9 grid = RasterModelGrid((n, n), xy_spacing=1e3) flex = Flexure(grid, method="flexure") load = grid.at_node["lithosphere__overlying_pressure_increment"] load[i_mid] = load_0 flex.update() dz = flex.grid.at_node["lithosphere_surface__elevation_increment"].reshape((n, n)) assert np.argmax(dz) == i_mid assert dz[n_mid, n_mid] > 0.0 assert np.all(dz[:, n_mid::-1] == dz[:, n_mid:]) assert np.all(dz[n_mid::-1, :] == dz[n_mid:, :])
def test_subside_loads(): n, load_0 = 11, 1e9 grid = RasterModelGrid((n, n), xy_spacing=1e3) flex = Flexure(grid, method="flexure") grid.at_node["lithosphere__overlying_pressure_increment"][0] = load_0 flex.update() dz_expected = flex.grid.at_node["lithosphere_surface__elevation_increment"] load = np.zeros((n, n)) load[0, 0] = load_0 dz = flex.subside_loads(load) assert np.all(dz.flatten() == pytest.approx(dz_expected)) out = np.zeros((n, n)) dz = flex.subside_loads(load, out=out) assert dz is out
def test_rho_mantle_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) grid.add_zeros("lithosphere__overlying_pressure_increment", at="node") for val in (10e3, 1e3): assert Flexure(grid, rho_mantle=val).rho_mantle == pytest.approx(val)
def test_with_flexure(): """Test integrating with flexure.""" crust_density = 2700.0 # density of crustal column, kg/m3 dx = 2500.0 # grid spacing, m dt = 125000.0 # time step, y upper_crust_base_depth = 10000.0 # m grid = RasterModelGrid((3, 7), xy_spacing=dx) topo = grid.add_zeros("topographic__elevation", at="node") load = grid.add_zeros("lithosphere__overlying_pressure_increment", at="node") thickness = grid.add_zeros("upper_crust_thickness", at="node") upper_crust_base = grid.add_zeros("upper_crust_base__elevation", at="node") extender = ListricKinematicExtender( grid, extension_rate=0.01, fault_location=2500.0, track_crustal_thickness=True, ) flexer = Flexure(grid, eet=5000.0, method="flexure") deflection = grid.at_node["lithosphere_surface__elevation_increment"] topo[ grid.x_of_node <= 7500.0] = 1000.0 # this will force thickness to be 1 km greater at left upper_crust_base[:] = -upper_crust_base_depth thickness[:] = topo - upper_crust_base unit_wt = crust_density * flexer.gravity load[:] = unit_wt * thickness # loading pressure # Get the initial deflection, which we'll need to calculate total current # deflection flexer.update() init_deflection = deflection.copy() # Run extension for half a grid cell. Elevations change, but thickness # doesn't, so deflection should not change. We should be able to recover # elevation from: # # topo = thickness + crust base - (deflection + subsidence) # extender.run_one_step(dt=dt) flexer.update() net_deflection = deflection - init_deflection assert_array_almost_equal( net_deflection[7:14], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], ) test_topo = thickness + upper_crust_base - (net_deflection + extender._cum_subs) assert_array_almost_equal(topo, test_topo) # Now extend for another half cell, which should force a shift. The # cumulative subsidence will be subtracted from the thickness field, # representing thinning as the hangingwall slides to the "right". This # will cause net upward isostatic deflection. extender.run_one_step(dt=dt) load[:] = unit_wt * thickness flexer.update() net_deflection = deflection - init_deflection assert_array_almost_equal( thickness[7:14], [ 11000.0, 11000.0, 8191.686362, # greatest subsidence: lost nearly 3 km 9178.66186, 9818.767044, # thicker because shifted (only lost <200 m) 9233.908704, 9503.149763, ], ) assert_array_almost_equal( net_deflection[7:14], [ -59.497362, -65.176276, -69.222531, -70.334462, -68.608952, -64.912352, -59.743080, ], )
class LakeFlexer(): """Calculate elastic lithosphere flexure for a (paleo)lake. Landlab-built model that takes a digital elevation model and a target water-surface elevation, and calculates flexure resulting from the load of the water. """ def __init__(self, param_filename=None): if param_filename is None: self.initialized = False else: self.initialize(param_filename) def initialize(self, param_filename): # Read parameters from input file params = load_params(param_filename) self.elastic_thickness = params['elastic_thickness'] self.youngs_modulus = params['youngs_modulus'] self.rho_m = params['mantle_density'] self.grav_accel = params['gravitational_acceleration'] self.water_surf_elev = params['water_surface_elevation'] self.water_density = params['lake_water_density'] self.tolerance = params['lake_elev_tolerance'] # Read DEM print('Reading DEM file...') (self.grid, self.dem) = read_esri_ascii(params['dem_filename']) print('done.') # Store a copy that we'll modify self.flexed_dem = self.dem.copy() # Create and initialize Flexure component self.flexer = Flexure(self.grid, eet=self.elastic_thickness, youngs=self.youngs_modulus, method="flexure", rho_mantle=self.rho_m, gravity=self.grav_accel) self.load = self.grid.at_node[ 'lithosphere__overlying_pressure_increment'] self.deflection = self.grid.at_node[ 'lithosphere_surface__elevation_increment'] self.initialized = True def update(self): # Make sure model has been initialized try: if self.initialized == False: raise RuntimeError('LakeFlexer must be initialized before' + 'calling update()') except RuntimeError: raise i = 0 done = False while not done: print('Iteration ' + str(i) + ':') # Calculate water depths print(' calculating water depth and loads...') self.water_depth = self.water_surf_elev - self.flexed_dem self.water_depth[self.water_depth < 0.0] = 0.0 # Calculate loads self.load[:] = (self.water_density * self.grav_accel * self.water_depth) # Calculate flexure and adjust elevations print(' calculating flexure...') self.flexer.update() self.flexed_dem = self.dem - self.deflection # Compare modeled and desired water-surface elevations flexed_wse = (self.flexed_dem[self.water_depth > 0.0] + self.water_depth[self.water_depth > 0.0]) residual = self.water_surf_elev - flexed_wse print(' max residual = ' + str(np.amax(np.abs(residual)))) if np.amax(np.abs(residual)) < self.tolerance: done = True i += 1 if i > MAX_ITERATIONS: print('Warning: maximum number of iterations exceeded') done = True print('Done. Maximum deflextion = ' + str(np.amax(self.deflection)) + ' meters.') def finalize(self): """Output data to file.""" write_netcdf("lake_flex.nc", self.grid)
def test_rho_mantle_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) for val in (10e3, 1e3): assert Flexure(grid, rho_mantle=val).rho_mantle == pytest.approx(val)
def test_gravity_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) for val in (10e3, 1e3): assert Flexure(grid, gravity=val).gravity == pytest.approx(val)
def test_youngs_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) for val in (10e3, 1e3): assert Flexure(grid, youngs=val).youngs == pytest.approx(val)
def test_eet_attribute(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) for val in (10e3, 1e3): assert Flexure(grid, eet=val).eet == pytest.approx(val) with pytest.raises(ValueError): assert Flexure(grid, eet=-10e3)
def test_method_names(): grid = RasterModelGrid((20, 20), xy_spacing=10e3) assert Flexure(grid, method="airy").method == "airy" assert Flexure(grid, method="flexure").method == "flexure" with pytest.raises(ValueError): Flexure(grid, method="bad-name")