tOnly allow short options, rework option parsing, global sim - cngf-pf - continuum model for granular flows with pore-pressure dynamics (renamed from 1d_fd_simple_shear)
 (HTM) git clone git://src.adamsgaard.dk/cngf-pf
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit acf33cd7db63d47c5a7ebbba9a568371ca3fe34f
 (DIR) parent dc46674d016883f15b65d5d0150429d1b142eebe
 (HTM) Author: Anders Damsgaard <anders@adamsgaard.dk>
       Date:   Thu,  5 Mar 2020 16:33:41 +0100
       
       Only allow short options, rework option parsing, global sim
       
       Diffstat:
         M 1d_fd_simple_shear.c                |     474 +++++++++++--------------------
         M Makefile                            |      15 +--------------
         A arg.h                               |      38 +++++++++++++++++++++++++++++++
         M fluid.c                             |     151 +++++++++++++++----------------
         M fluid.h                             |       7 ++++---
         M max_depth_simple_shear.c            |     213 +++++++++++--------------------
         M parameter_defaults.h                |      11 ++++++-----
         M simulation.c                        |     432 ++++++++++++++++---------------
         M simulation.h                        |      38 ++++++++++++++++++-------------
       
       9 files changed, 606 insertions(+), 773 deletions(-)
       ---
 (DIR) diff --git a/1d_fd_simple_shear.c b/1d_fd_simple_shear.c
       t@@ -2,14 +2,12 @@
        #include <stdio.h>
        #include <stdlib.h>
        #include <math.h>
       -#include <getopt.h>
        #include <string.h>
        #include <time.h>
        
        #include "simulation.h"
        #include "fluid.h"
       -
       -#define PROGNAME "1d_fd_simple_shear"
       +#include "arg.h"
        
        #include "parameter_defaults.h"
        
       t@@ -28,119 +26,34 @@
        /* uncomment to print time spent per time step to stdout */
        /*#define BENCHMARK_PERFORMANCE*/
        
       -static void
       -usage(void)
       -{
       -        struct simulation sim = init_sim();
       -        printf("%s: %s [OPTIONS] [NAME]\n"
       -                "runs a simulation and outputs state in files prefixed with NAME.\n"
       -                "If NAME is not specified, intermediate output files are not written.\n"
       -                "\nOptional arguments:\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] (default %g)\n"
       -                " -P, --normal-stress VAL         normal stress on top [Pa] (default %g)\n"
       -                " -m, --stress-ratio VAL          applied stress ratio [-] (default %g)\n"
       -                " -s, --set-shear-velocity VAL    set top shear velocity to this value [m/s]\n"
       -                "                                 (default %g), overrides --stress-ratio\n"
       -                " -l, --limit-shear-velocity VAL  limit top shear velocity to this value [m/s]\n"
       -                "                                 (default %g), overrides --stress-ratio and\n"
       -                "                                 --set-shear-velocity\n"
       -                " -V, --velocity-bottom VAL       base velocity at bottom [m/s] (default %g)\n"
       -                " -A, --nonlocal-amplitude VAL    amplitude of nonlocality [-] (default %g)\n"
       -                " -b, --rate-dependence VAL       rate dependence beyond yield [-] (default %g)\n"
       -                " -f, --friction-coefficient VAL  grain friction coefficient [-] (default %g)\n"
       -                " -C, --cohesion VAL              grain cohesion [Pa] (default %g)\n"
       -                " -p, --porosity VAL              porosity fraction [-] (default %g)\n"
       -                " -d, --grain-size VAL            representative grain size [m] (default %g)\n"
       -                " -r, --density VAL               grain material density [kg/m^3] (default %g)\n"
       -                " -n, --resolution VAL            number of cells in domain [-]\n"
       -                "                                 (default cell size equals grain size)\n"
       -                " -o, --origo VAL                 coordinate system origo [m] (default %g)\n"
       -                " -L, --length VAL                domain length [m] (default %g)\n"
       -                "\nOptional arguments only relevant with transient (fluid) simulation:\n"
       -                " -F, --fluid                     enable pore fluid computations\n"
       -                " -c, --fluid-compressibility VAL fluid compressibility [Pa^-1] (default %g)\n"
       -                " -i, --fluid-viscosity VAL       fluid viscosity [Pa*s] (default %g)\n"
       -                " -R, --fluid-density VAL         fluid density [kg/m^3] (default %g)\n"
       -                " -k, --fluid-permeability VAL    fluid intrinsic permeability [m^2] (default %g)\n"
       -                " -O, --fluid-pressure-top VAL    fluid pressure at +z edge [Pa] (default %g)\n"
       -                " -a, --fluid-pressure-ampl VAL   amplitude of pressure variations [Pa] (default %g)\n"
       -                " -q, --fluid-pressure-freq VAL   frequency of sinusoidal pressure variations [s^-1]\n"
       -                "                                 (default %g)\n"
       -                " -H, --fluid-pressure-phase VAL  fluid pressure at +z edge [Pa] (default %g)\n"
       -                " -u, --fluid-pressure-pulse-time VAL fluid pressure pulse peak time [s]\n"
       -                "                                 (default %g)\n"
       -                " -S, --fluid-pressure-pulse-shape VAL\n"
       -                "                                 where VAL is triangular (default) or square\n"
       -                " -t, --time VAL                  simulation start time [s] (default %g)\n"
       -                " -T, --time-end VAL              simulation end time [s] (default %g)\n"
       -                " -I, --file-interval VAL         interval between output files [s] (default %g)\n"
       -                "\n"
       -                "The output (stdout or output files) consists of the following "
       -                "tab-delimited\nfields, with one row per cell:\n"
       -                "   1. z_position [m]\n"
       -                "   2. x_velocity [m/s]\n"
       -                "   3. normal_stress [Pa]\n"
       -                "   4. friction [-]\n"
       -                "   5. strain_rate [1/s]\n\n"
       -                "With --fluid enabled:\n"
       -                "   1. z_position [m]\n"
       -                "   2. x_velocity [m/s]\n"
       -                "   3. effective_normal_stress [Pa]\n"
       -                "   4. fluid_pressure [Pa]\n"
       -                "   5. friction [-]\n"
       -                "   6. strain_rate [1/s]\n"
       -                ,
       -                __func__, PROGNAME,
       -                sim.G,
       -                sim.P_wall,
       -                sim.mu_wall,
       -                sim.v_x_fix,
       -                sim.v_x_limit,
       -                sim.v_x_bot,
       -                sim.A,
       -                sim.b,
       -                sim.mu_s,
       -                sim.C,
       -                sim.phi[0],
       -                sim.d,
       -                sim.rho_s,
       -                sim.origo_z,
       -                sim.L_z,
       -                sim.beta_f,
       -                sim.mu_f,
       -                sim.rho_f,
       -                sim.k[0],
       -                sim.p_f_top,
       -                sim.p_f_mod_ampl,
       -                sim.p_f_mod_freq,
       -                sim.p_f_mod_phase,
       -                sim.p_f_mod_pulse_time,
       -                sim.t,
       -                sim.t_end,
       -                sim.file_dt);
       -        free(sim.phi);
       -        free(sim.k);
       -}
       +char *argv0;
       +struct simulation sim;
        
        static void
       -version(void)
       +usage(void)
        {
       -        printf("%s v%s\n"
       -        "Licensed under the ISC License, see LICENSE for details.\n"
       -        "written by Anders Damsgaard, anders@adamsgaard.dk\n"
       -        "https://src.adamsgaard.dk/1d_fd_simple_shear\n"
       -        , PROGNAME, VERSION);
       +        dprintf(2, "usage: %s [-FNThnv] "
       +                "[-g gravity-accel] [-d grain-size] [-r grain-density] "
       +                "[-m grain-friction] [-c grain-cohesion] "
       +                "[-A grain-nonlocal-ampl] [-b grain-rate-dependance] "
       +                "[-p grain-porosity] [-y min-porosity] [-Y max-porosity] "
       +                "[-K dilatancy-constant] "
       +                "[-n normal-stress] [-f applied-shear-friction] "
       +                "[-s applied-shear-vel] [-l applied-shear-vel-limit] "
       +                "[-o origo] [-L length] [-U resolution] "
       +                "[-t curr-time] [-e end-time] [-I file-interval] "
       +                "[-O fluid-pressure-top] [-a fluid-pressure-ampl] "
       +                "[-q fluid-pressure-freq] [-H fluid-pressure-phase] "
       +                "[-S fluid-pressure-pulse-shape] [-u fluid-pulse-time] "
       +                "[-k fluid-permeability] [-R fluid-density] [-i fluid-viscosity] "
       +                "[-C fluid-compressibility] [name]\n", argv0);
       +        exit(1);
        }
        
        int
        main(int argc, char* argv[])
        {
       -        int norm, opt, i;
       -        struct simulation sim;
       -        const char* optstring;
       +        int i, normalize;
                unsigned long iter, stressiter;
                double new_phi, new_k, filetimeclock, res_norm, mu_wall_orig;
        #ifdef BENCHMARK_PERFORMANCE
       t@@ -150,193 +63,154 @@ main(int argc, char* argv[])
        
        #ifdef __OpenBSD__
                if (pledge("stdio wpath cpath", NULL) == -1) {
       -                fprintf(stderr, "error: pledge failed");
       +                dprintf(2, "error: pledge failed");
                        exit(1);
                }
        #endif
        
       -        /* load with default values */
       -        sim = init_sim();
       -
       -        norm = 0;
       -
       -        optstring = "hvNn:G:P:m:s:l:V:A:b:f:C:Fp:d:r:o:L:c:i:R:k:O:a:q:H:T:S:t:T:D:I:";
       -        const struct option longopts[] = {
       -                {"help",                      no_argument,       NULL, 'h'},
       -                {"version",                   no_argument,       NULL, 'v'},
       -                {"normalize",                 no_argument,       NULL, 'N'},
       -                {"gravity",                   required_argument, NULL, 'G'},
       -                {"normal-stress",             required_argument, NULL, 'P'},
       -                {"stress-ratio",              required_argument, NULL, 'm'},
       -                {"set-shear-velocity",        required_argument, NULL, 's'},
       -                {"limit-shear-velocity",      required_argument, NULL, 'l'},
       -                {"velocity-bottom",           required_argument, NULL, 'V'},
       -                {"nonlocal-amplitude",        required_argument, NULL, 'A'},
       -                {"rate-dependence",           required_argument, NULL, 'b'},
       -                {"friction-coefficient",      required_argument, NULL, 'f'},
       -                {"cohesion",                  required_argument, NULL, 'C'},
       -                {"porosity",                  required_argument, NULL, 'p'},
       -                {"grain-size",                required_argument, NULL, 'd'},
       -                {"density",                   required_argument, NULL, 'r'},
       -                {"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'},
       -                {"fluid-pressure-pulse-time", required_argument, NULL, 'u'},
       -                {"fluid-pressure-pulse-shape",required_argument, NULL, 'S'},
       -                {"time",                      required_argument, NULL, 't'},
       -                {"time-end",                  required_argument, NULL, 'T'},
       -                {"file-interval",             required_argument, NULL, 'I'},
       -                {NULL,                        0,                 NULL, 0}
       -        };
       +        atexit(free_arrays);
        
       +        init_sim();
       +        normalize = 0;
                new_phi = sim.phi[0];
                new_k = sim.k[0];
       -        while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) {
       -                switch (opt) {
       -                        case -1:   /* no more arguments */
       -                        case 0:    /* long options toggles */
       -                                break;
       -
       -                        case 'h':
       -                                usage();
       -                                free(sim.phi);
       -                                free(sim.k);
       -                                return 0;
       -                        case 'v':
       -                                version();
       -                                free(sim.phi);
       -                                free(sim.k);
       -                                return 0;
       -                        case 'n':
       -                                sim.nz = atoi(optarg);
       -                                break;
       -                        case 'N':
       -                                norm = 1;
       -                                break;
       -                        case 'G':
       -                                sim.G = atof(optarg);
       -                                break;
       -                        case 'P':
       -                                sim.P_wall = atof(optarg);
       -                                break;
       -                        case 'm':
       -                                sim.mu_wall = atof(optarg);
       -                                break;
       -                        case 's':
       -                                sim.v_x_fix = atof(optarg);
       -                                break;
       -                        case 'l':
       -                                sim.v_x_limit = atof(optarg);
       -                                break;
       -                        case 'V':
       -                                sim.v_x_bot = atof(optarg);
       -                                break;
       -                        case 'A':
       -                                sim.A = atof(optarg);
       -                                break;
       -                        case 'b':
       -                                sim.b = atof(optarg);
       -                                break;
       -                        case 'f':
       -                                sim.mu_s = atof(optarg);
       -                                break;
       -                        case 'C':
       -                                sim.C = atof(optarg);
       -                                break;
       -                        case 'p':
       -                                new_phi = atof(optarg);
       -                                break;
       -                        case 'd':
       -                                sim.d = atof(optarg);
       -                                break;
       -                        case 'r':
       -                                sim.rho_s = atof(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 'u':
       -                                sim.p_f_mod_pulse_time = atof(optarg);
       -                                break;
       -                        case 'S':
       -                                if (strcmp(optarg, "triangle") == 0)
       -                                        sim.p_f_mod_pulse_shape = 0;
       -                                else if (strcmp(optarg, "square") == 0)
       -                                        sim.p_f_mod_pulse_shape = 1;
       -                                else {
       -                                        fprintf(stderr, "error: invalid pulse shape '%s'\n",
       -                                                optarg);
       -                                        return 1;
       -                                }
       -                                break;
       -                        case 't':
       -                                sim.t = atof(optarg);
       -                                break;
       -                        case 'T':
       -                                sim.t_end = atof(optarg);
       -                                break;
       -                        case 'I':
       -                                sim.file_dt = atof(optarg);
       -                                break;
       -                        default:
       -                                fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);
       -                                fprintf(stderr, "Try `%s --help` for more information\n",
       -                                        argv[0]);
       -                                return -2;
       -                }
       -        }
       -        for (i=optind; i<argc; ++i) {
       -                if (i>optind) {
       -                        fprintf(stderr,
       -                                "error: more than one simulation name specified\n");
       +
       +        ARGBEGIN {
       +        case 'A':
       +                sim.A = atof(EARGF(usage()));
       +                break;
       +        case 'C':
       +                sim.beta_f = atof(EARGF(usage()));
       +                break;
       +        case 'F':
       +                sim.fluid = 1;
       +                break;
       +        case 'H':
       +                sim.p_f_mod_phase = atof(EARGF(usage()));
       +                break;
       +        case 'I':
       +                sim.file_dt = atof(EARGF(usage()));
       +                break;
       +        case 'K':
       +                sim.dilatancy_angle = atof(EARGF(usage()));
       +                break;
       +        case 'L':
       +                sim.L_z = atof(EARGF(usage()));
       +                break;
       +        case 'N':
       +                normalize = 1;
       +                break;
       +        case 'O':
       +                sim.p_f_top = atof(EARGF(usage()));
       +                break;
       +        case 'R':
       +                sim.rho_f = atof(EARGF(usage()));
       +                break;
       +        case 'S':
       +                if (argv[1] == NULL)
       +                        usage();
       +                else if (!strncmp(argv[1], "triangle", 8))
       +                        sim.p_f_mod_pulse_shape = 0;
       +                else if (!strncmp(argv[1], "square", 6))
       +                        sim.p_f_mod_pulse_shape = 1;
       +                else {
       +                        dprintf(2, "error: invalid pulse shape '%s'\n",
       +                                argv[1]);
                                return 1;
                        }
       -                snprintf(sim.name, sizeof(sim.name), "%s", argv[i]);
       -        }
       +                argv++;
       +                break;
       +        case 'T':
       +                sim.transient = 1;
       +                break;
       +        case 'U':
       +                sim.nz = atoi(EARGF(usage()));
       +                break;
       +        case 'V':
       +                sim.v_x_bot = atof(EARGF(usage()));
       +                break;
       +        case 'Y':
       +                sim.phi_max = atof(EARGF(usage()));
       +                break;
       +        case 'a':
       +                sim.p_f_mod_ampl = atof(EARGF(usage()));
       +                break;
       +        case 'b':
       +                sim.b = atof(EARGF(usage()));
       +                break;
       +        case 'c':
       +                sim.C = atof(EARGF(usage()));
       +                break;
       +        case 'd':
       +                sim.d = atof(EARGF(usage()));
       +                break;
       +        case 'e':
       +                sim.t_end = atof(EARGF(usage()));
       +                break;
       +        case 'f':
       +                sim.mu_wall = atof(EARGF(usage()));
       +                break;
       +        case 'g':
       +                sim.G = atof(EARGF(usage()));
       +                break;
       +        case 'h':
       +                usage();
       +                break;
       +        case 'i':
       +                sim.mu_f = atof(EARGF(usage()));
       +                break;
       +        case 'k':
       +                new_k = atof(EARGF(usage()));
       +                break;
       +        case 'l':
       +                sim.v_x_limit = atof(EARGF(usage()));
       +                break;
       +        case 'm':
       +                sim.mu_s = atof(EARGF(usage()));
       +                break;
       +        case 'n':
       +                sim.P_wall = atof(EARGF(usage()));
       +                break;
       +        case 'o':
       +                sim.origo_z = atof(EARGF(usage()));
       +                break;
       +        case 'p':
       +                new_phi = atof(EARGF(usage()));
       +                break;
       +        case 'q':
       +                sim.p_f_mod_freq = atof(EARGF(usage()));
       +                break;
       +        case 'r':
       +                sim.rho_s = atof(EARGF(usage()));
       +                break;
       +        case 's':
       +                sim.v_x_fix = atof(EARGF(usage()));
       +                break;
       +        case 't':
       +                sim.t = atof(EARGF(usage()));
       +                break;
       +        case 'u':
       +                sim.p_f_mod_pulse_time = atof(EARGF(usage()));
       +                break;
       +        case 'v':
       +                printf("%s-"VERSION"\n", argv0);
       +                return 0;
       +        case 'y':
       +                sim.phi_min = atof(EARGF(usage()));
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc == 1 && argv[1])
       +                snprintf(sim.name, sizeof(sim.name), "%s", argv[1]);
       +        else if (argc > 1)
       +                usage();
        
                if (sim.nz < 1)
                        sim.nz = (int)ceil(sim.L_z/sim.d);
        
       -        prepare_arrays(&sim);
       +        prepare_arrays();
        
                if (!isnan(new_phi))
                        for (i=0; i<sim.nz; ++i)
       t@@ -345,14 +219,14 @@ main(int argc, char* argv[])
                        for (i=0; i<sim.nz; ++i)
                                sim.k[i] = new_k;
        
       -        lithostatic_pressure_distribution(&sim);
       +        lithostatic_pressure_distribution();
        
                if (sim.fluid) {
       -                hydrostatic_fluid_pressure_distribution(&sim);
       -                set_largest_fluid_timestep(&sim, 0.5);
       +                hydrostatic_fluid_pressure_distribution();
       +                set_largest_fluid_timestep(0.5);
                }
        
       -        check_simulation_parameters(&sim);
       +        check_simulation_parameters();
        
                filetimeclock = 0.0;
                iter = 0;
       t@@ -367,20 +241,20 @@ main(int argc, char* argv[])
                        stressiter = 0;
                        do {
                                if (sim.fluid) {
       -                                if (darcy_solver_1d(&sim, MAX_ITER_DARCY, RTOL_DARCY))
       +                                if (darcy_solver_1d(MAX_ITER_DARCY, RTOL_DARCY))
                                                exit(1);
                                }
        
       -                        compute_effective_stress(&sim);
       -                        compute_friction(&sim);
       -                        compute_cooperativity_length(&sim);
       +                        compute_effective_stress();
       +                        compute_friction();
       +                        compute_cooperativity_length();
        
       -                        if (implicit_1d_jacobian_poisson_solver(&sim, MAX_ITER_GRANULAR,
       +                        if (implicit_1d_jacobian_poisson_solver(MAX_ITER_GRANULAR,
                                                                        RTOL_GRANULAR))
                                        exit(1);
        
       -                        compute_shear_strain_rate_plastic(&sim);
       -                        compute_shear_velocity(&sim);
       +                        compute_shear_strain_rate_plastic();
       +                        compute_shear_velocity();
        
                                if (!isnan(sim.v_x_limit) || !isnan(sim.v_x_fix)) {
                                        if (!isnan(sim.v_x_limit)) {
       t@@ -396,13 +270,11 @@ main(int argc, char* argv[])
                                }
        
                                if (++stressiter > MAX_ITER_STRESS) {
       -                                fprintf(stderr, "error: stress solution did not converge:\n");
       -                                fprintf(stderr,
       -                                        "v_x=%g, v_x_fix=%g, v_x_limit=%g, "
       +                                dprintf(2, "error: stress solution did not converge:\n");
       +                                dprintf(2, "v_x=%g, v_x_fix=%g, v_x_limit=%g, "
                                                "res_norm=%g, mu_wall=%g\n",
                                                sim.v_x[sim.nz-1], sim.v_x_fix, sim.v_x_limit,
                                                res_norm, sim.mu_wall);
       -                                free_arrays(&sim);
                                        return 10;
                                }
        
       t@@ -423,18 +295,14 @@ main(int argc, char* argv[])
        
                        if ((filetimeclock - sim.dt >= sim.file_dt || iter == 1) &&
                            strcmp(sim.name, DEFAULT_SIMULATION_NAME) != 0) {
       -                        write_output_file(&sim, norm);
       +                        write_output_file(normalize);
                                filetimeclock = 0.0;
                                if (iter == 1)
                                        sim.t = 0.0;
                        }
                }
        
       -        if (sim.fluid)
       -                print_wet_output(stdout, &sim, norm);
       -        else
       -                print_dry_output(stdout, &sim, norm);
       +        print_output(stdout, normalize);
        
       -        free_arrays(&sim);
                return 0;
        }
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -7,7 +7,7 @@ PREFIX ?= /usr/local
        INSTALL ?= install
        STRIP ?= strip
        
       -VERSION = 0.4.6
       +VERSION = 0.5.0
        GLOBALCONST = -DVERSION=\"${VERSION}\"
        
        default: ${BIN}
       t@@ -32,22 +32,9 @@ install: ${BIN}
        uninstall:
                rm -f ${DESTDIR}${PREFIX}/bin/${BIN}
        
       -watch:
       -        echo ${SRC} ${HDR} | tr ' ' '\n' | entr -s 'make && ./1d_fd_simple_shear'
       -
        test: ${BIN}
                make -C test/
        
       -memtest: 1d_fd_simple_shear
       -        valgrind --error-exitcode=1 --leak-check=full 1d_fd_simple_shear -h
       -        valgrind --error-exitcode=1 --leak-check=full 1d_fd_simple_shear
       -        valgrind --error-exitcode=1 --leak-check=full 1d_fd_simple_shear -F
       -        valgrind --error-exitcode=1 --leak-check=full 1d_fd_simple_shear -F \
       -                --fluid-pressure-top 50e3 \
       -                --fluid-pressure-ampl 50e3 \
       -                --fluid-pressure-freq $(echo "1/3600" | bc -l) \
       -                --time-end 3600
       -
        clean:
                rm -f *.txt
                rm -f *.o
 (DIR) diff --git a/arg.h b/arg.h
       t@@ -0,0 +1,38 @@
       +/* by 20h */
       +#ifndef ARG_H
       +#define ARG_H
       +
       +#define USED(x) ((void)(x))
       +
       +extern char *argv0;
       +
       +#define ARGBEGIN        for(argv0 = *argv, argv++, argc--;\
       +                                        argv[0] && argv[0][0] == '-'\
       +                                        && argv[0][1];\
       +                                        argc--, argv++) {\
       +                                char _argc;\
       +                                char **_argv;\
       +                                if(argv[0][1] == '-' && argv[0][2] == '\0') {\
       +                                        argv++;\
       +                                        argc--;\
       +                                        break;\
       +                                }\
       +                                int i_;\
       +                                for(i_ = 1, _argv = argv; argv[0][i_];\
       +                                                i_++) {\
       +                                        if(_argv != argv)\
       +                                                break;\
       +                                        _argc = argv[0][i_];\
       +                                        switch(_argc)
       +
       +#define ARGEND                        }\
       +                                USED(_argc);\
       +                        }\
       +                        USED(argv);\
       +                        USED(argc);
       +
       +#define        EARGF(x)        ((argv[1] == NULL)? ((x), abort(), (char *)0) :\
       +                        (argc--, argv++, argv[0]))
       +
       +#endif
       +
 (DIR) diff --git a/fluid.c b/fluid.c
       t@@ -6,13 +6,13 @@
        /* #define DEBUG true */
        
        void
       -hydrostatic_fluid_pressure_distribution(struct simulation* sim)
       +hydrostatic_fluid_pressure_distribution()
        {
                int i;
       -        for (i=0; i<sim->nz; ++i)
       -                sim->p_f_ghost[i+1] = sim->p_f_top +
       -                                      sim->phi[i]*sim->rho_f*sim->G*
       -                                      (sim->L_z - sim->z[i]);
       +        for (i=0; i<sim.nz; ++i)
       +                sim.p_f_ghost[i+1] = sim.p_f_top +
       +                                      sim.phi[i]*sim.rho_f*sim.G*
       +                                      (sim.L_z - sim.z[i]);
        }
        
        /* Determines the largest time step for the current simulation state. Note 
       t@@ -20,15 +20,15 @@ hydrostatic_fluid_pressure_distribution(struct simulation* sim)
         * (i.e., permeabilities, porosities, viscosities, or compressibilities)
         * change. The safety factor should be in ]0;1] */
        void
       -set_largest_fluid_timestep(struct simulation* sim, const double safety)
       +set_largest_fluid_timestep(const double safety)
        {
                int i;
                double dx_min, diff, diff_max;
                double *dx;
        
       -        dx = spacing(sim->z, sim->nz);
       +        dx = spacing(sim.z, sim.nz);
                dx_min = INFINITY;
       -        for (i=0; i<sim->nz-1; ++i) {
       +        for (i=0; i<sim.nz-1; ++i) {
                        if (dx[i] < 0.0) {
                                fprintf(stderr, "error: cell spacing negative (%g) in cell %d\n",
                                                dx[i], i);
       t@@ -40,14 +40,14 @@ set_largest_fluid_timestep(struct simulation* sim, const double safety)
                free(dx);
        
                diff_max = -INFINITY;
       -        for (i=0; i<sim->nz; ++i) {
       -                diff = sim->k[i]/(sim->phi[i]*sim->beta_f*sim->mu_f);
       +        for (i=0; i<sim.nz; ++i) {
       +                diff = sim.k[i]/(sim.phi[i]*sim.beta_f*sim.mu_f);
                        if (diff > diff_max) diff_max = diff;
                }
        
       -        sim->dt = safety*0.5*dx_min*dx_min/diff_max;
       -        if (sim->file_dt*0.5 < sim->dt)
       -                sim->dt = sim->file_dt;
       +        sim.dt = safety*0.5*dx_min*dx_min/diff_max;
       +        if (sim.file_dt*0.5 < sim.dt)
       +                sim.dt = sim.file_dt;
        }
        
        static double
       t@@ -87,15 +87,15 @@ square_pulse(const double time,
        }
        
        static void
       -set_fluid_bcs(struct simulation* sim, const double p_f_top)
       +set_fluid_bcs(const double p_f_top)
        {
       -        set_bc_dirichlet(sim->p_f_ghost, sim->nz, +1, p_f_top);
       -        sim->p_f_ghost[sim->nz] = p_f_top; /* Include top node in BC */
       -        set_bc_neumann(sim->p_f_ghost,
       -                       sim->nz,
       +        set_bc_dirichlet(sim.p_f_ghost, sim.nz, +1, p_f_top);
       +        sim.p_f_ghost[sim.nz] = p_f_top; /* Include top node in BC */
       +        set_bc_neumann(sim.p_f_ghost,
       +                       sim.nz,
                               -1,
       -                       sim->phi[0]*sim->rho_f*sim->G,
       -                       sim->dz);
       +                       sim.phi[0]*sim.rho_f*sim.G,
       +                       sim.dz);
        }
        
        static double
       t@@ -169,8 +169,7 @@ darcy_pressure_change_1d(double* dp_f_dt,
        }*/
        
        int
       -darcy_solver_1d(struct simulation* sim,
       -                const int max_iter,
       +darcy_solver_1d(const int max_iter,
                        const double rel_tol)
        {
                int i, iter, solved;
       t@@ -193,99 +192,99 @@ darcy_solver_1d(struct simulation* sim,
                /* TODO: values other than 1.0 do not work! */
                theta = 1.0;
        
       -        if (isnan(sim->p_f_mod_pulse_time))
       -                p_f_top = sim->p_f_top + sine_wave(sim->t,
       -                                                   sim->p_f_mod_ampl,
       -                                                   sim->p_f_mod_freq,
       -                                                   sim->p_f_mod_phase);
       +        if (isnan(sim.p_f_mod_pulse_time))
       +                p_f_top = sim.p_f_top + sine_wave(sim.t,
       +                                                   sim.p_f_mod_ampl,
       +                                                   sim.p_f_mod_freq,
       +                                                   sim.p_f_mod_phase);
                else
       -                if (sim->p_f_mod_pulse_shape == 1)
       -                        p_f_top = sim->p_f_top + square_pulse(sim->t,
       -                                                              sim->p_f_mod_ampl,
       -                                                              sim->p_f_mod_freq,
       -                                                              sim->p_f_mod_pulse_time);
       +                if (sim.p_f_mod_pulse_shape == 1)
       +                        p_f_top = sim.p_f_top + square_pulse(sim.t,
       +                                                              sim.p_f_mod_ampl,
       +                                                              sim.p_f_mod_freq,
       +                                                              sim.p_f_mod_pulse_time);
                        else
       -                        p_f_top = sim->p_f_top + triangular_pulse(sim->t,
       -                                                                  sim->p_f_mod_ampl,
       -                                                                  sim->p_f_mod_freq,
       -                                                                  sim->p_f_mod_pulse_time);
       +                        p_f_top = sim.p_f_top + triangular_pulse(sim.t,
       +                                                                  sim.p_f_mod_ampl,
       +                                                                  sim.p_f_mod_freq,
       +                                                                  sim.p_f_mod_pulse_time);
        
                /* set fluid BCs (1 of 2) */
       -        set_fluid_bcs(sim, p_f_top);
       +        set_fluid_bcs(p_f_top);
        
                solved = 0;
        
                if (epsilon < 1.0) {
                        /* compute explicit solution to pressure change */
       -                dp_f_dt_expl = zeros(sim->nz);
       -                for (i=0; i<sim->nz; ++i)
       +                dp_f_dt_expl = zeros(sim.nz);
       +                for (i=0; i<sim.nz; ++i)
                                dp_f_dt_expl[i] = darcy_pressure_change_1d(i,
       -                                                                   sim->nz,
       -                                                                   sim->p_f_ghost,
       -                                                                   sim->phi,
       -                                                                   sim->k,
       -                                                                   sim->dz,
       -                                                                   sim->beta_f,
       -                                                                   sim->mu_f);
       +                                                                   sim.nz,
       +                                                                   sim.p_f_ghost,
       +                                                                   sim.phi,
       +                                                                   sim.k,
       +                                                                   sim.dz,
       +                                                                   sim.beta_f,
       +                                                                   sim.mu_f);
                }
        
                if (epsilon > 0.0) {
                        /* compute implicit solution with Jacobian iterations */
       -                dp_f_dt_impl = zeros(sim->nz);
       -                p_f_ghost_new = zeros(sim->nz+2);
       -                r_norm = zeros(sim->nz);
       -                p_f_ghost_old = empty(sim->nz+2);
       -                copy_values(sim->p_f_ghost, p_f_ghost_old, sim->nz+2);
       +                dp_f_dt_impl = zeros(sim.nz);
       +                p_f_ghost_new = zeros(sim.nz+2);
       +                r_norm = zeros(sim.nz);
       +                p_f_ghost_old = empty(sim.nz+2);
       +                copy_values(sim.p_f_ghost, p_f_ghost_old, sim.nz+2);
        
                        for (iter=0; iter<max_iter; ++iter) {
        
                                /* set fluid BCs (2 of 2) */
       -                        set_fluid_bcs(sim, p_f_top);
       +                        set_fluid_bcs( p_f_top);
        #ifdef DEBUG
                                puts(".. p_f_ghost after BC:");
       -                        print_array(sim->p_f_ghost, sim->nz+2);
       +                        print_array(sim.p_f_ghost, sim.nz+2);
        #endif
        
       -                        for (i=0; i<sim->nz-1; ++i)
       +                        for (i=0; i<sim.nz-1; ++i)
                                        dp_f_dt_impl[i] = darcy_pressure_change_1d(i,
       -                                                                           sim->nz,
       -                                                                           sim->p_f_ghost,
       -                                                                           sim->phi,
       -                                                                           sim->k,
       -                                                                           sim->dz,
       -                                                                           sim->beta_f,
       -                                                                           sim->mu_f);
       -
       -                        for (i=0; i<sim->nz-1; ++i) {
       +                                                                           sim.nz,
       +                                                                           sim.p_f_ghost,
       +                                                                           sim.phi,
       +                                                                           sim.k,
       +                                                                           sim.dz,
       +                                                                           sim.beta_f,
       +                                                                           sim.mu_f);
       +
       +                        for (i=0; i<sim.nz-1; ++i) {
        #ifdef DEBUG
                                        printf("dp_f_expl[%d] = %g\ndp_f_impl[%d] = %g\n",
                                               i, dp_f_dt_expl[i], i, dp_f_dt_impl[i]);
        #endif
        
                                        p_f_ghost_new[i+1] = p_f_ghost_old[i+1]
       -                                                          + epsilon*dp_f_dt_impl[i]*sim->dt;
       +                                                          + epsilon*dp_f_dt_impl[i]*sim.dt;
        
                                        if (epsilon < 1.0)
                                                p_f_ghost_new[i+1] += (1.0 - epsilon)
       -                                                                   *dp_f_dt_expl[i]*sim->dt;
       +                                                                   *dp_f_dt_expl[i]*sim.dt;
        
                                        p_f_ghost_new[i+1] = p_f_ghost_old[i+1]*(1.0 - theta)
                                                                  + p_f_ghost_new[i+1]*theta;
        
       -                                r_norm[i] = fabs((p_f_ghost_new[i+1] - sim->p_f_ghost[i+1])
       -                                            /(sim->p_f_ghost[i+1] + 1e-16));
       +                                r_norm[i] = fabs((p_f_ghost_new[i+1] - sim.p_f_ghost[i+1])
       +                                            /(sim.p_f_ghost[i+1] + 1e-16));
                                }
        
       -                        r_norm_max = max(r_norm, sim->nz);
       +                        r_norm_max = max(r_norm, sim.nz);
        #ifdef DEBUG
                                puts(".. p_f_ghost_new:");
       -                        print_array(p_f_ghost_new, sim->nz+2);
       +                        print_array(p_f_ghost_new, sim.nz+2);
        #endif
        
       -                        copy_values(p_f_ghost_new, sim->p_f_ghost, sim->nz+2);
       +                        copy_values(p_f_ghost_new, sim.p_f_ghost, sim.nz+2);
        #ifdef DEBUG
                                puts(".. p_f_ghost after update:");
       -                        print_array(sim->p_f_ghost, sim->nz+2);
       +                        print_array(sim.p_f_ghost, sim.nz+2);
        #endif
        
                                if (r_norm_max <= rel_tol) {
       t@@ -307,17 +306,17 @@ darcy_solver_1d(struct simulation* sim,
                                fprintf(stderr, ".. Residual normalized error: %f\n", r_norm_max);
                        }
                } else {
       -                for (i=0; i<sim->nz; ++i)
       -                        sim->p_f_ghost[i+1] += dp_f_dt_expl[i]*sim->dt;
       +                for (i=0; i<sim.nz; ++i)
       +                        sim.p_f_ghost[i+1] += dp_f_dt_expl[i]*sim.dt;
                        solved = 1;
        #ifdef DEBUG
                        puts(".. dp_f_dt_expl:");
       -                print_array(dp_f_dt_expl, sim->nz);
       +                print_array(dp_f_dt_expl, sim.nz);
                        puts(".. p_f_ghost after explicit solution:");
       -                print_array(sim->p_f_ghost, sim->nz+2);
       +                print_array(sim.p_f_ghost, sim.nz+2);
        #endif
                }
       -        set_fluid_bcs(sim, p_f_top);
       +        set_fluid_bcs(p_f_top);
        
                if (epsilon < 1.0)
                        free(dp_f_dt_expl);
 (DIR) diff --git a/fluid.h b/fluid.h
       t@@ -3,12 +3,13 @@
        
        #include "simulation.h"
        
       -void hydrostatic_fluid_pressure_distribution(struct simulation* sim);
       +extern struct simulation sim;
        
       -void set_largest_fluid_timestep(struct simulation* sim, const double safety);
       +void hydrostatic_fluid_pressure_distribution();
       +
       +void set_largest_fluid_timestep(const double safety);
        
        int darcy_solver_1d(
       -        struct simulation* sim,
                const int max_iter,
                const double rel_tol);
        
 (DIR) diff --git a/max_depth_simple_shear.c b/max_depth_simple_shear.c
       t@@ -6,10 +6,8 @@
        #include <time.h>
        
        #include "simulation.h"
       -
       -#define PROGNAME "max_depth_simple_shear"
       -
        #include "parameter_defaults.h"
       +#include "arg.h"
        
        #define EPS 1e-12
        
       t@@ -24,64 +22,32 @@
        #define M_PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062
        #endif
        
       -static void
       -usage(void)
       -{
       -        struct simulation sim = init_sim();
       -        printf("%s: %s [OPTIONS]\n"
       -                "outputs the maximum deformation depth in a shear system with sinusoidal\n"
       -                "fluid-pressure perturbations from the top, assuming infinite layer thickness.\n"
       -                "\nOptional arguments:\n"
       -                " -v, --version                   show version information\n"
       -                " -h, --help                      show this message\n"
       -                " -G, --gravity VAL               gravity magnitude [m/s^2] (default %g)\n"
       -                " -p, --porosity VAL              porosity fraction [-] (default %g)\n"
       -                " -r, --density VAL               grain material density [kg/m^3] (default %g)\n"
       -                " -c, --fluid-compressibility VAL fluid compressibility [Pa^-1] (default %g)\n"
       -                " -i, --fluid-viscosity VAL       fluid viscosity [Pa*s] (default %g)\n"
       -                " -R, --fluid-density VAL         fluid density [kg/m^3] (default %g)\n"
       -                " -k, --fluid-permeability VAL    fluid intrinsic permeability [m^2] (default %g)\n"
       -                " -a, --fluid-pressure-ampl VAL   amplitude of pressure variations [Pa] (default %g)\n"
       -                " -q, --fluid-pressure-freq VAL   frequency of sinusoidal pressure variations [s^-1]\n"
       -                "                                 (default %g)\n"
       -                "\n"
       -                "The first column of the output is the max. deformation depth from the top in meters.\n"
       -                "The second column is the skin depth in meters.\n"
       -                ,
       -                __func__, PROGNAME,
       -                sim.G,
       -                sim.phi[0],
       -                sim.rho_s,
       -                sim.beta_f,
       -                sim.mu_f,
       -                sim.rho_f,
       -                sim.k[0],
       -                sim.p_f_mod_ampl,
       -                sim.p_f_mod_freq);
       -        free(sim.phi);
       -        free(sim.k);
       -}
       +char *argv0;
       +struct simulation sim;
        
        static void
       -version(void)
       +usage(void)
        {
       -        printf("%s v%s\n"
       -        "Licensed under the ISC License, see LICENSE for details.\n"
       -        "written by Anders Damsgaard, anders@adamsgaard.dk\n"
       -        "https://src.adamsgaard.dk/1d_fd_simple_shear\n"
       -        , PROGNAME, VERSION);
       +        dprintf(2, "usage: %s [-hv] "
       +                "[-g gravity-accel] [-r grain-density] "
       +                "[-p grain-porosity] "
       +                "[-O fluid-pressure-top] [-a fluid-pressure-ampl] "
       +                "[-q fluid-pressure-freq]"
       +                "[-k fluid-permeability] [-R fluid-density] [-i fluid-viscosity] "
       +                "[-C fluid-compressibility]\n", argv0);
       +        exit(1);
        }
        
        double
       -skin_depth(const struct simulation* sim)
       +skin_depth()
        {
       -        return sqrt(sim->k[0]/
       -               (sim->phi[0]*sim->mu_f*sim->beta_f*M_PI*sim->p_f_mod_freq));
       +        return sqrt(sim.k[0]/
       +               (sim.phi[0]*sim.mu_f*sim.beta_f*M_PI*sim.p_f_mod_freq));
        }
        
        /* using alternate form: sin(x) + cos(x) = sqrt(2)*sin(x + pi/4) */
        double
       -eff_normal_stress_gradient(const struct simulation* sim, double d_s, double z_)
       +eff_normal_stress_gradient(double d_s, double z_)
        {
                if (z_/d_s > 10.0) {
                        fprintf(stderr, "error: %s: unrealistic depth: %g m "
       t@@ -90,13 +56,12 @@ eff_normal_stress_gradient(const struct simulation* sim, double d_s, double z_)
                }
        
                return sqrt(2.0)*sin((3.0*M_PI/2.0 - z_/d_s) + M_PI/4.0)
       -               + (sim->rho_s - sim->rho_f)*sim->G*d_s/sim->p_f_mod_ampl*exp(z_/d_s);
       +               + (sim.rho_s - sim.rho_f)*sim.G*d_s/sim.p_f_mod_ampl*exp(z_/d_s);
        }
        
        /* use Brent's method for finding roots (Press et al., 2007) */
       -double zbrent(struct simulation* sim,
       -              double d_s,
       -              double (*f)(struct simulation* sim, double, double),
       +double zbrent(double d_s,
       +              double (*f)(double, double),
                      double x1,
                      double x2,
                      double tol)
       t@@ -105,8 +70,8 @@ double zbrent(struct simulation* sim,
                double a, b, c, d, e, min1, min2, fa, fb, fc, p, q, r, s, tol1, xm;
        
                a = x1; b=x2; c=x2;
       -        fa = (*f)(sim, d_s, a);
       -        fb = (*f)(sim, d_s, b);
       +        fa = (*f)(d_s, a);
       +        fb = (*f)(d_s, b);
        
                if ((fa > 0.0 && fb > 0.0) || (fa < 0.0 && fb < 0.0)) {
                        fprintf(stderr,
       t@@ -167,7 +132,7 @@ double zbrent(struct simulation* sim,
                                b += d;
                        else
                                b += ((xm) >= 0.0 ? fabs(tol1) : -fabs(tol1));
       -                fb = (*f)(sim, d_s, b);
       +                fb = (*f)(d_s, b);
                }
                fprintf(stderr,
                                "error: %s: exceeded maximum number of iterations",
       t@@ -179,9 +144,7 @@ double zbrent(struct simulation* sim,
        int
        main(int argc, char* argv[])
        {
       -        int opt, i;
       -        struct simulation sim;
       -        const char* optstring;
       +        int i;
                double new_phi, new_k;
                double d_s, depth, depth_limit1, depth_limit2;
        #ifdef BENCHMARK_PERFORMANCE
       t@@ -195,86 +158,56 @@ main(int argc, char* argv[])
                        exit(1);
                }
        #endif
       +        atexit(free_arrays);
        
       -        /* load with default values */
       -        sim = init_sim();
       -
       -        optstring = "hvG:p:r:c:i:R:k:a:q:";
       -        const struct option longopts[] = {
       -                {"help",                      no_argument,       NULL, 'h'},
       -                {"version",                   no_argument,       NULL, 'v'},
       -                {"gravity",                   required_argument, NULL, 'G'},
       -                {"porosity",                  required_argument, NULL, 'p'},
       -                {"density",                   required_argument, NULL, 'r'},
       -                {"fluid-compressibility",     required_argument, NULL, 'c'},
       -                {"fluid-viscosity",           required_argument, NULL, 'i'},
       -                {"fluid-density",             required_argument, NULL, 'R'},
       -                {"fluid-permeability",        required_argument, NULL, 'k'},
       -                {"fluid-pressure-ampl",       required_argument, NULL, 'a'},
       -                {"fluid-pressure-freq",       required_argument, NULL, 'q'},
       -                {NULL,                        0,                 NULL, 0}
       -        };
       -
       +        init_sim();
                new_phi = sim.phi[0];
                new_k = sim.k[0];
       -        while ((opt = getopt_long(argc, argv, optstring, longopts, NULL)) != -1) {
       -                switch (opt) {
       -                        case -1:   /* no more arguments */
       -                        case 0:    /* long options toggles */
       -                                break;
       -
       -                        case 'h':
       -                                usage();
       -                                free(sim.phi);
       -                                free(sim.k);
       -                                return 0;
       -                        case 'v':
       -                                version();
       -                                free(sim.phi);
       -                                free(sim.k);
       -                                return 0;
       -                        case 'G':
       -                                sim.G = atof(optarg);
       -                                break;
       -                        case 'p':
       -                                new_phi = atof(optarg);
       -                                break;
       -                        case 'r':
       -                                sim.rho_s = atof(optarg);
       -                                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 'a':
       -                                sim.p_f_mod_ampl = atof(optarg);
       -                                break;
       -                        case 'q':
       -                                sim.p_f_mod_freq = atof(optarg);
       -                                break;
       -                        default:
       -                                fprintf(stderr, "%s: invalid option -- %c\n", argv[0], opt);
       -                                fprintf(stderr, "Try `%s --help` for more information\n",
       -                                        argv[0]);
       -                                return -2;
       -                }
       -        }
        
       -        if (optind < argc) {
       -                fprintf(stderr, "error: unknown argument specified\n");
       -                return 1;
       -        }
       +        ARGBEGIN {
       +        case 'C':
       +                sim.beta_f = atof(EARGF(usage()));
       +                break;
       +        case 'R':
       +                sim.rho_f = atof(EARGF(usage()));
       +                break;
       +        case 'a':
       +                sim.p_f_mod_ampl = atof(EARGF(usage()));
       +                break;
       +        case 'g':
       +                sim.G = atof(EARGF(usage()));
       +                break;
       +        case 'h':
       +                usage();
       +                break;
       +        case 'i':
       +                sim.mu_f = atof(EARGF(usage()));
       +                break;
       +        case 'k':
       +                new_k = atof(EARGF(usage()));
       +                break;
       +        case 'p':
       +                new_phi = atof(EARGF(usage()));
       +                break;
       +        case 'q':
       +                sim.p_f_mod_freq = atof(EARGF(usage()));
       +                break;
       +        case 'r':
       +                sim.rho_s = atof(EARGF(usage()));
       +                break;
       +        case 'v':
       +                printf("%s-"VERSION"\n", argv0);
       +                return 0;
       +                break;
       +        default:
       +                usage();
       +        } ARGEND;
       +
       +        if (argc > 0)
       +                usage();
        
                sim.nz = 2;
       -        prepare_arrays(&sim);
       +        prepare_arrays();
        
                if (!isnan(new_phi))
                        for (i=0; i<sim.nz; ++i)
       t@@ -283,10 +216,10 @@ main(int argc, char* argv[])
                        for (i=0; i<sim.nz; ++i)
                                sim.k[i] = new_k;
        
       -        check_simulation_parameters(&sim);
       +        check_simulation_parameters();
        
                depth = 0.0;
       -        d_s = skin_depth(&sim);
       +        d_s = skin_depth();
        
        #ifdef BENCHMARK_PERFORMANCE
                t_begin = clock();
       t@@ -296,14 +229,13 @@ main(int argc, char* argv[])
                 * water pressure forcing, or if the stress gradient is positive at
                 * zero depth */
                if (fabs(sim.p_f_mod_ampl) > 1e-6 && 
       -                eff_normal_stress_gradient(&sim, d_s, 0.0) < 0.0) {
       +                eff_normal_stress_gradient(d_s, 0.0) < 0.0) {
        
                        depth_limit1 = 0.0;
                        depth_limit2 = 5.0*d_s;
        
       -                depth = zbrent(&sim,
       -                       d_s,
       -                       (double (*)(struct simulation*, double, double))
       +                depth = zbrent(d_s,
       +                       (double (*)(double, double))
                                           eff_normal_stress_gradient,
                               depth_limit1,
                               depth_limit2,
       t@@ -318,6 +250,5 @@ main(int argc, char* argv[])
        
                printf("%.17g\t%.17g\n", depth, d_s);
        
       -        free_arrays(&sim);
                return 0;
        }
 (DIR) diff --git a/parameter_defaults.h b/parameter_defaults.h
       t@@ -9,10 +9,9 @@
        #define DEFAULT_SIMULATION_NAME "unnamed_simulation"
        
        /* Simulation settings */
       -struct simulation init_sim(void)
       +void
       +init_sim()
        {
       -        struct simulation sim;
       -
                snprintf(sim.name, sizeof(sim.name), DEFAULT_SIMULATION_NAME);
        
                sim.G = 9.81;
       t@@ -43,6 +42,10 @@ struct simulation init_sim(void)
                sim.phi = initval(0.25, 1);
                sim.d = 0.04;        /* Damsgaard et al 2013 */
        
       +        sim.phi_min = 0.2;
       +        sim.phi_max = 0.8;
       +        sim.dilatancy_angle = 1.0;
       +
                /* Iverson et al 1997, 1998: Storglaciaren till */
                /* sim.mu_s = tan(DEG2RAD(26.3)); */
                /* sim.C = 5.0e3; */
       t@@ -107,8 +110,6 @@ struct simulation init_sim(void)
                sim.p_f_mod_phase = 0.0;
                sim.p_f_mod_pulse_time = NAN;
                sim.p_f_mod_pulse_shape = 0;
       -
       -        return sim;
        }
        
        #endif
 (DIR) diff --git a/simulation.c b/simulation.c
       t@@ -7,45 +7,49 @@
        /* #define SHOW_PARAMETERS */
        
        void
       -prepare_arrays(struct simulation* sim)
       +prepare_arrays()
        {
       -        if (sim->nz < 2) {
       +        if (sim.nz < 2) {
                        fprintf(stderr, "error: grid size (nz) must be at least 2 but is %d\n",
       -                                sim->nz);
       +                                sim.nz);
                        exit(1);
                }
       -        sim->z = linspace(sim->origo_z,    /* spatial coordinates */
       -                          sim->origo_z + sim->L_z,
       -                          sim->nz);
       -        sim->dz = sim->z[1] - sim->z[0];   /* cell spacing */
       -        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); /* shear velocity */
       -        sim->v_x = zeros(sim->nz);         /* shear velocity */
       -        sim->g_ghost = zeros(sim->nz+2);   /* fluidity with ghost nodes */
       +        sim.z = linspace(sim.origo_z,    /* spatial coordinates */
       +                          sim.origo_z + sim.L_z,
       +                          sim.nz);
       +        sim.dz = sim.z[1] - sim.z[0];    /* cell spacing */
       +        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); /* shear velocity */
       +        sim.v_x = zeros(sim.nz);         /* shear velocity */
       +        sim.g_ghost = zeros(sim.nz+2);   /* fluidity with ghost nodes */
       +        sim.I = zeros(sim.nz);           /* inertia number */
       +        sim.tau = zeros(sim.nz);         /* shear stress */
        }
        
        void
       -free_arrays(struct simulation* sim)
       +free_arrays()
        {
       -        free(sim->z);
       -        free(sim->mu);
       -        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);
       +        free(sim.z);
       +        free(sim.mu);
       +        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);
       +        free(sim.I);
       +        free(sim.tau);
        }
        
        static void
       t@@ -80,137 +84,156 @@ check_float(const char name[], const double value, int* return_status)
        }
        
        void
       -check_simulation_parameters(const struct simulation* sim)
       +check_simulation_parameters()
        {
                int return_status;
        
                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.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,
       +        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.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,
       +        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.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.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,
       +        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.C", sim->C, &return_status);
       +        check_float("sim.C", sim.C, &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,
       +        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,
       +        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,
       +        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)
       +        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);
       +                                     sim.L_z, &return_status);
        
       -        if (sim->nz <= 0)
       -                warn_parameter_value("sim.nz is not a positive number", sim->nz,
       +        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,
       +        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)
       +        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);
       +                                     sim.t, &return_status);
        
       -        check_float("sim.t_end", sim->t_end, &return_status);
       -        if (sim->t > sim->t_end)
       +        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);
       +                                     sim.t, &return_status);
        
       -        check_float("sim.dt", sim->dt, &return_status);
       -        if (sim->dt <= 0.0)
       +        check_float("sim.dt", sim.dt, &return_status);
       +        if (sim.dt <= 0.0)
                        warn_parameter_value("sim.dt is not a positive number",
       -                                     sim->dt, &return_status);
       +                                     sim.dt, &return_status);
        
       -        check_float("sim.file_dt", sim->file_dt, &return_status);
       -        if (sim->file_dt < 0.0)
       +        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);
       +                                     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)
       +        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);
       +                                     sim.phi[0], &return_status);
        
       -        if (sim->fluid != 0 && sim->fluid != 1)
       +        check_float("sim.phi_min", sim.phi_min, &return_status);
       +        if (sim.phi_min < 0.0 || sim.phi_min > 1.0)
       +                warn_parameter_value("sim.phi_min is not within [0;1]",
       +                                     sim.phi_min, &return_status);
       +
       +        check_float("sim.phi_max", sim.phi_max, &return_status);
       +        if (sim.phi_max < 0.0 || sim.phi_max > 1.0)
       +                warn_parameter_value("sim.phi_max is not within [0;1]",
       +                                     sim.phi_max, &return_status);
       +
       +        check_float("sim.dilatancy_angle", sim.dilatancy_angle, &return_status);
       +        if (sim.dilatancy_angle < 0.0 || sim.dilatancy_angle > 100.0)
       +                warn_parameter_value("sim.dilatancy_angle is not within [0;100]",
       +                                     sim.dilatancy_angle, &return_status);
       +
       +        if (sim.fluid != 0 && sim.fluid != 1)
                        warn_parameter_value("sim.fluid has an invalid value",
       -                                     (double)sim->fluid, &return_status);
       +                                     (double)sim.fluid, &return_status);
        
       -        if (sim->fluid) {
       +        if (sim.transient != 0 && sim.transient != 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)
       +                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);
       +                                             sim.p_f_mod_ampl, &return_status);
        
       -                if (sim->P_wall - sim->p_f_mod_ampl < 0.0)
       +                if (sim.P_wall - sim.p_f_mod_ampl < 0.0)
                                warn_parameter_value("sim.P_wall - sim.p_f_mod_ampl is negative",
       -                                             sim->P_wall - sim->p_f_mod_ampl,
       +                                             sim.P_wall - 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)
       +                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);
       +                                                     sim.p_f_mod_freq, &return_status);
        
       -                check_float("sim.beta_f", sim->beta_f, &return_status);
       -                        if (sim->beta_f <= 0.0)
       +                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);
       +                                                     sim.beta_f, &return_status);
        
       -                check_float("sim.mu_f", sim->mu_f, &return_status);
       -                        if (sim->mu_f <= 0.0)
       +                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);
       +                                                     sim.mu_f, &return_status);
        
       -                check_float("sim.rho_f", sim->rho_f, &return_status);
       -                        if (sim->rho_f <= 0.0)
       +                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);
       +                                                     sim.rho_f, &return_status);
        
       -                check_float("sim.k[0]", sim->k[0], &return_status);
       -                        if (sim->k[0] <= 0.0)
       +                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);
       +                                                     sim.k[0], &return_status);
                }
        
                if (return_status != 0) {
       t@@ -220,28 +243,28 @@ check_simulation_parameters(const struct simulation* sim)
        }
        
        void
       -lithostatic_pressure_distribution(struct simulation* sim)
       +lithostatic_pressure_distribution()
        {
                int i;
       -        for (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]);
       +        for (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)
       +compute_friction()
        {
                int i;
       -        if (sim->fluid)
       -                for (i=0; i<sim->nz; ++i)
       -                        sim->mu[i] = sim->mu_wall/
       -                                     (sim->sigma_n_eff[i]/(sim->P_wall - sim->p_f_top));
       +        if (sim.fluid)
       +                for (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 (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);
       +                for (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
       t@@ -251,37 +274,37 @@ shear_strain_rate_plastic(const double fluidity, const double friction)
        }
        
        void
       -compute_shear_strain_rate_plastic(struct simulation* sim)
       +compute_shear_strain_rate_plastic()
        {
                int i;
       -        for (i=0; i<sim->nz; ++i)
       -                sim->gamma_dot_p[i] = shear_strain_rate_plastic(sim->g_ghost[i+1],
       -                                                                sim->mu[i]);
       +        for (i=0; i<sim.nz; ++i)
       +                sim.gamma_dot_p[i] = shear_strain_rate_plastic(sim.g_ghost[i+1],
       +                                                                sim.mu[i]);
        }
        
        void
       -compute_shear_velocity(struct simulation* sim)
       +compute_shear_velocity()
        {
                int i;
        
                // TODO: implement iterative solver
                // Dirichlet BC at bottom
       -        sim->v_x[0] = sim->v_x_bot;
       +        sim.v_x[0] = sim.v_x_bot;
        
       -        for (i=1; i<sim->nz; ++i)
       -                sim->v_x[i] = sim->v_x[i-1] + sim->gamma_dot_p[i]*sim->dz;
       +        for (i=1; i<sim.nz; ++i)
       +                sim.v_x[i] = sim.v_x[i-1] + sim.gamma_dot_p[i]*sim.dz;
        }
        
        void
       -compute_effective_stress(struct simulation* sim)
       +compute_effective_stress()
        {
                int i;
       -        if (sim->fluid)
       -                for (i=0; i<sim->nz; ++i)
       -                        sim->sigma_n_eff[i] = sim->sigma_n[i] - sim->p_f_ghost[i+1];
       +        if (sim.fluid)
       +                for (i=0; i<sim.nz; ++i)
       +                        sim.sigma_n_eff[i] = sim.sigma_n[i] - sim.p_f_ghost[i+1];
                else
       -                for (i=0; i<sim->nz; ++i)
       -                        sim->sigma_n_eff[i] = sim->sigma_n[i];
       +                for (i=0; i<sim.nz; ++i)
       +                        sim.sigma_n_eff[i] = sim.sigma_n[i];
        }
        
        static double
       t@@ -296,16 +319,16 @@ cooperativity_length(const double A,
        }
        
        void
       -compute_cooperativity_length(struct simulation* sim)
       +compute_cooperativity_length()
        {
                int i;
       -        for (i=0; i<sim->nz; ++i)
       -                sim->xi[i] = cooperativity_length(sim->A,
       -                                                  sim->d,
       -                                                  sim->mu[i],
       -                                                  sim->sigma_n_eff[i],
       -                                                  sim->mu_s,
       -                                                  sim->C);
       +        for (i=0; i<sim.nz; ++i)
       +                sim.xi[i] = cooperativity_length(sim.A,
       +                                                  sim.d,
       +                                                  sim.mu[i],
       +                                                  sim.sigma_n_eff[i],
       +                                                  sim.mu_s,
       +                                                  sim.C);
        }
        
        static double
       t@@ -324,17 +347,17 @@ local_fluidity(const double p,
        }
        
        void
       -compute_local_fluidity(struct simulation* sim)
       +compute_local_fluidity()
        {
                int i;
       -        for (i=0; i<sim->nz; ++i)
       -                sim->g_ghost[i+1] = local_fluidity(sim->sigma_n_eff[i],
       -                                                   sim->mu[i],
       -                                                   sim->mu_s,
       -                                                   sim->C,
       -                                                   sim->b,
       -                                                   sim->rho_s,
       -                                                   sim->d);
       +        for (i=0; i<sim.nz; ++i)
       +                sim.g_ghost[i+1] = local_fluidity(sim.sigma_n_eff[i],
       +                                                   sim.mu[i],
       +                                                   sim.mu_s,
       +                                                   sim.C,
       +                                                   sim.b,
       +                                                   sim.rho_s,
       +                                                   sim.d);
        }
        
        void
       t@@ -406,8 +429,7 @@ poisson_solver_1d_cell_update(int i,
        }
        
        int
       -implicit_1d_jacobian_poisson_solver(struct simulation* sim,
       -                                    const int max_iter,
       +implicit_1d_jacobian_poisson_solver(const int max_iter,
                                            const double rel_tol)
        {
                double r_norm_max;
       t@@ -415,41 +437,41 @@ implicit_1d_jacobian_poisson_solver(struct simulation* sim,
                int iter, i;
        
                r_norm_max = NAN;
       -        g_ghost_out = empty(sim->nz+2);
       -        r_norm = empty(sim->nz);
       +        g_ghost_out = empty(sim.nz+2);
       +        r_norm = empty(sim.nz);
        
                for (iter=0; iter<max_iter; ++iter) {
        #ifdef DEBUG
                        printf("\n@@@ ITERATION %d @@@\n", iter);
        #endif
                        /* Dirichlet BCs resemble fixed particle velocities */
       -                set_bc_dirichlet(sim->g_ghost, sim->nz, -1, 0.0);
       -                set_bc_dirichlet(sim->g_ghost, sim->nz, +1, 0.0);
       +                set_bc_dirichlet(sim.g_ghost, sim.nz, -1, 0.0);
       +                set_bc_dirichlet(sim.g_ghost, sim.nz, +1, 0.0);
        
                        /* Neumann BCs resemble free surfaces */
       -                /* set_bc_neumann(sim->g_ghost, sim->nz, +1, 0.0, sim->dz); */
       +                /* set_bc_neumann(sim.g_ghost, sim.nz, +1, 0.0, sim.dz); */
        
       -                for (i=0; i<sim->nz; ++i)
       +                for (i=0; i<sim.nz; ++i)
                                poisson_solver_1d_cell_update(i,
       -                                                      sim->g_ghost,
       +                                                      sim.g_ghost,
                                                              g_ghost_out,
                                                              r_norm,
       -                                                      sim->dz,
       -                                                      sim->mu,
       -                                                      sim->sigma_n_eff,
       -                                                      sim->xi,
       -                                                      sim->mu_s,
       -                                                      sim->C,
       -                                                      sim->b,
       -                                                      sim->rho_s,
       -                                                      sim->d);
       -                r_norm_max = max(r_norm, sim->nz);
       -
       -                copy_values(g_ghost_out, sim->g_ghost, sim->nz+2);
       +                                                      sim.dz,
       +                                                      sim.mu,
       +                                                      sim.sigma_n_eff,
       +                                                      sim.xi,
       +                                                      sim.mu_s,
       +                                                      sim.C,
       +                                                      sim.b,
       +                                                      sim.rho_s,
       +                                                      sim.d);
       +                r_norm_max = max(r_norm, sim.nz);
       +
       +                copy_values(g_ghost_out, sim.g_ghost, sim.nz+2);
        
                        if (r_norm_max <= rel_tol) {
       -                        set_bc_dirichlet(sim->g_ghost, sim->nz, -1, 0.0);
       -                        set_bc_dirichlet(sim->g_ghost, sim->nz, +1, 0.0);
       +                        set_bc_dirichlet(sim.g_ghost, sim.nz, -1, 0.0);
       +                        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@@ -466,64 +488,44 @@ implicit_1d_jacobian_poisson_solver(struct simulation* sim,
        }
        
        void
       -write_output_file(struct simulation* sim, const int normalize)
       +write_output_file(const int normalize)
        {
                char outfile[200];
                FILE *fp;
        
                snprintf(outfile, sizeof(outfile), "%s.output%05d.txt",
       -                 sim->name, sim->n_file++);
       +                 sim.name, sim.n_file++);
        
                fp = fopen(outfile, "w");
       -        if (sim->fluid)
       -                print_wet_output(fp, sim, normalize);
       -        else
       -                print_dry_output(fp, sim, normalize);
       -
       +        print_output(fp, normalize);
                fclose(fp);
        }
        
        void
       -print_dry_output(FILE* fp, struct simulation* sim, const int norm)
       +print_output(FILE* fp, const int norm)
        {
                int i;
                double *v_x_out;
        
                if (norm)
       -                v_x_out = normalize(sim->v_x, sim->nz);
       +                v_x_out = normalize(sim.v_x, sim.nz);
                else
       -                v_x_out = copy(sim->v_x, sim->nz);
       -
       -        for (i=0; i<sim->nz; ++i)
       -                fprintf(fp, "%.17g\t%.17g\t%.17g\t%.17g\t%.17g\n",
       -                        sim->z[i],
       -                        v_x_out[i],
       -                        sim->sigma_n_eff[i],
       -                        sim->mu[i],
       -                        sim->gamma_dot_p[i]);
       -
       -        free(v_x_out);
       -}
       -
       -void
       -print_wet_output(FILE* fp, struct simulation* sim, const int norm)
       -{
       -        int i;
       -        double *v_x_out;
       -
       -        if (norm)
       -                v_x_out = normalize(sim->v_x, sim->nz);
       -        else
       -                v_x_out = copy(sim->v_x, sim->nz);
       -
       -        for (i=0; i<sim->nz; ++i)
       -                fprintf(fp, "%.17g\t%.17g\t%.17g\t%.17g\t%.17g\t%.17g\n",
       -                        sim->z[i],
       +                v_x_out = copy(sim.v_x, sim.nz);
       +
       +        for (i=0; i<sim.nz; ++i)
       +                fprintf(fp,
       +                            "%.17g\t%.17g\t%.17g\t"
       +                            "%.17g\t%.17g\t%.17g\t"
       +                                "%.17g\t%.17g\t%.17g\n",
       +                        sim.z[i],
                                v_x_out[i],
       -                        sim->sigma_n_eff[i],
       -                        sim->p_f_ghost[i+1],
       -                        sim->mu[i],
       -                        sim->gamma_dot_p[i]);
       +                        sim.sigma_n_eff[i],
       +                        sim.p_f_ghost[i+1],
       +                        sim.mu[i],
       +                        sim.gamma_dot_p[i],
       +                                sim.phi[i],
       +                                sim.I[i],
       +                                sim.tau[i]);
        
                free(v_x_out);
        }
 (DIR) diff --git a/simulation.h b/simulation.h
       t@@ -6,6 +6,8 @@
        #define PI 3.14159265358979323846
        #define DEG2RAD(x) (x*PI/180.0)
        
       +extern struct simulation sim;
       +
        /* Simulation settings */
        struct simulation {
        
       t@@ -30,8 +32,7 @@ struct simulation {
                /* stress ratio at top wall */
                double mu_wall;
        
       -        /* nonlocal amplitude [-] */
       -        double A;
       +        /* nonlocal amplitude [-] */ double A;
        
                /* rate dependence beyond yield [-] */
                double b;
       t@@ -78,6 +79,11 @@ struct simulation {
                /* output file number */
                int n_file;
        
       +        double transient;
       +        double phi_min;
       +        double phi_max;
       +        double dilatancy_angle;
       +
                /* Fluid parameters */
                int fluid;            /* flag to switch fluid on (1) or off (0) */
                double p_f_top;       /* fluid pressure at the top [Pa] */
       t@@ -101,15 +107,17 @@ struct simulation {
                double* gamma_dot_p;  /* plastic shear strain rate [1/s] */
                double* v_x;          /* shear velocity [m/s] */
                double* g_ghost;      /* fluidity with ghost nodes */
       +        double* I;            /* inertia number [-] */
       +        double* tau;          /* shear stress [Pa] */
        };
        
        
       -void prepare_arrays(struct simulation* sim);
       -void free_arrays(struct simulation* sim);
       +void prepare_arrays();
       +void free_arrays();
        
       -void check_simulation_parameters(const struct simulation* sim);
       +void check_simulation_parameters();
        
       -void lithostatic_pressure_distribution(struct simulation* sim);
       +void lithostatic_pressure_distribution();
        
        void set_bc_neumann(double* g_ghost,
                            const int nz,
       t@@ -122,18 +130,16 @@ void set_bc_dirichlet(double* g_ghost,
                              const int boundary,
                              const double value);
        
       -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);
       +void compute_cooperativity_length();
       +void compute_shear_strain_rate_plastic();
       +void compute_shear_velocity();
       +void compute_effective_stress();
       +void compute_friction();
        
       -int implicit_1d_jacobian_poisson_solver(struct simulation* sim,
       -                                        const int max_iter,
       +int implicit_1d_jacobian_poisson_solver(const int max_iter,
                                                const double rel_tol);
        
       -void write_output_file(struct simulation* sim, const int normalize);
       -void print_dry_output(FILE* fp, struct simulation* sim, const int normalize);
       -void print_wet_output(FILE* fp, struct simulation* sim, const int normalize);
       +void write_output_file(const int normalize);
       +void print_output(FILE* fp, const int normalize);
        
        #endif