src/common.h

    typedef double number; // used in macros to indicate "any numeric type"
    #define pi 3.14159265358979
    #undef HUGE
    #define HUGE 1e30f
    #define nodata HUGE
    
    macro number max (number a, number b) { return a > b ? a : b; }
    macro number min (number a, number b) { return a < b ? a : b; }
    macro number sq (number x) { return x*x; }
    macro number cube (number x) { return x*x*x; }
    macro int sign (number x) { return (int)(x > 0 ? 1 : -1); }
    macro int sign2 (number x) { return (int)(x > 0 ? 1 : x < 0 ? -1 : 0); }
    macro number clamp (number x, number a, number b) {
      return x < a ? a : x > b ? b : x;
    }
    
    #define swap(type,a,b) do { type _tmp_ = a; a = b; b = _tmp_; } while(false)
    
    #include "grid/config.h"
    
    static inline double noise() { return 1. - 2.*rand()/(double)RAND_MAX; }
    
    // the grid
    typedef struct {
      long n;       // number of (leaf) cells for this process
      long tn;      // number of (leaf) cells for all processes
      int depth;    // the depth for this process
      int maxdepth; // the maximum depth for all processes
    } Grid;
    Grid * grid = NULL;
    // coordinates of the lower-left corner of the box
    double X0 = 0., Y0 = 0., Z0 = 0.;
    // size of the box
    double L0 = 1. [1];
    // number of grid points
    #if dimension <= 2
    int N = 64;
    #else
    int N = 16;
    #endif
    
    typedef struct { int i; } scalar;
    
    typedef struct {
      scalar x;
    #if dimension > 1
      scalar y;
    #endif
    #if dimension > 2
      scalar z;
    #endif
    } vector;
    
    typedef struct {
      scalar * x;
    #if dimension > 1
      scalar * y;
    #endif
    #if dimension > 2
      scalar * z;
    #endif
    } vectorl;
    
    typedef struct {
      vector x;
    #if dimension > 1
      vector y;
    #endif
    #if dimension > 2
      vector z;
    #endif
    } tensor;
    
    struct { int x, y, z; } Period = {false, false, false};
    
    typedef struct {
      double x, y, z;
    } coord;
    
    OMP(omp declare reduction (+ : coord :
    			   omp_out.x += omp_in.x,
    			   omp_out.y += omp_in.y,
    			   omp_out.z += omp_in.z))
    
    #if dimension == 1
    # define norm(v) fabs(v.x[])
    # define dv() (Delta*cm[])
    #elif dimension == 2
    # define norm(v) (sqrt(sq(v.x[]) + sq(v.y[])))
    # define dv() (sq(Delta)*cm[])
    #else // dimension == 3
    # define norm(v) (sqrt(sq(v.x[]) + sq(v.y[]) + sq(v.z[])))
    # define dv() (cube(Delta)*cm[])
    #endif
    
    void normalize (coord * n)
    {
      double norm = 0.;
      foreach_dimension()
        norm += sq(n->x);
      norm = sqrt(norm);
      foreach_dimension()
        n->x /= norm;
    }
    
    void origin (double x = 0., double y = 0., double z = 0.) {
      X0 = x; Y0 = y; Z0 = z;
    }
    
    void size (double L) {
      L0 = L;
    }
    
    double zero (double s0, double s1, double s2) { return 0.; }
    
    // boundary conditions for each direction/variable
    
    #if dimension == 1
      enum { right, left };
    #elif dimension == 2
      enum { right, left, top, bottom };
    #else
      enum { right, left, top, bottom, front, back };
    #endif
    int nboundary = 2*dimension;
    
    #define none -1
    
    double  * _constant = NULL;
    size_t datasize = 0;
    typedef struct _Point Point;
    
    #include "grid/boundaries.h"
    
    // attributes for each scalar
    
    typedef struct {
      int x;
    #if dimension > 1
      int y;
    #endif
    #if dimension > 2
      int z;
    #endif
    } ivec;
    typedef double (* BoundaryFunc) (Point, Point, scalar, bool *);
    typedef struct {
      BoundaryFunc * boundary;
      BoundaryFunc * boundary_homogeneous;
      double (* gradient)              (double, double, double);
      void   (* delete)                (scalar);
      char * name;
      ivec d; // staggering
      vector v;
      int face;
      bool   nodump, freed;
      int    block;
      scalar * depends; // boundary conditions depend on other fields
    } _Attributes;
    
    static _Attributes * _attribute = NULL;
    
    #define foreach_block() // treatment of block data is disabled by default
    #define foreach_blockf(s)
    
    #if dimension == 1
    ivec Dimensions = {1};
    #elif dimension == 2
    ivec Dimensions = {1,1};
    #elif dimension == 3
    ivec Dimensions = {1,1,1};
    #endif
    
    // lists
    
    int list_len (scalar * list)
    {
      if (!list) return 0;
      int ns = 0;
      for (scalar s in list) ns++;
      return ns;
    }
    
    scalar * list_append (scalar * list, scalar s)
    {
      int len = list_len (list);
      qrealloc (list, len + 2, scalar);
      list[len] = s;
      list[len + 1].i = -1;
      return list;
    }
    
    scalar * list_prepend (scalar * list, scalar s)
    {
      int len = list_len (list);
      qrealloc (list, len + 2, scalar);
      for (int i = len; i >= 1; i--)
        list[i] = list[i-1];
      list[0] = s;
      list[len + 1].i = -1;
      return list;
    }
    
    scalar * list_add (scalar * list, scalar s)
    {
      for (scalar t in list)
        if (t.i == s.i)
          return list;
      return list_append (list, s);
    }
    
    int list_lookup (scalar * l, scalar s)
    {
      if (l != NULL)
        for (scalar s1 in l)
          if (s1.i == s.i)
    	return true;
      return false;
    }
    
    scalar * list_copy (scalar * l)
    {
      scalar * list = NULL;
      if (l != NULL)
        for (scalar s in l)
          list = list_append (list, s);
      return list;
    }
    
    scalar * list_concat (scalar * l1, scalar * l2)
    {
      scalar * l3 = list_copy (l1);
      for (scalar s in l2)
        l3 = list_append (l3, s);
      return l3;
    }
    
    void list_print (scalar * l, FILE * fp)
    {
      int i = 0;
      for (scalar s in l)
        fprintf (fp, "%s%s", i++ == 0 ? "{" : ",", s.name);
      fputs (i > 0 ? "}\n" : "{}\n", fp);
    }
    
    int vectors_len (vector * list)
    {
      if (!list) return 0;
      int nv = 0;
      for (vector v in list) nv++;
      return nv;
    }
    
    vector * vectors_append (vector * list, vector v)
    {
      int len = vectors_len (list);
      qrealloc (list, len + 2, vector);
      list[len] = v;
      list[len + 1] = (vector){{-1}};
      return list;
    }
    
    vector * vectors_add (vector * list, vector v)
    {
      for (vector w in list) {
        bool id = true;
        foreach_dimension()
          if (w.x.i != v.x.i)
    	id = false;
        if (id)
          return list;
      }
      return vectors_append (list, v);
    }
    
    vector * vectors_copy (vector * l)
    {
      vector * list = NULL;
      if (l != NULL)
        for (vector v in l)
          list = vectors_append (list, v);
      return list;
    }
    
    vector * vectors_from_scalars (scalar * s)
    {
      vector * list = NULL;
      while (s->i >= 0) {
        vector v;
        foreach_dimension() {
          assert (s->i >= 0);
          v.x = *s++;
        }
        list = vectors_append (list, v);
      }
      return list;
    }
    
    int tensors_len (tensor * list)
    {
      if (!list) return 0;
      int nt = 0;
      for (tensor t in list) nt++;
      return nt;
    }
    
    tensor * tensors_append (tensor * list, tensor t)
    {
      int len = tensors_len (list);
      qrealloc (list, len + 2, tensor);
      list[len] = t;
      list[len + 1] = (tensor){{{-1}}};
      return list;
    }
    
    tensor * tensors_from_vectors (vector * v)
    {
      tensor * list = NULL;
      while (v->x.i >= 0) {
        tensor t;
        foreach_dimension() {
          assert (v->x.i >= 0);
          t.x = *v++;
        }
        list = tensors_append (list, t);
      }
      return list;
    }
    
    static inline bool is_vertex_scalar (scalar s)
    {
      foreach_dimension()
        if (s.d.x != -1)
          return false;
      return true;
    }
    
    scalar * all = NULL; // all the fields
    scalar * baseblock = NULL; // base block fields
    
    // basic methods
    
    scalar (* init_scalar)        (scalar, const char *);
    scalar (* init_vertex_scalar) (scalar, const char *);
    vector (* init_vector)        (vector, const char *);
    vector (* init_face_vector)   (vector, const char *);
    tensor (* init_tensor)        (tensor, const char *);
    void   (* scalar_clone)       (scalar, scalar);
    
    #define vector(x) (*((vector *)&(x)))
    
    // timers
    
    #if _MPI
    static double mpi_time = 0.;
    #endif
    
    typedef struct {
      clock_t c;
      struct timeval tv;
      double tm;
    } timer;
    
    timer timer_start (void)
    {
      timer t;
      t.c = clock();
      gettimeofday (&t.tv, NULL);
    #if _MPI
      t.tm = mpi_time;
    #endif
      return t;
    }
    
    double timer_elapsed (timer t)
    {
      struct timeval tvend;
      gettimeofday (&tvend, NULL);
      return ((tvend.tv_sec - t.tv.tv_sec) + 
    	  (tvend.tv_usec - t.tv.tv_usec)/1e6);
    }
    
    // Constant fields
    
    const face vector zerof[] = {0.,0.,0.};
    const face vector unityf[] = {1.,1.,1.};
    const scalar unity[] = 1.;
    const scalar zeroc[] = 0.;
    
    // Metric
    
    (const) face vector fm[] = {1.[0],1.[0],1.[0]};
    (const) scalar cm[] = 1.[0];
    
    // Embedded boundaries
    // these macros are overloaded in embed.h
    
    #define SEPS 0.
    #define face_gradient_x(a,i) ((a[i] - a[i-1])/Delta)
    #define face_gradient_y(a,i) ((a[0,i] - a[0,i-1])/Delta)
    #define face_gradient_z(a,i) ((a[0,0,i] - a[0,0,i-1])/Delta)
    #define face_value(a,i)      ((a[i] + a[i-1])/2.)
    #define center_gradient(a)   ((a[1] - a[-1])/(2.*Delta))
    
    // matrices
    
    void * matrix_new (int n, int p, size_t size)
    {
      void ** m = qmalloc (n, void *);
      char * a = qmalloc (n*p*size, char);
      for (int i = 0; i < n; i++)
        m[i] = a + i*p*size;
      return m;
    }
    
    double matrix_inverse (double ** m, int n, double pivmin)
    {
      int indxc[n], indxr[n], ipiv[n];
      int i, icol = 0, irow = 0, j, k, l, ll;
      double big, dum, pivinv, minpiv = HUGE;
    
      for (j = 0; j < n; j++)
        ipiv[j] = -1;
    
      for (i = 0; i < n; i++) {
        big = 0.0;
        for (j = 0; j < n; j++)
          if (ipiv[j] != 0)
    	for (k = 0; k < n; k++) {
    	  if (ipiv[k] == -1) {
    	    if (fabs (m[j][k]) >= big) {
    	      big = fabs (m[j][k]);
    	      irow = j;
    	      icol = k;
    	    }
    	  }
    	}
        ipiv[icol]++;
        if (irow != icol)
          for (l = 0; l < n; l++) 
    	swap (double, m[irow][l], m[icol][l]);
        indxr[i] = irow;
        indxc[i] = icol;
        if (fabs (m[icol][icol]) <= pivmin)
          return 0.;
        if (fabs (m[icol][icol]) < minpiv)
          minpiv = fabs (m[icol][icol]);
        pivinv = 1.0/m[icol][icol];
        m[icol][icol] = 1.0;
        for (l = 0; l < n; l++) m[icol][l] *= pivinv;
        for (ll = 0; ll < n; ll++)
          if (ll != icol) {
    	dum = m[ll][icol];
    	m[ll][icol] = 0.0;
    	for (l = 0; l < n; l++)
    	  m[ll][l] -= m[icol][l]*dum;
          }
      }
      for (l = n - 1; l >= 0; l--) {
        if (indxr[l] != indxc[l])
          for (k = 0; k < n; k++)
    	swap (double, m[k][indxr[l]], m[k][indxc[l]]);
      }
      return minpiv;
    }
    
    void matrix_free (void * m)
    {
      free (((void **) m)[0]);
      free (m);
    }
    
    // Solver cleanup
    
    typedef void (* free_solver_func) (void);
    
    static Array * free_solver_funcs = NULL;
    
    void free_solver_func_add (free_solver_func func)
    {
      if (!free_solver_funcs)
        free_solver_funcs = array_new();
      array_append (free_solver_funcs, &func, sizeof(free_solver_func));
    }
    
    // Default objects to display
    
    static char * display_defaults = NULL;
    
    static void free_display_defaults() {
      free (display_defaults);
    }
    
    void display (const char * commands, bool overwrite = false)
    {
      if (display_defaults == NULL)
        free_solver_func_add (free_display_defaults);
      if (overwrite) {
        free (display_defaults);
        display_defaults = malloc (strlen(commands) + 2);
        strcpy (display_defaults, "@");
        strcat (display_defaults, commands);
      }
      else {
        if (!display_defaults)
          display_defaults = strdup ("@");
        display_defaults =
          realloc (display_defaults,
    	       strlen(display_defaults) + strlen(commands) + 1);
        strcat (display_defaults, commands);
      }
    }
    
    #define display_control(val, ...)
    
    typedef struct {
      double x;
    #if dimension > 1
      double y;
    #endif
    #if dimension > 2
      double z;
    #endif
    } _coord;
    
    // Types and macros for compatibility with GLSL
    
    typedef struct {
      float r, g, b, a;
    } vec4;
    
    #if dimension == 1
    # define avector(x, ...)    {x}
    #elif dimension == 2
    # define avector(x, y, ...) {x, y}
    #else // dimension == 3
    # define avector(x, y, z)   {x, y, z}
    #endif
    
    typedef struct {
      coord x, y, z;
    } mat3;
    
    OMP(omp declare reduction (+ : mat3 :
    			   omp_out.x.x += omp_in.x.x,
    			   omp_out.x.y += omp_in.x.y,
    			   omp_out.x.z += omp_in.x.z,
    			   omp_out.y.x += omp_in.y.x,
    			   omp_out.y.y += omp_in.y.y,
    			   omp_out.y.z += omp_in.y.z,
    			   omp_out.z.x += omp_in.z.x,
    			   omp_out.z.y += omp_in.z.y,
    			   omp_out.z.z += omp_in.z.z
    			   ))
    
    typedef struct {
      uint32_t s;
    } Adler32Hash;
    
    static
    inline void a32_hash_init (Adler32Hash * hash)
    {
      hash->s = 0;
    }
    
    static
    inline void a32_hash_add (Adler32Hash * hash, const void * data, size_t size)
    {
      const uint8_t * buffer = (const uint8_t*) data;
      for (size_t n = 0; n < size; n++, buffer++)
        hash->s = *buffer + (hash->s << 6) + (hash->s << 16) - hash->s;
    }
    
    static
    inline uint32_t a32_hash (const Adler32Hash * hash)
    {
      return hash->s;
    }