| tFirst commit - werner - cellular automata simulation of wind-driven sand trans… | |
| git clone git://src.adamsgaard.dk/werner | |
| Log | |
| Files | |
| Refs | |
| LICENSE | |
| --- | |
| commit d238e187ed68520db7a7d73e1fb9b011ec1d8c53 | |
| Author: Anders Damsgaard Christensen <[email protected]> | |
| Date: Sun, 21 Apr 2013 11:08:31 +0200 | |
| First commit | |
| Diffstat: | |
| A Makefile | 35 +++++++++++++++++++++++++++++… | |
| A README.rst | 31 +++++++++++++++++++++++++++++… | |
| A initrnd.c | 29 +++++++++++++++++++++++++++++ | |
| A iterate.c | 35 +++++++++++++++++++++++++++++… | |
| A out/plotmatrix.gp | 20 ++++++++++++++++++++ | |
| A printmat.c | 26 ++++++++++++++++++++++++++ | |
| A werner.c | 318 +++++++++++++++++++++++++++++… | |
| A werner.h | 23 +++++++++++++++++++++++ | |
| A wernerparams.h | 11 +++++++++++ | |
| 9 files changed, 528 insertions(+), 0 deletions(-) | |
| --- | |
| diff --git a/Makefile b/Makefile | |
| t@@ -0,0 +1,35 @@ | |
| +CFLAGS=-g -Wall -O3 -std=gnu11 -pg | |
| +LDLIBS=`pkg-config --libs gsl` | |
| +LDFLAGS=-pg | |
| + | |
| +default: plots | |
| + | |
| +initrnd: initrnd.o werner.o *.h | |
| + | |
| +iterate: iterate.o werner.o *.h | |
| + | |
| +printmat: printmat.o werner.o *.h | |
| + | |
| +display: matrix.png | |
| + display $< | |
| + | |
| +matrixes: initrnd iterate printmat Makefile | |
| + ./initrnd > tmp.mat | |
| + for i in {001..400}; do cat tmp.mat | ./iterate 1 > tmp_new.mat && cat… | |
| + | |
| +plots: matrixes | |
| + cd out && for f in *.txt; do gnuplot -e "matrixfile='$$f'" plotmatrix.… | |
| + | |
| +view: plots | |
| + feh out/*.png | |
| + | |
| +profile-iter: initrnd iterate | |
| + ./initrnd > tmp.mat | |
| + ./iterate 10 > tmp_new.mat | |
| + | |
| +clean: | |
| + $(RM) initrnd iterate printmat | |
| + $(RM) *.o | |
| + $(RM) tmp.mat | |
| + $(RM) out/*.txt | |
| + $(RM) out/*.png | |
| diff --git a/README.rst b/README.rst | |
| t@@ -0,0 +1,31 @@ | |
| +Werner | |
| +====== | |
| + | |
| +Discrete simulation of wind driven ( | |
| +`aeolian <https://en.wikipedia.org/wiki/Aeolian_processes>`_) erosion, transpo… | |
| +deposition and avalanching of sand, based on `B.T. Werner's algorithm | |
| +<http://geology.geoscienceworld.org/content/23/12/1107>`_. | |
| + | |
| +The software is licensed under the GNU General Public License, v.3. See | |
| +`license.txt` for more information. These programs are created by Anders | |
| +Damsgaard, `<[email protected]>`_. | |
| + | |
| +Requirements | |
| +------------ | |
| +The requirements are: | |
| + * A C compiler toolkit, e.g. the `GNU Compiler Collection | |
| + <http://gcc.gnu.org/>`_ (GCC) | |
| + * `GNU Make <https://www.gnu.org/software/make/>`_ | |
| + * `Gnuplot <http://www.gnuplot.info/>`_ | |
| + * `GSL - GNU Scientific Library <http://www.gnuplot.info/>`_ | |
| + | |
| +Build and run instructions | |
| +-------------------------- | |
| +From the root directory, execute the following command:: | |
| + make | |
| + | |
| +This will build the program, and run an example simulation. Output images are | |
| +placed in the `out/` folder. | |
| +Simulation parameters are changed in `wernerparams.h`. After changing this fil… | |
| +run ``make`` again. | |
| + | |
| diff --git a/initrnd.c b/initrnd.c | |
| t@@ -0,0 +1,29 @@ | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| + | |
| +// see https://www.gnu.org/software/gsl/manual/html_node/Matrices.html | |
| +#include <gsl/gsl_matrix.h> | |
| + | |
| +#include "wernerparams.h" | |
| +#include "werner.h" | |
| + | |
| + | |
| +int main(int argc, char** argv) | |
| +{ | |
| + | |
| + // Allocate matrix Z: number of sand slabs | |
| + gsl_matrix* Z = gsl_matrix_alloc(rows, cols); | |
| + | |
| + // Initialize with random values | |
| + init_rnd_matrix(Z, 1.0, 10.0); | |
| + | |
| + // Add 100 sand slabs to each cell | |
| + //gsl_matrix_add_constant(Z, 100.0); | |
| + | |
| + // Write matrix to stdout | |
| + gsl_matrix_fprintf(stdout, Z, "%f"); | |
| + | |
| + // End program | |
| + gsl_matrix_free(Z); | |
| + return 0; | |
| +} | |
| diff --git a/iterate.c b/iterate.c | |
| t@@ -0,0 +1,35 @@ | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| + | |
| +// see https://www.gnu.org/software/gsl/manual/html_node/Matrices.html | |
| +#include <gsl/gsl_matrix.h> | |
| + | |
| +#include "wernerparams.h" | |
| +#include "werner.h" | |
| + | |
| + | |
| +int main(int argc, char** argv) | |
| +{ | |
| + // check if the user specified the number of times to iterate | |
| + int N_c = 1; // Number of cycles, default value | |
| + if (argc > 1) | |
| + N_c = atoi(argv[1]); | |
| + | |
| + // Allocate matrix Z: number of sand slabs | |
| + gsl_matrix* Z = gsl_matrix_alloc(rows, cols); | |
| + | |
| + // Read matrix from stdin | |
| + FILE* fp = fopen("tmp.mat", "r"); | |
| + gsl_matrix_fscanf(fp, Z); | |
| + //gsl_matrix_fscanf(stdin, Z); | |
| + | |
| + // Run N_c Werner iterations | |
| + werner_loop(Z, N_c, d_l, p_ns, p_s); | |
| + | |
| + // Print result to stdout | |
| + gsl_matrix_fprintf(stdout, Z, "%f"); | |
| + | |
| + // End program | |
| + gsl_matrix_free(Z); | |
| + return 0; | |
| +} | |
| diff --git a/out/plotmatrix.gp b/out/plotmatrix.gp | |
| t@@ -0,0 +1,20 @@ | |
| +#!/usr/env gnuplot | |
| + | |
| +# plot matrix file. Invoke with: | |
| +# $ gnuplot -e "matrixfile='file.txt'" plotmatrix.gp | |
| + | |
| +set terminal pngcairo | |
| +set output matrixfile.".png" | |
| + | |
| +set size ratio -1 | |
| + | |
| +set title "Werner model for aeolian transport and deposition" | |
| +set xlabel "x" | |
| +set ylabel "y" | |
| +set cblabel "sand slabs" | |
| + | |
| +# With interpolation | |
| +set pm3d map interpolate 0,0 | |
| +set palette gray | |
| +splot matrixfile matrix | |
| + | |
| diff --git a/printmat.c b/printmat.c | |
| t@@ -0,0 +1,26 @@ | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| + | |
| +// see https://www.gnu.org/software/gsl/manual/html_node/Matrices.html | |
| +#include <gsl/gsl_matrix.h> | |
| + | |
| +#include "wernerparams.h" | |
| +#include "werner.h" | |
| + | |
| + | |
| +int main(int argc, char** argv) | |
| +{ | |
| + | |
| + // Allocate matrix Z: number of sand slabs | |
| + gsl_matrix* Z = gsl_matrix_alloc(rows, cols); | |
| + | |
| + // Read matrix from stdin | |
| + gsl_matrix_fscanf(stdin, Z); | |
| + | |
| + // Print formatted result to stdout | |
| + print_matrix(Z); | |
| + | |
| + // End program | |
| + gsl_matrix_free(Z); | |
| + return 0; | |
| +} | |
| diff --git a/werner.c b/werner.c | |
| t@@ -0,0 +1,318 @@ | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| +#include <gsl/gsl_matrix.h> | |
| + | |
| +// Return a random number in [0;1[ | |
| +double rnd(void) | |
| +{ | |
| + return (double)rand()/RAND_MAX; | |
| +} | |
| + | |
| +// Initialize matrix M with random ints from low to high | |
| +void init_rnd_matrix(gsl_matrix* M, double low, double high) | |
| +{ | |
| + int row, col; | |
| + for (row = 0; row < M->size1; row++) | |
| + for (col = 0; col < M->size2; col++) | |
| + gsl_matrix_set(M, row, col, | |
| + (int)(rnd() * (high-low) + low)); | |
| +} | |
| + | |
| +// Write matrix to stdout | |
| +void print_matrix(gsl_matrix* M) | |
| +{ | |
| + int row, col; | |
| + double val; | |
| + for (row = 0; row < M->size1; row++) { | |
| + for (col = 0; col < M->size2; col++) { | |
| + val = gsl_matrix_get(M, row, col); | |
| + printf("%f\t", val); | |
| + } | |
| + puts(""); // newline | |
| + } | |
| +} | |
| + | |
| +// Add a slab of sand from the target cell | |
| +void deposit(gsl_matrix* Z, int row, int col) | |
| +{ | |
| + gsl_matrix_set(Z, row, col, gsl_matrix_get(Z, row, col) + 1.0); | |
| +} | |
| + | |
| +// Remove a slab of sand from the target cell | |
| +void erode(gsl_matrix* Z, int row, int col) | |
| +{ | |
| + gsl_matrix_set(Z, row, col, gsl_matrix_get(Z, row, col) - 1.0); | |
| +} | |
| + | |
| +// Find out if cell is in shade (1) or not (0) | |
| +int inshade( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + int row, // row idx of interest | |
| + int col) // col idx of interest | |
| +{ | |
| + int js; | |
| + int i = 1; | |
| + int shade = 0; | |
| + int nx = Z->size2; | |
| + | |
| + while ((i <= nx/4) && (shade == 0)) { | |
| + js = col - i; | |
| + if (js < 0) // periodic boundary | |
| + js += nx; | |
| + if (gsl_matrix_get(Z, row, js) >= gsl_matrix_get(Z, row, col) + i) | |
| + shade = 1; | |
| + i++; | |
| + } | |
| + return shade; | |
| +} | |
| + | |
| +void find_max_slope_neighbor_ero( | |
| + gsl_matrix* Z, // sand slab values | |
| + int row, // target row | |
| + int col, // target col | |
| + int* row_max, // max slope neighbor row | |
| + int* col_max, // max slope neighbor col | |
| + double* dh_max) // max slope | |
| +{ | |
| + | |
| + int n; // 1d neighbor idx | |
| + int i, j; // 2d neighbor idx | |
| + double dh; // slope | |
| + | |
| + // relative neighbor coordinates and distances | |
| + int drow[] = {1, 1, 1, 0, -1, -1, -1, 0}; | |
| + int dcol[] = {-1, 0, 1, 1, 1, 0, -1, -1}; | |
| + double dx[] = {1.4142, 1.0, 1.4142, 1.0, 1.4142, 1.0, 1.4142, 1.0}; | |
| + | |
| + // matrix dimensions | |
| + int nrows = Z->size1; | |
| + int ncols = Z->size2; | |
| + | |
| + // check the 8 surrounding neighbor cells | |
| + for (n = 0; n<8; n++) { | |
| + | |
| + // absolute neighbor cell idx | |
| + i = row + drow[n]; | |
| + j = col + dcol[n]; | |
| + | |
| + // correct for periodic boundaries | |
| + if (i < 0) | |
| + i += nrows; | |
| + if (i >= nrows) | |
| + i -= nrows; | |
| + if (j < 0) | |
| + j += ncols; | |
| + if (j >= ncols) | |
| + j -= ncols; | |
| + | |
| + // find slope | |
| + dh = (gsl_matrix_get(Z, i, j) - gsl_matrix_get(Z, row, col)) / dx[n]; | |
| + | |
| + // save position if it is the highest slope so far | |
| + if (dh > *dh_max) { | |
| + *dh_max = dh; | |
| + *row_max = i; | |
| + *col_max = j; | |
| + } | |
| + } | |
| +} | |
| + | |
| +void find_max_slope_neighbor_depo( | |
| + gsl_matrix* Z, // sand slab values | |
| + int row, // target row | |
| + int col, // target col | |
| + int* row_max, // max slope neighbor row | |
| + int* col_max, // max slope neighbor col | |
| + double* dh_max) // max slope | |
| +{ | |
| + | |
| + int n; // 1d neighbor idx | |
| + int i, j; // 2d neighbor idx | |
| + double dh; // slope | |
| + | |
| + // relative neighbor coordinates and distances | |
| + int drow[] = {1, 1, 1, 0, -1, -1, -1, 0}; | |
| + int dcol[] = {-1, 0, 1, 1, 1, 0, -1, -1}; | |
| + double dx[] = {1.4142, 1.0, 1.4142, 1.0, 1.4142, 1.0, 1.4142, 1.0}; | |
| + | |
| + // matrix dimensions | |
| + int nrows = Z->size1; | |
| + int ncols = Z->size2; | |
| + | |
| + // check the 8 surrounding neighbor cells | |
| + for (n = 0; n<8; n++) { | |
| + | |
| + // absolute neighbor cell idx | |
| + i = row + drow[n]; | |
| + j = col + dcol[n]; | |
| + | |
| + // correct for periodic boundaries | |
| + if (i < 0) | |
| + i += nrows; | |
| + if (i >= nrows) | |
| + i -= nrows; | |
| + if (j < 0) | |
| + j += ncols; | |
| + if (j >= ncols) | |
| + j -= ncols; | |
| + | |
| + // find slope | |
| + dh = (gsl_matrix_get(Z, row, col) - gsl_matrix_get(Z, i, j)) / dx[n]; | |
| + | |
| + // save position if it is the highest slope so far | |
| + if (dh > *dh_max) { | |
| + *dh_max = dh; | |
| + *row_max = i; | |
| + *col_max = j; | |
| + } | |
| + } | |
| + | |
| +} | |
| + | |
| + | |
| +// Check and perform avalanche into cell if slope exceeds limit | |
| +void avalanche_erosion( | |
| + gsl_matrix* Z, // sand slab values | |
| + int row, // target row | |
| + int col) // target col | |
| +{ | |
| + // find the neighbor with the max. height difference and the slope value | |
| + double dh_max = 0.0; // max slope | |
| + int row_max, col_max; | |
| + find_max_slope_neighbor_ero(Z, row, col, &row_max, &col_max, &dh_max); | |
| + | |
| + // Perform avalanche along max slope neighbor | |
| + double threshold = 2.0; // avalanche threshold | |
| + if (dh_max > threshold) { | |
| + deposit(Z, row, col); // put sand in target cell | |
| + erode(Z, row_max, col_max); // remove sand from max slope neighbor cell | |
| + | |
| + // Recursion | |
| + avalanche_erosion(Z, row, col); | |
| + } | |
| +} | |
| + | |
| +// Check and perform avalanche away from cell if slope exceeds limit | |
| +void avalanche_deposition( | |
| + gsl_matrix* Z, // sand slab values | |
| + int row, // target row | |
| + int col) // target col | |
| +{ | |
| + // find the neighbor with the max. height difference and the slope value | |
| + double dh_max = 0.0; // max slope | |
| + int row_max, col_max; | |
| + find_max_slope_neighbor_depo(Z, row, col, &row_max, &col_max, &dh_max); | |
| + | |
| + // Perform avalanche along max slope neighbor | |
| + double threshold = 2.0; // avalanche threshold | |
| + if (dh_max > threshold) { | |
| + erode(Z, row, col); | |
| + deposit(Z, row_max, col_max); | |
| + | |
| + // Recursion | |
| + avalanche_deposition(Z, row, col); | |
| + } | |
| +} | |
| + | |
| +// Move a sand unit and deposit it where it fits | |
| +void move_and_deposit( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + double p_ns, // likelihood of deposition in no-sand cell | |
| + double p_s, // likelihood of deposition in sand cell | |
| + double d_l, // transport distance in no. of cells | |
| + int* row, // current cell row | |
| + int* col, // current cell col | |
| + int* deposited) // deposited? 1=yes, 0=no | |
| +{ | |
| + // move sand slab in wind direction | |
| + *col += d_l; | |
| + int ncols = Z->size1; | |
| + if (*col >= ncols) | |
| + *col -= ncols; | |
| + | |
| + // is the target in the shade? | |
| + // 1=yes, 0=no | |
| + int shade = 0; | |
| + shade = inshade(Z, *row, *col); | |
| + if (shade > 0) { | |
| + deposit(Z, *row, *col); | |
| + avalanche_deposition(Z, *row, *col); // check for avalanches | |
| + *deposited = 1; // sand deposited, stop moving it | |
| + } | |
| + | |
| + // if not in the shade, check against deposition probabilities | |
| + else { | |
| + | |
| + // sand in cell | |
| + if (gsl_matrix_get(Z, *row, *col) > 0.) { | |
| + if (rnd() <= p_s) { // deposit in cell with sand | |
| + deposit(Z, *row, *col); | |
| + avalanche_deposition(Z, *row, *col); // check for avalanches | |
| + *deposited = 1; // sand deposited, stop moving it | |
| + } | |
| + } else { // no sand in cell | |
| + if (rnd() <= p_ns) { // deposit in cell without sand | |
| + deposit(Z, *row, *col); | |
| + avalanche_deposition(Z, *row, *col); // check for avalanches | |
| + *deposited = 1; // sand deposited, stop moving it | |
| + } | |
| + } | |
| + } | |
| +} | |
| + | |
| +// Perform a single Werner iteration | |
| +void werner_iter( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + int d_l, // wind transport distance | |
| + double p_ns, // likelihood of deposition in sand-free cell | |
| + double p_s) // likelihood of deposition in sand-covered cell | |
| +{ | |
| + // Evaluate N=nx*ny cells in random order | |
| + int row, col, deposited; | |
| + int nrows = Z->size1; // row major | |
| + int ncols = Z->size2; | |
| + long int n; | |
| + long int N = nrows*ncols; | |
| + double cellval; | |
| + | |
| + | |
| + // Perform cycle | |
| + for (n=0; n<N; n++) { | |
| + | |
| + // random cell idx | |
| + row = rand()%nrows; | |
| + col = rand()%ncols; | |
| + | |
| + // If the cell has sand in it (val>0), and is not in the shadow zone | |
| + cellval = gsl_matrix_get(Z, row, col); | |
| + if ((cellval > 0.) && (inshade(Z, row, col) == 0)) { | |
| + | |
| + // erode | |
| + erode(Z, row, col); | |
| + | |
| + // check for avalanche | |
| + avalanche_erosion(Z, row, col); | |
| + | |
| + // move eroded sand and deposit where it fits | |
| + deposited = 0; | |
| + while (deposited == 0) | |
| + move_and_deposit(Z, p_ns, p_s, d_l, &row, &col, &deposited); | |
| + | |
| + } | |
| + } | |
| +} | |
| + | |
| +// Loop system through time | |
| +void werner_loop( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + long int N_c, // number of iterations | |
| + int d_l, // wind transport distance | |
| + double p_ns, // likelihood of deposition in sand-free cell | |
| + double p_s) // likelihood of deposition in sand-covered cell | |
| +{ | |
| + long int t; | |
| + for (t = 0; t<N_c; t++) | |
| + werner_iter(Z, d_l, p_ns, p_s); | |
| +} | |
| + | |
| + | |
| diff --git a/werner.h b/werner.h | |
| t@@ -0,0 +1,23 @@ | |
| +#ifndef WERNER_H_ | |
| +#define WERNER_H_ | |
| + | |
| +#include <stdio.h> | |
| +#include <stdlib.h> | |
| +#include <gsl/gsl_matrix.h> | |
| + | |
| +void init_rnd_matrix(gsl_matrix* M, double low, double high); | |
| +void print_matrix(gsl_matrix* M); | |
| +void werner_iter( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + int d_l, // wind transport distance | |
| + double p_ns, // likelihood of deposition in sand-free cell | |
| + double p_s); // likelihood of deposition in sand-covered cell | |
| +void werner_loop( | |
| + gsl_matrix* Z, // matrix with sand slabs | |
| + long int N_c, // number of iterations | |
| + int d_l, // wind transport distance | |
| + double p_ns, // likelihood of deposition in sand-free cell | |
| + double p_s); // likelihood of deposition in sand-covered cell | |
| + | |
| + | |
| +#endif | |
| diff --git a/wernerparams.h b/wernerparams.h | |
| t@@ -0,0 +1,11 @@ | |
| +#ifndef WERNERPARAMS_H_ | |
| +#define WERNERPARAMS_H_ | |
| + | |
| +// set simulation parameters | |
| +const int rows = 400; | |
| +const int cols = 400; | |
| +const int d_l = 5; // wind transport distance (left to right) | |
| +const double p_ns = 0.4; // likelihood of deposition in sand free cells | |
| +const double p_s = 0.6; // likelihood of deposition in sand covered cells | |
| + | |
| +#endif |