granular-channel-hydro

Subglacial hydrology model for sedimentary channels
git clone git://src.adamsgaard.dk/granular-channel-hydro
Log | Files | Refs | README | LICENSE

commit f93ba7d18a7e1c4571d858a6281ae493558a630f
parent 46dfffde617f0688622073bd949a6d64311f8368
Author: Anders Damsgaard <andersd@riseup.net>
Date:   Tue, 17 Oct 2017 13:08:00 -0400

update README, add LICENSE and remove old and unused files

Diffstat:
D1d-channel-flux.py | 292-------------------------------------------------------------------------------
D1d-channel-wilcock-two-phase.py | 431-------------------------------------------------------------------------------
M1d-channel.py | 49++++++++++++++++++++++++-------------------------
ALICENSE.md | 636+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MREADME.md | 13+++++++++++++
Dgranular_channel_drainage/__init__.py | 5-----
Dgranular_channel_drainage/model.py | 137-------------------------------------------------------------------------------
Mrequirements.txt | 1-
8 files changed, 673 insertions(+), 891 deletions(-)

diff --git a/1d-channel-flux.py b/1d-channel-flux.py @@ -1,292 +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. -# -# License: Gnu Public License v3 -# Author: Anders Damsgaard, adamsgaard@ucsd.edu, 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.*120. # 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 -safety = 0.1 # Safety factor ]0;1] for adaptive timestepping - -# 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 - -# 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 -S_min = 1.5e-2 - - -# # 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-sect. area of channel segments [m^2] -S_max = numpy.zeros_like(S) # Max. channel size [m^2] -dSdt = numpy.zeros_like(S) # Transient in channel cross-sect. 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] -dQ_s_ds = numpy.empty_like(S) # Transient in channel cross-sect. area [m^2/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] -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 update_channel_size_with_limit(S, dSdt, dt, N): - # Damsgaard et al, in prep - S_max = ((c_1*N.clip(min=0.)/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 sediment_flux(Q): - #return Q**(3./2.) - return Q/2. - -def sediment_flux_divergence(Q_s, ds): - # Damsgaard et al, in prep - return (Q_s[1:] - Q_s[:-1])/ds[1:] - -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$') - ax_m3s.plot(s_c/1000., Q_s, ':b', label='$Q_s$') - - 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_m2 = plt.subplot(2, 1, 2, sharex=ax_Pa) - ax_m2.plot(s_c/1000., S, '-k', label='$S$') - ax_m2.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_m2s = ax_m2.twinx() - ax_m2s.plot(s_c/1000., dSdt, ':b', label='$dS/dt$') - - ax_m2.legend(loc=2) - ax_m2s.legend(loc=1) - ax_m2.set_xlabel('$s$ [km]') - ax_m2.set_ylabel('[m$^2$]') - ax_m2s.set_ylabel('[m$^2$/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 - 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: - - #print('@ @ @ step ' + str(step)) - - dt = find_new_timestep(ds, Q, S) - - print_status_to_stdout(time, dt) - - # Find the sediment flux - Q_s = sediment_flux(Q) - - # Find sediment flux divergence which determines channel growth, no growth - # in first segment - dSdt[1:] = sediment_flux_divergence(Q_s, ds) - - # 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) - - #import ipdb; ipdb.set_trace() - #if step > 0: - #break - - # Update time - time += dt - step += 1 diff --git a/1d-channel-wilcock-two-phase.py b/1d-channel-wilcock-two-phase.py @@ -1,431 +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. -# -# License: Gnu Public License v3 -# Author: Anders Damsgaard, adamsgaard@ucsd.edu, https://adamsgaard.dk - -import numpy -import matplotlib.pyplot as plt -import sys - - -# # Model parameters -Ns = 25 # Number of nodes [-] -Ls = 1e3 # Model length [m] -total_days = 60. # Total simulation time [d] -t_end = 24.*60.*60.*total_days # Total simulation time [s] -tol_S = 1e-3 # Tolerance criteria for the norm. max. residual for Q -tol_Q = 1e-3 # Tolerance criteria for the norm. max. residual for Q -tol_N_c = 1e-3 # Tolerance criteria for the norm. max. residual for N_c -max_iter = 1e2*Ns # Maximum number of solver iterations before failure -print_output_convergence = False # Display convergence in nested loops -print_output_convergence_main = True # Display convergence in main loop -safety = 0.01 # Safety factor ]0;1] for adaptive timestepping -plot_interval = 20 # Time steps between plots -plot_during_iterations = False # Generate plots for intermediate results -#plot_during_iterations = True # Generate plots for intermediate results -speedup_factor = 1. # Speed up channel growth to reach steady state faster -#relax_dSdt = 0.3 # Relaxation parameter for channel growth rate ]0;1] -relax = 0.05 # Relaxation parameter for effective pressure ]0;1] - -# 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] -sand_fraction = 0.5 # Initial volumetric fraction of sand relative to gravel -D_g = 5e-3 # Mean grain size in gravel fraction (> 2 mm) [m] -D_s = 5e-4 # Mean grain size in sand fraction (<= 2 mm) [m] -#D_g = 1 -#D_g = 0.1 - -# Boundary conditions -P_terminus = 0. # Water pressure at terminus [Pa] -#m_dot = 3.5e-6 -m_dot = numpy.linspace(0., 3.5e-6, Ns-1) # Water source term [m/s] -Q_upstream = 1e-5 # Water influx upstream (must be larger than 0) [m^3/s] - -# Channel hydraulic properties -manning = 0.1 # Manning roughness coefficient [m^{-1/3} s] -friction_factor = 0.1 # Darcy-Weisbach friction factor [-] - -# 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-2 -# S_min = 1e-1 -# S_min = 1. - - -# # Initialize model arrays -# Node positions, terminus at Ls -s = numpy.linspace(0., Ls, Ns) -ds = s[1:] - s[:-1] - -# Ice thickness [m] -H = 6.*(numpy.sqrt(Ls - s + 5e3) - numpy.sqrt(5e3)) + 1.0 -# slope = 0.1 # Surface slope [%] -# H = 1000. + -slope/100.*s - -# Bed topography [m] -b = numpy.zeros_like(H) - -N = H*0.1*rho_i*g # Initial effective stress [Pa] - -# Initialize arrays for channel segments between nodes -S = numpy.ones(len(s) - 1)*S_min # Cross-sect. area of channel segments[m^2] -S_max = numpy.zeros_like(S) # Max. channel size [m^2] -dSdt = numpy.zeros_like(S) # Transient in channel cross-sect. 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] -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 -Q_t = numpy.zeros_like(S) # Total sediment flux [m3/s] -Q_s = numpy.zeros_like(S) # Sediment flux where D <= 2 mm [m3/s] -Q_g = numpy.zeros_like(S) # Sediment flux where D > 2 mm [m3/s] -f_s = numpy.ones_like(S)*sand_fraction # Initial sediment fraction of sand [-] - - -# # 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_hydraulic_roughness(manning, S, W, theta): - # Determine hydraulic roughness assuming that the channel has no channel - # floor wedge. - l = W + W/numpy.cos(numpy.deg2rad(theta)) # wetted perimeter - return manning**2.*(l**2./S)**(2./3.) - - -def channel_shear_stress(Q, S): - # Determine mean wall shear stress from Darcy-Weisbach friction loss - u_bar = Q/S - return 1./8.*friction_factor*rho_w*u_bar**2. - - -def channel_sediment_flux_sand(tau, W, f_s, D_s): - # Parker 1979, Wilcock 1997, 2001, Egholm 2013 - # tau: Shear stress by water flow - # W: Channel width - # f_s: Sand volume fraction - # D_s: Mean sand fraction grain size - - # Piecewise linear functions for nondimensional critical shear stresses - # dependent on sand fraction from Gasparini et al 1999 of Wilcock 1997 - # data. - ref_shear_stress = numpy.ones_like(f_s)*0.04 - ref_shear_stress[numpy.nonzero(f_s <= 0.1)] = 0.88 - I = numpy.nonzero((0.1 < f_s) & (f_s <= 0.4)) - ref_shear_stress[I] = 0.88 - 2.8*(f_s[I] - 0.1) - - # Non-dimensionalize shear stress - shields_stress = tau/((rho_s - rho_w)*g*D_s) - - # import ipdb; ipdb.set_trace() - Q_c = 11.2*f_s*W/((rho_s - rho_w)/rho_w*g) \ - * (tau/rho_w)**1.5 \ - * numpy.maximum(0.0, - (1.0 - 0.846*numpy.sqrt(ref_shear_stress/shields_stress)) - )**4.5 - - return Q_c - - -def channel_sediment_flux_gravel(tau, W, f_g, D_g): - # Parker 1979, Wilcock 1997, 2001, Egholm 2013 - # tau: Shear stress by water flow - # W: Channel width - # f_g: Gravel volume fraction - # D_g: Mean gravel fraction grain size - - # Piecewise linear functions for nondimensional critical shear stresses - # dependent on sand fraction from Gasparini et al 1999 of Wilcock 1997 - # data. - ref_shear_stress = numpy.ones_like(f_g)*0.01 - ref_shear_stress[numpy.nonzero(f_g <= 0.1)] = 0.04 - I = numpy.nonzero((0.1 < f_g) & (f_g <= 0.4)) - ref_shear_stress[I] = 0.04 - 0.1*(f_g[I] - 0.1) - - # Non-dimensionalize shear stress - shields_stress = tau/((rho_s - rho_w)*g*D_g) - - # From Wilcock 2001, eq. 3 - Q_g = 11.2*f_g*W/((rho_s - rho_w)/rho_w*g) \ - * (tau/rho_w)**1.5 \ - * numpy.maximum(0.0, - (1.0 - 0.846*ref_shear_stress/shields_stress))**4.5 - - # From Wilcock 2001, eq. 4 - I = numpy.nonzero(ref_shear_stress/shields_stress < 1.) - Q_g[I] = f_g[I]*W[I]/((rho_s - rho_w)/rho_w*g) \ - * (tau[I]/rho_w)**1.5 \ - * 0.0025*(shields_stress[I]/ref_shear_stress[I])**14.2 - - return Q_g - - -def channel_growth_rate_sedflux(Q_t, porosity, s_c): - # Damsgaard et al, in prep - return 1./porosity[1:] * gradient(Q_t, s_c) - - -def update_channel_size_with_limit(S, S_old, dSdt, dt, N_c): - # Damsgaard et al, in prep - S_max = numpy.maximum( - numpy.maximum( - 1./4.*(c_1*numpy.maximum(N_c, 0.)/1000. + c_2), 0.)**2. * - numpy.tan(numpy.deg2rad(theta)), S_min) - S = numpy.maximum(numpy.minimum(S_old + dSdt*dt, S_max), S_min) - W = S/numpy.tan(numpy.deg2rad(theta)) # Assume no channel floor wedge - dSdt = S - S_old # adjust dSdt for clipping due to channel size limits - return S, W, S_max, dSdt - - -def flux_solver(m_dot, ds): - # Iteratively find new water 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: - - Q_old = Q.copy() - # dQ/ds = m_dot -> Q_out = m*delta(s) + Q_in - # Upwind information propagation (upwind) - Q[0] = Q_upstream - Q[1:] = m_dot[1:]*ds[1:] + Q[:-1] - max_res = numpy.max(numpy.abs((Q - Q_old)/(Q + 1e-16))) - - if print_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 - # dN_c/ds = f*rho_w*g*Q^2/S^{8/3} - psi (Kingslake and Ng 2013) - - it = 0 - max_res = 1e9 # arbitrary large value - while max_res > tol_N_c: - - N_c_old = N_c.copy() - - # Dirichlet BC (fixed pressure) at terminus - N_c[-1] = rho_i*g*H_c[-1] - P_terminus - - N_c[:-1] = N_c[1:] \ - + psi[:-1]*ds[:-1] \ - - f[:-1]*rho_w*g*Q[:-1]*numpy.abs(Q[:-1]) \ - /(S[:-1]**(8./3.))*ds[:-1] - - max_res = numpy.max(numpy.abs((N_c - N_c_old)/(N_c + 1e-16))) - - if print_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 N_c') - it += 1 - - return N_c - #return N_c_old*(1 - relax_N_c) + N_c*relax_N_c - - -def plot_state(step, time, S_, S_max_, title=True): - # Plot parameters along profile - fig = plt.gcf() - fig.set_size_inches(3.3*1.1, 3.3*1.1*1.5) - - ax_Pa = plt.subplot(3, 1, 1) # axis with Pascals as y-axis unit - ax_Pa.plot(s_c/1000., N_c/1e6, '-k', label='$N$') - ax_Pa.plot(s_c/1000., H_c*rho_i*g/1e6, '--r', label='$P_i$') - ax_Pa.plot(s_c/1000., P_c/1e6, ':y', 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$') - - if title: - plt.title('Day: {:.3}'.format(time/(60.*60.*24.))) - ax_Pa.legend(loc=2) - ax_m3s.legend(loc=4) - ax_Pa.set_ylabel('[MPa]') - ax_m3s.set_ylabel('[m$^3$/s]') - - ax_m3s_sed = plt.subplot(3, 1, 2, sharex=ax_Pa) - ax_m3s_sed.plot(s_c/1000., Q_t, '-', label='$Q_{total}$') - ax_m3s_sed.plot(s_c/1000., Q_s, ':', label='$Q_{sand}$') - ax_m3s_sed.plot(s_c/1000., Q_g, '--', label='$Q_{gravel}$') - ax_m3s_sed.set_ylabel('[m$^3$/s]') - ax_m3s_sed.legend(loc=2) - - ax_m2 = plt.subplot(3, 1, 3, sharex=ax_Pa) - ax_m2.plot(s_c/1000., S_, '-k', label='$S$') - ax_m2.plot(s_c/1000., S_max_, '--', color='#666666', label='$S_{max}$') - - ax_m2s = ax_m2.twinx() - ax_m2s.plot(s_c/1000., dSdt, ':', label='$dS/dt$') - - ax_m2.legend(loc=2) - ax_m2s.legend(loc=3) - ax_m2.set_xlabel('$s$ [km]') - ax_m2.set_ylabel('[m$^2$]') - ax_m2s.set_ylabel('[m$^2$/s]') - - ax_Pa.set_xlim([s.min()/1000., s.max()/1000.]) - - 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() - plt.close() - - -def find_new_timestep(ds, Q, Q_t, S): - # Determine the timestep using the Courant-Friedrichs-Lewy condition - dt = safety*numpy.minimum(60.*60.*24., - numpy.min(numpy.abs(ds/(Q*S),\ - ds/(Q_t*S)+1e-16))) - - 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(step, time, dt): - sys.stdout.write('\rstep = {}, '.format(step) + - 't = {:.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] -H_c = avg_midpoint(H) - -# 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, S, S_max) - - -# # Time loop -time = 0. -step = 0 -while time <= t_end: - - # Determine time step length from water flux - dt = find_new_timestep(ds, Q, Q_t, S) - - # Display current simulation status - print_status_to_stdout(step, time, dt) - - it = 0 - - # Initialize the maximum normalized residual for S to an arbitrary large - # value - max_res = 1e9 - - S_old = S.copy() - # Iteratively find solution with the Jacobi relaxation method - while max_res > tol_S: - - S_prev_it = S.copy() - - # Find new water fluxes consistent with mass conservation and local - # meltwater production (m_dot) - Q = flux_solver(m_dot, ds) - - # Find average shear stress from water flux for each channel segment - tau = channel_shear_stress(Q, S) - - # Determine sediment fluxes for each size fraction - f_g = 1./f_s # gravel volume fraction is reciprocal to sand - Q_s = channel_sediment_flux_sand(tau, W, f_s, D_s) - Q_g = channel_sediment_flux_gravel(tau, W, f_g, D_g) - Q_t = Q_s + Q_g - - # Determine change in channel size for each channel segment. - # Use backward differences and assume dS/dt=0 in first segment. - dSdt[1:] = channel_growth_rate_sedflux(Q_t, porosity, s_c) - #dSdt *= speedup_factor * relax - - # Update channel cross-sectional area and width according to growth - # rate and size limit for each channel segment - #S_prev = S.copy() - S, W, S_max, dSdt = \ - update_channel_size_with_limit(S, S_old, dSdt, dt, N_c) - #S = S_prev*(1.0 - relax) + S*relax - - - # Find hydraulic roughness - f = channel_hydraulic_roughness(manning, S, W, theta) - - # Find new water pressures consistent with the flow law - N_c = pressure_solver(psi, f, Q, S) - - # Find new effective pressure in channel segments - P_c = rho_i*g*H_c - N_c - - if plot_during_iterations: - plot_state(step + it/1e4, time, S, S_max) - - # Find new maximum normalized residual value - max_res = numpy.max(numpy.abs((S - S_prev_it)/(S + 1e-16))) - if print_output_convergence_main: - 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') - it += 1 - - # Generate an output figure for every n time steps - if step % plot_interval == 0: - plot_state(step, time, S, S_max) - - # Update time - time += dt - step += 1 diff --git a/1d-channel.py b/1d-channel.py @@ -3,16 +3,16 @@ # # 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. +# soft beds as presented in `Damsgaard et al. "Sediment behavior controls +# equilibrium width of subglacial channels"`, accepted for publicaiton in +# 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 +# License: GNU Public License v3 # Author: Anders Damsgaard, andersd@princeton.edu, https://adamsgaard.dk import numpy @@ -27,7 +27,7 @@ total_days = 2. # Total simulation time [d] t_end = 24.*60.*60.*total_days # Total simulation time [s] tol_S = 1e-2 # Tolerance criteria for the norm. max. residual for S tol_Q = 1e-2 # Tolerance criteria for the norm. max. residual for Q -tol_N_c = 1e-2 # Tolerance criteria for the norm. max. residual for N_c +tol_P_c = 1e-2 # Tolerance criteria for the norm. max. residual for P_c max_iter = 1e2*Ns # Maximum number of solver iterations before failure print_output_convergence = False # Display convergence in nested loops print_output_convergence_main = True # Display convergence in main loop @@ -81,8 +81,8 @@ dSdt = numpy.zeros_like(S) # Transient in channel cross-sect. 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] +P_c = numpy.zeros_like(S) # Effective pressure in channel segments [Pa] +P_w = numpy.zeros_like(S) # Effective pressure in channel segments [Pa] 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 @@ -132,11 +132,11 @@ def channel_growth_rate_sedflux(Q_s, porosity, s_c): return 1./porosity[1:] * gradient(Q_s, s_c) -def update_channel_size_with_limit(S, S_old, dSdt, dt, N_c): +def update_channel_size_with_limit(S, S_old, dSdt, dt, P_c): # Damsgaard et al, in prep S_max = numpy.maximum( numpy.maximum( - 1./4.*(c_1*numpy.maximum(N_c, 0.)/1000. + c_2), 0.)**2. * + 1./4.*(c_1*numpy.maximum(P_c, 0.)/1000. + c_2), 0.)**2. * numpy.tan(numpy.deg2rad(theta)), S_min) S = numpy.maximum(numpy.minimum(S_old + dSdt*dt, S_max), S_min) W = S/numpy.tan(numpy.deg2rad(theta)) # Assume no channel floor wedge @@ -174,33 +174,33 @@ def flux_solver(m_dot, ds): def pressure_solver(psi, f, Q, S): # Iteratively find new water pressures - # dN_c/ds = f*rho_w*g*Q^2/S^{8/3} - psi (Kingslake and Ng 2013) + # dP_c/ds = f*rho_w*g*Q^2/S^{8/3} - psi (Kingslake and Ng 2013) it = 0 max_res = 1e9 # arbitrary large value - while max_res > tol_N_c: + while max_res > tol_P_c: - N_c_old = N_c.copy() + P_c_old = P_c.copy() # Dirichlet BC (fixed pressure) at terminus - N_c[-1] = rho_i*g*H_c[-1] - P_terminus + P_c[-1] = rho_i*g*H_c[-1] - P_terminus - N_c[:-1] = N_c[1:] \ + P_c[:-1] = P_c[1:] \ + psi[:-1]*ds[:-1] \ - f[:-1]*rho_w*g*Q[:-1]*numpy.abs(Q[:-1]) \ / (S[:-1]**(8./3.))*ds[:-1] - max_res = numpy.max(numpy.abs((N_c - N_c_old)/(N_c + 1e-16))) + max_res = numpy.max(numpy.abs((P_c - P_c_old)/(P_c + 1e-16))) if print_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 N_c') + 'Iterative solution not found for P_c') it += 1 - return N_c + return P_c def plot_state(step, time, S_, S_max_, title=False): @@ -209,9 +209,9 @@ def plot_state(step, time, S_, S_max_, title=False): fig.set_size_inches(3.3*1.1, 3.3*1.1*1.5) ax_Pa = plt.subplot(3, 1, 1) # axis with Pascals as y-axis unit - ax_Pa.plot(s_c/1000., N_c/1e6, '-k', label='$N$') + ax_Pa.plot(s_c/1000., P_c/1e6, '-k', label='$P_c$') ax_Pa.plot(s_c/1000., H_c*rho_i*g/1e6, '--r', label='$P_i$') - ax_Pa.plot(s_c/1000., P_c/1e6, ':y', label='$P_c$') + ax_Pa.plot(s_c/1000., P_w/1e6, ':y', label='$P_w$') ax_m3s = ax_Pa.twinx() # axis with m3/s as y-axis unit ax_m3s.plot(s_c/1000., Q, '.-b', label='$Q$') @@ -339,15 +339,14 @@ while time <= t_end: # Update channel cross-sectional area and width according to growth # rate and size limit for each channel segment S, W, S_max, dSdt = \ - update_channel_size_with_limit(S, S_old, dSdt, dt, N_c) + update_channel_size_with_limit(S, S_old, dSdt, dt, P_c) f = channel_hydraulic_roughness(manning, S, W, theta) - # Find new water pressures consistent with the flow law - N_c = pressure_solver(psi, f, Q, S) - - # Find new effective pressure in channel segments - P_c = rho_i*g*H_c - N_c + # Find new effective pressures consistent with the flow law and water + # pressures in channel segments + P_c = pressure_solver(psi, f, Q, S) + P_w = rho_i*g*H_c - P_c if plot_during_iterations: plot_state(step + it/1e4, time, S, S_max) diff --git a/LICENSE.md b/LICENSE.md @@ -0,0 +1,636 @@ +The SeaIce.jl package is licensed under the GNU Public License, Version 3.0+: + +> Copyright (c) 2017: Anders Damsgaard. +> This program is free software: you can redistribute it and/or modify +> it under the terms of the GNU General Public License as published by +> the Free Software Foundation, either version 3 of the License, or +> (at your option) any later version. +> +> This program is distributed in the hope that it will be useful, +> but WITHOUT ANY WARRANTY; without even the implied warranty of +> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +> GNU General Public License for more details. +> +> +> GNU GENERAL PUBLIC LICENSE +> Version 3, 29 June 2007 +> +> Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> +> Everyone is permitted to copy and distribute verbatim copies +> of this license document, but changing it is not allowed. +> +> Preamble +> +> The GNU General Public License is a free, copyleft license for +> software and other kinds of works. +> +> The licenses for most software and other practical works are designed +> to take away your freedom to share and change the works. By contrast, +> the GNU General Public License is intended to guarantee your freedom to +> share and change all versions of a program--to make sure it remains free +> software for all its users. We, the Free Software Foundation, use the +> GNU General Public License for most of our software; it applies also to +> any other work released this way by its authors. You can apply it to +> your programs, too. +> +> When we speak of free software, we are referring to freedom, not +> price. Our General Public Licenses are designed to make sure that you +> have the freedom to distribute copies of free software (and charge for +> them if you wish), that you receive source code or can get it if you +> want it, that you can change the software or use pieces of it in new +> free programs, and that you know you can do these things. +> +> To protect your rights, we need to prevent others from denying you +> these rights or asking you to surrender the rights. Therefore, you have +> certain responsibilities if you distribute copies of the software, or if +> you modify it: responsibilities to respect the freedom of others. +> +> For example, if you distribute copies of such a program, whether +> gratis or for a fee, you must pass on to the recipients the same +> freedoms that you received. You must make sure that they, too, receive +> or can get the source code. And you must show them these terms so they +> know their rights. +> +> Developers that use the GNU GPL protect your rights with two steps: +> (1) assert copyright on the software, and (2) offer you this License +> giving you legal permission to copy, distribute and/or modify it. +> +> For the developers' and authors' protection, the GPL clearly explains +> that there is no warranty for this free software. For both users' and +> authors' sake, the GPL requires that modified versions be marked as +> changed, so that their problems will not be attributed erroneously to +> authors of previous versions. +> +> Some devices are designed to deny users access to install or run +> modified versions of the software inside them, although the manufacturer +> can do so. This is fundamentally incompatible with the aim of +> protecting users' freedom to change the software. The systematic +> pattern of such abuse occurs in the area of products for individuals to +> use, which is precisely where it is most unacceptable. Therefore, we +> have designed this version of the GPL to prohibit the practice for those +> products. If such problems arise substantially in other domains, we +> stand ready to extend this provision to those domains in future versions +> of the GPL, as needed to protect the freedom of users. +> +> Finally, every program is threatened constantly by software patents. +> States should not allow patents to restrict development and use of +> software on general-purpose computers, but in those that do, we wish to +> avoid the special danger that patents applied to a free program could +> make it effectively proprietary. To prevent this, the GPL assures that +> patents cannot be used to render the program non-free. +> +> The precise terms and conditions for copying, distribution and +> modification follow. +> +> TERMS AND CONDITIONS +> +> 0. Definitions. +> +> "This License" refers to version 3 of the GNU General Public License. +> +> "Copyright" also means copyright-like laws that apply to other kinds of +> works, such as semiconductor masks. +> +> "The Program" refers to any copyrightable work licensed under this +> License. Each licensee is addressed as "you". "Licensees" and +> "recipients" may be individuals or organizations. +> +> To "modify" a work means to copy from or adapt all or part of the work +> in a fashion requiring copyright permission, other than the making of an +> exact copy. The resulting work is called a "modified version" of the +> earlier work or a work "based on" the earlier work. +> +> A "covered work" means either the unmodified Program or a work based +> on the Program. +> +> To "propagate" a work means to do anything with it that, without +> permission, would make you directly or secondarily liable for +> infringement under applicable copyright law, except executing it on a +> computer or modifying a private copy. Propagation includes copying, +> distribution (with or without modification), making available to the +> public, and in some countries other activities as well. +> +> To "convey" a work means any kind of propagation that enables other +> parties to make or receive copies. Mere interaction with a user through +> a computer network, with no transfer of a copy, is not conveying. +> +> An interactive user interface displays "Appropriate Legal Notices" +> to the extent that it includes a convenient and prominently visible +> feature that (1) displays an appropriate copyright notice, and (2) +> tells the user that there is no warranty for the work (except to the +> extent that warranties are provided), that licensees may convey the +> work under this License, and how to view a copy of this License. If +> the interface presents a list of user commands or options, such as a +> menu, a prominent item in the list meets this criterion. +> +> 1. Source Code. +> +> The "source code" for a work means the preferred form of the work +> for making modifications to it. "Object code" means any non-source +> form of a work. +> +> A "Standard Interface" means an interface that either is an official +> standard defined by a recognized standards body, or, in the case of +> interfaces specified for a particular programming language, one that +> is widely used among developers working in that language. +> +> The "System Libraries" of an executable work include anything, other +> than the work as a whole, that (a) is included in the normal form of +> packaging a Major Component, but which is not part of that Major +> Component, and (b) serves only to enable use of the work with that +> Major Component, or to implement a Standard Interface for which an +> implementation is available to the public in source code form. A +> "Major Component", in this context, means a major essential component +> (kernel, window system, and so on) of the specific operating system +> (if any) on which the executable work runs, or a compiler used to +> produce the work, or an object code interpreter used to run it. +> +> The "Corresponding Source" for a work in object code form means all +> the source code needed to generate, install, and (for an executable +> work) run the object code and to modify the work, including scripts to +> control those activities. However, it does not include the work's +> System Libraries, or general-purpose tools or generally available free +> programs which are used unmodified in performing those activities but +> which are not part of the work. For example, Corresponding Source +> includes interface definition files associated with source files for +> the work, and the source code for shared libraries and dynamically +> linked subprograms that the work is specifically designed to require, +> such as by intimate data communication or control flow between those +> subprograms and other parts of the work. +> +> The Corresponding Source need not include anything that users +> can regenerate automatically from other parts of the Corresponding +> Source. +> +> The Corresponding Source for a work in source code form is that +> same work. +> +> 2. Basic Permissions. +> +> All rights granted under this License are granted for the term of +> copyright on the Program, and are irrevocable provided the stated +> conditions are met. This License explicitly affirms your unlimited +> permission to run the unmodified Program. The output from running a +> covered work is covered by this License only if the output, given its +> content, constitutes a covered work. This License acknowledges your +> rights of fair use or other equivalent, as provided by copyright law. +> +> You may make, run and propagate covered works that you do not +> convey, without conditions so long as your license otherwise remains +> in force. You may convey covered works to others for the sole purpose +> of having them make modifications exclusively for you, or provide you +> with facilities for running those works, provided that you comply with +> the terms of this License in conveying all material for which you do +> not control copyright. Those thus making or running the covered works +> for you must do so exclusively on your behalf, under your direction +> and control, on terms that prohibit them from making any copies of +> your copyrighted material outside their relationship with you. +> +> Conveying under any other circumstances is permitted solely under +> the conditions stated below. Sublicensing is not allowed; section 10 +> makes it unnecessary. +> +> 3. Protecting Users' Legal Rights From Anti-Circumvention Law. +> +> No covered work shall be deemed part of an effective technological +> measure under any applicable law fulfilling obligations under article +> 11 of the WIPO copyright treaty adopted on 20 December 1996, or +> similar laws prohibiting or restricting circumvention of such +> measures. +> +> When you convey a covered work, you waive any legal power to forbid +> circumvention of technological measures to the extent such circumvention +> is effected by exercising rights under this License with respect to +> the covered work, and you disclaim any intention to limit operation or +> modification of the work as a means of enforcing, against the work's +> users, your or third parties' legal rights to forbid circumvention of +> technological measures. +> +> 4. Conveying Verbatim Copies. +> +> You may convey verbatim copies of the Program's source code as you +> receive it, in any medium, provided that you conspicuously and +> appropriately publish on each copy an appropriate copyright notice; +> keep intact all notices stating that this License and any +> non-permissive terms added in accord with section 7 apply to the code; +> keep intact all notices of the absence of any warranty; and give all +> recipients a copy of this License along with the Program. +> +> You may charge any price or no price for each copy that you convey, +> and you may offer support or warranty protection for a fee. +> +> 5. Conveying Modified Source Versions. +> +> You may convey a work based on the Program, or the modifications to +> produce it from the Program, in the form of source code under the +> terms of section 4, provided that you also meet all of these conditions: +> +> a) The work must carry prominent notices stating that you modified +> it, and giving a relevant date. +> +> b) The work must carry prominent notices stating that it is +> released under this License and any conditions added under section +> 7. This requirement modifies the requirement in section 4 to +> "keep intact all notices". +> +> c) You must license the entire work, as a whole, under this +> License to anyone who comes into possession of a copy. This +> License will therefore apply, along with any applicable section 7 +> additional terms, to the whole of the work, and all its parts, +> regardless of how they are packaged. This License gives no +> permission to license the work in any other way, but it does not +> invalidate such permission if you have separately received it. +> +> d) If the work has interactive user interfaces, each must display +> Appropriate Legal Notices; however, if the Program has interactive +> interfaces that do not display Appropriate Legal Notices, your +> work need not make them do so. +> +> A compilation of a covered work with other separate and independent +> works, which are not by their nature extensions of the covered work, +> and which are not combined with it such as to form a larger program, +> in or on a volume of a storage or distribution medium, is called an +> "aggregate" if the compilation and its resulting copyright are not +> used to limit the access or legal rights of the compilation's users +> beyond what the individual works permit. Inclusion of a covered work +> in an aggregate does not cause this License to apply to the other +> parts of the aggregate. +> +> 6. Conveying Non-Source Forms. +> +> You may convey a covered work in object code form under the terms +> of sections 4 and 5, provided that you also convey the +> machine-readable Corresponding Source under the terms of this License, +> in one of these ways: +> +> a) Convey the object code in, or embodied in, a physical product +> (including a physical distribution medium), accompanied by the +> Corresponding Source fixed on a durable physical medium +> customarily used for software interchange. +> +> b) Convey the object code in, or embodied in, a physical product +> (including a physical distribution medium), accompanied by a +> written offer, valid for at least three years and valid for as +> long as you offer spare parts or customer support for that product +> model, to give anyone who possesses the object code either (1) a +> copy of the Corresponding Source for all the software in the +> product that is covered by this License, on a durable physical +> medium customarily used for software interchange, for a price no +> more than your reasonable cost of physically performing this +> conveying of source, or (2) access to copy the +> Corresponding Source from a network server at no charge. +> +> c) Convey individual copies of the object code with a copy of the +> written offer to provide the Corresponding Source. This +> alternative is allowed only occasionally and noncommercially, and +> only if you received the object code with such an offer, in accord +> with subsection 6b. +> +> d) Convey the object code by offering access from a designated +> place (gratis or for a charge), and offer equivalent access to the +> Corresponding Source in the same way through the same place at no +> further charge. You need not require recipients to copy the +> Corresponding Source along with the object code. If the place to +> copy the object code is a network server, the Corresponding Source +> may be on a different server (operated by you or a third party) +> that supports equivalent copying facilities, provided you maintain +> clear directions next to the object code saying where to find the +> Corresponding Source. Regardless of what server hosts the +> Corresponding Source, you remain obligated to ensure that it is +> available for as long as needed to satisfy these requirements. +> +> e) Convey the object code using peer-to-peer transmission, provided +> you inform other peers where the object code and Corresponding +> Source of the work are being offered to the general public at no +> charge under subsection 6d. +> +> A separable portion of the object code, whose source code is excluded +> from the Corresponding Source as a System Library, need not be +> included in conveying the object code work. +> +> A "User Product" is either (1) a "consumer product", which means any +> tangible personal property which is normally used for personal, family, +> or household purposes, or (2) anything designed or sold for incorporation +> into a dwelling. In determining whether a product is a consumer product, +> doubtful cases shall be resolved in favor of coverage. For a particular +> product received by a particular user, "normally used" refers to a +> typical or common use of that class of product, regardless of the status +> of the particular user or of the way in which the particular user +> actually uses, or expects or is expected to use, the product. A product +> is a consumer product regardless of whether the product has substantial +> commercial, industrial or non-consumer uses, unless such uses represent +> the only significant mode of use of the product. +> +> "Installation Information" for a User Product means any methods, +> procedures, authorization keys, or other information required to install +> and execute modified versions of a covered work in that User Product from +> a modified version of its Corresponding Source. The information must +> suffice to ensure that the continued functioning of the modified object +> code is in no case prevented or interfered with solely because +> modification has been made. +> +> If you convey an object code work under this section in, or with, or +> specifically for use in, a User Product, and the conveying occurs as +> part of a transaction in which the right of possession and use of the +> User Product is transferred to the recipient in perpetuity or for a +> fixed term (regardless of how the transaction is characterized), the +> Corresponding Source conveyed under this section must be accompanied +> by the Installation Information. But this requirement does not apply +> if neither you nor any third party retains the ability to install +> modified object code on the User Product (for example, the work has +> been installed in ROM). +> +> The requirement to provide Installation Information does not include a +> requirement to continue to provide support service, warranty, or updates +> for a work that has been modified or installed by the recipient, or for +> the User Product in which it has been modified or installed. Access to a +> network may be denied when the modification itself materially and +> adversely affects the operation of the network or violates the rules and +> protocols for communication across the network. +> +> Corresponding Source conveyed, and Installation Information provided, +> in accord with this section must be in a format that is publicly +> documented (and with an implementation available to the public in +> source code form), and must require no special password or key for +> unpacking, reading or copying. +> +> 7. Additional Terms. +> +> "Additional permissions" are terms that supplement the terms of this +> License by making exceptions from one or more of its conditions. +> Additional permissions that are applicable to the entire Program shall +> be treated as though they were included in this License, to the extent +> that they are valid under applicable law. If additional permissions +> apply only to part of the Program, that part may be used separately +> under those permissions, but the entire Program remains governed by +> this License without regard to the additional permissions. +> +> When you convey a copy of a covered work, you may at your option +> remove any additional permissions from that copy, or from any part of +> it. (Additional permissions may be written to require their own +> removal in certain cases when you modify the work.) You may place +> additional permissions on material, added by you to a covered work, +> for which you have or can give appropriate copyright permission. +> +> Notwithstanding any other provision of this License, for material you +> add to a covered work, you may (if authorized by the copyright holders of +> that material) supplement the terms of this License with terms: +> +> a) Disclaiming warranty or limiting liability differently from the +> terms of sections 15 and 16 of this License; or +> +> b) Requiring preservation of specified reasonable legal notices or +> author attributions in that material or in the Appropriate Legal +> Notices displayed by works containing it; or +> +> c) Prohibiting misrepresentation of the origin of that material, or +> requiring that modified versions of such material be marked in +> reasonable ways as different from the original version; or +> +> d) Limiting the use for publicity purposes of names of licensors or +> authors of the material; or +> +> e) Declining to grant rights under trademark law for use of some +> trade names, trademarks, or service marks; or +> +> f) Requiring indemnification of licensors and authors of that +> material by anyone who conveys the material (or modified versions of +> it) with contractual assumptions of liability to the recipient, for +> any liability that these contractual assumptions directly impose on +> those licensors and authors. +> +> All other non-permissive additional terms are considered "further +> restrictions" within the meaning of section 10. If the Program as you +> received it, or any part of it, contains a notice stating that it is +> governed by this License along with a term that is a further +> restriction, you may remove that term. If a license document contains +> a further restriction but permits relicensing or conveying under this +> License, you may add to a covered work material governed by the terms +> of that license document, provided that the further restriction does +> not survive such relicensing or conveying. +> +> If you add terms to a covered work in accord with this section, you +> must place, in the relevant source files, a statement of the +> additional terms that apply to those files, or a notice indicating +> where to find the applicable terms. +> +> Additional terms, permissive or non-permissive, may be stated in the +> form of a separately written license, or stated as exceptions; +> the above requirements apply either way. +> +> 8. Termination. +> +> You may not propagate or modify a covered work except as expressly +> provided under this License. Any attempt otherwise to propagate or +> modify it is void, and will automatically terminate your rights under +> this License (including any patent licenses granted under the third +> paragraph of section 11). +> +> However, if you cease all violation of this License, then your +> license from a particular copyright holder is reinstated (a) +> provisionally, unless and until the copyright holder explicitly and +> finally terminates your license, and (b) permanently, if the copyright +> holder fails to notify you of the violation by some reasonable means +> prior to 60 days after the cessation. +> +> Moreover, your license from a particular copyright holder is +> reinstated permanently if the copyright holder notifies you of the +> violation by some reasonable means, this is the first time you have +> received notice of violation of this License (for any work) from that +> copyright holder, and you cure the violation prior to 30 days after +> your receipt of the notice. +> +> Termination of your rights under this section does not terminate the +> licenses of parties who have received copies or rights from you under +> this License. If your rights have been terminated and not permanently +> reinstated, you do not qualify to receive new licenses for the same +> material under section 10. +> +> 9. Acceptance Not Required for Having Copies. +> +> You are not required to accept this License in order to receive or +> run a copy of the Program. Ancillary propagation of a covered work +> occurring solely as a consequence of using peer-to-peer transmission +> to receive a copy likewise does not require acceptance. However, +> nothing other than this License grants you permission to propagate or +> modify any covered work. These actions infringe copyright if you do +> not accept this License. Therefore, by modifying or propagating a +> covered work, you indicate your acceptance of this License to do so. +> +> 10. Automatic Licensing of Downstream Recipients. +> +> Each time you convey a covered work, the recipient automatically +> receives a license from the original licensors, to run, modify and +> propagate that work, subject to this License. You are not responsible +> for enforcing compliance by third parties with this License. +> +> An "entity transaction" is a transaction transferring control of an +> organization, or substantially all assets of one, or subdividing an +> organization, or merging organizations. If propagation of a covered +> work results from an entity transaction, each party to that +> transaction who receives a copy of the work also receives whatever +> licenses to the work the party's predecessor in interest had or could +> give under the previous paragraph, plus a right to possession of the +> Corresponding Source of the work from the predecessor in interest, if +> the predecessor has it or can get it with reasonable efforts. +> +> You may not impose any further restrictions on the exercise of the +> rights granted or affirmed under this License. For example, you may +> not impose a license fee, royalty, or other charge for exercise of +> rights granted under this License, and you may not initiate litigation +> (including a cross-claim or counterclaim in a lawsuit) alleging that +> any patent claim is infringed by making, using, selling, offering for +> sale, or importing the Program or any portion of it. +> +> 11. Patents. +> +> A "contributor" is a copyright holder who authorizes use under this +> License of the Program or a work on which the Program is based. The +> work thus licensed is called the contributor's "contributor version". +> +> A contributor's "essential patent claims" are all patent claims +> owned or controlled by the contributor, whether already acquired or +> hereafter acquired, that would be infringed by some manner, permitted +> by this License, of making, using, or selling its contributor version, +> but do not include claims that would be infringed only as a +> consequence of further modification of the contributor version. For +> purposes of this definition, "control" includes the right to grant +> patent sublicenses in a manner consistent with the requirements of +> this License. +> +> Each contributor grants you a non-exclusive, worldwide, royalty-free +> patent license under the contributor's essential patent claims, to +> make, use, sell, offer for sale, import and otherwise run, modify and +> propagate the contents of its contributor version. +> +> In the following three paragraphs, a "patent license" is any express +> agreement or commitment, however denominated, not to enforce a patent +> (such as an express permission to practice a patent or covenant not to +> sue for patent infringement). To "grant" such a patent license to a +> party means to make such an agreement or commitment not to enforce a +> patent against the party. +> +> If you convey a covered work, knowingly relying on a patent license, +> and the Corresponding Source of the work is not available for anyone +> to copy, free of charge and under the terms of this License, through a +> publicly available network server or other readily accessible means, +> then you must either (1) cause the Corresponding Source to be so +> available, or (2) arrange to deprive yourself of the benefit of the +> patent license for this particular work, or (3) arrange, in a manner +> consistent with the requirements of this License, to extend the patent +> license to downstream recipients. "Knowingly relying" means you have +> actual knowledge that, but for the patent license, your conveying the +> covered work in a country, or your recipient's use of the covered work +> in a country, would infringe one or more identifiable patents in that +> country that you have reason to believe are valid. +> +> If, pursuant to or in connection with a single transaction or +> arrangement, you convey, or propagate by procuring conveyance of, a +> covered work, and grant a patent license to some of the parties +> receiving the covered work authorizing them to use, propagate, modify +> or convey a specific copy of the covered work, then the patent license +> you grant is automatically extended to all recipients of the covered +> work and works based on it. +> +> A patent license is "discriminatory" if it does not include within +> the scope of its coverage, prohibits the exercise of, or is +> conditioned on the non-exercise of one or more of the rights that are +> specifically granted under this License. You may not convey a covered +> work if you are a party to an arrangement with a third party that is +> in the business of distributing software, under which you make payment +> to the third party based on the extent of your activity of conveying +> the work, and under which the third party grants, to any of the +> parties who would receive the covered work from you, a discriminatory +> patent license (a) in connection with copies of the covered work +> conveyed by you (or copies made from those copies), or (b) primarily +> for and in connection with specific products or compilations that +> contain the covered work, unless you entered into that arrangement, +> or that patent license was granted, prior to 28 March 2007. +> +> Nothing in this License shall be construed as excluding or limiting +> any implied license or other defenses to infringement that may +> otherwise be available to you under applicable patent law. +> +> 12. No Surrender of Others' Freedom. +> +> If conditions are imposed on you (whether by court order, agreement or +> otherwise) that contradict the conditions of this License, they do not +> excuse you from the conditions of this License. If you cannot convey a +> covered work so as to satisfy simultaneously your obligations under this +> License and any other pertinent obligations, then as a consequence you may +> not convey it at all. For example, if you agree to terms that obligate you +> to collect a royalty for further conveying from those to whom you convey +> the Program, the only way you could satisfy both those terms and this +> License would be to refrain entirely from conveying the Program. +> +> 13. Use with the GNU Affero General Public License. +> +> Notwithstanding any other provision of this License, you have +> permission to link or combine any covered work with a work licensed +> under version 3 of the GNU Affero General Public License into a single +> combined work, and to convey the resulting work. The terms of this +> License will continue to apply to the part which is the covered work, +> but the special requirements of the GNU Affero General Public License, +> section 13, concerning interaction through a network will apply to the +> combination as such. +> +> 14. Revised Versions of this License. +> +> The Free Software Foundation may publish revised and/or new versions of +> the GNU General Public License from time to time. Such new versions will +> be similar in spirit to the present version, but may differ in detail to +> address new problems or concerns. +> +> Each version is given a distinguishing version number. If the +> Program specifies that a certain numbered version of the GNU General +> Public License "or any later version" applies to it, you have the +> option of following the terms and conditions either of that numbered +> version or of any later version published by the Free Software +> Foundation. If the Program does not specify a version number of the +> GNU General Public License, you may choose any version ever published +> by the Free Software Foundation. +> +> If the Program specifies that a proxy can decide which future +> versions of the GNU General Public License can be used, that proxy's +> public statement of acceptance of a version permanently authorizes you +> to choose that version for the Program. +> +> Later license versions may give you additional or different +> permissions. However, no additional obligations are imposed on any +> author or copyright holder as a result of your choosing to follow a +> later version. +> +> 15. Disclaimer of Warranty. +> +> THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +> APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +> HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +> OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +> THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +> PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +> IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +> ALL NECESSARY SERVICING, REPAIR OR CORRECTION. +> +> 16. Limitation of Liability. +> +> IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +> WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +> THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +> GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +> USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +> DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +> PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +> EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +> SUCH DAMAGES. +> +> 17. Interpretation of Sections 15 and 16. +> +> If the disclaimer of warranty and limitation of liability provided +> above cannot be given local legal effect according to their terms, +> reviewing courts shall apply local law that most closely approximates +> an absolute waiver of all civil liability in connection with the +> Program, unless a warranty or assumption of liability accompanies a +> copy of the Program in return for a fee. +> +> END OF TERMS AND CONDITIONS +> diff --git a/README.md b/README.md @@ -1,2 +1,15 @@ # README +Supplementary code for *Sediment behavior controls equilibrium width of +subglacial channels* (A. Damsgaard, J. Suckale, J.A. Piotrowski, M. Houssais, +M.R. Siegfried, H.A. Fricker) accepted for publication in Journal of +Glaciology. +This finite-difference example implementation will simulate the dynamics of a +1d channel segment along a square-root ice geometry, with constant water +pressure at the terminus. + +## License +GNU Public License v3, see `LICENSE.md` for details. + +## Author +Anders Damsgaard, https://adamsgaard.dk diff --git a/granular_channel_drainage/__init__.py b/granular_channel_drainage/__init__.py @@ -1,5 +0,0 @@ -#!/usr/bin/env python -__all__ = ['model'] -__version__ = '0.01' - -from model import model diff --git a/granular_channel_drainage/model.py b/granular_channel_drainage/model.py @@ -1,137 +0,0 @@ -#!/usr/bin/env python -import numpy -import matplotlib.pyplot as plt -import landlab - -class model: - def __init__(self, name='unnamed'): - ''' - Initialize a blank hydrology model object and optionally assign a - simulation name to it. - - :param name: A uniquely identifying simulation name - :type name: str - ''' - self.name = name - - def genreateRegularGrid(self, Lx, Ly, Nx, Ny): - ''' - Generate a uniform, regular and orthogonal grid using Landlab. - - :param Lx: A tuple containing the length along x of the model - domain. - :type Lx: float - :param Ly: A tuple containing the length along y of the model - domain. - :type Ly: float - :param Nx: The number of random model nodes along ``x`` in the model. - :type Nx: int - :param Ny: The number of random model nodes along ``y`` in the model. - :type Ny: int - ''' - self.grid_type = 'Regular' - self.grid = landlab.grid.RasterModelGrid(shape=(Nx, Ny), spacing=Lx/Nx) - - def generateVoronoiDelaunayGrid(self, Lx, Ly, Nx, Ny, - structure='pseudorandom', - distribution='uniform'): - ''' - Generate a Voronoi Delaunay grid with randomly positioned nodes using - Landlab. - - :param Lx: A tuple containing the length along x of the model - domain. - :type Lx: float - :param Ly: A tuple containing the length along y of the model - domain. - :type Ly: float - :param Nx: The number of random model nodes along ``x`` in the model. - :type Nx: int - :param Ny: The number of random model nodes along ``y`` in the model. - :type Ny: int - :param structure: The type of numeric distribution used to seed the - grid. A ``random`` grid will produce uniformly random-distributed - grid points, while ``pseudorandom`` (default) will add random noise - to a regular grid. - :type structure: str - :name distribution: Type of random numeric distribution adding noise to - the pseudorandom structured grid. Accepted values are 'uniform' - (default) or 'normal'. - :type distribution: str - ''' - self.grid_type = 'VoronoiDelaunay' - - if structure == 'random': - x = numpy.random.rand(Nx*Ny)*Lx - y = numpy.random.rand(Nx*Ny)*Ly - - elif structure == 'pseudorandom': - dx = Lx/Nx - dy = Ly/Ny - xPoints = numpy.linspace(dx*.5, Lx - dx*.5, Nx) - yPoints = numpy.linspace(dy*.5, Ly - dy*.5, Ny) - gridPoints = numpy.array([[x,y] for y in yPoints for x in xPoints]) - N = len(gridPoints[:, 0]) - - if distribution == 'normal': - gridPoints[::2, 1] = gridPoints[::2, 1] + dy*0.5 - x = gridPoints[:, 0] + numpy.random.normal(0., dx*0.10, N) - y = gridPoints[:, 1] + numpy.random.normal(0., dy*0.10, N) - - elif distribution == 'uniform': - x = gridPoints[:, 0] + numpy.random.uniform(-dx*.4, dx*.4, N) - y = gridPoints[:, 1] + numpy.random.uniform(-dy*.4, dy*.4, N) - - else: - raise Exception('generateVoronoiDelaunayGrid: ' + - 'distribution type "' + distribution + - '" not understood.') - - self.grid = landlab.grid.VoronoiDelaunayGrid(x, y) - - def plotGrid(self, field='nodes', - save=False, saveformat='pdf'): - ''' - Plot the grid nodes or one of the fields associated with the grid. - - :param field: Field to plot (e.g., 'bed_elevation') - :type field: str - :param save: Save figure to file (default) or show in interactive - window? - :type save: bool - :param saveformat: File format to save the plot as if ``save=True``. - :type saveformat: str - ''' - - fig = plt.figure() - if field == 'nodes': - plt.plot(self.grid.node_x, self.grid.node_y, '.') - plt.axis('equal') - else: - landlab.plot.imshow_grid(self.grid, field) - #plt.tight_layout() - if save: - plt.savefig(self.name + '-' + field + '.' + saveformat) - else: - plt.show() - plt.clf() - plt.close() - - def gridCoordinates(self): - ''' - Returns the grid coordinates. - ''' - return self.grid.node_x, self.grid.node_y - - def addScalarField(self, name, values, units): - ''' - Add scalar field to the model grid. - - :param name: A uniquely identifying name for the scalar field. - :type name: str - :param values: The values to be inserted to the scalar field. - :type name: ndarray - :param units: The unit associated with the values, e.g. 's' or 'm' - :type units: str - ''' - self.grid.add_field('node', name, values, units=units, copy=True) diff --git a/requirements.txt b/requirements.txt @@ -1,4 +1,3 @@ scipy>=0.14 numpy -landlab matplotlib