tImplement implicit Poisson solver - cngf-pf - continuum model for granular flo… | |
git clone git://src.adamsgaard.dk/cngf-pf | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit f463d4d2404fe59625621e49a7db22b70a9202d4 | |
parent 461dca87e55ffa2b46791b589f65cb3b050b533f | |
Author: Anders Damsgaard <[email protected]> | |
Date: Fri, 5 Apr 2019 14:33:35 +0200 | |
Implement implicit Poisson solver | |
Diffstat: | |
M arrays.c | 53 +++++++++++++++++++++++++----… | |
M arrays.h | 6 ++++++ | |
D damsgaard2013-fig8.png | 0 | |
M simulation.c | 171 ++++++++++++++++++++++++++++-… | |
M simulation.h | 32 ++++++++++++++++++++++++-----… | |
5 files changed, 233 insertions(+), 29 deletions(-) | |
--- | |
diff --git a/arrays.c b/arrays.c | |
t@@ -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) | |
t@@ -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) | |
t@@ -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)); | |
t@@ -45,7 +52,7 @@ double* linspace(const double lower, const double upper, con… | |
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)); | |
t@@ -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)); | |
t@@ -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 | |
t@@ -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 | |
t@@ -1,3 +1,4 @@ | |
+#include <stdio.h> | |
#include <stdlib.h> | |
#include "arrays.h" | |
#include "simulation.h" | |
t@@ -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) | |
t@@ -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 | |
t@@ -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 |