commit 76f099629e26cfd4d8338b5862856ebc974d4e74
parent 9e079cfadd9105a19d6d651546fd09fe069612e3
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date: Mon, 29 Apr 2019 15:02:51 +0000
Merge branch 'darcy' into 'master'
Darcian diffusion of porewater
See merge request admesg/1d_fd_simple_shear!1
Diffstat:
23 files changed, 878 insertions(+), 412 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
@@ -4,7 +4,7 @@ build-alpine:
before_script:
- apk --no-cache add build-base gnuplot bash
script:
- - make
+ - make plots
artifacts:
paths:
- 1d_fd_simple_shear.png
diff --git a/1d_fd_simple_shear.png b/1d_fd_simple_shear.png
Binary files differ.
diff --git a/1d_fd_simple_shear_damsgaard2013.h b/1d_fd_simple_shear_damsgaard2013.h
@@ -1,66 +0,0 @@
-#ifndef ONED_FD_SIMPLE_SHEAR_
-#define ONED_FD_SIMPLE_SHEAR_
-
-#include <math.h>
-#include <stdio.h>
-#include "arrays.h"
-#include "simulation.h"
-
-#define PI 3.14159265358979323846
-#define DEG2RAD(x) (x*PI/180.0)
-
-/* Simulation settings */
-struct simulation init_sim(void)
-{
- struct simulation sim;
-
- sim.G = 9.81;
-
- sim.P_wall = 120e3; /* larger normal stress deepens the shear depth */
- sim.mu_wall = 0.40;
- sim.v_x_bot = 0.0;
-
- sim.nz = 100;
-
- /* lower values of A mean that the velocity curve can have sharper curves,
- * e.g. at the transition from μ ≈ μ_s */
- sim.A = 0.40; /* Loose fit to Damsgaard et al 2013 */
-
- /* lower values of b mean larger shear velocity for a given stress ratio
- * above yield */
- sim.b = 0.9377; /* Henann and Kamrin 2016 */
-
- sim.mu_s = atan(DEG2RAD(22.0)); /* Damsgaard et al 2013 */
-
- sim.phi = 0.25; /* Damsgaard et al 2013 */
-
- /* lower values of d mean that the shear velocity curve can have sharper
- * curves, e.g. at the transition from μ ≈ μ_s */
- sim.d = 0.04; /* Damsgaard et al 2013 */
-
- /* grain material density [kg/m^3] */
- sim.rho_s = 2.6e3; /* Damsgaard et al 2013 */
-
- /* Spatial settings */
- sim.origo_z = 0.0;
- sim.L_z = 0.7; /* Damsgaard et al 2013 */
-
- return sim;
-}
-
-void init_pressure(struct simulation* sim)
-{
- for (int i=0; i<sim->nz; ++i)
- sim->p[i] = sim->P_wall +
- (1.0 - sim->phi)*sim->rho_s*sim->G*(sim->L_z - sim->z[i]);
-}
-
-void init_friction(struct simulation* sim)
-{
- for (int i=0; i<sim->nz; ++i)
- sim->mu[i] = sim->mu_wall /
- (1.0 + (1.0 - sim->phi)*sim->rho_s*sim->G*(sim->L_z - sim->z[i])/
- sim->P_wall);
-}
-
-#endif
diff --git a/1d_fd_simple_shear_fluid.gp b/1d_fd_simple_shear_fluid.gp
@@ -0,0 +1,35 @@
+#!/usr/bin/env gnuplot
+
+# specify input file with:
+# gnuplot -e "filename='file.txt'" 1d_fd_simple_shear_fluid.gp
+
+set terminal pngcairo color size 60 cm, 17.6 cm
+set multiplot layout 1,3
+# set multiplot layout 1,4
+
+
+set yrange [0.0:2.0]
+
+set key bottom right #samplen 0.9
+
+set xlabel "Water pressure, p_f [Pa]"
+set ylabel "Vertical position, z [m]" offset 2
+set xrange [p_min:p_max]
+plot filename u 4:1 w l lw 2 lc "blue" t ""
+
+set xlabel "Effective normal stress [Pa]"
+set ylabel ""
+set xrange [0:200e3]
+plot filename u 3:1 w l lw 2 lc "black" t ""
+
+# set xlabel "Friction, mu [-]"
+# set xrange [-0.05:1.5]
+# plot filename u 5:1 w l lw 2 lc "gray" t ""
+
+set xlabel "Horizontal velocity, v_x [m/s]"
+set ylabel ""
+set xrange [0.0:0.025]
+plot filename u 2:1 w l lw 2 lc "red" t ""
+
+
+unset multiplot
diff --git a/1d_fd_simple_shear_henann_kamrin2016.h b/1d_fd_simple_shear_henann_kamrin2016.h
@@ -23,7 +23,7 @@ struct simulation init_sim(void)
sim.A = 0.48;
sim.b = 0.9377;
sim.mu_s = 0.3819;
- sim.phi = 0.38;
+ sim.phi = initval(0.38, sim.nz);
sim.d = 1e-3;
sim.rho_s = 2.485e3;
diff --git a/1d_fd_simple_shear_rheology.png b/1d_fd_simple_shear_rheology.png
Binary files differ.
diff --git a/1d_fd_simple_shear_rheology_iverson.png b/1d_fd_simple_shear_rheology_iverson.png
Binary files differ.
diff --git a/1d_fd_simple_shear_rheology_kamb.png b/1d_fd_simple_shear_rheology_kamb.png
Binary files differ.
diff --git a/1d_fd_simple_shear_rheology_tulaczyk.png b/1d_fd_simple_shear_rheology_tulaczyk.png
Binary files differ.
diff --git a/Makefile b/Makefile
@@ -4,12 +4,29 @@ SRC=$(wildcard *.c)
OBJ=$(patsubst %.c,%.o,$(SRC))
HDR=$(wildcard *.h)
-default: 1d_fd_simple_shear.png \
+.PHONY: default
+default: 1d_fd_simple_shear
+
+.PHONY: plots
+plots: 1d_fd_simple_shear.png \
1d_fd_simple_shear_rheology.png \
1d_fd_simple_shear_rheology_kamb.png \
1d_fd_simple_shear_rheology_iverson.png \
1d_fd_simple_shear_rheology_tulaczyk.png
+diurnal.mp4: 1d_fd_simple_shear 1d_fd_simple_shear_fluid.gp
+ /usr/bin/env zsh -c '\
+ ./$< --resolution 50 --length 2.0 --normal-stress 150e3 --fluid --fluid-permeability 1e-17 --fluid-pressure-top 50e3 --fluid-pressure-ampl 50e3 --fluid-pressure-freq $$(( 1.0/(3600*24) )) --time-step 1e-1 --file-interval $$(( 60*10 )) --time-end $$(( 3600*24*4 )) diurnal'
+ /bin/bash -c '\
+ for f in diurnal.output*.txt; do \
+ gnuplot -e "filename=\"$$f\"; p_min=\"0\"; p_max=\"100e3\"" $<_fluid.gp > $$f.png; \
+ done'
+ ffmpeg -i diurnal.output%05d.txt.png -y diurnal.mp4
+
+diurnal.gif: diurnal.mp4
+ convert diurnal.output*.txt.png \
+ -delay 1 -loop 0 -fuzz 10% -layers Optimize $@
+
1d_fd_simple_shear: $(OBJ) $(HDR)
$(CC) $(LDFLAGS) $(OBJ) -o $@
diff --git a/README.md b/README.md
@@ -12,6 +12,44 @@ directory and an output PNG figure is generated.
Alternatively, an implementation in [Julia](https://julialang.org) resides in
**julia/**.
+### Advanced usage
+The majority of simulation parameters can be adjusted from the command line:
+
+```
+usage: 1d_fd_simple_shear [OPTIONS] [NAME]
+runs a simulation and outputs state in files prefixed with NAME.
+optional arguments:
+ -N, --normalize normalize output velocity
+ -G, --gravity VAL gravity magnitude [m/s^2]
+ -P, --normal-stress VAL normal stress on top [Pa]
+ -m, --stress-ratio VAL applied stress ratio [-]
+ -V, --velocity-bottom VAL base velocity at bottom [m/s]
+ -A, --nonlocal-amplitude VAL amplitude of nonlocality [-]
+ -b, --rate-dependence VAL rate dependence beyond yield [-]
+ -f, --friction-coefficient VAL grain friction coefficient [-]
+ -p, --porosity VAL porosity fraction [-]
+ -d, --grain-size VAL representative grain size [m]
+ -r, --density VAL grain material density [kg/m^3]
+ -n, --resolution VAL number of cells in domain [-]
+ -o, --origo VAL coordinate system origo [m]
+ -L, --length VAL domain length [m]
+ -F, --fluid enable pore fluid computations
+ -c, --fluid-compressibility VAL fluid compressibility [Pa^-1]
+ -i, --fluid-viscosity VAL fluid viscosity [Pa*s]
+ -R, --fluid-density VAL fluid density [kg/m^3]
+ -k, --fluid-permeability VAL fluid intrinsic permeability [m^2]
+ -O, --fluid-pressure-top VAL fluid pressure at +z edge [Pa]
+ -a, --fluid-pressure-ampl VAL amplitude of pressure variations [Pa]
+ -q, --fluid-pressure-freq VAL frequency of pressure variations [s^-1]
+ -H, --fluid-pressure-phase VAL fluid pressure at +z edge [Pa]
+ -t, --time VAL simulation start time [s]
+ -T, --time-end VAL simulation end time [s]
+ -D, --time-step VAL computational time step length [s]
+ -I, --file-interval VAL interval between output files [s]
+ -v, --version show version information
+ -h, --help show this message
+```
+
## Results
### Strain distribution
@@ -26,7 +64,6 @@ probably be improved further.
|  |  |
### Stress and strain rate
-
The rheology is of Bingham type, where no deformation occurs beneath the
Mohr-Coulomb yield limit. Above it, deformation is highly non-linearly viscous.
The model has a parameter *b* for rate dependence beyond yield. Glass beads
@@ -41,3 +78,10 @@ have *b* = 0.94 ([Forterre and Pouliquen
|  |  |
| Whillans Ice Plain ([Tulaczyk 2006](https://doi.org/10.3189/172756506781828601)): | |
|  |  |
+
+### Variable water pressure
+The model is expanded from the Henann and Kamrin 2013 model by including a
+diffusive porewater pressure parameterization. Below is an example of diurnal
+water-pressure variations that gradually propagate into the bed.
+
+
diff --git a/arrays.c b/arrays.c
@@ -54,7 +54,7 @@ double* linspace(const double lower, const double upper, const int n)
}
/* Return an array of `n` values with the value 0.0 */
-double* zeros(const double n)
+double* zeros(const int n)
{
double *x = malloc(n*sizeof(double));
for (int i=0; i<n; ++i)
@@ -63,7 +63,7 @@ double* zeros(const double n)
}
/* Return an array of `n` values with the value 1.0 */
-double* ones(const double n)
+double* ones(const int n)
{
double *x = malloc(n*sizeof(double));
for (int i=0; i<n; ++i)
@@ -71,8 +71,17 @@ double* ones(const double n)
return x;
}
+/* Return an array of `n` values with a specified value */
+double* initval(const double value, const int n)
+{
+ double *x = malloc(n*sizeof(double));
+ for (int i=0; i<n; ++i)
+ x[i] = value;
+ return x;
+}
+
/* Return an array of `n` uninitialized values */
-double* empty(const double n)
+double* empty(const int n)
{
return malloc(n*sizeof(double));
}
@@ -116,6 +125,37 @@ void print_arrays_2nd_normalized(const double* a, const double* b, const int n)
printf("%.17g\t%.17g\n", a[i], b[i]/max_b);
}
+void print_three_arrays(
+ const double* a,
+ const double* b,
+ const double* c,
+ const int n)
+{
+ for (int i=0; i<n; ++i)
+ printf("%.17g\t%.17g\t%.17g\n", a[i], b[i], c[i]);
+}
+
+void fprint_arrays(
+ FILE* fp,
+ const double* a,
+ const double* b,
+ const int n)
+{
+ for (int i=0; i<n; ++i)
+ fprintf(fp, "%.17g\t%.17g\n", a[i], b[i]);
+}
+
+void fprint_three_arrays(
+ FILE* fp,
+ const double* a,
+ const double* b,
+ const double* c,
+ const int n)
+{
+ for (int i=0; i<n; ++i)
+ fprintf(fp, "%.17g\t%.17g\t%.17g\n", a[i], b[i], c[i]);
+}
+
void copy_values(const double* in, double* out, const int n)
{
for (int i=0; i<n; ++i)
diff --git a/arrays.h b/arrays.h
@@ -1,3 +1,5 @@
+#include <stdio.h>
+
#ifndef ARRAYS_
#define ARRAYS_
@@ -18,9 +20,10 @@ unsigned int idx2g(
unsigned int idx1g(const unsigned int i);
double* linspace(const double lower, const double upper, const int n);
-double* zeros(const double n);
-double* ones(const double n);
-double* empty(const double n);
+double* zeros(const int n);
+double* ones(const int n);
+double* initval(const double value, const int n);
+double* empty(const int n);
double max(const double* a, const int n);
double min(const double* a, const int n);
@@ -28,6 +31,20 @@ double min(const double* a, const int n);
void print_array(const double* a, const int n);
void print_arrays(const double* a, const double* b, const int n);
void print_arrays_2nd_normalized(const double* a, const double* b, const int n);
+void print_three_arrays(
+ const double* a,
+ const double* b,
+ const double* c,
+ const int n);
+
+void fprint_arrays(FILE* fp, const double* a, const double* b, const int n);
+
+void fprint_three_arrays(
+ FILE* fp,
+ const double* a,
+ const double* b,
+ const double* c,
+ const int n);
void copy_values(const double* in, double* out, const int n);
diff --git a/diurnal.gif b/diurnal.gif
Binary files differ.
diff --git a/fluid.c b/fluid.c
@@ -0,0 +1,185 @@
+#include <stdlib.h>
+#include <math.h>
+#include "simulation.h"
+#include "arrays.h"
+
+void hydrostatic_fluid_pressure_distribution(struct simulation* sim)
+{
+ for (int i=0; i<sim->nz; ++i)
+ sim->p_f_ghost[idx1g(i)] = sim->p_f_top +
+ sim->phi[i]*sim->rho_f*sim->G*(sim->L_z - sim->z[i]);
+}
+
+static double sine_wave(
+ const double time,
+ const double amplitude,
+ const double frequency,
+ const double phase,
+ const double base_value)
+{
+ return amplitude*sin(2.0*PI*frequency*time + phase) + base_value;
+}
+
+static double darcy_pressure_change_1d(
+ const int i,
+ const int nz,
+ const double* p_f_ghost_in,
+ const double* phi,
+ const double* k,
+ const double dz,
+ const double dt,
+ const double beta_f,
+ const double mu_f)
+{
+ const double p = p_f_ghost_in[idx1g(i)];
+ const double p_zn = p_f_ghost_in[idx1g(i-1)];
+ const double p_zp = p_f_ghost_in[idx1g(i+1)];
+
+ const double k_ = k[i];
+ double k_zn, k_zp;
+ if (i==0) k_zn = k_; else k_zn = k[i-1];
+ if (i==nz-1) k_zp = k_; else k_zp = k[i+1];
+#ifdef DEBUG
+ printf("%d->%d: p=[%g, %g, %g]\tk=[%g, %g, %g]\n",
+ i, idx1g(i),
+ p_zn, p, p_zp,
+ k_zn, k_, k_zp);
+#endif
+
+ const double div_k_grad_p =
+ (2.0*k_zp*k_/(k_zp + k_) * (p_zp - p)/dz -
+ 2.0*k_zn*k_/(k_zn + k_) * (p - p_zn)/dz
+ )/dz;
+#ifdef DEBUG
+ printf("phi[%d]=%g\tdiv_k_grad_p[%d]=%g\n",
+ i, phi[i], i, div_k_grad_p);
+#endif
+
+ /* return delta p */
+ return dt/(beta_f*phi[i]*mu_f)*div_k_grad_p;
+}
+
+int darcy_solver_1d(
+ struct simulation* sim,
+ const int max_iter,
+ const double rel_tol)
+{
+
+ /* compute explicit solution to pressure change */
+ double* dp_f_expl = zeros(sim->nz);
+ for (int i=0; i<sim->nz; ++i)
+ dp_f_expl[i] = darcy_pressure_change_1d(
+ i,
+ sim->nz,
+ sim->p_f_ghost,
+ sim->phi,
+ sim->k,
+ sim->dz,
+ sim->dt,
+ sim->beta_f,
+ sim->mu_f);
+
+ /* choose integration method, parameter in [0.0; 1.0]
+ * epsilon = 0.0: explicit
+ * epsilon = 0.5: Crank-Nicolson
+ * epsilon = 1.0: implicit */
+ const double epsilon = 0.5;
+
+ /* choose relaxation factor, parameter in ]0.0; 1.0]
+ * theta in ]0.0; 1.0]: underrelaxation
+ * theta = 1.0: Gauss-Seidel
+ * theta > 1.0: overrrelaxation */
+ const double theta = 0.05;
+ /* const double theta = 1.7; */
+
+ double p_f;
+
+ /* compute implicit solution to pressure change */
+ int iter;
+ double* dp_f_impl = zeros(sim->nz);
+ double* p_f_ghost_out = zeros(sim->nz+2);
+ double* r_norm = zeros(sim->nz);
+ double r_norm_max = NAN;
+ double p_f_top = sine_wave(
+ sim->t,
+ sim->p_f_mod_ampl,
+ sim->p_f_mod_freq,
+ sim->p_f_mod_phase,
+ sim->p_f_top);
+
+
+ for (iter=0; iter<max_iter; ++iter) {
+
+ set_bc_dirichlet(sim->p_f_ghost, sim->nz, +1, p_f_top);
+ sim->p_f_ghost[idx1g(sim->nz-1)] = p_f_top; /* Include top node in BC */
+ set_bc_neumann(sim->p_f_ghost, sim->nz, -1);
+#ifdef DEBUG
+ puts(".. p_f_ghost after BC:"); print_array(sim->p_f_ghost, sim->nz+2);
+#endif
+
+ /* for (int i=0; i<sim->nz; ++i) */
+ for (int i=0; i<sim->nz-1; ++i)
+ dp_f_impl[i] = darcy_pressure_change_1d(
+ i,
+ sim->nz,
+ sim->p_f_ghost,
+ sim->phi,
+ sim->k,
+ sim->dz,
+ sim->dt,
+ sim->beta_f,
+ sim->mu_f);
+ /* for (int i=0; i<sim->nz; ++i) { */
+ for (int i=0; i<sim->nz-1; ++i) {
+#ifdef DEBUG
+ printf("dp_f_expl[%d] = %g\ndp_f_impl[%d] = %g\n",
+ i, dp_f_expl[i], i, dp_f_impl[i]);
+#endif
+
+ p_f = sim->p_f_ghost[idx1g(i)];
+
+ p_f_ghost_out[idx1g(i)] = p_f
+ + (1.0 - epsilon)*dp_f_expl[i] + epsilon*dp_f_impl[i];
+
+ /* apply relaxation */
+ p_f_ghost_out[idx1g(i)] = p_f*(1.0 - theta)
+ + p_f_ghost_out[idx1g(i)]*theta;
+
+ r_norm[i] = (p_f_ghost_out[idx1g(i)] - p_f)/(p_f + 1e-16);
+ }
+
+ r_norm_max = max(r_norm, sim->nz);
+#ifdef DEBUG
+ puts(".. p_f_ghost_out:"); print_array(p_f_ghost_out, sim->nz+2);
+#endif
+
+ copy_values(p_f_ghost_out, sim->p_f_ghost, sim->nz+2);
+#ifdef DEBUG
+ puts(".. p_f_ghost after update:");
+ print_array(sim->p_f_ghost, sim->nz+2);
+#endif
+
+ if (r_norm_max <= rel_tol) {
+ set_bc_dirichlet(sim->p_f_ghost, sim->nz, +1, p_f_top);
+ sim->p_f_ghost[idx1g(sim->nz-1)] = p_f_top; /* top node in BC */
+ set_bc_neumann(sim->p_f_ghost, sim->nz, -1);
+ free(dp_f_expl);
+ free(dp_f_impl);
+ free(p_f_ghost_out);
+ free(r_norm);
+#ifdef DEBUG
+ printf(".. Solution converged after %d iterations\n", iter);
+#endif
+ return 0;
+ }
+ }
+
+ free(dp_f_expl);
+ free(dp_f_impl);
+ free(p_f_ghost_out);
+ free(r_norm);
+ fprintf(stderr, "darcy_solver_1d: ");
+ fprintf(stderr, "Solution did not converge after %d iterations\n", iter);
+ fprintf(stderr, ".. Residual normalized error: %f\n", r_norm_max);
+ return 1;
+}
diff --git a/fluid.h b/fluid.h
@@ -0,0 +1,13 @@
+#ifndef FLUID_H_
+#define FLUID_H_
+
+#include "simulation.h"
+
+void hydrostatic_fluid_pressure_distribution(struct simulation* sim);
+
+int darcy_solver_1d(
+ struct simulation* sim,
+ const int max_iter,
+ const double rel_tol);
+
+#endif
diff --git a/julia/1d_fd_simple_shear.jl b/julia/1d_fd_simple_shear.jl
@@ -1,277 +0,0 @@
-#!/usr/bin/env julia
-
-ENV["MPLBACKEND"] = "Agg"
-import PyPlot
-
-let
-
-# Simulation settings
-
-## Gravitational acceleration magnitude
-G = 9.81
-
-## Wall parameters
-
-### Effective normal stress exerted by top wall
-# A larger normal stress deepens the deformational depth
-P_wall_ = [10, 20, 40, 60, 80, 120] .* 1e3 # normal stress [Pa]
-
-### bottom velocity along x [m/s]
-v_x_bot = 0.0
-
-# stress ratio at top wall
-μ_wall = 0.40
-
-### Nodes along z
-nz = 100
-
-## Material properties
-
-### nonlocal amplitude [-]
-# lower values of A mean that the velocity curve can have sharper curves, e.g.
-# at the transition from μ ≈ μ_s
-#A = 0.48 # Henann and Kamrin 2016
-A = 0.40 # Loose fit to Damsgaard et al 2013
-
-### rate dependence beyond yield [-]
-# lower values of b mean larger shear velocity for a given stress ratio above
-# yield
-b = 0.9377 # Henann and Kamrin 2016
-
-### bulk and critical state static yield friction coefficient [-]
-#μ_s = 0.3819 # Henann and Kamrin 2016
-μ_s = atan(deg2rad(22.0)) # Damsgaard et al 2013
-
-### porosity [-]
-#ϕ = 0.38 # Henann and Kamrin 2016
-ϕ = 0.25 # Damsgaard et al 2013
-
-# representative grain size [m]
-# lower values of d mean that the shear velocity curve can have sharper curves,
-# e.g. at the transition from μ ≈ μ_s
-#d = 1e-3 # Henann and Kamrin 2016
-d = 0.04 # Damsgaard et al 2013
-
-### grain material density [kg/m^3]
-#ρ_s = 2.485e3 # Henann and Kamrin 2016
-ρ_s = 2.6e3 # Damsgaard et al 2013
-
-## Spatial settings
-origo_z = 0.0
-#L_z = 20.0*d # Henann and Kamrin 2016
-L_z = 0.7 # Damsgaard et al 2013
-z = collect(range(origo_z, L_z, length=nz))
-Δz = z[2] - z[1]
-
-## Allocate other arrays
-μ = zero(z) # local stress ratio
-p = zero(z) # local pressure
-v_x = zero(z) # local shear velocity
-g_ghost = zeros(size(z)[1]+2) # local fluidity with ghost nodes
-
-
-# Function definitions
-
-## Shear plastic strain rate (eq 2)
-γ_dot_p(g, μ) = g.*μ
-
-## Normal stress
-p_lithostatic(P_wall, z) = P_wall .+ (1 - ϕ).*ρ_s.*G.*(L_z .- z)
-
-## local cooperativity length
-ξ(μ) = A*d./sqrt.(abs.(μ .- μ_s))
-
-## Local fluidity
-function g_local(p, μ)
- if μ <= μ_s
- return 0.0
- else
- return sqrt(p./ρ_s.*d.^2.0) .* (μ .- μ_s)./(b.*μ)
- end
-end
-
-## Update ghost nodes for g from current values
-## BC: Neumann (dg/dx = 0)
-function set_bc_neumann(g_ghost, boundary)
- if boundary == "-z"
- g_ghost[1] = g_ghost[2]
- elseif boundary == "+z"
- g_ghost[end] = g_ghost[end-1]
- else
- @error "boundary '$boundary' not understood"
- end
-end
-
-## Update ghost nodes for g from current values
-## BC: Dirichlet (g = 0)
-function set_bc_dirichlet(g_ghost, boundary; value=0.0, idx_offset=0)
- if boundary == "-z"
- g_ghost[1+idx_offset] = value
- elseif boundary == "+z"
- g_ghost[end-idx_offset] = value
- else
- @error "boundary '$boundary' not understood"
- end
-end
-
-## Compute shear stress from velocity gradient using finite differences
-# function shear_stress(v, Δz)
-# τ = zero(v)
-#
-# # compute inner values with central differences
-# for i=2:length(v)-1
-# τ[i] = (v[i+1] - v[i-1])/(2.0*Δz)
-# end
-#
-# # use forward/backward finite differences at edges
-# τ[1] = (v[2] - v[1])/Δz
-# τ[end] = (v[end] - v[end-1])/Δz
-#
-# return τ
-# end
-
-#friction(τ, p) = τ./(p .+ 1e-16)
-
-## A single iteration for solving a Poisson equation Laplace(phi) = f on a
-## Cartesian grid. The function returns the normalized residual value
-function poisson_solver_1d_iteration(g_in, g_out, r_norm,
- μ, p, i, Δz,
- verbose=false)
-
- coorp_term = Δz^2.0/(2.0*ξ(μ[i])^2.0)
- g_out[i+1] = 1.0/(1.0 + coorp_term) * (coorp_term*g_local(p[i], μ[i])
- + g_in[i+1+1]/2.0 + g_in[i-1+1]/2.0)
- r_norm[i] = (g_out[i+1] - g_in[i+1])^2.0 / (g_out[i+1]^2.0 + 1e-16)
-
- if verbose
- println("-- $i -----------------")
- println("coorp_term: $coorp_term")
- println(" g_local: $(g_local(p[i], μ[i]))")
- println(" g_in: $(g_in[i+1])")
- println(" g_out: $(g_out[i+1])")
- println(" r_norm: $(r_norm[i])")
- end
-end
-
-## Iteratively solve the system laplace(phi) = f
-function implicit_1d_jacobian_poisson_solver(g, p, μ, Δz,
- rel_tol=1e-5,
- max_iter=10_000,
- verbose=false)
-
- # allocate second array of g for Jacobian solution procedure
- g_out = zero(g)
-
- if verbose
- println("g: ")
- println(g)
- println()
- println("g_out: ")
- println(g_out)
- end
-
- # array of normalized residuals
- r_norm = zero(p)
- r_norm_max = 0.0
-
- for iter=1:max_iter
- #println("\n@@@ ITERATION $iter @@@")
-
- set_bc_dirichlet(g, "-z")
- set_bc_dirichlet(g, "+z")
- #set_bc_neumann(g, "+z")
-
- if verbose
- println("g after BC: ")
- println(g)
- end
-
- # perform a single jacobi iteration in each cell
- for iz=1:length(p)
- poisson_solver_1d_iteration(g, g_out, r_norm,
- μ, p, iz, Δz)
- end
- r_norm_max = maximum(r_norm)
-
- # Flip-flop arrays
- tmp = g
- g = g_out
- g_out = tmp
-
- if verbose
- @info ".. Relative normalized error: $r_norm_max"
- end
-
- # stop iterating if the relative tolerance is satisfied
- if r_norm_max <= rel_tol
- @info ".. Solution converged after $iter iterations"
- return
- end
- end
- @error "Solution didn't converge after $max_iter iterations ($r_norm_max)"
-end
-
-function shear_velocity(γ_dot, Δz, v_x_bot)
-
- v_x = zero(γ_dot)
-
- # BC
- v_x[1] = v_x_bot
-
- for i=2:length(v_x)
- v_x[i] = v_x[i-1] + γ_dot[i]*Δz
- end
-
- return v_x
-end
-
-function plot_profile(z, v, label, filename)
- PyPlot.figure(figsize=[4,4])
- PyPlot.plot(v, z, "+k")
- PyPlot.xlabel(label)
- PyPlot.ylabel("\$z\$ [m]")
- PyPlot.tight_layout()
- PyPlot.savefig(filename)
- PyPlot.close()
-end
-
-init_μ(μ_wall, ϕ, ρ_s, G, z, P_wall) =
- μ_wall./(1.0 .+ (1.0-ϕ)*ρ_s*G.*(L_z .- z)./P_wall)
-
-
-# Main
-
-for P_wall in P_wall_
-
- ## calculate stresses
- p = p_lithostatic(P_wall, z)
- μ = init_μ(μ_wall, ϕ, ρ_s, G, z, P_wall)
-
- ## solve for fluidity
- implicit_1d_jacobian_poisson_solver(g_ghost, p, μ, Δz)
-
- ## calculate shear velocitiesj
- γ_dot = γ_dot_p(g_ghost[2:end-1], μ)
- v_x = shear_velocity(γ_dot, Δz, v_x_bot)
-
- ## plot results
- P = Int(round(P_wall/1e3))
- PyPlot.plot(v_x/maximum(v_x), z, "+-", label="\$P_{wall}\$ = $P kPa")
- # plot_profile(z, v_x, "Shear velocity, \$v_x\$ [m/s]",
- # "1d_fd_simple_shear_v_x_P$(P)kPa.png")
- # plot_profile(z, μ, "Stress ratio, μ [-]",
- # "1d_fd_simple_shear_mu_P$(P)kPa.png")
- # plot_profile(z, p, "Normal stress, \$p\$ [Pa]",
- # "1d_fd_simple_shear_p_P$(P)kPa.png")
- # plot_profile(z, g_ghost[2:end-1], "Fluidity, \$g\$",
- # "1d_fd_simple_shear_g_P$(P)kPa.png")
-end
-
-PyPlot.xlabel("Normalized shear displacement, [m]")
-PyPlot.ylabel("Vertical position, \$z\$ [m]")
-PyPlot.legend()
-PyPlot.tight_layout()
-PyPlot.savefig("1d_fd_simple_shear.png")
-PyPlot.close()
-
-end # end let
diff --git a/julia/1d_fd_simple_shear.png b/julia/1d_fd_simple_shear.png
Binary files differ.
diff --git a/julia/Makefile b/julia/Makefile
@@ -1,7 +0,0 @@
-JULIA=julia --banner=no --color=yes
-.PHONY: run-julia
-run-julia: 1d_fd_simple_shear.jl
- echo "$<" | entr -s '$(JULIA) "$<"'
-
-1d_fd_simple_shear.png: 1d_fd_simple_shear.jl
- $(JULIA) $<
diff --git a/main.c b/main.c
@@ -4,33 +4,47 @@
#include <getopt.h>
#include "simulation.h"
+#include "fluid.h"
-#define VERSION "0.1"
+#define VERSION "0.2"
#define PROGNAME "1d_fd_simple_shear"
-/* set default simulation parameter values */
-#include "1d_fd_simple_shear_damsgaard2013.h"
+#include "parameter_defaults.h"
static void usage(void)
{
- printf("%s: %s [OPTIONS]\n"
+ printf("%s: %s [OPTIONS] [NAME]\n"
+ "runs a simulation and outputs state in files prefixed with NAME.\n"
"optional arguments:\n"
- " -N, --normalize normalize output velocity\n"
- " -G, --gravity VAL gravity magnitude [m/s^2]\n"
- " -P, --pressure VAL normal stress [Pa]\n"
- " -m, --stress-ratio VAL applied stress ratio [-]\n"
- " -V, --velocity-bottom VAL base velocity at bottom [m/s]\n"
- " -A, --nonlocal-amplitude VAL amplitude of nonlocality [-]\n"
- " -b, --rate-dependence VAL rate dependence beyond yield [-]\n"
- " -f, --friction-coefficient VAL grain friction coefficient [-]\n"
- " -p, --porosity VAL porosity fraction [-]\n"
- " -d, --grain-size VAL representative grain size [m]\n"
- " -r, --density VAL grain material density [kg/m^3]\n"
- " -n, --resolution VAL number of cells in domain [-]\n"
- " -o, --origo VAL coordinate system origo [m]\n"
- " -L, --length VAL domain length [m]\n"
- " -v, --version show version information\n"
- " -h, --help show this message\n"
+ " -N, --normalize normalize output velocity\n"
+ " -G, --gravity VAL gravity magnitude [m/s^2]\n"
+ " -P, --normal-stress VAL normal stress on top [Pa]\n"
+ " -m, --stress-ratio VAL applied stress ratio [-]\n"
+ " -V, --velocity-bottom VAL base velocity at bottom [m/s]\n"
+ " -A, --nonlocal-amplitude VAL amplitude of nonlocality [-]\n"
+ " -b, --rate-dependence VAL rate dependence beyond yield [-]\n"
+ " -f, --friction-coefficient VAL grain friction coefficient [-]\n"
+ " -p, --porosity VAL porosity fraction [-]\n"
+ " -d, --grain-size VAL representative grain size [m]\n"
+ " -r, --density VAL grain material density [kg/m^3]\n"
+ " -n, --resolution VAL number of cells in domain [-]\n"
+ " -o, --origo VAL coordinate system origo [m]\n"
+ " -L, --length VAL domain length [m]\n"
+ " -F, --fluid enable pore fluid computations\n"
+ " -c, --fluid-compressibility VAL fluid compressibility [Pa^-1]\n"
+ " -i, --fluid-viscosity VAL fluid viscosity [Pa*s]\n"
+ " -R, --fluid-density VAL fluid density [kg/m^3]\n"
+ " -k, --fluid-permeability VAL fluid intrinsic permeability [m^2]\n"
+ " -O, --fluid-pressure-top VAL fluid pressure at +z edge [Pa]\n"
+ " -a, --fluid-pressure-ampl VAL amplitude of pressure variations [Pa]\n"
+ " -q, --fluid-pressure-freq VAL frequency of pressure variations [s^-1]\n"
+ " -H, --fluid-pressure-phase VAL fluid pressure at +z edge [Pa]\n"
+ " -t, --time VAL simulation start time [s]\n"
+ " -T, --time-end VAL simulation end time [s]\n"
+ " -D, --time-step VAL computational time step length [s]\n"
+ " -I, --file-interval VAL interval between output files [s]\n"
+ " -v, --version show version information\n"
+ " -h, --help show this message\n"
, __func__, PROGNAME);
}
@@ -52,12 +66,12 @@ int main(int argc, char* argv[])
int normalize = 0;
int opt;
- const char* optstring = "hvNG:P:m:V:A:b:f:p:d:r:n:o:L:";
+ const char* optstring = "hvNn:G:P:m:V:A:b:f:Fp:d:r:o:L:c:i:R:k:O:a:q:H:t:T:D:I:";
const struct option longopts[] = {
{"help", no_argument, NULL, 'h'},
{"version", no_argument, NULL, 'v'},
{"gravity", required_argument, NULL, 'G'},
- {"pressure", required_argument, NULL, 'P'},
+ {"normal-stress", required_argument, NULL, 'P'},
{"stress-ratio", required_argument, NULL, 'm'},
{"velocity-bottom", required_argument, NULL, 'V'},
{"nonlocal-amplitude", required_argument, NULL, 'A'},
@@ -69,9 +83,24 @@ int main(int argc, char* argv[])
{"resolution", required_argument, NULL, 'n'},
{"origo", required_argument, NULL, 'o'},
{"length", required_argument, NULL, 'L'},
+ {"fluid", no_argument, NULL, 'F'},
+ {"fluid-compressiblity", required_argument, NULL, 'c'},
+ {"fluid-viscosity", required_argument, NULL, 'i'},
+ {"fluid-density", required_argument, NULL, 'R'},
+ {"fluid-permeability", required_argument, NULL, 'k'},
+ {"fluid-pressure-top", required_argument, NULL, 'O'},
+ {"fluid-pressure-ampl", required_argument, NULL, 'a'},
+ {"fluid-pressure-freq", required_argument, NULL, 'q'},
+ {"fluid-pressure-phase", required_argument, NULL, 'H'},
+ {"time", required_argument, NULL, 't'},
+ {"time-end", required_argument, NULL, 'T'},
+ {"time-step", required_argument, NULL, 'D'},
+ {"file-interval", required_argument, NULL, 'I'},
{NULL, 0, NULL, 0}
};
+ double new_phi = sim.phi[0];
+ double new_k = sim.k[0];
while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) {
switch (opt) {
case -1: /* no more arguments */
@@ -84,6 +113,9 @@ int main(int argc, char* argv[])
case 'v':
version();
return 0;
+ case 'n':
+ sim.nz = atoi(optarg);
+ break;
case 'N':
normalize = 1;
break;
@@ -109,7 +141,7 @@ int main(int argc, char* argv[])
sim.mu_s = atof(optarg);
break;
case 'p':
- sim.phi = atof(optarg);
+ new_phi = atof(optarg);
break;
case 'd':
sim.d = atof(optarg);
@@ -117,15 +149,51 @@ int main(int argc, char* argv[])
case 'r':
sim.rho_s = atof(optarg);
break;
- case 'n':
- sim.nz = atoi(optarg);
- break;
case 'o':
sim.origo_z = atof(optarg);
break;
case 'L':
sim.L_z = atof(optarg);
break;
+ case 'F':
+ sim.fluid = 1;
+ break;
+ case 'c':
+ sim.beta_f = atof(optarg);
+ break;
+ case 'i':
+ sim.mu_f = atof(optarg);
+ break;
+ case 'R':
+ sim.rho_f = atof(optarg);
+ break;
+ case 'k':
+ new_k = atof(optarg);
+ break;
+ case 'O':
+ sim.p_f_top = atof(optarg);
+ break;
+ case 'a':
+ sim.p_f_mod_ampl = atof(optarg);
+ break;
+ case 'q':
+ sim.p_f_mod_freq = atof(optarg);
+ break;
+ case 'H':
+ sim.p_f_mod_phase = atof(optarg);
+ break;
+ case 't':
+ sim.t = atof(optarg);
+ break;
+ case 'T':
+ sim.t_end = atof(optarg);
+ break;
+ case 'D':
+ sim.dt = atof(optarg);
+ break;
+ case 'I':
+ sim.file_dt = atof(optarg);
+ break;
default:
fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);
@@ -134,29 +202,90 @@ int main(int argc, char* argv[])
return -2;
}
}
+ for (int i=optind; i<argc; ++i) {
+ if (i>optind) {
+ fprintf(stderr, "error: more than one simulation name specified\n");
+ return 1;
+ }
+ sprintf(sim.name, "%s", argv[i]);
+ }
prepare_arrays(&sim);
- init_pressure(&sim);
- init_friction(&sim);
- compute_cooperativity_length(&sim);
+ if (!isnan(new_phi))
+ for (int i=0; i<sim.nz; ++i)
+ sim.phi[i] = new_phi;
+ if (!isnan(new_k))
+ for (int i=0; i<sim.nz; ++i)
+ sim.k[i] = new_k;
+
+ lithostatic_pressure_distribution(&sim);
+
+ if (sim.fluid)
+ hydrostatic_fluid_pressure_distribution(&sim);
+
+#ifdef DEBUG
+ puts(".. p_f_ghost before iterations:"); print_array(sim.p_f_ghost, sim.nz+2);
+ puts("");
+ puts(".. normal stress before iterations:"); print_array(sim.sigma_n, sim.nz);
+ puts("");
+#endif
+
+ double filetimeclock = 0.0;
+ unsigned long iter = 0;
+ while (sim.t <= sim.t_end) {
+
+ if (sim.fluid) {
+ if (darcy_solver_1d(&sim, 10000, 1e-3))
+ exit(1);
+#ifdef DEBUG
+ puts(".. p_f_ghost:"); print_array(sim.p_f_ghost, sim.nz+2);
+ puts("");
+#endif
+ }
+
+ compute_effective_stress(&sim);
+ compute_friction(&sim);
+ compute_cooperativity_length(&sim);
+
+ if (iter == 0)
+ check_simulation_parameters(&sim);
#ifdef DEBUG
- puts("\n## Before solver");
- puts(".. p:"); print_array(sim.p, sim.nz);
- puts(".. mu:"); print_array(sim.mu, sim.nz);
+ puts("\n## Before solver");
+ puts(".. sigma_n_eff:"); print_array(sim.sigma_n_eff, sim.nz);
+ puts(".. mu:"); print_array(sim.mu, sim.nz);
#endif
- if (implicit_1d_jacobian_poisson_solver(&sim, 10000, 1e-5))
- exit(1);
+ if (implicit_1d_jacobian_poisson_solver(&sim, 10000, 1e-3))
+ exit(1);
- compute_shear_strain_rate_plastic(&sim);
- compute_shear_velocity(&sim);
+ compute_shear_strain_rate_plastic(&sim);
+ compute_shear_velocity(&sim);
+
+ sim.t += sim.dt;
+ filetimeclock += sim.dt;
+ iter++;
+
+ if (filetimeclock >= sim.file_dt) {
+ write_output_file(&sim);
+ filetimeclock = 0.0;
+ }
+ }
if (normalize)
print_arrays_2nd_normalized(sim.z, sim.v_x, sim.nz);
else
- print_arrays(sim.z, sim.v_x, sim.nz);
+ if (sim.fluid)
+ for (int i=0; i<sim.nz; ++i)
+ printf("%.17g\t%.17g\t%.17g\t%.17g\n",
+ sim.z[i],
+ sim.v_x[i],
+ sim.sigma_n_eff[i],
+ sim.mu[i]);
+ /* sim.p_f_ghost[idx1g(i)]); */
+ else
+ print_three_arrays(sim.z, sim.v_x, sim.sigma_n_eff, sim.nz);
free_arrays(&sim);
return 0;
diff --git a/parameter_defaults.h b/parameter_defaults.h
@@ -0,0 +1,71 @@
+#ifndef ONED_FD_SIMPLE_SHEAR_
+#define ONED_FD_SIMPLE_SHEAR_
+
+#include <math.h>
+#include <stdio.h>
+#include "arrays.h"
+#include "simulation.h"
+
+/* Simulation settings */
+struct simulation init_sim(void)
+{
+ struct simulation sim;
+
+ sprintf(sim.name, "unnamed");
+
+ sim.G = 9.81;
+
+ sim.P_wall = 120e3; /* larger normal stress deepens the shear depth */
+ sim.mu_wall = 0.40;
+ sim.v_x_bot = 0.0;
+
+ sim.nz = 100;
+
+ /* lower values of A mean that the velocity curve can have sharper curves,
+ * e.g. at the transition from μ ≈ μ_s */
+ sim.A = 0.40; /* Loose fit to Damsgaard et al 2013 */
+
+ /* lower values of b mean larger shear velocity for a given stress ratio
+ * above yield */
+ sim.b = 0.9377; /* Henann and Kamrin 2016 */
+
+ sim.mu_s = atan(DEG2RAD(22.0)); /* Damsgaard et al 2013 */
+
+ sim.phi = initval(0.25, 1); /* Damsgaard et al 2013 */
+
+ /* lower values of d mean that the shear velocity curve can have sharper
+ * curves, e.g. at the transition from μ ≈ μ_s */
+ sim.d = 0.04; /* Damsgaard et al 2013 */
+
+ /* grain material density [kg/m^3] */
+ sim.rho_s = 2.6e3; /* Damsgaard et al 2013 */
+
+ /* spatial settings */
+ sim.origo_z = 0.0;
+ sim.L_z = 0.7; /* Damsgaard et al 2013 */
+
+ /* temporal settings */
+ sim.t = 0.0;
+ sim.dt = 2.0;
+ sim.t_end = 1.0;
+ sim.file_dt = 0.1;
+ sim.n_file = 0;
+
+ /* fluid settings */
+ sim.fluid = 0;
+
+ sim.beta_f = 4.5e-10; /* Water, Goren et al 2011 */
+ sim.mu_f = 1e-3; /* Water, Goren et al 2011 */
+ sim.rho_f = 1e3; /* Water */
+ sim.k = initval(1.9e-15, 1); /* Damsgaard et al 2015 */
+
+ /* no fluid-pressure variations */
+ sim.p_f_top = 0.0;
+ sim.p_f_mod_ampl = 0.0;
+ sim.p_f_mod_freq = 1.0;
+ sim.p_f_mod_phase = 0.0;
+
+ return sim;
+}
+
+#endif
diff --git a/simulation.c b/simulation.c
@@ -1,5 +1,6 @@
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
#include "arrays.h"
#include "simulation.h"
@@ -9,25 +10,213 @@ void prepare_arrays(struct simulation* sim)
sim->origo_z + sim->L_z,
sim->nz);
sim->dz = sim->z[1] - sim->z[0]; /* cell spacing */
- sim->mu = zeros(sim->nz); /* local stress ratio */
- sim->p = zeros(sim->nz); /* local pressure */
+ sim->mu = zeros(sim->nz); /* stress ratio */
+ sim->sigma_n_eff = zeros(sim->nz); /* effective normal stress */
+ sim->sigma_n = zeros(sim->nz); /* normal stess */
+ sim->p_f_ghost = zeros(sim->nz+2); /* fluid pressure with ghost nodes */
+ free(sim->phi);
+ sim->phi = zeros(sim->nz); /* porosity */
+ free(sim->k);
+ sim->k = zeros(sim->nz); /* permeability */
sim->xi = zeros(sim->nz); /* cooperativity length */
- sim->gamma_dot_p = zeros(sim->nz); /* local shear velocity */
- sim->v_x = zeros(sim->nz); /* local shear velocity */
- sim->g_ghost = zeros(sim->nz+2); /* local fluidity with ghost nodes */
+ sim->gamma_dot_p = zeros(sim->nz); /* shear velocity */
+ sim->v_x = zeros(sim->nz); /* shear velocity */
+ sim->g_ghost = zeros(sim->nz+2); /* fluidity with ghost nodes */
}
void free_arrays(struct simulation* sim)
{
free(sim->z);
free(sim->mu);
- free(sim->p);
+ free(sim->sigma_n_eff);
+ free(sim->sigma_n);
+ free(sim->p_f_ghost);
+ free(sim->k);
+ free(sim->phi);
free(sim->xi);
free(sim->gamma_dot_p);
free(sim->v_x);
free(sim->g_ghost);
}
+static void warn_parameter_value(
+ const char message[],
+ const double value,
+ int* return_status)
+{
+ fprintf(stderr, "check_simulation_parameters: %s (%.17g)\n",
+ message, value);
+ *return_status = 1;
+}
+
+static void check_float(
+ const char name[],
+ const double value,
+ int* return_status)
+{
+ if (isnan(value)) {
+ warn_parameter_value("%s is NaN", value, return_status);
+ *return_status = 1;
+ } else if (isinf(value)) {
+ warn_parameter_value("%s is infinite", value, return_status);
+ *return_status = 1;
+ }
+}
+
+void check_simulation_parameters(const struct simulation* sim)
+{
+ int return_status = 0;
+
+ check_float("sim.G", sim->G, &return_status);
+ if (sim->G < 0.0)
+ warn_parameter_value("sim.G is negative", sim->G, &return_status);
+
+ check_float("sim.P_wall", sim->P_wall, &return_status);
+ if (sim->P_wall < 0.0)
+ warn_parameter_value("sim.P_wall is negative", sim->P_wall,
+ &return_status);
+
+ check_float("sim.v_x_bot", sim->v_x_bot, &return_status);
+
+ check_float("sim.mu_wall", sim->mu_wall, &return_status);
+ if (sim->mu_wall < 0.0)
+ warn_parameter_value("sim.mu_wall is negative", sim->mu_wall,
+ &return_status);
+
+ check_float("sim.A", sim->A, &return_status);
+ if (sim->A < 0.0)
+ warn_parameter_value("sim.A is negative", sim->A, &return_status);
+
+ check_float("sim.b", sim->b, &return_status);
+ if (sim->b < 0.0)
+ warn_parameter_value("sim.b is negative", sim->b, &return_status);
+
+ check_float("sim.mu_s", sim->mu_s, &return_status);
+ if (sim->mu_s < 0.0)
+ warn_parameter_value("sim.mu_s is negative", sim->mu_s,
+ &return_status);
+
+ check_float("sim.d", sim->d, &return_status);
+ if (sim->d <= 0.0)
+ warn_parameter_value("sim.d is not a positive number", sim->d,
+ &return_status);
+
+ check_float("sim.rho_s", sim->rho_s, &return_status);
+ if (sim->rho_s <= 0.0)
+ warn_parameter_value("sim.rho_s is not a positive number", sim->rho_s,
+ &return_status);
+
+ if (sim->nz <= 0)
+ warn_parameter_value("sim.nz is not a positive number", sim->nz,
+ &return_status);
+
+ check_float("sim.origo_z", sim->origo_z, &return_status);
+ check_float("sim.L_z", sim->L_z, &return_status);
+ if (sim->L_z <= sim->origo_z)
+ warn_parameter_value("sim.L_z is smaller or equal to sim.origo_z",
+ sim->L_z, &return_status);
+
+ if (sim->nz <= 0)
+ warn_parameter_value("sim.nz is not a positive number", sim->nz,
+ &return_status);
+
+ check_float("sim.dz", sim->dz, &return_status);
+ if (sim->dz <= 0.0)
+ warn_parameter_value("sim.dz is not a positive number", sim->dz,
+ &return_status);
+
+ check_float("sim.t", sim->t, &return_status);
+ if (sim->t < 0.0)
+ warn_parameter_value("sim.t is a negative number",
+ sim->t, &return_status);
+
+ check_float("sim.t_end", sim->t_end, &return_status);
+ if (sim->t > sim->t_end)
+ warn_parameter_value("sim.t_end is smaller than sim.t",
+ sim->t, &return_status);
+
+ check_float("sim.dt", sim->t_end, &return_status);
+ if (sim->dt <= 0.0)
+ warn_parameter_value("sim.dt is not a positive number",
+ sim->dt, &return_status);
+
+ check_float("sim.file_dt", sim->file_dt, &return_status);
+ if (sim->file_dt < 0.0)
+ warn_parameter_value("sim.file_dt is a negative number",
+ sim->file_dt, &return_status);
+
+ check_float("sim.phi[0]", sim->phi[0], &return_status);
+ if (sim->phi[0] < 0.0 || sim->phi[0] > 1.0)
+ warn_parameter_value("sim.phi[0] is not within [0;1]",
+ sim->phi[0], &return_status);
+
+ if (sim->fluid != 0 && sim->fluid != 1)
+ warn_parameter_value("sim.fluid has an invalid value",
+ (double)sim->fluid, &return_status);
+
+ if (sim->fluid) {
+
+ check_float("sim.p_f_mod_ampl", sim->p_f_mod_ampl, &return_status);
+ if (sim->p_f_mod_ampl < 0.0)
+ warn_parameter_value("sim.p_f_mod_ampl is not a zero or positive",
+ sim->p_f_mod_ampl, &return_status);
+
+ check_float("sim.p_f_mod_freq", sim->p_f_mod_freq, &return_status);
+ if (sim->p_f_mod_freq < 0.0)
+ warn_parameter_value("sim.p_f_mod_freq is not a zero or positive",
+ sim->p_f_mod_freq, &return_status);
+
+ check_float("sim.beta_f", sim->beta_f, &return_status);
+ if (sim->beta_f <= 0.0)
+ warn_parameter_value("sim.beta_f is not positive",
+ sim->beta_f, &return_status);
+
+ check_float("sim.mu_f", sim->mu_f, &return_status);
+ if (sim->mu_f <= 0.0)
+ warn_parameter_value("sim.mu_f is not positive",
+ sim->mu_f, &return_status);
+
+ check_float("sim.rho_f", sim->rho_f, &return_status);
+ if (sim->rho_f <= 0.0)
+ warn_parameter_value("sim.rho_f is not positive",
+ sim->rho_f, &return_status);
+
+ check_float("sim.k[0]", sim->k[0], &return_status);
+ if (sim->k[0] <= 0.0)
+ warn_parameter_value("sim.k[0] is not positive",
+ sim->k[0], &return_status);
+
+ }
+
+ if (return_status != 0) {
+ fprintf(stderr, "error: aborting due to invalid parameter choices\n");
+ exit(return_status);
+ }
+}
+
+void lithostatic_pressure_distribution(struct simulation* sim)
+{
+ for (int i=0; i<sim->nz; ++i)
+ sim->sigma_n[i] = sim->P_wall +
+ (1.0 - sim->phi[i])*sim->rho_s*sim->G*(sim->L_z - sim->z[i]);
+}
+
+void compute_friction(struct simulation* sim)
+{
+ if (sim->fluid)
+ for (int i=0; i<sim->nz; ++i)
+ sim->mu[i] = sim->mu_wall/
+ (sim->sigma_n_eff[i]/(sim->P_wall - sim->p_f_top));
+
+ else
+ for (int i=0; i<sim->nz; ++i)
+ sim->mu[i] = sim->mu_wall /
+ (1.0 + (1.0 - sim->phi[i])*sim->rho_s*sim->G*(sim->L_z -
+ sim->z[i])
+ /sim->P_wall);
+
+}
+
double shear_strain_rate_plastic(
const double fluidity,
const double friction)
@@ -52,6 +241,16 @@ void compute_shear_velocity(struct simulation* sim)
sim->v_x[i] = sim->v_x[i-1] + sim->gamma_dot_p[i]*sim->dz;
}
+void compute_effective_stress(struct simulation* sim)
+{
+ if (sim->fluid)
+ for (int i=0; i<sim->nz; ++i)
+ sim->sigma_n_eff[i] = sim->sigma_n[i] - sim->p_f_ghost[idx1g(i)];
+ else
+ for (int i=0; i<sim->nz; ++i)
+ sim->sigma_n_eff[i] = sim->sigma_n[i];
+}
+
double cooperativity_length(
const double A,
const double d,
@@ -86,7 +285,12 @@ void compute_local_fluidity(struct simulation* sim)
{
for (int i=0; i<sim->nz; ++i)
sim->g_ghost[idx1g(i)] = local_fluidity(
- sim->p[i], sim->mu[i], sim->mu_s, sim->b, sim->rho_s, sim->d);
+ sim->sigma_n_eff[i],
+ sim->mu[i],
+ sim->mu_s,
+ sim->b,
+ sim->rho_s,
+ sim->d);
}
void set_bc_neumann(double* g_ghost, const int nz, const int boundary)
@@ -180,7 +384,7 @@ int implicit_1d_jacobian_poisson_solver(
r_norm,
sim->dz,
sim->mu,
- sim->p,
+ sim->sigma_n_eff,
sim->xi,
sim->mu_s,
sim->b,
@@ -192,7 +396,7 @@ int implicit_1d_jacobian_poisson_solver(
if (r_norm_max <= rel_tol) {
set_bc_dirichlet(sim->g_ghost, sim->nz, -1, 0.0);
- set_bc_neumann(sim->g_ghost, sim->nz, +1);
+ set_bc_dirichlet(sim->g_ghost, sim->nz, +1, 0.0);
free(g_ghost_out);
free(r_norm);
/* printf(".. Solution converged after %d iterations\n", iter); */
@@ -207,3 +411,25 @@ int implicit_1d_jacobian_poisson_solver(
fprintf(stderr, ".. Residual normalized error: %f\n", r_norm_max);
return 1;
}
+
+void write_output_file(struct simulation* sim)
+{
+
+ char outfile[200];
+ FILE *fp;
+ sprintf(outfile, "%s.output%05d.txt", sim->name, sim->n_file++);
+
+ fp = fopen(outfile, "w");
+ if (sim->fluid)
+ for (int i=0; i<sim->nz; ++i)
+ fprintf(fp, "%.17g\t%.17g\t%.17g\t%.17g\t%.17g\n",
+ sim->z[i],
+ sim->v_x[i],
+ sim->sigma_n_eff[i],
+ sim->p_f_ghost[idx1g(i)],
+ sim->mu[i]);
+ else
+ fprint_three_arrays(fp, sim->z, sim->v_x, sim->sigma_n_eff, sim->nz);
+
+ fclose(fp);
+}
diff --git a/simulation.h b/simulation.h
@@ -1,12 +1,17 @@
#ifndef SIMULATION_
#define SIMULATION_
-#include <math.h>
#include "arrays.h"
+#define PI 3.14159265358979323846
+#define DEG2RAD(x) (x*PI/180.0)
+
/* Simulation settings */
struct simulation {
+ /* simulation name to use for output files */
+ char name[100];
+
/* gravitational acceleration magnitude [m/s^2] */
double G;
@@ -28,9 +33,6 @@ struct simulation {
/* bulk and critical state static yield friction coefficient [-] */
double mu_s;
- /* porosity [-] */
- double phi;
-
/* representative grain size [m] */
double d;
@@ -52,9 +54,38 @@ struct simulation {
/* cell spacing [m] */
double dz;
- /* other arrays */
+ /* current time [s] */
+ double t;
+
+ /* end time [s] */
+ double t_end;
+
+ /* time step length [s] */
+ double dt;
+
+ /* interval between output files [s] */
+ double file_dt;
+
+ /* output file number */
+ int n_file;
+
+ /* Fluid parameters */
+ int fluid; /* flag to switch fluid on (1) or off (0) */
+ double p_f_top; /* fluid pressure at the top [Pa] */
+ double p_f_mod_ampl; /* amplitude of fluid pressure variations [Pa] */
+ double p_f_mod_freq; /* frequency of fluid pressure variations [s^-1] */
+ double p_f_mod_phase; /* phase of fluid pressure variations [s^-1] */
+ double beta_f; /* adiabatic fluid compressibility [Pa^-1] */
+ double mu_f; /* fluid dynamic viscosity [Pa*s] */
+ double rho_f; /* fluid density [kg/m^3] */
+
+ /* arrays */
double* mu; /* static yield friction [-] */
- double* p; /* effective normal pressure [Pa] */
+ double* sigma_n_eff; /* effective normal pressure [Pa] */
+ double* sigma_n; /* normal stress [Pa] */
+ double* p_f_ghost; /* fluid pressure [Pa] */
+ double* k; /* hydraulic permeability [m^2] */
+ double* phi; /* porosity [-] */
double* xi; /* cooperativity length */
double* gamma_dot_p; /* plastic shear strain rate [1/s] */
double* v_x; /* shear velocity [m/s] */
@@ -65,6 +96,10 @@ struct simulation {
void prepare_arrays(struct simulation* sim);
void free_arrays(struct simulation* sim);
+void check_simulation_parameters(const struct simulation* sim);
+
+void lithostatic_pressure_distribution(struct simulation* sim);
+
void set_bc_neumann(
double* g_ghost,
const int nz,
@@ -79,10 +114,14 @@ void set_bc_dirichlet(
void compute_cooperativity_length(struct simulation* sim);
void compute_shear_strain_rate_plastic(struct simulation* sim);
void compute_shear_velocity(struct simulation* sim);
+void compute_effective_stress(struct simulation* sim);
+void compute_friction(struct simulation* sim);
int implicit_1d_jacobian_poisson_solver(
struct simulation* sim,
const int max_iter,
const double rel_tol);
+void write_output_file(struct simulation* sim);
+
#endif