commit f463d4d2404fe59625621e49a7db22b70a9202d4
parent 461dca87e55ffa2b46791b589f65cb3b050b533f
Author: Anders Damsgaard <anders@adamsgaard.dk>
Date:   Fri,  5 Apr 2019 14:33:35 +0200
Implement implicit Poisson solver
Diffstat:
5 files changed, 233 insertions(+), 29 deletions(-)
diff --git a/arrays.c b/arrays.c
@@ -1,9 +1,10 @@
 #include <stdlib.h>
+#include <math.h>
 
 #define DEG2RAD(x) (x*M_PI/180.0)
 
-// Translate a i,j,k index in grid with dimensions nx, ny, nz into a linear
-// index
+/* Translate a i,j,k index in grid with dimensions nx, ny, nz into a linear
+ * index */
 unsigned int idx3(
         const unsigned int i, const unsigned int j, const unsigned int k,
         const unsigned int nx, const unsigned int ny)
@@ -11,8 +12,8 @@ unsigned int idx3(
     return i + nx*j + nx*ny*k;
 }
 
-// Translate a i,j,k index in grid with dimensions nx, ny, nz and a padding of
-// single ghost nodes into a linear index
+/* Translate a i,j,k index in grid with dimensions nx, ny, nz and a padding of
+ * single ghost nodes into a linear index */
 unsigned int idx3g(
         const unsigned int i, const unsigned int j, const unsigned int k,
         const unsigned int nx, const unsigned int ny)
@@ -20,22 +21,28 @@ unsigned int idx3g(
     return i+1 + (nx+2)*(j+1) + (nx+2)*(ny+2)*(k+1);
 }
 
-// Translate a i,j index in grid with dimensions nx, ny into a linear index
+/* Translate a i,j index in grid with dimensions nx, ny into a linear index */
 unsigned int idx2(
         const unsigned int i, const unsigned int j, const unsigned int nx)
 {
     return i + nx*j;
 }
 
-// Translate a i,j index in grid with dimensions nx, ny and a padding of single
-// ghost nodes into a linear index
+/* Translate a i,j index in grid with dimensions nx, ny and a padding of single
+ * ghost nodes into a linear index */
 unsigned int idx2g(
         const unsigned int i, const unsigned int j, const unsigned int nx)
 {
     return i+1 + (nx+2)*(j+1);
 }
 
-// Return an array of `n` linearly spaced values in the range [lower; upper]
+/* Translate a i index in grid with a padding of single into a linear index */
+unsigned int idx1g(const unsigned int i)
+{
+    return i+1;
+}
+
+/* Return an array of `n` linearly spaced values in the range [lower; upper] */
 double* linspace(const double lower, const double upper, const int n)
 {
     double *x = malloc(n*sizeof(double));
@@ -45,7 +52,7 @@ double* linspace(const double lower, const double upper, const int n)
     return x;
 }
 
-// Return an array of `n` values with the value 0.0
+/* Return an array of `n` values with the value 0.0 */
 double* zeros(const double n)
 {
     double *x = malloc(n*sizeof(double));
@@ -54,7 +61,7 @@ double* zeros(const double n)
     return x;
 }
 
-// Return an array of `n` values with the value 1.0
+/* Return an array of `n` values with the value 1.0 */
 double* ones(const double n)
 {
     double *x = malloc(n*sizeof(double));
@@ -63,3 +70,29 @@ double* ones(const double n)
     return x;
 }
 
+/* Return an array of `n` uninitialized values */
+double* empty(const double n)
+{
+    return malloc(n*sizeof(double));
+}
+
+/* Return largest value in array `a` with size `n` */
+double max(const double* a, const int n)
+{
+    double maxval = -INFINITY;
+    for (int i=0; i<n; ++i)
+        if (a[i] > maxval)
+            maxval = a[i];
+    return maxval;
+}
+
+/* Return smallest value in array `a` with size `n` */
+double min(const double* a, const int n)
+{
+    double minval = +INFINITY;
+    for (int i=0; i<n; ++i)
+        if (a[i] < minval)
+            minval = a[i];
+    return minval;
+}
+
diff --git a/arrays.h b/arrays.h
@@ -15,8 +15,14 @@ unsigned int idx2(
 unsigned int idx2g(
         const unsigned int i, const unsigned int j, const unsigned int nx);
 
+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 max(const double* a, const int n);
+double min(const double* a, const int n);
 
 #endif
diff --git a/damsgaard2013-fig8.png b/damsgaard2013-fig8.png
Binary files differ.
diff --git a/simulation.c b/simulation.c
@@ -1,3 +1,4 @@
+#include <stdio.h>
 #include <stdlib.h>
 #include "arrays.h"
 #include "simulation.h"
@@ -5,11 +6,13 @@
 void prepare_arrays(struct simulation* sim)
 {
     sim->z = linspace(sim->origo_z, sim->L_z, sim->nz); /* spatial coordinates */
-    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->v_x = zeros(sim->nz);        /* local shear velocity */
-    sim->g_ghost = zeros(sim->nz+2);  /* local fluidity with ghost nodes */
+    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->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 */
 }
 
 void free_arrays(struct simulation* sim)
@@ -17,16 +20,160 @@ void free_arrays(struct simulation* sim)
     free(sim->z);
     free(sim->mu);
     free(sim->p);
+    free(sim->xi);
+    free(sim->gamma_dot_p);
     free(sim->v_x);
     free(sim->g_ghost);
 }
 
-void shear_strain_rate_plastic(
-        const double* fluidity,
-        const double* friction,
-        double* shear_strain_rate,
-        const int n)
+double shear_strain_rate_plastic(
+        const double fluidity,
+        const double friction)
 {
-    for (int i=0; i<n; ++i)
-        shear_strain_rate[i] = fluidity[i]*friction[i];
+        return fluidity*friction;
+}
+
+void compute_shear_strain_rate_plastic(struct simulation* sim)
+{
+    for (int i=0; i<sim->nz; ++i)
+        sim->gamma_dot_p[i] =
+            shear_strain_rate_plastic(sim->g_ghost[idx1g(i)], sim->mu[i]);
+}
+
+double cooperativity_length(
+        const double A,
+        const double d,
+        const double mu,
+        const double mu_s)
+{
+    return A*d/sqrt(fabs(mu - mu_s));
+}
+
+void compute_cooperativity_length(struct simulation* sim)
+{
+    for (int i=0; i<sim->nz; ++i)
+        sim->xi[i] = cooperativity_length(
+                sim->A, sim->d, sim->mu[i], sim->mu_s);
+}
+
+double local_fluidity(
+        const double p,
+        const double mu,
+        const double mu_s,
+        const double b,
+        const double rho_s,
+        const double d)
+{
+    if (mu <= mu_s)
+        return 0.0;
+    else
+        return sqrt(p/rho_s*d*d) * (mu - mu_s)/(b*mu);
+}
+
+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);
+}
+
+void set_bc_neumann(double* g_ghost, const int nz, const int boundary)
+{
+    if (boundary == -1)
+        g_ghost[0] = g_ghost[1];
+    else if (boundary == +1)
+        g_ghost[idx1g(nz)+1] = g_ghost[idx1g(nz)];
+    else {
+        fprintf(stderr, "set_bc_neumann: Unknown boundary %d\n", boundary);
+        exit(1);
+    }
+}
+
+void set_bc_dirichlet(
+        double* g_ghost,
+        const int nz,
+        const int boundary,
+        const double value)
+{
+    if (boundary == -1)
+        g_ghost[0] = value;
+    else if (boundary == +1)
+        g_ghost[idx1g(nz)+1] = value;
+    else {
+        fprintf(stderr, "set_bc_dirichlet: Unknown boundary %d\n", boundary);
+        exit(1);
+    }
+}
+
+void poisson_solver_1d_cell_update(
+        int i,
+        const double* g_in,
+        double* g_out,
+        double* r_norm,
+        const double dz,
+        const double* mu,
+        const double* p,
+        const double* xi,
+        const double mu_s,
+        const double b,
+        const double rho_s,
+        const double d)
+{
+    double coorp_term = dz*dz/(2.0*pow(xi[i], 2.0));
+    g_out[idx1g(i)] = 1.0/(1.0 + coorp_term)*(coorp_term*
+            local_fluidity(p[i], mu[i], mu_s, b, rho_s, d)
+            + g_in[idx1g(i)+1]/2.0
+            + g_in[idx1g(i)-1]/2.0);
+}
+
+int implicit_1d_jacobian_poisson_solver(
+        struct simulation* sim,
+        const int max_iter,
+        const double rel_tol)
+{
+    double* g_ghost_out = empty(sim->nz);
+    double* r_norm = empty(sim->nz);
+
+    set_bc_neumann(sim->g_ghost, sim->nz, +1);
+    set_bc_dirichlet(sim->g_ghost, sim->nz, -1, 0.0);
+
+    int iter;
+    double r_norm_max = NAN;
+
+    for (iter=0; iter<max_iter; ++iter) {
+
+        for (int i=0; i<sim->nz; ++i)
+            poisson_solver_1d_cell_update(
+                    i,
+                    sim->g_ghost,
+                    g_ghost_out,
+                    r_norm,
+                    sim->dz,
+                    sim->mu,
+                    sim->p,
+                    sim->xi,
+                    sim->mu_s,
+                    sim->b,
+                    sim->rho_s,
+                    sim->d);
+        r_norm_max = max(r_norm, sim->nz);
+
+        double* tmp = sim->g_ghost;
+        sim->g_ghost = g_ghost_out;
+        g_ghost_out = tmp;
+
+        if (r_norm_max <= rel_tol) {
+            free(g_ghost_out);
+            free(r_norm);
+            printf(".. Solution converged after %d iterations\n", iter);
+            return 0;
+        }
+    }
+
+    free(g_ghost_out);
+    free(r_norm);
+    fprintf(stderr, "implicit_1d_jacobian_poisson_solver: ");
+    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/simulation.h b/simulation.h
@@ -40,27 +40,45 @@ struct simulation {
     /* nodes along z */
     int nz;
 
-    /* origo of axis */
+    /* origo of axis [m] */
     double origo_z;
 
-    /* length of domain */
+    /* length of domain [m] */
     double L_z;
 
     /* array of cell coordinates */
     double* z;
 
-    /* cell spacin */
+    /* cell spacing [m] */
     double dz;
 
     /* other arrays */
-    double* mu;
-    double* p;
-    double* v_x;
-    double* g_ghost;
+    double* mu;           /* static yield friction [-] */
+    double* p;            /* effective normal pressure [Pa] */
+    double* xi;           /* cooperativity length */
+    double* gamma_dot_p;  /* plastic shear strain rate [1/s] */
+    double* v_x;          /* shear velocity [m/s] */
+    double* g_ghost;      /* fluidity with ghost nodes */
 };
 
 
 void prepare_arrays(struct simulation* sim);
 void free_arrays(struct simulation* sim);
 
+void set_bc_neumann(
+        double* g_ghost,
+        const int nz,
+        const int boundary);
+
+void set_bc_dirichlet(
+        double* g_ghost,
+        const int nz,
+        const int boundary,
+        const double value);
+
+int implicit_1d_jacobian_poisson_solver(
+        struct simulation* sim,
+        const int max_iter,
+        const double rel_tol);
+
 #endif