src/grid/cartesian-common.h
#include "events.h"
void (* debug) (Point);
@define _val_constant(a,k,l,m) ((const double) _constant[a.i -_NVARMAX])
@define diagonalize(a)
@define val_diagonal(a,k,l,m) ((k) == 0 && (l) == 0 && (m) == 0)
@undef VARIABLES
@def VARIABLES
double Delta = L0*_DELTA; /* cell size */
double Delta_x = Delta; /* cell size (with mapping) */
#if dimension > 1
double Delta_y = Delta; /* cell size (with mapping) */
#endif
#if dimension > 2
double Delta_z = Delta; /* cell size (with mapping) */
#endif
/* cell/face center coordinates */
double x = (ig/2. + _I + 0.5)*Delta + X0; NOT_UNUSED(x);
#if dimension > 1
double y = (jg/2. + _J + 0.5)*Delta + Y0;
#else
double y = 0.;
#endif
NOT_UNUSED(y);
#if dimension > 2
double z = (kg/2. + _K + 0.5)*Delta + Z0;
#else
double z = 0.;
#endif
NOT_UNUSED(z);
/* we need this to avoid compiler warnings */
NOT_UNUSED(Delta);
NOT_UNUSED(Delta_x);
#if dimension > 1
NOT_UNUSED(Delta_y);
#endif
#if dimension > 2
NOT_UNUSED(Delta_z);
#endif
/* and this when catching FPEs */
_CATCH;
@
#include "fpe.h"
@define end_foreach_face()
@def foreach_point(...)
{
int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
coord _p = { S__VA_ARGS__ };
Point point = locate (_p.x, _p.y, _p.z); // fixme
if (point.level >= 0) {
POINT_VARIABLES
@
@define end_foreach_point() }}
@def foreach_region(p, box, n)
OMP_PARALLEL() { NOT_UNUSED (p);
coord p = {0, 0, box[0].z};
OMP(omp for schedule(static))
for (int _i = 0; _i < (int) n.x; _i++) {
p.x = box[0].x + (box[1].x - box[0].x)/n.x*(_i + 0.5);
for (int _j = 0; _j < (int) n.y; _j++) {
p.y = box[0].y + (box[1].y - box[0].y)/n.y*(_j + 0.5);
Point point = locate (p.x, p.y, p.z); // fixme
if (point.level >= 0) {
int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
POINT_VARIABLES
@
@define end_foreach_region() }}}}
Register functions on GPUs
#if _GPU
#include "khash.h"
KHASH_MAP_INIT_INT64(PTR, External)
static khash_t(PTR) * _functions = NULL;
static External * _get_function (long ptr)
{
if (!_functions)
return NULL;
khiter_t k = kh_get (PTR, _functions, ptr);
if (k == kh_end (_functions))
return NULL;
return &kh_value (_functions, k);
}
static void register_function (void (* ptr) (void), const char * name,
const char * kernel, const void * externals)
{
static int index = 1;
if (!_functions)
_functions = kh_init (PTR), index = 1;
int m = 0;
for (const External * i = externals; i && i->name; i++, m++);
External * copy = NULL;
if (m > 0) {
copy = malloc ((m + 1)*sizeof (External));
memcpy (copy, externals, (m + 1)*sizeof (External));
}
int ret;
khiter_t k = kh_put(PTR, _functions, (long) ptr, &ret);
External p = {
.name = (char *) name,
.type = sym_function_definition,
.pointer = (void *)(long) ptr, .nd = index++,
.data = (void *) kernel, .externals = copy
};
kh_value(_functions, k) = p;
}
#define foreach_function(f, body) do { \
for (khiter_t k = kh_begin(_functions); k != kh_end(_functions); ++k) \
if (kh_exist(_functions, k)) { \
External * f = &kh_value(_functions, k); \
body; \
} \
} while(0)
#endif // _GPU
Field allocation
If this routine is modified, do not forget to update /src/ast/interpreter/overload.h.
static void init_block_scalar (scalar sb, const char * name, const char * ext,
int n, int block)
{
char bname[strlen(name) + strlen(ext) + 10];
if (n == 0) {
strcat (strcpy (bname, name), ext);
sb.block = block;
baseblock = list_append (baseblock, sb);
}
else {
sprintf (bname, "%s%d%s", name, n, ext);
sb.block = - n;
}
sb.name = strdup (bname);
all = list_append (all, sb);
}
@define interpreter_set_int(...)
@define interpreter_reset_scalar(...)
scalar alloc_block_scalar (const char * name, const char * ext, int block)
{
interpreter_set_int (&block);
int nvar = datasize/sizeof(real);
scalar s = {0};
while (s.i < nvar) {
int n = 0;
scalar sb = s;
while (sb.i < nvar && n < block && sb.freed)
n++, sb.i++;
if (n >= block) { // found n free slots
memset (&_attribute[s.i], 0, block*sizeof (_Attributes));
for (sb.i = s.i, n = 0; n < block; n++, sb.i++) {
init_block_scalar (sb, name, ext, n, block);
interpreter_reset_scalar (sb);
}
trash (((scalar []){s, {-1}})); // fixme: only trashes one block?
return s;
}
s.i = sb.i + 1;
}
// need to allocate new slots
s = (scalar){nvar};
assert (nvar + block <= _NVARMAX);
if (_attribute == NULL)
_attribute = (_Attributes *) calloc (nvar + block + 1, sizeof (_Attributes));
else
_attribute = (_Attributes *)
realloc (_attribute, (nvar + block + 1)*sizeof (_Attributes));
memset (&_attribute[nvar], 0, block*sizeof (_Attributes));
for (int n = 0; n < block; n++, nvar++) {
scalar sb = (scalar){nvar};
init_block_scalar (sb, name, ext, n, block);
}
// allocate extra space on the grid
realloc_scalar (block*sizeof(real));
trash (((scalar []){s, {-1}})); // fixme: only trashes one block?
return s;
}
scalar new_block_scalar (const char * name, const char * ext, int block)
{
scalar s = alloc_block_scalar (name, ext, block), sb;
int n = 0;
for (sb.i = s.i, n = 0; n < block; n++, sb.i++)
init_scalar (sb, NULL);
return s;
}
scalar new_scalar (const char * name)
{
return init_scalar (alloc_block_scalar (name, "", 1), NULL);
}
scalar new_vertex_scalar (const char * name)
{
return init_vertex_scalar (alloc_block_scalar (name, "", 1), NULL);
}
static vector alloc_block_vector (const char * name, int block)
{
vector v;
struct { char * x, * y, * z; } ext = {".x", ".y", ".z"};
foreach_dimension()
v.x = alloc_block_scalar (name, ext.x, block);
return v;
}
vector new_vector (const char * name)
{
vector v = alloc_block_vector (name, 1);
init_vector (v, NULL);
return v;
}
vector new_face_vector (const char * name)
{
vector v = alloc_block_vector (name, 1);
init_face_vector (v, NULL);
return v;
}
vector new_block_vector (const char * name, int block)
{
vector v = alloc_block_vector (name, block);
for (int i = 0; i < block; i++) {
vector vb;
foreach_dimension()
vb.x.i = v.x.i + i;
init_vector (vb, NULL);
foreach_dimension()
vb.x.block = - i;
}
foreach_dimension()
v.x.block = block;
return v;
}
vector new_block_face_vector (const char * name, int block)
{
vector v = alloc_block_vector (name, block);
for (int i = 0; i < block; i++) {
vector vb;
foreach_dimension()
vb.x.i = v.x.i + i;
init_face_vector (vb, NULL);
foreach_dimension()
vb.x.block = - i;
}
foreach_dimension()
v.x.block = block;
return v;
}
tensor new_tensor (const char * name)
{
char cname[strlen(name) + 3];
struct { char * x, * y, * z; } ext = {".x", ".y", ".z"};
tensor t;
foreach_dimension() {
strcat (strcpy (cname, name), ext.x);
t.x = alloc_block_vector (cname, 1);
}
init_tensor (t, NULL);
return t;
}
tensor new_symmetric_tensor (const char * name)
{
struct { char * x, * y, * z; } ext = {".x.x", ".y.y", ".z.z"};
tensor t;
foreach_dimension()
t.x.x = alloc_block_scalar (name, ext.x, 1);
#if dimension > 1
t.x.y = alloc_block_scalar (name, ".x.y", 1);
t.y.x = t.x.y;
#endif
#if dimension > 2
t.x.z = alloc_block_scalar (name, ".x.z", 1);
t.z.x = t.x.z;
t.y.z = alloc_block_scalar (name, ".y.z", 1);
t.z.y = t.y.z;
#endif
/* fixme: boundary conditions don't work! This is because boundary
attributes depend on the index and should (but cannot) be
different for t.x.y and t.y.x */
init_tensor (t, NULL);
return t;
}
static int nconst = 0;
void init_const_scalar (scalar s, const char * name, double val)
{
if (s.i - _NVARMAX >= nconst) {
qrealloc (_constant, s.i - _NVARMAX + 1, double);
for (int i = nconst; i < s.i - _NVARMAX; i++)
_constant[i] = 0.;
nconst = s.i - _NVARMAX + 1;
}
_constant[s.i - _NVARMAX] = val;
}
scalar new_const_scalar (const char * name, int i, double val)
{
scalar s = (scalar){i + _NVARMAX};
init_const_scalar (s, name, val);
return s;
}
void init_const_vector (vector v, const char * name, double * val)
{
foreach_dimension()
init_const_scalar (v.x, name, *val++);
}
vector new_const_vector (const char * name, int i, double * val)
{
vector v;
foreach_dimension()
v.x.i = _NVARMAX + i++;
init_const_vector (v, name, val);
return v;
}
static void cartesian_scalar_clone (scalar clone, scalar src)
{
char * cname = clone.name;
BoundaryFunc * boundary = clone.boundary;
BoundaryFunc * boundary_homogeneous = clone.boundary_homogeneous;
assert (src.block > 0 && clone.block == src.block);
free (clone.depends);
_attribute[clone.i] = _attribute[src.i];
clone.name = cname;
clone.boundary = boundary;
clone.boundary_homogeneous = boundary_homogeneous;
for (int i = 0; i < nboundary; i++) {
clone.boundary[i] = src.boundary[i];
clone.boundary_homogeneous[i] = src.boundary_homogeneous[i];
}
clone.depends = list_copy (src.depends);
}
scalar * list_clone (scalar * l)
{
scalar * list = NULL;
int nvar = datasize/sizeof(real), map[nvar];
for (int i = 0; i < nvar; i++)
map[i] = -1;
for (scalar s in l) {
scalar c = s.block > 1 ? new_block_scalar("c", "", s.block) : new_scalar("c");
scalar_clone (c, s);
map[s.i] = c.i;
list = list_append (list, c);
}
for (scalar s in list)
foreach_dimension()
if (s.v.x.i >= 0 && map[s.v.x.i] >= 0)
s.v.x.i = map[s.v.x.i];
return list;
}
void delete (scalar * list)
{
if (all == NULL) // everything has already been freed
return;
for (scalar f in list) {
for (int i = 0; i < f.block; i++) {
scalar fb = {f.i + i};
if (f.delete)
f.delete (fb);
free (fb.name); fb.name = NULL;
free (fb.boundary); fb.boundary = NULL;
free (fb.boundary_homogeneous); fb.boundary_homogeneous = NULL;
free (fb.depends); fb.depends = NULL;
fb.freed = true;
}
}
if (list == all) {
all[0].i = -1;
baseblock[0].i = -1;
return;
}
trash (list);
for (scalar f in list) {
if (f.block > 0) {
scalar * s;
for (s = all; s->i >= 0 && s->i != f.i; s++);
if (s->i == f.i) {
for (; s[f.block].i >= 0; s++)
s[0] = s[f.block];
s->i = -1;
}
for (s = baseblock; s->i >= 0 && s->i != f.i; s++);
if (s->i == f.i) {
for (; s[1].i >= 0; s++)
s[0] = s[1];
s->i = -1;
}
}
}
}
void free_solver()
{
assert (_val_higher_dimension == 0.);
if (free_solver_funcs) {
free_solver_func * a = (free_solver_func *) free_solver_funcs->p;
for (int i = 0; i < free_solver_funcs->len/sizeof(free_solver_func); i++)
a[i] ();
array_free (free_solver_funcs);
}
delete (all);
free (all); all = NULL;
free (baseblock); baseblock = NULL;
for (Event * ev = Events; !ev->last; ev++) {
Event * e = ev->next;
while (e) {
Event * next = e->next;
free (e);
e = next;
}
}
free (Events); Events = NULL;
free (_attribute); _attribute = NULL;
free (_constant); _constant = NULL;
#if _GPU
foreach_function (f, free ((void *) f->externals));
kh_destroy (PTR, _functions); _functions = NULL;
#endif
free_grid();
qpclose_all();
@if TRACE
trace_off();
@endif
@if MTRACE
pmuntrace();
@endif
@if _CADNA
cadna_end();
@endif
}
// Cartesian methods
void (* boundary_level) (scalar *, int l);
void (* boundary_face) (vectorl);
#define boundary(...) \
boundary_internal ((scalar *)__VA_ARGS__, __FILE__, LINENO)
void boundary_flux (vector * list) __attribute__ ((deprecated));
void boundary_flux (vector * list)
{
vectorl list1 = {NULL};
for (vector v in list)
foreach_dimension()
list1.x = list_append (list1.x, v.x);
boundary_face (list1);
foreach_dimension()
free (list1.x);
}
static scalar * list_add_depends (scalar * list, scalar s)
{
for (scalar t in list)
if (t.i == s.i)
return list;
scalar * list1 = list;
for (scalar d in _attribute[s.i].depends)
if (d.dirty)
list1 = list_add_depends (list1, d);
return list_append (list1, s);
}
trace
void boundary_internal (scalar * list, const char * fname, int line)
{
if (list == NULL)
return;
scalar * listc = NULL;
vectorl listf = {NULL};
bool flux = false;
for (scalar s in list)
if (!is_constant(s) && s.block > 0) {
if (scalar_is_dirty (s)) {
if (s.face && s.dirty != 2)
foreach_dimension()
if (s.v.x.i == s.i)
listf.x = list_add (listf.x, s), flux = true;
if (!is_constant(cm) && cm.dirty)
listc = list_add_depends (listc, cm);
if (s.face != 2) // flux only
listc = list_add_depends (listc, s);
}
#if 0
else
fprintf (stderr, "warning: bc already applied on '%s'\n", s.name);
#endif
}
if (flux) {
boundary_face (listf);
foreach_dimension()
free (listf.x);
}
if (listc) {
#if PRINTBOUNDARY
fprintf (stderr, "boundary_internal: listc:");
for (scalar s in listc)
fprintf (stderr, " %d:%s", s.i, s.name);
fputc ('\n', stderr);
#endif
boundary_level (listc, -1);
for (scalar s in listc)
s.dirty = false;
free (listc);
}
}
void cartesian_boundary_level (scalar * list, int l)
{
boundary_iterate (level, list, l);
}
void cartesian_boundary_face (vectorl list)
{
foreach_dimension()
for (scalar s in list.x)
s.dirty = 2;
}
static double symmetry (Point point, Point neighbor, scalar s, bool * data)
{
return s[];
}
static double antisymmetry (Point point, Point neighbor, scalar s, bool * data)
{
return -s[];
}
BoundaryFunc default_scalar_bc[] = {
symmetry, symmetry, symmetry, symmetry, symmetry, symmetry
};
scalar cartesian_init_scalar (scalar s, const char * name)
{
// keep name
char * pname;
if (name) {
free (s.name);
pname = strdup (name);
}
else
pname = s.name;
int block = s.block;
BoundaryFunc * boundary = s.boundary;
BoundaryFunc * boundary_homogeneous = s.boundary_homogeneous;
s.name = pname;
if (block < 0)
s.block = block;
else
s.block = block > 0 ? block : 1;
/* set default boundary conditions */
s.boundary = boundary ? boundary : (BoundaryFunc *) malloc (nboundary*sizeof (BoundaryFunc));
s.boundary_homogeneous = boundary_homogeneous ? boundary_homogeneous :
(BoundaryFunc *) malloc (nboundary*sizeof (BoundaryFunc));
for (int b = 0; b < nboundary; b++)
s.boundary[b] = s.boundary_homogeneous[b] =
b < 2*dimension ? default_scalar_bc[b] : symmetry;
s.gradient = NULL;
foreach_dimension() {
s.d.x = 0; // not face
s.v.x.i = -1; // not a vector component
}
s.face = false;
return s;
}
scalar cartesian_init_vertex_scalar (scalar s, const char * name)
{
cartesian_init_scalar (s, name);
foreach_dimension()
s.d.x = -1;
for (int d = 0; d < nboundary; d++)
s.boundary[d] = s.boundary_homogeneous[d] = NULL;
return s;
}
BoundaryFunc default_vector_bc[] = {
antisymmetry, antisymmetry,
antisymmetry, antisymmetry,
antisymmetry, antisymmetry
};
vector cartesian_init_vector (vector v, const char * name)
{
struct { char * x, * y, * z; } ext = {".x", ".y", ".z"};
foreach_dimension() {
if (name) {
char cname[strlen(name) + 3];
strcat (strcpy (cname, name), ext.x);
cartesian_init_scalar (v.x, cname);
}
else
cartesian_init_scalar (v.x, NULL);
v.x.v = v;
}
/* set default boundary conditions */
for (int d = 0; d < nboundary; d++)
v.x.boundary[d] = v.x.boundary_homogeneous[d] =
d < 2*dimension ? default_vector_bc[d] : antisymmetry;
return v;
}
vector cartesian_init_face_vector (vector v, const char * name)
{
v = cartesian_init_vector (v, name);
foreach_dimension() {
v.x.d.x = -1;
v.x.face = true;
}
for (int d = 0; d < nboundary; d++)
v.x.boundary[d] = v.x.boundary_homogeneous[d] = NULL;
return v;
}
tensor cartesian_init_tensor (tensor t, const char * name)
{
struct { char * x, * y, * z; } ext = {".x", ".y", ".z"};
foreach_dimension() {
if (name) {
char cname[strlen(name) + 3];
strcat (strcpy (cname, name), ext.x);
cartesian_init_vector (t.x, cname);
}
else
cartesian_init_vector (t.x, NULL);
}
/* set default boundary conditions */
#if dimension == 1
for (int b = 0; b < nboundary; b++)
t.x.x.boundary[b] = t.x.x.boundary_homogeneous[b] =
b < 2*dimension ? default_scalar_bc[b] : symmetry;
#elif dimension == 2
for (int b = 0; b < nboundary; b++) {
t.x.x.boundary[b] = t.y.x.boundary[b] =
t.x.x.boundary_homogeneous[b] = t.y.y.boundary_homogeneous[b] =
b < 2*dimension ? default_scalar_bc[b] : symmetry;
t.x.y.boundary[b] = t.y.y.boundary[b] =
t.x.y.boundary_homogeneous[b] = t.y.x.boundary_homogeneous[b] =
b < 2*dimension ? default_vector_bc[b] : antisymmetry;
}
#else
assert (false); // not implemented yet
#endif
return t;
}
void output_cells (FILE * fp = stdout, coord c = {0}, double size = 0.)
{
foreach() {
bool inside = true;
coord o = {x,y,z};
foreach_dimension()
if (inside && size > 0. &&
(o.x > c.x + size || o.x < c.x - size))
inside = false;
if (inside) {
Delta /= 2.;
#if dimension == 1
fprintf (fp, "%g 0\n%g 0\n\n", x - Delta, x + Delta);
#elif dimension == 2
fprintf (fp, "%g %g\n%g %g\n%g %g\n%g %g\n%g %g\n\n",
x - Delta, y - Delta,
x - Delta, y + Delta,
x + Delta, y + Delta,
x + Delta, y - Delta,
x - Delta, y - Delta);
#else // dimension == 3
for (int i = -1; i <= 1; i += 2) {
fprintf (fp, "%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n%g %g %g\n\n",
x - Delta, y - Delta, z + i*Delta,
x - Delta, y + Delta, z + i*Delta,
x + Delta, y + Delta, z + i*Delta,
x + Delta, y - Delta, z + i*Delta,
x - Delta, y - Delta, z + i*Delta);
for (int j = -1; j <= 1; j += 2)
fprintf (fp, "%g %g %g\n%g %g %g\n\n",
x + i*Delta, y + j*Delta, z - Delta,
x + i*Delta, y + j*Delta, z + Delta);
}
#endif
}
}
fflush (fp);
}
#if TREE && _MPI
static void output_cells_internal (FILE * fp)
{
output_cells (fp);
}
#endif
static char * replace_ (const char * vname)
{
char * name = strdup (vname), * c = name;
while (*c != '\0') {
if (*c == '.')
*c = '_';
c++;
}
return name;
}
static void debug_plot (FILE * fp, const char * name, const char * cells,
const char * stencil)
{
char * vname = replace_ (name);
fprintf (fp,
" load 'debug.plot'\n"
" v=%s\n"
#if dimension == 1
" plot '%s' w l lc 0, "
"'%s' u 1+2*v:(0):2+2*v w labels tc lt 1 title columnhead(2+2*v)",
#elif dimension == 2
" plot '%s' w l lc 0, "
"'%s' u 1+3*v:2+3*v:3+3*v w labels tc lt 1 title columnhead(3+3*v)",
#elif dimension == 3
" splot '%s' w l lc 0, "
"'%s' u 1+4*v:2+4*v:3+4*v:4+4*v w labels tc lt 1"
" title columnhead(4+4*v)",
#endif
vname, cells, stencil);
free (vname);
}
void cartesian_debug (Point point)
{
char name[80] = "cells";
if (pid() > 0)
sprintf (name, "cells-%d", pid());
FILE * fp = fopen (name, "w");
output_cells (fp, (coord){x,y,z}, 4.*Delta);
fclose (fp);
char stencil[80] = "stencil";
if (pid() > 0)
sprintf (stencil, "stencil-%d", pid());
fp = fopen (stencil, "w");
for (scalar v in all)
#if dimension == 1
fprintf (fp, "x %s ", v.name);
#elif dimension == 2
fprintf (fp, "x y %s ", v.name);
#elif dimension == 3
fprintf (fp, "x y z %s ", v.name);
#endif
fputc ('\n', fp);
#if dimension == 1
for (int k = -2; k <= 2; k++) {
for (scalar v in all) {
fprintf (fp, "%g ", x + k*Delta + v.d.x*Delta/2.);
if (allocated(k))
fprintf (fp, "%g ", v[k]);
else
fputs ("n/a ", fp);
}
fputc ('\n', fp);
}
#elif dimension == 2
for (int k = -2; k <= 2; k++)
for (int l = -2; l <= 2; l++) {
for (scalar v in all) {
fprintf (fp, "%g %g ",
x + k*Delta + v.d.x*Delta/2.,
y + l*Delta + v.d.y*Delta/2.);
if (allocated(k,l))
fprintf (fp, "%g ", v[k,l]);
else
fputs ("n/a ", fp);
}
fputc ('\n', fp);
}
#elif dimension == 3
for (int k = -2; k <= 2; k++)
for (int l = -2; l <= 2; l++)
for (int m = -2; m <= 2; m++) {
for (scalar v in all) {
fprintf (fp, "%g %g %g ",
x + k*Delta + v.d.x*Delta/2.,
y + l*Delta + v.d.y*Delta/2.,
z + m*Delta + v.d.z*Delta/2.);
if (allocated(k,l,m))
fprintf (fp, "%g ", v[k,l,m]);
else
fputs ("n/a ", fp);
}
fputc ('\n', fp);
}
#endif
fclose (fp);
fp = fopen ("debug.plot", "w");
fprintf (fp,
"set term x11\n"
"set size ratio -1\n"
"set key outside\n");
for (scalar s in all) {
char * name = replace_ (s.name);
fprintf (fp, "%s = %d\n", name, s.i);
free (name);
}
fclose (fp);
fprintf (stderr, "Last point stencils can be displayed using (in gnuplot)\n");
debug_plot (stderr, _attribute[0].name, name, stencil);
fflush (stderr);
fp = fopen ("plot", "w");
debug_plot (fp, _attribute[0].name, name, stencil);
fclose (fp);
}
void cartesian_methods()
{
init_scalar = cartesian_init_scalar;
init_vertex_scalar = cartesian_init_vertex_scalar;
init_vector = cartesian_init_vector;
init_face_vector = cartesian_init_face_vector;
init_tensor = cartesian_init_tensor;
boundary_level = cartesian_boundary_level;
boundary_face = cartesian_boundary_face;
scalar_clone = cartesian_scalar_clone;
debug = cartesian_debug;
}
tensor init_symmetric_tensor (tensor t, const char * name)
{
return init_tensor (t, name);
}
static double interpolate_linear (Point point, scalar v,
double xp = 0., double yp = 0., double zp = 0.)
{
#if dimension == 1
x = (xp - x)/Delta - v.d.x/2.;
int i = sign(x);
x = fabs(x);
/* linear interpolation */
return v[]*(1. - x) + v[i]*x;
#elif dimension == 2
x = (xp - x)/Delta - v.d.x/2.;
y = (yp - y)/Delta - v.d.y/2.;
int i = sign(x), j = sign(y);
x = fabs(x); y = fabs(y);
/* bilinear interpolation */
return ((v[]*(1. - x) + v[i]*x)*(1. - y) +
(v[0,j]*(1. - x) + v[i,j]*x)*y);
#else // dimension == 3
x = (xp - x)/Delta - v.d.x/2.;
y = (yp - y)/Delta - v.d.y/2.;
z = (zp - z)/Delta - v.d.z/2.;
int i = sign(x), j = sign(y), k = sign(z);
x = fabs(x); y = fabs(y); z = fabs(z);
/* trilinear interpolation */
return (((v[]*(1. - x) + v[i]*x)*(1. - y) +
(v[0,j]*(1. - x) + v[i,j]*x)*y)*(1. - z) +
((v[0,0,k]*(1. - x) + v[i,0,k]*x)*(1. - y) +
(v[0,j,k]*(1. - x) + v[i,j,k]*x)*y)*z);
#endif
}
trace
double interpolate (scalar v, double xp = 0., double yp = 0., double zp = 0.,
bool linear = true)
{
double val = nodata;
foreach_point (xp, yp, zp, reduction (min:val))
val = linear ? interpolate_linear (point, v, xp, yp, zp) : v[];
return val;
}
trace
void interpolate_array (scalar * list, coord * a, int n, double * v,
bool linear = false)
{
int len = 0;
for (scalar s in list)
len++;
for (int i = 0; i < n; i++) {
double * w = v;
#if _GPU
coord p = a[i];
for (scalar s in list) {
double value = nodata;
foreach_point (p.x, p.y, p.z, reduction(min:value))
value = !linear ? s[] : interpolate_linear (point, s, p.x, p.y, 0.);
*(w++) = value;
}
#else // !_GPU
for (scalar s in list)
*(w++) = nodata;
foreach_point (a[i].x, a[i].y, a[i].z, reduction(min:v[:len])) {
int j = 0;
for (scalar s in list)
v[j++] = !linear ? s[] : interpolate_linear (point, s, a[i].x, a[i].y, a[i].z);
}
#endif // !_GPU
v = w;
}
}
// Boundaries
typedef int bid;
bid new_bid()
{
int b = nboundary++;
for (scalar s in all) {
s.boundary = (BoundaryFunc *) realloc (s.boundary, nboundary*sizeof (BoundaryFunc));
s.boundary_homogeneous = (BoundaryFunc *)
realloc (s.boundary_homogeneous, nboundary*sizeof (BoundaryFunc));
}
for (scalar s in all) {
if (s.v.x.i < 0) // scalar
s.boundary[b] = s.boundary_homogeneous[b] = symmetry;
else if (s.v.x.i == s.i) { // vector
vector v = s.v;
foreach_dimension()
v.y.boundary[b] = v.y.boundary_homogeneous[b] = symmetry;
v.x.boundary[b] = v.x.boundary_homogeneous[b] =
v.x.face ? NULL : antisymmetry;
}
}
return b;
}
// Periodic boundary conditions
static double periodic_bc (Point point, Point neighbor, scalar s, bool * data)
{
return s[];
}
static void periodic_boundary (int d)
{
/* We change the conditions for existing scalars. */
for (scalar s in all)
if (is_vertex_scalar (s))
s.boundary[d] = s.boundary_homogeneous[d] = NULL;
else
s.boundary[d] = s.boundary_homogeneous[d] = periodic_bc;
/* Normal components of face vector fields should remain NULL. */
for (scalar s in all)
if (s.face) {
vector v = s.v;
v.x.boundary[d] = v.x.boundary_homogeneous[d] = NULL;
}
/* We also change the default boundary conditions (for new fields). */
default_scalar_bc[d] = periodic_bc;
default_vector_bc[d] = periodic_bc;
}
void periodic (int dir)
{
#if dimension < 2
assert (dir <= left);
#elif dimension < 3
assert (dir <= bottom);
#else
assert (dir <= back);
#endif
// This is the component in the given direction i.e. 0 for x and 1 for y
int c = dir/2;
periodic_boundary (2*c);
periodic_boundary (2*c + 1);
(&Period.x)[c] = true;
}
// for debugging
double getvalue (Point point, scalar s, int i, int j, int k)
{
return s[i,j,k];
}
void default_stencil (Point p, scalar * list)
{
for (scalar s in list)
s.input = true, s.width = 2;
}
This displays a (1D,2D,3D) stencil index.
static void write_stencil_index (int * index)
{
fprintf (qstderr(), "[%d", index[0]);
for (int d = 1; d < dimension; d++)
fprintf (qstderr(), ",%d", index[d]);
fputs ("]", qstderr());
}
void stencil_val (Point p, scalar s, int i, int j, int k,
const char * file, int line, bool overflow)
{
if (is_constant(s) || s.i < 0)
return;
int index[] = {i, j, k};
for (int d = 0; d < dimension; d++)
index[d] += (&p.i)[d];
bool central = true;
for (int d = 0; d < dimension; d++) {
if (!overflow && (index[d] > 2 || index[d] < - 2)) {
fprintf (qstderr(), "%s:%d: error: stencil overflow: %s",
file, line, s.name);
write_stencil_index (index);
fprintf (qstderr(), "\n");
fflush (qstderr());
abort();
}
if (index[d] != 0)
central = false;
}
if (central) {
if (!s.output)
s.input = true;
}
else {
s.input = true;
int d = 0;
foreach_dimension() {
if ((!s.face || s.v.x.i != s.i) && abs(index[d]) > s.width)
s.width = abs(index[d]);
d++;
}
}
}
void stencil_val_a (Point p, scalar s, int i, int j, int k, bool input,
const char * file, int line)
{
if (is_constant(s) || s.i < 0)
abort();
int index[] = {i, j, k};
for (int d = 0; d < dimension; d++)
index[d] += (&p.i)[d];
for (int d = 0; d < dimension; d++)
if (index[d] != 0) {
fprintf (qstderr(), "%s:%d: error: illegal write: %s",
file, line, s.name);
write_stencil_index (index);
fprintf (qstderr(), "\n");
fflush (qstderr());
abort();
}
if (input && !s.output)
s.input = true;
s.output = true;
}
Macros overloaded by the interpreter.
@define dimensional(...)
#define show_dimension(...) show_dimension_internal (__VA_ARGS__ + 10293847566574839201.)
@define show_dimension_internal(...)
@define display_value(...)
@define interpreter_verbosity(...)