Introduction
Introduction Statistics Contact Development Disclaimer Help
timportant fix for water velocity and shear stress - granular-channel-hydro - s…
git clone git://src.adamsgaard.dk/granular-channel-hydro
Log
Files
Refs
README
LICENSE
---
commit 8119c0ae2e91d175f51c319d32a10abc108ebcd3
parent cdd2e02befacebb825dd8718658f44c28fe27e82
Author: Anders Damsgaard Christensen <[email protected]>
Date: Wed, 1 Feb 2017 20:52:27 -0800
important fix for water velocity and shear stress
Diffstat:
A 1d-channel.py | 340 +++++++++++++++++++++++++++++…
D 1d-test.py | 322 -----------------------------…
2 files changed, 340 insertions(+), 322 deletions(-)
---
diff --git a/1d-channel.py b/1d-channel.py
t@@ -0,0 +1,340 @@
+#!/usr/bin/env python
+
+## ABOUT THIS FILE
+# The following script uses basic Python and Numpy functionality to solve the
+# coupled systems of equations describing subglacial channel development in
+# soft beds as presented in `Damsgaard et al. "Sediment plasticity controls
+# channelization of subglacial meltwater in soft beds"`, submitted to Journal
+# of Glaciology.
+#
+# High performance is not the goal for this implementation, which is instead
+# intended as a heavily annotated example on the solution procedure without
+# relying on solver libraries, suitable for low-level languages like C, Fortran
+# or CUDA.
+#
+# License: Gnu Public License v3
+# Author: Anders Damsgaard, [email protected], https://adamsgaard.dk
+
+import numpy
+import matplotlib.pyplot as plt
+import sys
+
+
+## Model parameters
+Ns = 25 # Number of nodes [-]
+Ls = 100e3 # Model length [m]
+t_end = 24.*60.*60.*2 # Total simulation time [s]
+tol_Q = 1e-3 # Tolerance criteria for the normalized max. residual for Q
+tol_P_c = 1e-3 # Tolerance criteria for the normalized max. residual for P_c
+max_iter = 1e2*Ns # Maximum number of solver iterations before failure
+output_convergence = False # Display convergence statistics during run
+
+# Physical parameters
+rho_w = 1000. # Water density [kg/m^3]
+rho_i = 910. # Ice density [kg/m^3]
+rho_s = 2600. # Sediment density [kg/m^3]
+g = 9.8 # Gravitational acceleration [m/s^2]
+theta = 30. # Angle of internal friction in sediment [deg]
+
+# Water source term [m/s]
+#m_dot = 7.93e-11
+#m_dot = 4.5e-8
+m_dot = 5.79e-5
+
+# Walder and Fowler 1994 sediment transport parameters
+K_e = 0.1 # Erosion constant [-], disabled when 0.0
+K_d = 6.0 # Deposition constant [-], disabled when 0.0
+#D50 = 1e-3 # Median grain size [m]
+#tau_c = 0.5*g*(rho_s - rho_i)*D50 # Critical shear stress for transport
+d15 = 1e-3 # Characteristic grain size [m]
+tau_c = 0.025*d15*g*(rho_s - rho_i) # Critical shear stress (Carter 2016)
+#tau_c = 0.
+mu_w = 1.787e-3 # Water viscosity [Pa*s]
+froude = 0.1 # Friction factor [-]
+v_s = d15**2.*g*2.*(rho_s - rho_i)/(9.*mu_w) # Settling velocity (Carter 2016)
+
+# Hewitt 2011 channel flux parameters
+manning = 0.1 # Manning roughness coefficient [m^{-1/3} s]
+F = rho_w*g*manning*(2.*(numpy.pi + 2)**2./numpy.pi)**(2./3.)
+
+# Channel growth-limit parameters
+c_1 = -0.118 # [m/kPa]
+c_2 = 4.60 # [m]
+
+# Minimum channel size [m^2], must be bigger than 0
+S_min = 1e-1
+
+
+## Initialize model arrays
+# Node positions, terminus at Ls
+s = numpy.linspace(0., Ls, Ns)
+ds = s[1:] - s[:-1]
+
+# Ice thickness and bed topography
+H = 6.*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0 # max: 1.5 km
+#H = 1.*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0 # max: 255 m
+#H = 0.6*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0
+b = numpy.zeros_like(H)
+
+N = H*0.1*rho_i*g # Initial effective stress [Pa]
+p_w = rho_i*g*H - N # Initial guess of water pressure [Pa]
+hydro_pot = rho_w*g*b + p_w # Initial guess of hydraulic potential [Pa]
+
+# Initialize arrays for channel segments between nodes
+S = numpy.ones(len(s) - 1)*S_min # Cross-sectional area of channel segments[m^…
+S_max = numpy.zeros_like(S) # Max. channel size [m^2]
+dSdt = numpy.empty_like(S) # Transient in channel cross-sectional area [m^2/s]
+W = S/numpy.tan(numpy.deg2rad(theta)) # Assuming no channel floor wedge
+Q = numpy.zeros_like(S) # Water flux in channel segments [m^3/s]
+Q_s = numpy.zeros_like(S) # Sediment flux in channel segments [m^3/s]
+N_c = numpy.zeros_like(S) # Effective pressure in channel segments [Pa]
+P_c = numpy.zeros_like(S) # Water pressure in channel segments [Pa]
+e_dot = numpy.zeros_like(S) # Sediment erosion rate in channel segments [m/s]
+d_dot = numpy.zeros_like(S) # Sediment deposition rate in chan. segments [m/s]
+c_bar = numpy.zeros_like(S) # Vertically integrated sediment content [m]
+tau = numpy.zeros_like(S) # Avg. shear stress from current [Pa]
+porosity = numpy.ones_like(S)*0.3 # Sediment porosity [-]
+res = numpy.zeros_like(S) # Solution residual during solver iterations
+
+
+## Helper functions
+def gradient(arr, arr_x):
+ # Central difference gradient of an array ``arr`` with node positions at
+ # ``arr_x``.
+ return (arr[:-1] - arr[1:])/(arr_x[:-1] - arr_x[1:])
+
+def avg_midpoint(arr):
+ # Averaged value of neighboring array elements
+ return (arr[:-1] + arr[1:])/2.
+
+def channel_water_flux(S, hydro_pot_grad):
+ # Hewitt 2011
+ return numpy.sqrt(1./F*S**(8./3.)*-hydro_pot_grad)
+
+def channel_shear_stress(Q, S):
+ # Weertman 1972, Walder and Fowler 1994
+ u_bar = Q/S
+ return 1./8.*froude*rho_w*u_bar**2.
+
+def channel_erosion_rate(tau):
+ # Parker 1979, Walder and Fowler 1994
+ return K_e*v_s*(tau - tau_c).clip(0.)/(g*(rho_s - rho_w)*d15)
+
+def channel_deposition_rate_kernel(tau, c_bar, ix):
+ # Parker 1979, Walder and Fowler 1994
+ return K_d*v_s*c_bar[ix]*(g*(rho_s - rho_w)*d15/tau[ix])**0.5
+
+def channel_deposition_rate(tau, c_bar, d_dot, Ns):
+ # Parker 1979, Walder and Fowler 1994
+ # Find deposition rate from upstream to downstream, margin at is=0
+
+ # No sediment deposition at upstream end
+ c_bar[0] = 0.
+ d_dot[0] = 0.
+ for ix in numpy.arange(1, Ns - 1):
+
+ # Net erosion in upstream cell
+ c_bar[ix] += numpy.maximum((e_dot[ix - 1] - d_dot[ix - 1])*dt, 0.)
+
+ d_dot[ix] = channel_deposition_rate_kernel(tau, c_bar, ix)
+
+ return d_dot, c_bar
+
+def channel_growth_rate(e_dot, d_dot, porosity, W):
+ # Damsgaard et al, in prep
+ return (e_dot - d_dot)/porosity*W
+
+def update_channel_size_with_limit(S, dSdt, dt, N):
+ # Damsgaard et al, in prep
+ S_max = ((c_1*N/1000. + c_2)*\
+ numpy.tan(numpy.deg2rad(theta))).clip(min=S_min)
+ S = numpy.minimum(S + dSdt*dt, S_max).clip(min=S_min)
+ W = S/numpy.tan(numpy.deg2rad(theta)) # Assume no channel floor wedge
+ return S, W, S_max
+
+def flux_solver(m_dot, ds):
+ # Iteratively find new fluxes
+ it = 0
+ max_res = 1e9 # arbitrary large value
+
+ # Iteratively find solution, do not settle for less iterations than the
+ # number of nodes
+ while max_res > tol_Q or it < Ns:
+
+ Q_old = Q.copy()
+ # dQ/ds = m_dot -> Q_out = m*delta(s) + Q_in
+ # Upwind information propagation (upwind)
+ Q[0] = 1e-2 # Ng 2000
+ Q[1:] = m_dot*ds[1:] + Q[:-1]
+ max_res = numpy.max(numpy.abs((Q - Q_old)/(Q + 1e-16)))
+
+ if output_convergence:
+ print('it = {}: max_res = {}'.format(it, max_res))
+
+ #import ipdb; ipdb.set_trace()
+ if it >= max_iter:
+ raise Exception('t = {}, step = {}:'.format(time, step) +
+ 'Iterative solution not found for Q')
+ it += 1
+
+ return Q
+
+def suspended_sediment_flux(c_bar, Q, S):
+ # Find the fluvial sediment flux through the system
+ # Q_s = c_bar * u * S, where u = Q/S
+ return c_bar*Q
+
+def pressure_solver(psi, F, Q, S):
+ # Iteratively find new water pressures
+ # dP_c/ds = psi - FQ^2/S^{8/3}
+
+ it = 0
+ max_res = 1e9 # arbitrary large value
+ while max_res > tol_P_c or it < Ns*40:
+
+ P_c_old = P_c.copy()
+
+ # Upwind finite differences
+ P_c[:-1] = -psi[:-1]*ds[:-1] \
+ + F*Q[:-1]**2./(S[:-1]**(8./3.))*ds[:-1] \
+ + P_c[1:] # Upstream
+
+ # Dirichlet BC (fixed pressure) at terminus
+ P_c[-1] = 0.
+
+ # von Neumann BC (no gradient = no flux) at s=0
+ P_c[0] = P_c[1]
+
+ max_res = numpy.max(numpy.abs((P_c - P_c_old)/(P_c + 1e-16)))
+
+ if output_convergence:
+ print('it = {}: max_res = {}'.format(it, max_res))
+
+ if it >= max_iter:
+ raise Exception('t = {}, step = {}:'.format(time, step) +
+ 'Iterative solution not found for P_c')
+ it += 1
+
+ return P_c
+
+def plot_state(step, time):
+ # Plot parameters along profile
+ fig = plt.gcf()
+ fig.set_size_inches(3.3, 3.3)
+
+ ax_Pa = plt.subplot(2, 1, 1) # axis with Pascals as y-axis unit
+ ax_Pa.plot(s_c/1000., P_c/1000., '--r', label='$P_c$')
+
+ ax_m3s = ax_Pa.twinx() # axis with m3/s as y-axis unit
+ ax_m3s.plot(s_c/1000., Q, '-b', label='$Q$')
+
+ plt.title('Day: {:.3}'.format(time/(60.*60.*24.)))
+ ax_Pa.legend(loc=2)
+ ax_m3s.legend(loc=1)
+ ax_Pa.set_ylabel('[kPa]')
+ ax_m3s.set_ylabel('[m$^3$/s]')
+
+ ax_m = plt.subplot(2, 1, 2, sharex=ax_Pa)
+ #ax_m.plot(s_c/1000., S, '-k', label='$S$')
+ #ax_m.plot(s_c/1000., S_max, '--k', label='$S_{max}$')
+ ax_m.semilogy(s_c/1000., S, '-k', label='$S$')
+ ax_m.semilogy(s_c/1000., S_max, '--k', label='$S_{max}$')
+
+ ax_ms = ax_m.twinx()
+ ax_ms.plot(s_c/1000., e_dot, '--r', label='$\dot{e}$')
+ ax_ms.plot(s_c/1000., d_dot, ':b', label='$\dot{d}$')
+
+ ax_m.legend(loc=2)
+ ax_ms.legend(loc=1)
+ ax_m.set_xlabel('$s$ [km]')
+ ax_m.set_ylabel('[m]')
+ ax_ms.set_ylabel('[m/s]')
+
+ plt.setp(ax_Pa.get_xticklabels(), visible=False)
+ plt.tight_layout()
+ if step == -1:
+ plt.savefig('chan-0.init.pdf')
+ else:
+ plt.savefig('chan-' + str(step) + '.pdf')
+ plt.clf()
+
+def find_new_timestep(ds, Q, S):
+ # Determine the timestep using the Courant-Friedrichs-Lewy condition
+ safety = 0.2
+ dt = safety*numpy.minimum(60.*60.*24., numpy.min(numpy.abs(ds/(Q*S))))
+
+ if dt < 1.0:
+ raise Exception('Error: Time step less than 1 second at step '
+ + '{}, time '.format(step)
+ + '{:.3} s/{:.3} d'.format(time, time/(60.*60.*24.)))
+
+ return dt
+
+def print_status_to_stdout(time, dt):
+ sys.stdout.write('\rt = {:.2} s or {:.4} d, dt = {:.2} s '\
+ .format(time, time/(60.*60.*24.), dt))
+ sys.stdout.flush()
+
+s_c = avg_midpoint(s) # Channel section midpoint coordinates [m]
+
+# Find gradient in hydraulic potential between the nodes
+hydro_pot_grad = gradient(hydro_pot, s)
+
+# Find field values at the middle of channel segments
+N_c = avg_midpoint(N)
+H_c = avg_midpoint(N)
+
+# Find fluxes in channel segments [m^3/s]
+Q = channel_water_flux(S, hydro_pot_grad)
+
+# Water-pressure gradient from geometry [Pa/m]
+psi = -rho_i*g*gradient(H, s) - (rho_w - rho_i)*g*gradient(b, s)
+
+# Prepare figure object for plotting during the simulation
+fig = plt.figure('channel')
+plot_state(-1, 0.0)
+
+
+## Time loop
+time = 0.; step = 0
+while time <= t_end:
+
+ dt = find_new_timestep(ds, Q, S)
+
+ print_status_to_stdout(time, dt)
+
+ # Find average shear stress from water flux for each channel segment
+ tau = channel_shear_stress(Q, S)
+
+ # Find sediment erosion and deposition rates for each channel segment
+ e_dot = channel_erosion_rate(tau)
+ d_dot, c_bar = channel_deposition_rate(tau, c_bar, d_dot, Ns)
+
+ # Determine change in channel size for each channel segment
+ dSdt = channel_growth_rate(e_dot, d_dot, porosity, W)
+
+ # Update channel cross-sectional area and width according to growth rate
+ # and size limit for each channel segment
+ S, W, S_max = update_channel_size_with_limit(S, dSdt, dt, N_c)
+
+ # Find new water fluxes consistent with mass conservation and local
+ # meltwater production (m_dot)
+ Q = flux_solver(m_dot, ds)
+
+ # Find the corresponding sediment flux
+ #Q_b = bedload_sediment_flux(
+ Q_s = suspended_sediment_flux(c_bar, Q, S)
+
+ # Find new water pressures consistent with the flow law
+ P_c = pressure_solver(psi, F, Q, S)
+
+ # Find new effective pressure in channel segments
+ N_c = rho_i*g*H_c - P_c
+
+ plot_state(step, time)
+
+ if step > 0:
+ break
+ # Update time
+ time += dt
+ step += 1
diff --git a/1d-test.py b/1d-test.py
t@@ -1,322 +0,0 @@
-#!/usr/bin/env python
-
-## ABOUT THIS FILE
-# The following script uses basic Python and Numpy functionality to solve the
-# coupled systems of equations describing subglacial channel development in
-# soft beds as presented in `Damsgaard et al. "Sediment plasticity controls
-# channelization of subglacial meltwater in soft beds"`, submitted to Journal
-# of Glaciology.
-# High performance is not the goal for this implementation, which is instead
-# intended as a heavily annotated example on the solution procedure without
-# relying on solver libraries, suitable for low-level languages like C, Fortran
-# or CUDA.
-
-
-import numpy
-import matplotlib.pyplot as plt
-import sys
-
-## Model parameters
-Ns = 25 # Number of nodes [-]
-Ls = 100e3 # Model length [m]
-t_end = 24.*60.*60.*2 # Total simulation time [s]
-tol_Q = 1e-3 # Tolerance criteria for the normalized max. residual for Q
-tol_P_c = 1e-3 # Tolerance criteria for the normalized max. residual for P_c
-max_iter = 1e2*Ns # Maximum number of solver iterations before failure
-output_convergence = False
-
-# Physical parameters
-rho_w = 1000. # Water density [kg/m^3]
-rho_i = 910. # Ice density [kg/m^3]
-rho_s = 2600. # Sediment density [kg/m^3]
-g = 9.8 # Gravitational acceleration [m/s^2]
-theta = 30. # Angle of internal friction in sediment [deg]
-
-# Water source term [m/s]
-#m_dot = 7.93e-11
-m_dot = 5.79e-5
-#m_dot = 4.5e-8
-
-# Walder and Fowler 1994 sediment transport parameters
-K_e = 0.1 # Erosion constant [-], disabled when 0.0
-K_d = 6.0 # Deposition constant [-], disabled when 0.0
-#D50 = 1e-3 # Median grain size [m]
-#tau_c = 0.5*g*(rho_s - rho_i)*D50 # Critical shear stress for transport
-d15 = 1e-3 # Characteristic grain size [m]
-tau_c = 0.025*d15*g*(rho_s - rho_i) # Critical shear stress (Carter 2016)
-#tau_c = 0.
-mu_w = 1.787e-3 # Water viscosity [Pa*s]
-froude = 0.1 # Friction factor [-]
-v_s = d15**2.*g*2.*(rho_s - rho_i)/(9.*mu_w) # Settling velocity (Carter 2016)
-
-# Hewitt 2011 channel flux parameters
-manning = 0.1 # Manning roughness coefficient [m^{-1/3} s]
-F = rho_w*g*manning*(2.*(numpy.pi + 2)**2./numpy.pi)**(2./3.)
-
-# Channel growth-limit parameters
-c_1 = -0.118 # [m/kPa]
-c_2 = 4.60 # [m]
-
-# Minimum channel size [m^2], must be bigger than 0
-S_min = 1e-1
-
-
-## Initialize model arrays
-# Node positions, terminus at Ls
-s = numpy.linspace(0., Ls, Ns)
-ds = s[1:] - s[:-1]
-
-# Ice thickness and bed topography
-H = 6.*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0 # max: 1.5 km
-#H = 1.*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0 # max: 255 m
-#H = 0.6*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0
-b = numpy.zeros_like(H)
-
-N = H*0.1*rho_i*g # Initial effective stress [Pa]
-p_w = rho_i*g*H - N # Initial guess of water pressure [Pa]
-hydro_pot = rho_w*g*b + p_w # Initial guess of hydraulic potential [Pa]
-
-# Initialize arrays for channel segments between nodes
-S = numpy.ones(len(s) - 1)*S_min # Cross-sectional area of channel segments[m^…
-S_max = numpy.zeros_like(S) # Max. channel size [m^2]
-dSdt = numpy.empty_like(S) # Transient in channel cross-sectional area [m^2/s]
-W = S/numpy.tan(numpy.deg2rad(theta)) # Assuming no channel floor wedge
-Q = numpy.zeros_like(S) # Water flux in channel segments [m^3/s]
-Q_s = numpy.zeros_like(S) # Sediment flux in channel segments [m^3/s]
-N_c = numpy.zeros_like(S) # Effective pressure in channel segments [Pa]
-P_c = numpy.zeros_like(S) # Water pressure in channel segments [Pa]
-e_dot = numpy.zeros_like(S) # Sediment erosion rate in channel segments [m/s]
-d_dot = numpy.zeros_like(S) # Sediment deposition rate in chan. segments [m/s]
-c_bar = numpy.zeros_like(S) # Vertically integrated sediment content [m]
-tau = numpy.zeros_like(S) # Avg. shear stress from current [Pa]
-porosity = numpy.ones_like(S)*0.3 # Sediment porosity [-]
-res = numpy.zeros_like(S) # Solution residual during solver iterations
-
-
-## Helper functions
-def gradient(arr, arr_x):
- # Central difference gradient of an array ``arr`` with node positions at
- # ``arr_x``.
- return (arr[:-1] - arr[1:])/(arr_x[:-1] - arr_x[1:])
-
-def avg_midpoint(arr):
- # Averaged value of neighboring array elements
- return (arr[:-1] + arr[1:])/2.
-
-def channel_water_flux(S, hydro_pot_grad):
- # Hewitt 2011
- return numpy.sqrt(1./F*S**(8./3.)*-hydro_pot_grad)
-
-def channel_shear_stress(Q, S):
- # Weertman 1972, Walder and Fowler 1994
- u_bar = Q*S
- return 1./8.*froude*rho_w*u_bar**2.
-
-def channel_erosion_rate(tau):
- # Parker 1979, Walder and Fowler 1994
- return K_e*v_s*(tau - tau_c).clip(0.)/(g*(rho_s - rho_w)*d15)
-
-def channel_deposition_rate_kernel(tau, c_bar, ix):
- # Parker 1979, Walder and Fowler 1994
- return K_d*v_s*c_bar[ix]*(g*(rho_s - rho_w)*d15/tau[ix])**0.5
-
-def channel_deposition_rate(tau, c_bar, d_dot, Ns):
- # Parker 1979, Walder and Fowler 1994
- # Find deposition rate from upstream to downstream, margin at is=0
- #for ix in numpy.arange(Ns-2, -1, -1):
- for ix in numpy.arange(Ns - 1):
- if ix == 0: # No sediment deposition at upstream end
- c_bar[ix] = 0.
- d_dot[ix] = 0.
- else:
- c_bar[ix] = (e_dot[ix - 1] - d_dot[ix - 1])*dt # Net erosion upstr.
- d_dot[ix] = channel_deposition_rate_kernel(tau, c_bar, ix)
- return d_dot, c_bar
-
-def channel_growth_rate(e_dot, d_dot, porosity, W):
- # Damsgaard et al, in prep
- return (e_dot - d_dot)/porosity*W
-
-def update_channel_size_with_limit(S, dSdt, dt, N):
- # Damsgaard et al, in prep
- S_max = ((c_1*N/1000. + c_2)*\
- numpy.tan(numpy.deg2rad(theta))).clip(min=S_min)
- S = numpy.minimum(S + dSdt*dt, S_max).clip(min=S_min)
- W = S/numpy.tan(numpy.deg2rad(theta)) # Assume no channel floor wedge
- return S, W, S_max
-
-def flux_solver(m_dot, ds):
- # Iteratively find new fluxes
- it = 0
- max_res = 1e9 # arbitrary large value
-
- # Iteratively find solution, do not settle for less iterations than the
- # number of nodes
- while max_res > tol_Q or it < Ns:
-
- Q_old = Q.copy()
- # dQ/ds = m_dot -> Q_out = m*delta(s) + Q_in
- # Upwind information propagation (upwind)
- Q[0] = 1e-2 # Ng 2000
- Q[1:] = m_dot*ds[1:] + Q[:-1]
- max_res = numpy.max(numpy.abs((Q - Q_old)/(Q + 1e-16)))
-
- if output_convergence:
- print('it = {}: max_res = {}'.format(it, max_res))
-
- #import ipdb; ipdb.set_trace()
- if it >= max_iter:
- raise Exception('t = {}, step = {}:'.format(time, step) +
- 'Iterative solution not found for Q')
- it += 1
-
- return Q
-
-def pressure_solver(psi, F, Q, S):
- # Iteratively find new water pressures
- # dP_c/ds = psi - FQ^2/S^{8/3}
-
- it = 0
- max_res = 1e9 # arbitrary large value
- while max_res > tol_P_c or it < Ns*40:
-
- P_c_old = P_c.copy()
-
- # Upwind finite differences
- P_c[:-1] = -psi[:-1]*ds[:-1] \
- + F*Q[:-1]**2./(S[:-1]**(8./3.))*ds[:-1] \
- + P_c[1:] # Upstream
-
- # Dirichlet BC (fixed pressure) at terminus
- P_c[-1] = 0.
-
- # von Neumann BC (no gradient = no flux) at s=0
- P_c[0] = P_c[1]
-
- max_res = numpy.max(numpy.abs((P_c - P_c_old)/(P_c + 1e-16)))
-
- if output_convergence:
- print('it = {}: max_res = {}'.format(it, max_res))
-
- if it >= max_iter:
- raise Exception('t = {}, step = {}:'.format(time, step) +
- 'Iterative solution not found for P_c')
- it += 1
-
- return P_c
-
-def plot_state(step, time):
- # Plot parameters along profile
- fig = plt.gcf()
- fig.set_size_inches(3.3, 3.3)
-
- ax_Pa = plt.subplot(2, 1, 1) # axis with Pascals as y-axis unit
- ax_Pa.plot(s_c/1000., P_c/1000., '--r', label='$P_c$')
-
- ax_m3s = ax_Pa.twinx() # axis with m3/s as y-axis unit
- ax_m3s.plot(s_c/1000., Q, '-b', label='$Q$')
-
- plt.title('Day: {:.3}'.format(time/(60.*60.*24.)))
- ax_Pa.legend(loc=2)
- ax_m3s.legend(loc=1)
- ax_Pa.set_ylabel('[kPa]')
- ax_m3s.set_ylabel('[m$^3$/s]')
-
- ax_m = plt.subplot(2, 1, 2, sharex=ax_Pa)
- #ax_m.plot(s_c/1000., S, '-k', label='$S$')
- #ax_m.plot(s_c/1000., S_max, '--k', label='$S_{max}$')
- ax_m.semilogy(s_c/1000., S, '-k', label='$S$')
- ax_m.semilogy(s_c/1000., S_max, '--k', label='$S_{max}$')
-
- ax_ms = ax_m.twinx()
- ax_ms.plot(s_c/1000., e_dot, '--r', label='$\dot{e}$')
- ax_ms.plot(s_c/1000., d_dot, ':b', label='$\dot{d}$')
-
- ax_m.legend(loc=2)
- ax_ms.legend(loc=1)
- ax_m.set_xlabel('$s$ [km]')
- ax_m.set_ylabel('[m]')
- ax_ms.set_ylabel('[m/s]')
-
- plt.setp(ax_Pa.get_xticklabels(), visible=False)
- plt.tight_layout()
- if step == -1:
- plt.savefig('chan-0.init.pdf')
- else:
- plt.savefig('chan-' + str(step) + '.pdf')
- plt.clf()
-
-def find_new_timestep(ds, Q, S):
- # Determine the timestep using the Courant-Friedrichs-Lewy condition
- safety = 0.2
- dt = safety*numpy.minimum(60.*60.*24., numpy.min(numpy.abs(ds/(Q*S))))
-
- if dt < 1.0:
- raise Exception('Error: Time step less than 1 second at step '
- + '{}, time '.format(step)
- + '{:.3} s/{:.3} d'.format(time, time/(60.*60.*24.)))
-
- return dt
-
-def print_status_to_stdout(time, dt):
- sys.stdout.write('\rt = {:.2} s or {:.4} d, dt = {:.2} s '\
- .format(time, time/(60.*60.*24.), dt))
- sys.stdout.flush()
-
-s_c = avg_midpoint(s) # Channel section midpoint coordinates [m]
-
-# Find gradient in hydraulic potential between the nodes
-hydro_pot_grad = gradient(hydro_pot, s)
-
-# Find field values at the middle of channel segments
-N_c = avg_midpoint(N)
-H_c = avg_midpoint(N)
-
-# Find fluxes in channel segments [m^3/s]
-Q = channel_water_flux(S, hydro_pot_grad)
-
-# Water-pressure gradient from geometry [Pa/m]
-psi = -rho_i*g*gradient(H, s) - (rho_w - rho_i)*g*gradient(b, s)
-
-# Prepare figure object for plotting during the simulation
-fig = plt.figure('channel')
-plot_state(-1, 0.0)
-
-
-## Time loop
-time = 0.; step = 0
-while time <= t_end:
-
- dt = find_new_timestep(ds, Q, S)
-
- print_status_to_stdout(time, dt)
-
- # Find average shear stress from water flux for each channel segment
- tau = channel_shear_stress(Q, S)
-
- # Find sediment erosion and deposition rates for each channel segment
- e_dot = channel_erosion_rate(tau)
- d_dot, c_bar = channel_deposition_rate(tau, c_bar, d_dot, Ns)
-
- # Determine change in channel size for each channel segment
- dSdt = channel_growth_rate(e_dot, d_dot, porosity, W)
-
- # Update channel cross-sectional area and width according to growth rate
- # and size limit for each channel segment
- S, W, S_max = update_channel_size_with_limit(S, dSdt, dt, N_c)
-
- # Find new water fluxes consistent with mass conservation and local
- # meltwater production (m_dot)
- Q = flux_solver(m_dot, ds)
-
- # Find new water pressures consistent with the flow law
- P_c = pressure_solver(psi, F, Q, S)
-
- # Find new effective pressure in channel segments
- N_c = rho_i*g*H_c - P_c
-
- plot_state(step, time)
-
- # Update time
- time += dt
- step += 1
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.