#if SINGLE_PRECISION
typedef float real;
#else
typedef double real;
#endif
#ifndef GRIDNAME
# define GRIDNAME "Cartesian"
#endif
#define dimension 2
#define GHOSTS 1
#define _I (point.i - 1)
#define _J (point.j - 1)
#define _DELTA (1./(real)N)
typedef struct {
Grid g;
char * d;
int n;
} Cartesian;
struct _Point {
int i, j, level, n;
#if LAYERS
int l;
@define _BLOCK_INDEX , point.l
#else
@define _BLOCK_INDEX
#endif
};
static Point last_point;
#define cartesian ((Cartesian *)grid)
@undef val
@define val(a,k,l,m) (((real *)cartesian->d)[(point.i + k + _index(a,m)*(size_t)(point.n + 2))*(point.n + 2) + point.j + l])
@define allocated(...) true
macro POINT_VARIABLES (Point point = point) { VARIABLES(); }
macro2 foreach (char flags = 0, Reduce reductions = None)
{
OMP_PARALLEL (reductions) {
int ig = 0, jg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg);
Point point = {0};
point.n = cartesian->n;
int _k;
OMP(omp for schedule(static))
for (_k = 1; _k <= point.n; _k++) {
point.i = _k;
for (point.j = 1; point.j <= point.n; point.j++)
{...}
}
}
}
macro2 foreach_face_generic (char flags = 0, Reduce reductions = None,
const char * order = "xyz")
{
OMP_PARALLEL (reductions) {
int ig = 0, jg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg);
Point point = {0};
point.n = cartesian->n;
int _k;
OMP(omp for schedule(static))
for (_k = 1; _k <= point.n + 1; _k++) {
point.i = _k;
for (point.j = 1; point.j <= point.n + 1; point.j++)
{...}
}
}
}
#define foreach_edge() foreach_face(y,x)
macro1 is_face_x (Point p = point) {
if (p.j <= p.n) {
int ig = -1; NOT_UNUSED(ig);
{...}
}
}
macro1 is_face_y (Point p = point) {
if (p.i <= p.n) {
int jg = -1; NOT_UNUSED(jg);
{...}
}
}
@if TRASH
@ undef trash
@ define trash(list) reset(list, undefined)
@endif
#include "neighbors.h"
void reset (void * alist, double val)
{
scalar * list = (scalar *) alist;
size_t len = sq(cartesian->n + 2);
for (scalar s in list)
if (!is_constant(s))
for (size_t i = 0; i < len; i++)
((real *)cartesian->d)[i + s.i*len] = val;
}
// Boundaries
macro2 foreach_boundary_dir (int l, int d)
{
OMP_PARALLEL() {
int ig = 0, jg = 0, kg = 0; NOT_UNUSED(ig); NOT_UNUSED(jg); NOT_UNUSED(kg);
Point point = {0};
point.n = cartesian->n;
int * _i = &point.j;
if (d == left) {
point.i = GHOSTS;
ig = -1;
}
else if (d == right) {
point.i = point.n + GHOSTS - 1;
ig = 1;
}
else if (d == bottom) {
point.j = GHOSTS;
_i = &point.i;
jg = -1;
}
else if (d == top) {
point.j = point.n + GHOSTS - 1;
_i = &point.i;
jg = 1;
}
int _l;
OMP(omp for schedule(static))
for (_l = 0; _l < point.n + 2*GHOSTS; _l++) {
*_i = _l;
{...}
}
}
}
@define neighbor(o,p,q) ((Point){point.i+o, point.j+p, point.level, point.n})
@def is_boundary(point) (point.i < GHOSTS || point.i >= point.n + GHOSTS ||
point.j < GHOSTS || point.j >= point.n + GHOSTS)
@
// ghost cell coordinates for each direction
static int _ig[] = {1,-1,0,0}, _jg[] = {0,0,1,-1};
static void box_boundary_level_normal (const Boundary * b, scalar * list, int l)
{
int d = ((BoxBoundary *)b)->d;
OMP_PARALLEL() {
Point point = {0};
int ig, jg;
point.n = cartesian->n;
if (d % 2)
ig = jg = 0;
else {
ig = _ig[d]; jg = _jg[d];
}
int _start = GHOSTS, _end = point.n + GHOSTS, _k;
OMP(omp for schedule(static))
for (_k = _start; _k < _end; _k++) {
point.i = d > left ? _k : d == right ? point.n + GHOSTS - 1 : GHOSTS;
point.j = d < top ? _k : d == top ? point.n + GHOSTS - 1 : GHOSTS;
Point neighbor = {point.i + ig, point.j + jg};
for (scalar s in list) {
scalar b = s.v.x;
val(s,ig,jg) = b.boundary[d] (point, neighbor, s, NULL);
}
}
}
}
static void box_boundary_level_tangent (const Boundary * b,
scalar * list, int l)
{
int d = ((BoxBoundary *)b)->d;
OMP_PARALLEL() {
Point point = {0};
point.n = cartesian->n;
int ig = _ig[d], jg = _jg[d];
int _start = GHOSTS, _end = point.n + 2*GHOSTS, _k;
OMP(omp for schedule(static))
for (_k = _start; _k < _end; _k++) {
point.i = d > left ? _k : d == right ? point.n + GHOSTS - 1 : GHOSTS;
point.j = d < top ? _k : d == top ? point.n + GHOSTS - 1 : GHOSTS;
Point neighbor = {point.i + ig, point.j + jg};
for (scalar s in list) {
scalar b = s.v.y;
val(s,ig,jg) = b.boundary[d] (point, neighbor, s, NULL);
}
}
}
}
extern double (* default_scalar_bc[]) (Point, Point, scalar, bool *);
static double periodic_bc (Point point, Point neighbor, scalar s, bool * data);
macro2 foreach_boundary (int b)
{
if (default_scalar_bc[b] != periodic_bc)
foreach_boundary_dir (depth(), b)
if (!is_boundary(point))
{...}
}
static void box_boundary_level (const Boundary * b, scalar * list, int l)
{
int d = ((BoxBoundary *)b)->d;
scalar * centered = NULL, * normal = NULL, * tangent = NULL;
int component = d/2;
for (scalar s in list)
if (!is_constant(s)) {
if (s.face) {
if ((&s.d.x)[component]) {
scalar b = s.v.x;
if (b.boundary[d] && b.boundary[d] != periodic_bc)
normal = list_add (normal, s);
}
else {
scalar b = s.v.y;
if (b.boundary[d] && b.boundary[d] != periodic_bc)
tangent = list_add (tangent, s);
}
}
else if (s.boundary[d] && s.boundary[d] != periodic_bc)
centered = list_add (centered, s);
}
OMP_PARALLEL() {
Point point = {0};
point.n = cartesian->n;
int ig = _ig[d], jg = _jg[d];
int _start = 1, _end = point.n, _k;
/* traverse corners only for top and bottom */
if (d > left) { _start--; _end++; }
OMP(omp for schedule(static))
for (_k = _start; _k <= _end; _k++) {
point.i = d > left ? _k : d == right ? point.n : 1;
point.j = d < top ? _k : d == top ? point.n : 1;
Point neighbor = {point.i + ig, point.j + jg};
for (scalar s in centered) {
scalar b = (s.v.x.i < 0 ? s :
s.i == s.v.x.i && d < top ? s.v.x :
s.i == s.v.y.i && d >= top ? s.v.x :
s.v.y);
val(s,ig,jg) = b.boundary[d] (point, neighbor, s, NULL);
}
}
}
free (centered);
box_boundary_level_normal (b, normal, l);
free (normal);
box_boundary_level_tangent (b, tangent, l);
free (tangent);
}
/* Periodic boundaries */
#if !_MPI
@define VT _attribute[s.i].v.y
foreach_dimension()
static void periodic_boundary_level_x (const Boundary * b, scalar * list, int l)
{
scalar * list1 = NULL;
for (scalar s in list)
if (!is_constant(s) && s.block > 0) {
if (s.face) {
scalar vt = VT;
if (vt.boundary[right] == periodic_bc)
list1 = list_add (list1, s);
}
else if (s.boundary[right] == periodic_bc)
list1 = list_add (list1, s);
}
if (!list1)
return;
OMP_PARALLEL() {
Point point = {0};
point.n = cartesian->n;
int j;
OMP(omp for schedule(static))
for (j = 0; j < point.n + 2*GHOSTS; j++) {
for (int i = 0; i < GHOSTS; i++)
for (scalar s in list1)
memcpy (&s[i,j], &s[i + point.n,j], s.block*sizeof(real));
for (int i = point.n + GHOSTS; i < point.n + 2*GHOSTS; i++)
for (scalar s in list1)
memcpy (&s[i,j], &s[i - point.n,j], s.block*sizeof(real));
}
}
free (list1);
}
@undef VT
#endif // !_MPI
void free_grid (void)
{
if (!grid)
return;
free_boundaries();
free (cartesian->d);
free (cartesian);
grid = NULL;
}
void init_grid (int n)
{
if (cartesian && n == cartesian->n)
return;
free_grid();
Cartesian * p = qmalloc (1, Cartesian);
size_t len = sq((size_t)n + 2)*datasize;
p->n = N = n;
p->d = qmalloc (len, char);
grid = (Grid *) p;
reset (all, 0.);
for (int d = 0; d < nboundary; d++) {
BoxBoundary * box = qcalloc (1, BoxBoundary);
box->d = d;
Boundary * b = (Boundary *) box;
b->level = box_boundary_level;
add_boundary (b);
}
// periodic boundaries
foreach_dimension() {
Boundary * b = qcalloc (1, Boundary);
b->level = periodic_boundary_level_x;
add_boundary (b);
}
// mesh size
grid->n = grid->tn = sq((size_t)n);
}
void realloc_scalar (int size)
{
Cartesian * p = cartesian;
datasize += size;
qrealloc (p->d, sq((size_t)p->n + 2)*datasize, char);
}
Point locate (double xp = 0, double yp = 0, double zp = 0)
{
Point point;
point.n = cartesian->n;
point.i = (xp - X0)/L0*point.n + 1;
point.j = (yp - Y0)/L0*point.n + 1;
point.level = (point.i >= 1 && point.i <= point.n &&
point.j >= 1 && point.j <= point.n) ? 0 : - 1;
return point;
}
#include "variables.h"
#if !_GPU
#include "cartesian-common.h"
#endif
macro2 foreach_vertex (char flags = 0, Reduce reductions = None)
{
foreach_face_generic (flags, reductions) {
int ig = -1, jg = -1; NOT_UNUSED(ig); NOT_UNUSED(jg);
{...}
}
}