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; }