tMerge branch 'darcy' into 'master' - cngf-pf - continuum model for granular fl… | |
git clone git://src.adamsgaard.dk/cngf-pf | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 76f099629e26cfd4d8338b5862856ebc974d4e74 | |
parent 9e079cfadd9105a19d6d651546fd09fe069612e3 | |
Author: Anders Damsgaard <[email protected]> | |
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: | |
M .gitlab-ci.yml | 2 +- | |
M 1d_fd_simple_shear.png | 0 | |
D 1d_fd_simple_shear_damsgaard2013.h | 66 -----------------------------… | |
A 1d_fd_simple_shear_fluid.gp | 35 +++++++++++++++++++++++++++++… | |
M 1d_fd_simple_shear_henann_kamrin20… | 2 +- | |
M 1d_fd_simple_shear_rheology.png | 0 | |
M 1d_fd_simple_shear_rheology_iverso… | 0 | |
M 1d_fd_simple_shear_rheology_kamb.p… | 0 | |
M 1d_fd_simple_shear_rheology_tulacz… | 0 | |
M Makefile | 19 ++++++++++++++++++- | |
M README.md | 46 +++++++++++++++++++++++++++++… | |
M arrays.c | 46 +++++++++++++++++++++++++++++… | |
M arrays.h | 23 ++++++++++++++++++++--- | |
A diurnal.gif | 0 | |
A fluid.c | 185 ++++++++++++++++++++++++++++++ | |
A fluid.h | 13 +++++++++++++ | |
D julia/1d_fd_simple_shear.jl | 277 -----------------------------… | |
D julia/1d_fd_simple_shear.png | 0 | |
D julia/Makefile | 7 ------- | |
M main.c | 203 +++++++++++++++++++++++++----… | |
A parameter_defaults.h | 71 +++++++++++++++++++++++++++++… | |
M simulation.c | 244 +++++++++++++++++++++++++++++… | |
M simulation.h | 51 +++++++++++++++++++++++++++--… | |
23 files changed, 878 insertions(+), 412 deletions(-) | |
--- | |
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml | |
t@@ -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_damsgaard2… | |
t@@ -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 | |
t@@ -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… | |
t@@ -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_rheol… | |
Binary files differ. | |
diff --git a/1d_fd_simple_shear_rheology_kamb.png b/1d_fd_simple_shear_rheology… | |
Binary files differ. | |
diff --git a/1d_fd_simple_shear_rheology_tulaczyk.png b/1d_fd_simple_shear_rheo… | |
Binary files differ. | |
diff --git a/Makefile b/Makefile | |
t@@ -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 --flui… | |
+ /bin/bash -c '\ | |
+ for f in diurnal.output*.txt; do \ | |
+ gnuplot -e "filename=\"$$f\"; p_min=\"0\"; p_max=\"100e3\"" $<… | |
+ 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 | |
t@@ -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 | |
t@@ -26,7 +64,6 @@ probably be improved further. | |
| ![damsgaard2013-fig8.png](https://gitlab.com/admesg/1d_fd_simple_shear/raw/m… | |
### 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 | |
t@@ -41,3 +78,10 @@ have *b* = 0.94 ([Forterre and Pouliquen | |
| ![iverson2010-fig2a.png](https://gitlab.com/admesg/1d_fd_simple_shear/raw/ma… | |
| Whillans Ice Plain ([Tulaczyk 2006](https://doi.org/10.3189/1727565067818286… | |
| ![tulaczyk2006-fig1.png](https://gitlab.com/admesg/1d_fd_simple_shear/raw/ma… | |
+ | |
+### 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. | |
+ | |
+![diurnal.gif](https://gitlab.com/admesg/1d_fd_simple_shear/raw/master/diurnal… | |
diff --git a/arrays.c b/arrays.c | |
t@@ -54,7 +54,7 @@ double* linspace(const double lower, const double upper, con… | |
} | |
/* 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) | |
t@@ -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) | |
t@@ -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)); | |
} | |
t@@ -116,6 +125,37 @@ void print_arrays_2nd_normalized(const double* a, const d… | |
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 | |
t@@ -1,3 +1,5 @@ | |
+#include <stdio.h> | |
+ | |
#ifndef ARRAYS_ | |
#define ARRAYS_ | |
t@@ -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); | |
t@@ -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 | |
t@@ -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 | |
t@@ -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 | |
t@@ -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 | |
t@@ -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 | |
t@@ -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.\… | |
"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 [-]\… | |
- " -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 [-]… | |
+ " -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, --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^… | |
+ " -O, --fluid-pressure-top VAL fluid pressure at +z edge [Pa]\n" | |
+ " -a, --fluid-pressure-ampl VAL amplitude of pressure variations… | |
+ " -q, --fluid-pressure-freq VAL frequency of pressure variations… | |
+ " -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 [… | |
+ " -I, --file-interval VAL interval between output files [s… | |
+ " -v, --version show version information\n" | |
+ " -h, --help show this message\n" | |
, __func__, PROGNAME); | |
} | |
t@@ -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… | |
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'}, | |
t@@ -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 */ | |
t@@ -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; | |
t@@ -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); | |
t@@ -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); | |
t@@ -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… | |
+ puts(""); | |
+ puts(".. normal stress before iterations:"); print_array(sim.sigma_n, sim.… | |
+ 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 | |
t@@ -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 | |
t@@ -1,5 +1,6 @@ | |
#include <stdio.h> | |
#include <stdlib.h> | |
+#include <math.h> | |
#include "arrays.h" | |
#include "simulation.h" | |
t@@ -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) | |
t@@ -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, | |
t@@ -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) | |
t@@ -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, | |
t@@ -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); */ | |
t@@ -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 | |
t@@ -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; | |
t@@ -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; | |
t@@ -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] */ | |
t@@ -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, | |
t@@ -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 |