sandbox/cselcuk/dlmfd_functions.h
Helper functions for the fictitious-domain method with distributed
Lagrangian multipliers.
Structure for the coordinates of the fictitious domain’s boundary.
typedef struct {
double *x;
double *y;
double *z;
int m;
int nm;
} SolidBodyBoundary;
Geometric parameters of the particle.
typedef struct {
;
coord centerdouble radius;
int ncorners, allPoints, allFaces;
double ** cornersCoord;
long int ** cornersIndex;
long int * numPointsOnFaces;
/*3 principals vectors of the cube */
, v1, w1;
coord u1, maxs;
coord mins
} GeomParameter;
typedef struct {
SolidBodyBoundary s;
GeomParameter g;
GeomParameter gnm1;
#if DLM_Moving_particle
double kn, en, vzero, wished_ratio;
;
coord normalvector;
coord gravitydouble M, Ip[6], rho_s, Vp, DLMFD_couplingfactor;
#if TRANSLATION
, Unm1, qU, tU;
coord U#endif
#if ROTATION
, wnm1, qw, tw;
coord w#endif
#endif
size_t pnum, iswall, iscube;
, wallmin, wallpos;
coord wallmax, imposedw;
coord imposedUCache Interior;
Cache reduced_domain;
;
coord adforcelong tcells, tmultipliers;
} particle;
Function that allocates in memory the SolidBodyBoundary structure.
void allocate_SolidBodyBoundary (SolidBodyBoundary *sbm, const int m) {
->x = (double*) calloc( m, sizeof(double));
sbm->y = (double*) calloc( m, sizeof(double));
sbm
if ( dimension == 3 )
->z = (double*) calloc( m, sizeof(double));
sbm
else->z = NULL;
sbm
->m = m;
sbm}
void reallocate_SolidBodyBoundary (SolidBodyBoundary *sbm, const int m) {
->x = (double*) realloc (sbm->x, m*sizeof(double));
sbm->y = (double*) realloc (sbm->y, m*sizeof(double));
sbm
if (dimension == 3)
->z = (double*) realloc (sbm->z, m*sizeof(double));
sbm
->m = m;
sbm}
Function that de-allocates in memory the SolidBodyBoundary structure.
void free_SolidBodyBoundary (SolidBodyBoundary *sbm) {
free(sbm->x); sbm->x = NULL;
free(sbm->y); sbm->y = NULL;
if ( dimension == 3 ){free(sbm->z); sbm->z = NULL;}
}
Function that allocates an initial Cache structure
void allocate_Cache (Cache * p) {
->n = 0;
p->nm = 0;
pif (p->n >= p->nm) {
->p = (Index *) calloc (5, sizeof(int));
p}
}
Set of functions for the sphere/circle as fictitious domain
void compute_nboundary (const GeomParameter gcp, int * nb) {
[6];
coord posCache poscache = {0};
;
Point lpoint
[0].x = gcp.center.x + gcp.radius + X0;
pos[0].y = gcp.center.y + Y0;
pos
[1].x = gcp.center.x - gcp.radius + X0;
pos[1].y = gcp.center.y + Y0;
pos
[2].x = gcp.center.x + X0;
pos[2].y = gcp.center.y + gcp.radius + Y0;
pos
[3].x = gcp.center.x + X0;
pos[3].y = gcp.center.y - gcp.radius + Y0;
pos
#if dimension == 3
[0].z = gcp.center.z + Z0;
pos[1].z = gcp.center.z + Z0;
pos[2].z = gcp.center.z + Z0;
pos[3].z = gcp.center.z + Z0;
pos[4].x = gcp.center.x + X0;
pos[4].y = gcp.center.y + Y0;
pos
[4].z = gcp.center.z + gcp.radius + Z0;
pos[5].x = gcp.center.x + X0;
pos[5].y = gcp.center.y + Y0;
pos[5].z = gcp.center.z - gcp.radius + Z0;
pos#endif
*nb = 0;
.level = -1;
lpointint ip = 0;
/* We assume that around the sphere at least one point has to be at
maximum level of refinement. */
for (ip = 0; ip < dimension*2; ip++) {
#if dimension == 3
= locate (pos[ip].x, pos[ip].y, pos[ip].z);
lpoint #elif dimension ==2
= locate (pos[ip].x, pos[ip].y);
lpoint #endif
if (lpoint.level == depth())
break;
}
Multiple threads can have a different point at the same level of refinement. This is fine, they will do the same computation for *nb. This problem does not exist in serial but the code below still works.
if (lpoint.level == depth()) {
Only this thread creates the Cache …
cache_append(&poscache, lpoint, 0);
and only this thread computes the number of boundary points …
foreach_cache(poscache) {
#if dimension == 2
*nb += (int){floor(gcp.radius*2*pi/(sqrt(2)*Delta))};
/* Debug periodic boundaries, we use only one multiplier */
/* *nb =1.; */
#elif dimension == 3
*nb += (int){floor(pow( 3.809 * gcp.radius / (sqrt(3)*Delta), 2.))};
#endif
}
and finally, this thread destroys the cache.
free(poscache.p);
}
#if _MPI
(MPI_COMM_WORLD);
MPI_Barrier(*nb, MPI_INT, MPI_MAX);
mpi_all_reduce #endif
if(*nb == 0)
printf("nboundary = 0: No boundary points !!!\n");
}
void create_FD_Interior_Particle (particle * p, vector Index_lambda, vector shift, scalar flag) {
GeomParameter gci = p->g;
Cache * fd = &(p->Interior);
Create the cache for the interior points
foreach() {
#if dimension == 2
if ((sq(x - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambda}
if (Period.x) {
if ((sq(x - L0 - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambdaif ((int)Index_lambda.y[] == p->pnum)
.x[] = L0;
shift}
if ((sq(x + L0 - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambdaif ((int)Index_lambda.y[] == p->pnum)
.x[] = -L0;
shift}
}
if (Period.y) {
if ((sq(x - (gci.center.x + X0)) + sq(y - L0 - (gci.center.y + Y0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.y[] = L0;
shift}
}
if ((sq(x - (gci.center.x + X0)) + sq(y + L0 - (gci.center.y + Y0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.y[] = -L0;
shift}
}
}
#endif
#if dimension == 3
if ((sq(x - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0)) + sq(z - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambda}
if (Period.x) {
if ((sq(x - L0 - (gci.center.x + X0) ) + sq(y - (gci.center.y + Y0)) + sq(z - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambdaif ((int)Index_lambda.y[] == p->pnum)
.x[] = L0;
shift}
if ((sq(x + L0 - (gci.center.x + X0) ) + sq(y - (gci.center.y + Y0)) + sq(z - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambdaif ((int)Index_lambda.y[] == p->pnum)
.x[] = -L0;
shift}
}
if (Period.y) {
if ((sq(x - (gci.center.x + X0)) + sq(y - L0 - (gci.center.y + Y0)) + sq(z - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.y[] = L0;
shift}
}
if ((sq(x - (gci.center.x + X0)) + sq(y + L0 - (gci.center.y + Y0)) + sq(z - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.y[] = -L0;
shift}
}
}
if (Period.z) {
if ((sq(x - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0)) + sq(z - L0 - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.z[] = L0;
shift}
}
if ((sq(x - (gci.center.x + X0)) + sq(y - (gci.center.y + Y0)) + sq(z + L0 - (gci.center.z + Z0))) < sq(gci.radius)) {
cache_append (fd, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1) {
.y[] = p->pnum;
Index_lambdaif (flag[] < 1)
.z[] = -L0;
shift}
}
}
#endif
}
cache_shrink (fd);
}
void create_FD_Boundary_Particle (GeomParameter gcp, SolidBodyBoundary * dlm_bd, const int nsphere, vector pshift) {
int m = nsphere;
;
coord pos;
Point lpoint
= {0., 0., 0.};
coord shift = {X0, Y0, Z0};
coord ori
#if dimension == 2
int i;
double theta[m];
double radius = gcp.radius;
[m];
coord fact_theta
for (i = 0; i < m; i++) {
[i] = i*2*pi/m;
theta[i].x = cos (theta[i]);
fact_theta[i].y = sin (theta[i]);
fact_theta
/* Assign positions x,y on a circle's boundary */
.x = radius*fact_theta[i].x + gcp.center.x + X0;
pos.y = radius*fact_theta[i].y + gcp.center.y + Y0;
pos
/* Check if the point falls outside of the domain */
foreach_dimension() {
if (Period.x) {
.x = 0.;
shiftif (pos.x > (L0 + ori.x)) {
.x -= L0;
pos.x = -L0;
shift}
if (pos.x < (0. + ori.x)) {
.x += L0;
pos.x = L0;
shift}
}
->x[i] = pos.x;
dlm_bd}
Cache poscache = {0};
= locate (pos.x, pos.y);
lpoint
if (lpoint.level > -1) {
cache_append (&poscache, lpoint, 0);
foreach_cache (poscache) {
foreach_dimension() {
.x[] = shift.x;
pshift}
}
free (poscache.p);
}
}
#elif dimension == 3
/* Lay out points on a sphere with a Z oriented spiral scheme */
/* This portion of code is recovered from Peligriff and adapted */
/* More information of this method can be found at: */
/* Saff, E. & Kuijlaars, A. Distributing many points on a sphere The
Mathematical Intelligencer, 1997 */
double spiral_spacing_correction = 0;
(depth())
foreach_level= 2.*Delta/sqrt(3.);
spiral_spacing_correction
double hydro_radius = gcp.radius;
size_t k;
/* Number of points */
size_t NSpiral = m;
/* Spiral points construction */
double hk, thetak, phik, phikm1 = 0., TwoPi = 2. * pi,
= 3.6 / sqrt( NSpiral ), dphi = 0.;
Cspiral
for (k = 0; k < NSpiral; ++k) {
= - 1. + 2. * (double)(k) / ( NSpiral - 1. );
hk = acos( hk ) ;
thetak if ( k == 0 ) {
= 0.;
phik = pi - 0.5 * spiral_spacing_correction / hydro_radius ;
thetak }
else if ( k == NSpiral - 1 ) {
= phikm1 + 1. * dphi;
phik if ( phik > TwoPi ) phik -= TwoPi ;
= 0.5 * spiral_spacing_correction / hydro_radius ;
thetak }
else {
= Cspiral / sqrt( 1. - hk * hk ) ;
dphi = phikm1 + dphi ;
phik if ( phik > TwoPi ) phik -= TwoPi ;
}
= phik ;
phikm1
if ( k == 1 ) thetak -= 0.4 * spiral_spacing_correction / hydro_radius ;
if ( k == NSpiral - 2 ) {
-= 0.1 * dphi ;
phik += 0.25 * spiral_spacing_correction / hydro_radius ;
thetak }
.x = hydro_radius * cos( phik ) * sin( thetak ) + gcp.center.x + X0;
pos.y = hydro_radius * sin( phik ) * sin( thetak ) + gcp.center.y + Y0;
pos.z = hydro_radius * cos( thetak ) + gcp.center.z + Z0;
pos
foreach_dimension() {
if (Period.x) {
.x = 0.;
shiftif (pos.x > (L0 + ori.x)) {
.x -= L0;
pos.x = -L0;
shift}
if (pos.x < (0. + ori.x)) {
.x += L0;
pos.x = L0;
shift}
}
}
Cache poscache = {0};
/* find the cell of this multiplier */
= locate (pos.x, pos.y, pos.z);
lpoint
if (lpoint.level > -1) {
cache_append(&poscache, lpoint, 0);
foreach_cache(poscache) {
foreach_dimension() {
.x[] = shift.x;
pshift}
}
free(poscache.p);
}
->x[k] = pos.x;
dlm_bd->y[k] = pos.y;
dlm_bd->z[k] = pos.z;
dlm_bd
}
#endif
boundary((scalar*){pshift});
}
Set of functions for the walls as fictitious domain
void create_FD_Interior_Wall (particle *p, vector index, scalar flag) {
, wallmax;
coord wallminCache * c;
Create the cache of the interior points for a wall
= &(p->Interior);
c = p->wallmin;
wallmin = p->wallmax;
wallmax foreach() {
#if dimension == 2
if ((x >= wallmin.x) && (y >= wallmin.y) && (x <= wallmax.x) && (y <= wallmax.y)) {
.y[] = p->pnum;
indexcache_append (c, point, 0);
}
#elif dimension == 3
if ((x > wallmin.x) && (y > wallmin.y) && (z > wallmin.z) && (x < wallmax.x) && (y < wallmax.y) && (z < wallmax.z)) {
if ((int)index.y[] == -1 && flag[] < 1)
.y[] = p->pnum;
indexcache_append (c, point, 0);
}
#endif
}
cache_shrink (c);
}
void create_FD_Boundary_Wall (particle *p) {
SolidBodyBoundary * sbm;
int m = 0;
;
coord wallpos
double h = 0;
(depth())
foreach_level= Delta;
h
= &(p->s);
sbm = sbm->m;
m = p->wallpos;
wallpos for (int i = 0; i < m; i++) {
->x[i] = (3.*h/4.) + i*h;
sbm->y[i] = wallpos.y;
sbm}
for (int i = m/2; i < m; i++) {
->x[i] -= h/2.;
sbm}
}
void compute_nboundary_Wall (coord wallpos, int * nb) {
double mindelta = 0.;
(depth())
foreach_level= Delta;
mindelta
*nb = floor(wallpos.x/mindelta);
}
Set of functions for the cube as fictitious domain
void compute_nboundary_Cube_v2 (GeomParameter * gcp, int * nb, int * lN) {
Cache poscache = {0};
;
Point lpoint*nb = 0;
= {0., 0., 0.};
coord pos int ip = 0;
while (*nb == 0) {
.x = gcp->cornersCoord[ip][0];
pos.y = gcp->cornersCoord[ip][1];
pos
#if dimension == 3
.z = gcp->cornersCoord[ip][2];
pos= locate(pos.x, pos.y, pos.z);
lpoint #elif dimension ==2
= locate(pos.x, pos.y);
lpoint #endif
Only one thread has the point in its domain (works in serial too).
if (lpoint.level > -1) {
Only this thread creates the Cache …
cache_append(&poscache, lpoint, 0);
and only this thread computes the number of boundary points …
/* Grains sends an equivalent radius that is multiplied by sqrt(3)/2 */
double lengthedge = 2.*(gcp->radius)/sqrt(3.);
/* printf ("lengthedge = %f on thread %d\n", lengthedge, pid() ); */
foreach_cache (poscache) {
*lN = floor (sqrt(3.)*lengthedge/(2.*Delta));
}
#if dimension == 2
/* number of points required for the 4 edges of the square */
*nb += (*lN-2)*4;
/* number of points required for the face */
*nb += (*lN-2)*(*lN-2);
/* number of points required for the 4 corners */
*nb += 4;
#elif dimension == 3
/* number of points required for the 12 edges of the cube */
*nb += (*lN-2)*12;
/* number of points required for the 6 faces of the cube */
*nb += 6*(*lN-2)*(*lN-2);
/* number of points required for the 8 corners */
*nb += 8;
#endif
and finally, this thread destroys the cache.
free(poscache.p);
}
#if _MPI
(MPI_COMM_WORLD);
MPI_Barrier(*nb, MPI_INT, MPI_MAX);
mpi_all_reduce(*lN, MPI_INT, MPI_MAX);
mpi_all_reduce#endif
if (ip < gcp->ncorners)
++;
ip
elsebreak;
}
/* printf("lN number of points for a complete edge:%d\n",*lN); */
if (*nb == 0)
fprintf(stderr,"nboundary = 0: No boundary points for the cube/square !!!\n");
}
void distribute_points_edge_Cube_v2 (coord const corner1, coord const corner2, SolidBodyBoundary * dlm_bd, int const lN, int const istart) {
# if dimension == 3
if (lN > 0) {
;
coord dinc
foreach_dimension() {
.x = (corner2.x - corner1.x)/(lN-1);
dinc}
/* printf( "length edge corner to corner = %f\n", sqrt( sq(corner2.x - corner1.x) + sq(corner2.y - corner1.y)+ sq(corner2.z - corner1.z))); */
for (int i = 1; i <= lN-2; i++) {
->x[istart + i -1] = corner1.x + (double)i * dinc.x;
dlm_bd->y[istart + i -1] = corner1.y + (double)i * dinc.y;
dlm_bd->z[istart + i -1] = corner1.z + (double)i * dinc.z;
dlm_bd}
}
#endif
}
bool is_it_in_cube_v2 (coord * u, coord * v, coord * w, coord * mins, coord * maxs, coord * checkpt) {
/* a point x with coord (x,y,z) lies in the rectangle if the 3
following conditions are satisfied */
/* 1- u.p0 <= u.x <= u.p3 */
/* 2- v.p0 <= v.x <= v.p1 */
/* 3- w.p0 <= w.w <= w.p4 */
double x = checkpt->x;
double y = checkpt->y;
double z = checkpt->z;
double checkval = 0.;
= *u;
coord u1 = *v;
coord v1 = *w;
coord w1 = {0., 0., 0.};
coord cpt bool isin = false;
= u1.x*x + u1.y*y + u1.z*z;
checkval .x = checkval;
cpt
= v1.x*x + v1.y*y + v1.z*z;
checkval .y = checkval;
cpt
= w1.x*x + w1.y*y + w1.z*z;
checkval .z = checkval;
cpt
if ((cpt.x >= maxs->x) && (cpt.x <= mins->x) && (cpt.y >= maxs->y) && (cpt.y <= mins->y) && (cpt.z >= maxs->z) && (cpt.z <= mins->z) )
{
= true;
isin }
return isin;
}
void compute_principal_vectors_Cubes (particle * p) {
GeomParameter * gcp = &(p->g);
int nfaces = gcp->allFaces;
int npoints;
/* get the 3 directions u1, u2, u3 of the cube with such that */
/* u1 = corner0 - corner3; */
/* u2 = corner0 - corner1; */
/* u3 = corner0 - corner4; */
= {0, 0, 0}, corner1 = {0, 0, 0}, corner3 = {0, 0, 0}, corner4 = {0, 0, 0};
coord corner0 , v1, w1;
coord u1, maxs;
coord mins
/* find the coordinates of these 4 corners */
for (int i = 0; i < nfaces; i++) {
= gcp->numPointsOnFaces[i];
npoints
for (int j = 0; j < npoints; j++) {
/* printf("index = %lu\n", gcp->cornersIndex[i][j]); */
if (gcp->cornersIndex[i][j] == 0) {
long int ii = gcp->cornersIndex[i][j];
.x = gcp->cornersCoord[ii][0];
corner0.y = gcp->cornersCoord[ii][1];
corner0.z = gcp->cornersCoord[ii][2];
corner0/* printf("index = %lu with coordinate (%f,%f,%f)\n", gcp->cornersIndex[i][j], corner0.x, corner0.y, corner0.z); */
}
if (gcp->cornersIndex[i][j] == 1) {
long int ii = gcp->cornersIndex[i][j];
.x = gcp->cornersCoord[ii][0];
corner1.y = gcp->cornersCoord[ii][1];
corner1.z = gcp->cornersCoord[ii][2];
corner1/* printf("index = %lu with coordinate (%f,%f,%f)\n", gcp->cornersIndex[i][j], corner1.x, corner1.y, corner1.z); */
}
if (gcp->cornersIndex[i][j] == 3) {
long int ii = gcp->cornersIndex[i][j];
.x = gcp->cornersCoord[ii][0];
corner3.y = gcp->cornersCoord[ii][1];
corner3.z = gcp->cornersCoord[ii][2];
corner3/* printf("index = %lu with coordinate (%f,%f,%f)\n", gcp->cornersIndex[i][j], corner3.x, corner3.y, corner3.z); */
}
if (gcp->cornersIndex[i][j] == 4) {
long int ii = gcp->cornersIndex[i][j];
.x = gcp->cornersCoord[ii][0];
corner4.y = gcp->cornersCoord[ii][1];
corner4.z = gcp->cornersCoord[ii][2];
corner4/* printf("index = %lu with coordinate (%f,%f,%f)\n", gcp->cornersIndex[i][j], corner4.x, corner4.y, corner4.z); */
}
}
}
foreach_dimension() {
.x = corner0.x - corner3.x;
u1.x = corner0.x - corner1.x;
v1.x = corner0.x - corner4.x;
w1.x = 0.;
mins.x = 0.;
maxs}
->u1 = u1;
gcp->v1 = v1;
gcp->w1 = w1;
gcp
double minval = 0., maxval = 0.;
foreach_dimension() {
+= u1.x*corner0.x;
minval += u1.x*corner3.x;
maxval }
.x = (minval); maxs.x = (maxval);
mins
= 0; maxval = 0;
minval foreach_dimension() {
+= v1.x*corner0.x;
minval += v1.x*corner1.x;
maxval }
.y = (minval); maxs.y = (maxval);
mins
= 0; maxval = 0;
minval foreach_dimension() {
+= w1.x*corner0.x;
minval += w1.x*corner4.x;
maxval }
.z = (minval); maxs.z = (maxval);
mins
->mins = mins;
gcp->maxs = maxs;
gcp
}
/* void compute_principal_mins_maxs_Cubes (particle * p) { */
/* GeomParameter * gcp = &(p->g); */
/* coord u1 = gcp->u1; */
/* coord v1 = gcp->v1; */
/* coord w1 = gcp->w1; */
/* } */
void create_FD_Boundary_Cube_v2 (GeomParameter * gcp, SolidBodyBoundary * dlm_bd, const int m, const int lN, vector pshift) {
int nfaces = gcp->allFaces;
int iref, i1, i2, ichoice;
= 0;
ichoice int isb = 0;
int npoints;
/* Add first interrior points on surfaces */
for (int i = 0; i < nfaces; i++) {
= gcp->numPointsOnFaces[i];
npoints
= gcp->cornersIndex[i][ichoice];
iref = gcp->cornersIndex[i][ichoice + 1];
i1 = gcp->cornersIndex[i][npoints-1];
i2
/* printf("on face %d, iref = %d, i1 = %d, i2 = %d\n", i, iref, i1, i2); */
= {gcp->cornersCoord[iref][0], gcp->cornersCoord[iref][1],gcp->cornersCoord[iref][2]} ;
coord refcorner
= {gcp->cornersCoord[i1][0], gcp->cornersCoord[i1][1],gcp->cornersCoord[i1][2]};
coord dir1
= {gcp->cornersCoord[i2][0], gcp->cornersCoord[i2][1],gcp->cornersCoord[i2][2]};
coord dir2
/* printf ("corresponding coord for ref = (%f,%f,%f)\n",refcorner.x, refcorner.y, refcorner.z); */
/* printf ("corresponding coord for i1 = (%f,%f,%f)\n", dir1.x, dir1.y, dir1.z); */
/* printf ("corresponding coord for i2 = (%f,%f,%f)\n", dir2.x, dir2.y, dir2.z); */
foreach_dimension() {
.x -= refcorner.x;
dir1.x -= refcorner.x;
dir2.x /= (lN-1);
dir1.x /= (lN-1);
dir2}
for (int ii = 1; ii <= lN-2; ii++) {
for (int jj = 1; jj <= lN-2; jj++) {
->x[isb] = refcorner.x + (double) ii * dir1.x + (double) jj * dir2.x;
dlm_bd
->y[isb] = refcorner.y + (double) ii * dir1.y + (double) jj * dir2.y;
dlm_bd
->z[isb] = refcorner.z + (double) ii * dir1.z + (double) jj * dir2.z;
dlm_bd++;
isb}
}
}
int allindextable[8][8] = {{0}};
int j1,jm1;
/* Add points on the edges without the corners*/
for (int i = 0; i < nfaces; i++) {
= gcp->numPointsOnFaces[i];
npoints = gcp->cornersIndex[i][1];
i1
for (int j = 1; j < npoints; j++) {
= gcp->cornersIndex[i][j-1];
jm1 = gcp->cornersIndex[i][j];
j1 if (jm1 > j1) {
if (allindextable[jm1][j1] == 0) {
= {gcp->cornersCoord[jm1][0], gcp->cornersCoord[jm1][1], gcp->cornersCoord[jm1][2]};
coord c1 = {gcp->cornersCoord[j1][0], gcp->cornersCoord[j1][1], gcp->cornersCoord[j1][2]};
coord c2 distribute_points_edge_Cube_v2 (c1, c2, dlm_bd, lN, isb);
[jm1][j1] = 1;
allindextable+=lN-2;
isb }
}
else {
if (allindextable[j1][jm1] == 0) {
= {gcp->cornersCoord[j1][0], gcp->cornersCoord[j1][1], gcp->cornersCoord[j1][2]};
coord c1 = {gcp->cornersCoord[jm1][0], gcp->cornersCoord[jm1][1], gcp->cornersCoord[jm1][2]};
coord c2 distribute_points_edge_Cube_v2 (c1, c2, dlm_bd, lN, isb);
[j1][jm1] = 1;
allindextable+=lN-2;
isb }
}
/* printf ("isb after face %d = %d\n", i, isb); */
}
}
/* printf ("isb after all edges = %d\n", isb); */
/* Add the final 8 corners points */
for (int i = 0; i < gcp->ncorners; i++) {
->x[isb] = gcp->cornersCoord[i][0];
dlm_bd->y[isb] = gcp->cornersCoord[i][1];
dlm_bd->z[isb] = gcp->cornersCoord[i][2];
dlm_bd++;
isb}
/* printf ("isb after 8 corners = %d\n", isb); */
}
void create_FD_Interior_Cube_v2 (particle *p, vector Index_lambda, vector pshift) {
Cache * c;
Create the cache of the interior points for a cube
= &(p->Interior);
c
/* compute the 3 principal vector of the cube */
compute_principal_vectors_Cubes (p);
/* a point x with coord (x,y,z) lies in the cube if the 3
following conditions are satisfied */
/* 1- u.p0 <= u.x <= u.p3 */
/* 2- v.p0 <= v.x <= v.p1 */
/* 3- w.p0 <= w.w <= w.p4 */
;
coord checkpt= p->g.u1;
coord u1 = p->g.v1;
coord v1 = p->g.w1;
coord w1 = p->g.mins;
coord mins = p->g.maxs;
coord maxs
/* Min/Max coordinates for the AABB (Axed-Aligned-Bounding-Box) */
= {HUGE, HUGE, HUGE};
coord mincoord = {-HUGE, -HUGE, -HUGE};
coord maxcoord
double ** table = p->g.cornersCoord;
for (int ii = 0; ii < p->g.ncorners; ii++) {
if (mincoord.x > table[ii][0])
.x = table[ii][0];
mincoord
if (mincoord.y > table[ii][1])
.y = table[ii][1];
mincoord
if (mincoord.z > table[ii][2])
.z = table[ii][2];
mincoord
if (maxcoord.x < table[ii][0])
.x = table[ii][0];
maxcoord
if (maxcoord.y < table[ii][1])
.y = table[ii][1];
maxcoord
if (maxcoord.z < table[ii][2])
.z = table[ii][2];
maxcoord}
/* if (pid() == 0) { */
/* printf ("mincoord = (%f,%f,%f)\n",mincoord.x, mincoord.y, mincoord.z); */
/* printf ("maxcoord = (%f,%f,%f)\n",maxcoord.x, maxcoord.y, maxcoord.z); */
/* } */
foreach() {
.x = x;
checkpt.y = y;
checkpt.z = z;
checkpt
/* Check only if the point is in the AABB (Axed-Aligned-Bounding-Box) */
if ((x > mincoord.x) && (x < maxcoord.x))
if ((y > mincoord.y) && (y < maxcoord.y))
if ((z > mincoord.z) && (z < maxcoord.z))
/* If yes: check if it is inside the cube now */
if (is_it_in_cube_v2 (&u1, &v1, &w1, &mins, &maxs, &checkpt)) {
cache_append (c, point, 0);
/* tagg cell with the number of the particle */
if ((int)Index_lambda.y[] == -1)
.y[] = p->pnum;
Index_lambda}
/* /\* For periodic boundaries, we have to check for the image-cubes as well *\/ */
/* if (Period.x) */
/* if (mincoord.x < 0 + X0) */
}
/* foreach_dimension() { */
/* if (Period.x) { */
/* } */
/* } */
cache_shrink (c);
}
void free_particles (particle * pp, const int n) {
for (int k = 0; k < n; k++) {
SolidBodyBoundary * sbm = &(pp[k].s);
free_SolidBodyBoundary(sbm);
Cache * c = &(pp[k].Interior);
free(c->p);
= &(pp[k].reduced_domain);
c free(c->p);
/* free corner coordinates tables */
double * cc;
GeomParameter * gg = &(pp[k].g);
for (int i = 0; i < gg->ncorners; i++) {
= &(gg->cornersCoord[i][0]);
cc if(cc) {
free(cc);
}
}
free(gg->cornersCoord);
/* free corner's indices tables */
for (int i = 0; i < gg->allFaces; i++) {
free(gg->cornersIndex[i]);
}
free(gg->cornersIndex);
free(gg->numPointsOnFaces);
}
}
Function that creates the scalar field where the cells contain the indices of the dlmfd points. If there is no dlmfd point it is tagged -1.
void create_index_lambda_scalar (const SolidBodyBoundary dlm_bd, vector Index_lambda, const int kk) {
;
Point lpointint i;
Cache *fdlocal;
= (Cache *){calloc(dlm_bd.m, sizeof(Cache))};
fdlocal
for (i = 0; i < dlm_bd.m; i++) {
#if dimension == 2
= locate(dlm_bd.x[i], dlm_bd.y[i]);
lpoint #elif dimension == 3
= locate(dlm_bd.x[i], dlm_bd.y[i], dlm_bd.z[i]);
lpoint #endif
/* */
if ((lpoint.level) == depth()) {
/* Create a cache for each fictitious domain's boundary point */
cache_append(&fdlocal[i], lpoint, 0);
foreach_cache(fdlocal[i]) {
/* Tag cell only if it was not tagged by another particle */
if (Index_lambda.x[] < 0){
.x[] = i;
Index_lambda.y[] = kk;
Index_lambdaif (level != depth()) {
printf("On thread %d, point dlmfd %d at (%f, %f, %f) is in a cell that has not the maximum level of refinnement %d, it is on level %d \n", pid(), i, x, y, z, depth(), level);
}
}
}
}
}
for (i = 0; i < dlm_bd.m; i++) {
free(fdlocal[i].p);
}
free (fdlocal);
boundary ((scalar*) {Index_lambda});
}
#include "weights_functions_backup.h"
# ifndef STENCIL_EXTERIOR
# define STENCIL_EXTERIOR 0
# endif
# ifndef STENCIL_INTERIOR
# define STENCIL_INTERIOR 0
# endif
Function that returns the weight associated to a Lagrange multipliers for a cell within a foreach() loop (ie for a “real” or local cell) associated to a Lagrange multiplier in it’s neighborhood. The neighboor can be in another process (i.e be a ghost cell for the current thread).
double reversed_weight (particle * pp, const coord weightcellpos, const coord lambdacellpos, const coord lambdapos, const double delta, const coord pshift, const double a, const double b) {
/* this function has to be embedded within a double foreach_cache() and foreach_neighbor() loop */
= {0., 0., 0.};
coord rel = {0., 0., 0.};
coord relnl int NCX = 0, CX = 0, weight_id = 0;
size_t goflag = 0;
double weight = 0.;
GeomParameter gcb = pp->g;
GeomParameter gcbdum = gcb;
= lambdapos;
coord lambdaposdum
/* Shift artificially the center of the particle and position of the
Lagrange multipliers for periodic boundary cases */
foreach_dimension() {
.center.x = gcb.center.x + a*pshift.x;
gcbdum.x = lambdapos.x + b*pshift.x;
lambdaposdum}
/* compute relative vector X_boundary - X_local = rel from the cell (containning the boundary) position to the boundary's (analytical) position .i.e vector goes from first argument to the second */
compute_relative_vector (lambdacellpos, lambdaposdum, &rel);
/* reset dials integers */
= 0; CX = 0; weight_id = 0; goflag = 0;
NCX
/* assign first normal (gives the quadrant) */
assign_dial (rel, &CX);
/* assign fictitious-boundary's normal (use boundary's analytical position) */
assign_dial_fd_boundary (pp, lambdaposdum, gcbdum, delta, &NCX);
if (pp->iswall) {
#if STENCIL_EXTERIOR
/* Stencils oriented toward the wall */
if (lambdapos.y > 0) {
if (lambdapos.x < L0/2)
= 1;
NCX if (lambdapos.x > L0/2)
= 2;
NCX }
if (lambdapos.y < 0) {
if (lambdapos.x < L0/2)
= 4;
NCX if (lambdapos.x > L0/2)
= 3;
NCX }
#endif
#if STENCIL_INTERIOR
/* Second normal oriented toward the fluid */
if (lambdapos.y > 0) {
if (lambdapos.x < L0/2) {
= 4;
NCX }
if (lambdapos.x > L0/2) {
= 3;
NCX }
}
if (lambdapos.y < 0) {
if (lambdapos.x < L0/2) {
= 1;
NCX }
if (lambdapos.x > L0/2) {
= 2;
NCX }
}
#endif
}
/* compute relative vector from the neighbor cell to the local cell */
compute_relative_vector (weightcellpos, lambdacellpos , &relnl);
/* Assign weight ids. */
assign_weight_id_quad_outward (NCX, CX, relnl, delta, &weight_id, &goflag);
if (goflag == 1) {
= compute_weight_Quad (weight_id, lambdaposdum, lambdacellpos, NCX, CX, delta);
weight }
return weight;
}
void remove_too_close_multipliers (particle * p, vector index_lambda) {
for (int k = 0; k < NPARTICLES; k++) {
SolidBodyBoundary dlm_lambda_to_desactivate;
int allocated = 1;
allocate_SolidBodyBoundary (&dlm_lambda_to_desactivate, allocated*BSIZE);
int countalloc = 0;
int other_part;
int is_in_other_particle;
(depth()) {
foreach_level
int direct_neigh = 0; is_in_other_particle = 0; other_part = -1;
if (((int)index_lambda.x[] > -1) && level == depth() && is_leaf(cell) && (p[k].pnum == (int)index_lambda.y[])) {
/* check here if this multiplier is not in another particle's
domain, if yes desactive it */
for (int l = 0; l < NPARTICLES; l++) {
if (l != p[k].pnum) {
particle * other_particle = &(p[l]);
/* printf("thread %d, this is particle %zu checkin on particle %zu iteration %d\n", pid(), p[k].pnum, other_particle->pnum, l); */
/* Check particle's type */
if (other_particle->iscube) {
compute_principal_vectors_Cubes (other_particle);
= other_particle->g.u1;
coord u = other_particle->g.v1;
coord v = other_particle->g.w1;
coord w = other_particle->g.mins;
coord mins = other_particle->g.maxs;
coord maxs
/* current cell's position */
= {x, y, z};
coord checkpt if (is_it_in_cube_v2 (&u, &v, &w, &mins, &maxs, &checkpt)) {
= 1; other_part = other_particle->pnum;
is_in_other_particle break;
}
}
/* if sphere */
else {
GeomParameter gp = other_particle->g;
if (is_it_in_sphere (x, y, z, gp)) {
= 1; other_part = other_particle->pnum;
is_in_other_particle break;
}
}
}
}
if (is_in_other_particle) {
/* printf("thread %d, this is particle %zu which has a cell in particle %d\n", pid(), p[k].pnum, other_part); */
.x[] = -1; index_lambda.y[] = other_part;
index_lambda}
/* Check if two (or more) Lagrange multipliers (from different
particles) are in the same neighborhoods (i.e a 5x5 stencil
in 2D), if yes desactivate them. Otherwise the cells of
their stencils may be located in each other's domain */
= 0;
direct_neigh foreach_neighbor() {
if (((int)index_lambda.x[] > -1) && level == depth() && is_leaf(cell) && (p[k].pnum != (int)index_lambda.y[])) {
= 1;
direct_neigh /* We may catch and identical multiplier more than once here */
/* Add the multiplier(s) indices to a list because MPI imposes that we can't modify the cell within a foreach_neighbor loop */
if (countalloc >= allocated*BSIZE) {
++;
allocated reallocate_SolidBodyBoundary (&dlm_lambda_to_desactivate, allocated*BSIZE);
}
.x[countalloc] = x;
dlm_lambda_to_desactivate.y[countalloc] = y;
dlm_lambda_to_desactivate#if dimension == 3
.z[countalloc] = z;
dlm_lambda_to_desactivate#endif
++;
countalloc }
}
/* Desactivate the local multiplier here */
if (direct_neigh) {
.x[] = -1; index_lambda.y[] = -1;
index_lambda}
}
}
/* if (countalloc > 0) */
/* printf("there is %d points to desactivate on thread %d\n", countalloc, pid()); */
Cache c = {0};
;
Point lpoint
#if _MPI
int size = npe();
int counts[size];
/* Each thread tells the root how many multipliers it holds */
(&countalloc, 1, MPI_INT, &counts, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Gather
/* if (pid() == 0) */
/* for (int i = 0; i < size; i++) */
/* printf("particle %d, this is root receiving %d elements by thread %d\n",k, counts[i], i); */
/* Displacements in the receive buffer for MPI_GATHERV */
int disps[size];
/* Displacement for the first chunk of data - 0 */
for (int i = 0; i < size; i++)
[i] = (i > 0) ? (disps[i-1] + counts[i-1]) : 0;
disps
double * alldatax = NULL;
double * alldatay = NULL;
#if dimension == 3
double * alldataz = NULL;
#endif
int m = 0;
/* Threads 0 allocates and compute the total number of multipliers */
if (pid() == 0) {
/* disps[size-1] + counts[size-1] == total number of elements */
/* printf("thread %d : disps[size-1]+counts[size-1] = %d\n", pid(), disps[size-1]+counts[size-1]); */
= disps[size-1] + counts[size-1];
m = (double*) calloc (m, sizeof(double));
alldatax = (double*) calloc (m, sizeof(double));
alldatay #if dimension == 3
= (double*) calloc (m, sizeof(double));
alldataz #endif
}
/* Gather on thread 0 the coordinates of the multipliers */
(&dlm_lambda_to_desactivate.x[0], countalloc, MPI_DOUBLE, &alldatax[0], counts, disps, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Gatherv (&dlm_lambda_to_desactivate.y[0], countalloc, MPI_DOUBLE, &alldatay[0], counts, disps, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Gatherv #if dimension == 3
(&dlm_lambda_to_desactivate.z[0], countalloc, MPI_DOUBLE, &alldataz[0], counts, disps, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Gatherv #endif
/* send the total number of multipliers to all threads */
(m, MPI_INT, MPI_MAX);
mpi_all_reduce
/* allocate now alldatax, alldatay, alldataz on threads !=0 */
if (pid() != 0) {
= (double*) calloc (m, sizeof(double));
alldatax = (double*) calloc (m, sizeof(double));
alldatay #if dimension == 3
= (double*) calloc (m, sizeof(double));
alldataz #endif
}
/* Now broadcast alldatax,alldatay,alldataz from thread 0 to other threads */
(alldatax, m, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast (alldatay, m, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast #if dimension == 3
(alldataz, m, MPI_DOUBLE, 0, MPI_COMM_WORLD);
MPI_Bcast #endif
/* for (int i = 0; i < m; i++) { */
/* #if dimension == 2 */
/* printf("thread %d: particle %d, coord of the multiplier %d to be removed (%g,%g,%g)\n", pid(), k, i, alldatax[i], alldatay[i], 0.); */
/* #elif dimension ==3 */
/* printf("thread %d: particle %d, coord of the multiplier %d to be removed (%g,%g,%g)\n", pid(), k, i, alldatax[i], alldatay[i], alldataz[i]); */
/* #endif */
/* } */
for (int i = 0; i < m; i++) {
#if dimension == 2
= locate(alldatax[i], alldatay[i]);
lpoint #elif dimension == 3
= locate(alldatax[i], alldatay[i], alldataz[i]);
lpoint #endif
if (lpoint.level > -1) cache_append(&c, lpoint, 0);
}
free(alldatax);
free(alldatay);
#if dimension == 3
free(alldataz);
#endif
#elif _MPI == 0
for (int i = 0; i < countalloc; i++) {
#if dimension == 2
= locate(dlm_lambda_to_desactivate.x[i], dlm_lambda_to_desactivate.y[i]);
lpoint #elif dimension == 3
= locate(dlm_lambda_to_desactivate.x[i], dlm_lambda_to_desactivate.y[i], dlm_lambda_to_desactivate.z[i]);
lpoint #endif
if (lpoint.level > -1) cache_append(&c, lpoint, 0);
}
#endif /* End if _MPI */
/* Finally desactivate the multiplicators */
int counter = 0;
foreach_cache(c) {
if (index_lambda.x[] > -1 && index_lambda.y[] > -1) {
.x[] = -1;
index_lambda.y[] = -1;
index_lambda++;
counter }
}
/* printf("thread %d: removed %d multipliers \n", pid(), counter); */
free(c.p);
free_SolidBodyBoundary(&dlm_lambda_to_desactivate);
} /* End loop NPARTICLES */
boundary((scalar*) {index_lambda});
}
Function that tags cells associated to a Lagrange multiplier on the boundary of the fictitious domain.
void reverse_fill_flagfield (particle * p, scalar f, vector index_lambda, const int cacheflag) {
for (int k = 0; k < NPARTICLES; k++) {
= {0., 0., 0.};
coord rel = {0., 0., 0.};
coord relnl int NCX, CX, weight_id;
size_t goflag = 0;
= {0., 0., 0.};
coord lambdacellpos = {0., 0., 0.};
coord lambdapos = {0., 0., 0.};
coord localcellpos
SolidBodyBoundary dlm_lambda = p[k].s;
GeomParameter gcb = p[k].g;
Cache * reduced_domain = &(p[k].reduced_domain);
GeomParameter gcbdum = gcb;
= lambdapos;
coord lambdaposdum
(depth()) {
foreach_level.x = x;
localcellpos.y = y;
localcellpos#if dimension == 3
.z = z;
localcellpos#endif
= 0;
goflag // Check if there is a Lagrange multiplier in the neigborhood of this cell;
foreach_neighbor() {
if (((int)index_lambda.x[] > -1) && level == depth() && is_leaf(cell) && (p[k].pnum == (int)index_lambda.y[])) {
.x = x; lambdacellpos.y = y;
lambdacellpos.x = dlm_lambda.x[(int)index_lambda.x[]];
lambdapos.y = dlm_lambda.y[(int)index_lambda.x[]];
lambdapos
#if dimension == 3
.z = z;
lambdacellpos.z = dlm_lambda.z[(int)index_lambda.x[]];
lambdapos#endif
/* Shift artificially the center of the particle and position of the
Lagrange multipliers for periodic boundary cases */
= {0., 0., 0.};
coord ppshift foreach_dimension() {
.x = 0.;
ppshiftif (lambdacellpos.x < 0.) ppshift.x = -L0;
if (lambdacellpos.x > L0) ppshift.x = +L0;
.center.x = gcb.center.x + ppshift.x;
gcbdum.x = lambdapos.x + ppshift.x;
lambdaposdum}
/* compute relative vector X_boundary - X_local = rel from the cell (containning the boundary) position to the boundary's (analytical) position */
compute_relative_vector (lambdacellpos, lambdaposdum, &rel);
/* reset dials integers */
= 0; CX = 0; weight_id = 0;
NCX
/* assign first normal (gives the quadrant) */
assign_dial (rel, &CX);
/* assign fictitious-boundary's normal (use boundary's position) */
assign_dial_fd_boundary (&p[k], lambdaposdum, gcbdum, Delta, &NCX);
if (p->iswall) {
#if STENCIL_EXTERIOR
/* Stencils oriented toward the wall */
if (lambdapos.y > 0) {
if (lambdapos.x < L0/2)
= 1;
NCX if (lambdapos.x > L0/2)
= 2;
NCX }
if (lambdapos.y <0) {
if (lambdapos.x < L0/2)
= 4;
NCX if (lambdapos.x > L0/2)
= 3;
NCX }
#endif
#if STENCIL_INTERIOR
/* Stencils oriented toward the fluid */
if ((lambdapos.y) > 0) {
if (lambdapos.x < L0/2)
= 4;
NCX if (lambdapos.x > L0/2)
= 3;
NCX }
if (lambdapos.y <0) {
if (lambdapos.x < L0/2) {
= 1;
NCX }
if (lambdapos.x > L0/2)
= 2;
NCX }
#endif
}
/* compute relative vector neighbor to the local cell */
compute_relative_vector (localcellpos, lambdacellpos , &relnl);
/* Assign weight ids. */
assign_weight_id_quad_outward (NCX, CX, relnl, Delta, &weight_id, &goflag);
} // end if (lambda.x[] > -1)
} // end foreach_neigboor loop
/* If the cell belongs to the stencil of a Lagrange multiplier tagg it and create a reduced domain to optimize the stencil-traversal cost */
if (goflag == 1) {
[] = 1;
fif (cacheflag == 1)
cache_append (reduced_domain, point, 0);
}
}
boundary ({f, index_lambda.x, index_lambda.y});
}// loop on particles id
}
Function that initialize the particles and the scalar/vector fields needed to the method
void allocate_and_init_particles (particle * p, const int n, vector e, scalar g, scalar h, vector pshift) {
foreach() {
.x[] = -1;// index_lambda.x => lambda indices
e.y[] = -1;// particle structure/fd number;
e.z[] = -1;// constrained cells (-1:not constrained)
e[] = 0; // flagfield
g[] = 0; // flagfield_mailleur
h
/* Reset the shift vector for the periodic case */
if (Period.x || Period.y || Period.z) {
foreach_dimension() {
.x[] = 0.;
pshift}
}
}
boundary ({g, h});
boundary ((scalar *){e, pshift});
for (int k = 0; k < n; k++) {
Cache * c = NULL;
#if debugBD == 0
GeomParameter gci = p[k].g;
int m = 0;
/* default case, sphere */
if (!(p[k].iswall) && !(p[k].iscube)) {
compute_nboundary (gci, &m);
allocate_SolidBodyBoundary(&(p[k].s), m);
create_FD_Boundary_Particle (gci, &(p[k].s), m, pshift);
}
if (p[k].iswall) {
= p[k].wallmax;
coord wallpos compute_nboundary_Wall (wallpos, &m);
allocate_SolidBodyBoundary(&(p[k].s), m);
create_FD_Boundary_Wall (&p[k]);
}
if (p[k].iscube) {
int lN = 0;
compute_nboundary_Cube_v2 (&gci, &m, &lN);
allocate_SolidBodyBoundary(&(p[k].s), m);
create_FD_Boundary_Cube_v2 (&gci, &(p[k].s), m, lN, pshift);
}
create_index_lambda_scalar ((p[k].s), e, k);
= &(p[k].reduced_domain);
c allocate_Cache(c);
#endif
#if debugInterior == 0
= &(p[k].Interior);
c allocate_Cache(c);
#endif
}
}
#if DLM_Moving_particle
#if TRANSLATION
void compute_contact_distance (particle * p, const coord gci, double * delta) {
GeomParameter gc = p->g;
double radius = gc.radius;
*delta = gci.y - radius;
}
double compute_fwo (const double en, const double v, const double wo) {
double k = log(en)/sqrt(sq(pi) + sq(log(en)));
double g = atan(-sqrt(1 - sq(k))/k);
double val;
return val = v*exp(k*g/sqrt(1- sq(k)))*sin(g)/(wo*sqrt(1 - sq(k)));
}
double derivative_fwo (const double en, const double v, const double wo) {
double k = log(en)/sqrt(sq(pi) + sq(log(en)));
double g = atan(-sqrt(1 - sq(k))/k);
double val;
return val = -v*exp(k*g/sqrt(1 - sq(k)))*sin(g)/(sqrt(1 - sq(k))*sq(wo));
}
void compute_wo (particle * p) {
/* compute an estimate of (kn,gamman) derived from (deltamax,en) */
/* Guess value for wo */
double wo = 100.;
double epsilo = 1e-2;
int maxiter = 200;
double aa = 0.;
double bb = 0.;
GeomParameter g = p->g;
double r = g.radius;
double deltamax = (p->wished_ratio)*r;
double en = p->en;
double v = p->vzero;
/* Newton iteration to find the root of delta(w0) */
if (en < 1) {
for (int pp = 1; pp <= maxiter; pp++) {
= compute_fwo (wo, v, en) - deltamax;
aa = derivative_fwo (wo, v, en);
bb
if (abs(aa-deltamax)/deltamax < epsilo) {
break;
}
+= -aa/bb;
wo }
->kn = (p->M)*sq(wo);
p}
else {
/* if en = 1 the formula simplifies as such */
->kn = (p->M)*sq(p->vzero)/(sq(deltamax));
p}
}
void compute_Fontact (coord * Fc, particle * p, coord * gci, coord * U, const double gamman) {
double delta_colision = 0.;
foreach_dimension() {
(*Fc).x = 0.;
}
compute_contact_distance(p, *gci, &delta_colision);
if (delta_colision < 0.) {
double kn = p->kn;
double M = p->M;
= *U;
coord vrel = {0., 0., 0.};
coord Fel = {0., 0., 0.};
coord Fdm = p->normalvector;
coord normalvec
foreach_dimension() {
/* compute Hookean elastic restoring force */
.x = -kn*delta_colision*normalvec.x;
Fel
/* compute viscous dynamic force */
.x = -2.*gamman*M*fabs(vrel.x);
Fdm
/* Fc is the sum of these two forces */
(*Fc).x = Fel.x + Fdm.x;
}
}
}
void granular_subproblem (particle * p, const int gravity_flag, const double dt, const double rho_f) {
// Mini Granular solver, which solves (1 - rho_f/rho_s)MdU/dt = (1-rho_f/rho_s)Mg + F_c
// (1 - rho_f/rho_s) Ip dw/dt = sum_all_particles (r x F_c) - (1 - rho_f/rho_s)w x Ip w
// where F_c is the contact force, g the gravity acceleration and M the particle's mass and Ip the inertia tensor
double wo = 0. ;
double gamman = 0.;
double T_c = 0., dtg = 0., M = 0., kn = 0., en = 0.;
int miter, gi;
, Xold;
coord Uold, k2, k3, k4, Xtemp, Utemp;
coord k1double fsf;
/* particle's structure pointers */
GeomParameter * gci;
GeomParameter * gcinm1;
* U;
coord * Unm1;
coord
* gravity;
coord = {X0, Y0, Z0};
coord decal
for (int k = 0; k < NPARTICLES; k++) {
= (1. - (rho_f)/(p[k].rho_s));
fsf
= 0;
miter = p[k].M;
M = p[k].kn;
kn = p[k].en;
en
/* compute wo and gamman */
= sqrt(kn/M); // wo = sqrt(2kn/M) for sphere-sphere contact and wo = sqrt(kn/M) for sphere-wall contact (Powder tech. Rakotonirina 2018)
wo = -wo*log(en)/sqrt(sq(pi) + sq(log(en)));
gamman
/* compute the contact time Tc */
= pi/(sqrt(sq(wo) - sq(gamman)));
T_c
/* set granular timestep */
= T_c/20.;
dtg = ceil(dt/dtg);
miter = dt/miter;
dtg
if (k == 0) fprintf (stderr,"Tc = %g, dt = %20.18f, dtg = %20.18f, Tc/dtg = %g, miter = %d, particle = %d\n",T_c, dt, dtg, T_c/dtg, miter, k);
/* get particle structure pointers */
/* position */
= &(p[k].gnm1);
gcinm1 = &(p[k].g);
gci
/* translational velocity */
= &(p[k].U);
U = &(p[k].Unm1);
Unm1
= &(p[k].gravity);
gravity
/* fprintf (stderr,"gravity = (%f,%f,%f)\n",(*gravity).x,(*gravity).y,(*gravity).z); */
if (gravity_flag) {
/* Before solving the granular problem: save previous particle's
position and velocity (predictor step
with gravity, first subproblem after N-S) */
foreach_dimension() {
(*Unm1).x = (*U).x;
/* Check if the domain is periodic, if yes shift the particle's
position when the end of the domain is reached */
if (Period.x) {
if ((*gci).center.x > (L0 + decal.x)) {
(*gci).center.x -= L0;
}
if ((*gci).center.x < (0. + decal.x)) {
(*gci).center.x += L0;
}
}
(*gcinm1).center.x = (*gci).center.x;
}
}
else {
/* corrector step without gravity: fourth subproblem after the
fictitious domain problem (correction step) */
foreach_dimension() {
(*gci).center.x = (*gcinm1).center.x;
}
}
/* integrating in time with rk4 */
for (gi = 1; gi <= miter; gi++) {
= (*U);
Uold = (*gci).center;
Xold
/* compute k1 */
compute_Fontact (&k1, &p[k], &Xold, &Uold, gamman);
foreach_dimension() {
.x /= (fsf*M);
k1.x += gravity_flag*(*gravity).x;
k1.x = Xold.x + 0.5*dtg*Uold.x;
Xtemp.x = Uold.x + 0.5*dtg*k1.x;
Utemp}
/* compute k2 */
compute_Fontact (&k2, &p[k], &Xtemp, &Utemp, gamman);
foreach_dimension() {
.x /= (fsf*M);
k2.x += gravity_flag*(*gravity).x;
k2.x = Xold.x + 0.5*dtg*Uold.x + 0.25*sq(dtg)*k1.x;
Xtemp.x = Uold.x + 0.5*dtg*k2.x;
Utemp}
/* compute k3 */
compute_Fontact (&k3, &p[k], &Xtemp, &Utemp, gamman);
foreach_dimension() {
.x /= (fsf*M);
k3.x += gravity_flag*(*gravity).x;
k3.x = Xold.x + dtg*Uold.x + 0.5*sq(dtg)*k2.x;
Xtemp.x = Uold.x + dtg*k3.x;
Utemp}
/* compute k4 */
compute_Fontact (&k4, &p[k], &Xtemp, &Utemp, gamman);
foreach_dimension() {
.x /= (fsf*M);
k4.x += gravity_flag*(*gravity).x;
k4}
foreach_dimension () {
(*gci).center.x = Xold.x + dtg*Uold.x + sq(dtg)*(k1.x + k2.x + k3.x)/6.;
/* Check if the domain is periodic, if yes shift the particle's
position when the end of the domain is reached */
if (Period.x) {
if ((*gci).center.x > (L0 + decal.x)) {
(*gci).center.x -= L0;
}
if ((*gci).center.x < (0. + decal.x)) {
(*gci).center.x += L0;
}
}
(*U).x = Uold.x + dtg*(k1.x + 2*k2.x + 2*k3.x + k4.x)/6.;
}
}
if (k == 0) {
if (gravity_flag) {
fprintf (stderr,"Prediction: particle-0's velocity on thread %d is (%20.18f, %20.18f, %20.18f)\n",pid(), (*U).x, (*U).y, (*U).z);
fprintf (stderr,"Prediction: particle-0's position on thread %d is (%20.18f, %20.18f, %20.18f)\n",pid(), (*gci).center.x, (*gci).center.y, (*gci).center.z);
}
else {
fprintf(stderr,"Correction: particle-0's velocity on thread %d is (%20.18f, %20.18f, %20.18f)\n",pid(), (*U).x, (*U).y, (*U).z);
fprintf(stderr,"Correction: particle-0's position on thread %d is (%20.18f, %20.18f, %20.18f)\n",pid(), (*gci).center.x, (*gci).center.y, (*gci).center.z);
}
}
}
}
#endif
#endif
Diagnostic functions.
void writer_headers (FILE * pdata, FILE * sl) {
#if _MPI
if(pid() == 0)
#endif
{
/* Write header for particles positions and velocities */
#if dimension == 2
fprintf(pdata, "#t\t position.x\t position.y\t U.x\t U.y\t w.z\n");
fprintf(sl, "#t\t F.x\t F.y\t T.z\n");
#elif dimension == 3
fprintf (pdata, "#t\t position.x\t position.y\t position.z\t U.x\t U.y\t U.z\t w.x\t w.y\t w.z\n");
fprintf (sl, "#t\t F.x\t F.y\t F.z\t T.x\t T.y\t T.z\n");
#endif
fflush(pdata);
fflush(sl);
}
}
void particle_data (particle * p, const double t, const int i, FILE ** pdata) {
for (int k = 0; k < NPARTICLES; k++) {
GeomParameter * GCi = &(p[k].g);
#if DLM_Moving_particle
#if TRANSLATION
* U = &(p[k].U);
coord #endif
#if ROTATION
* w = &(p[k].w);
coord #endif
#endif
#if dimension == 2
if(pid() == 0) {
fprintf(pdata[k], "%20.18f\t %20.18f\t %20.18f %20.18f\t %20.18f\t %20.18f \n", t, (*GCi).center.x, (*GCi).center.y
#if DLM_Moving_particle
#if TRANSLATION
, (*U).x, (*U).y
#elif TRANSLATION == 0
, 0., 0.
#endif
#if ROTATION
, (*w).z
#elif ROTATION == 0
, 0.
#endif
#elif DLM_Moving_particle == 0
, 0., 0.
, 0.
#endif
);
fflush(pdata[k]);
}
#elif dimension == 3
if(pid() == 0) {
fprintf(pdata[k], "%20.18f\t %20.18f\t %20.18f\t %20.18f\t %20.18f\t %20.18f %20.18f\t %20.18f\t %20.18f\t %20.18f\n", t, (*GCi).center.x, (*GCi).center.y, (*GCi).center.z
#if DLM_Moving_particle
#if TRANSLATION
, (*U).x, (*U).y, (*U).z
#elif TRANSLATION == 0
, 0., 0., 0.
#endif
#if ROTATION
,(*w).x, (*w).y, (*w).z
#elif ROTATION == 0
, 0., 0., 0.
#endif
#elif DLM_Moving_particle == 0
, 0., 0., 0.
, 0., 0., 0.
#endif
);
fflush(pdata[k]);
}
#endif
}
}
(particle * p, FILE ** sl, const double t, const double dt, scalar Flagfield, vector Lambda, vector Index_lambda, const double rho_f, vector pshift) {
coord sumLambda /* Compute hydrodynamic force & torque and write to a file */
/* Fh = <lambda,V>_P + (rho_f/rho_s)MdU/dt */
/* Mh = <lambda,xi^GM>_P + (rho_f/rho_s).( Idom/dt + om x (I.om)) */
/* The inertia tensor is: */
/* Ip[0] = Ixx */
/* Ip[1] = Iyy */
/* Ip[2] = Izz */
/* Ip[3] = Ixy */
/* Ip[4] = Ixz */
/* Ip[5] = Iyz */
;
coord lambdasumint;
coord lambdasumboundary;
coord lambdasum;
coord crossLambdaSumInt;
coord crossLambdaSumBoundary;
coord crossLambdaSumCache * Interior[NPARTICLES];
Cache * Boundary[NPARTICLES];
GeomParameter * gci;
SolidBodyBoundary * sbm;
/* Loop over all particles */
for (int k = 0; k < NPARTICLES; k++) {
foreach_dimension() {
.x = 0.;
lambdasumint.x = 0.;
lambdasumboundary.x = 0;
lambdasum
.x = 0.;
crossLambdaSumInt.x = 0.;
crossLambdaSumBoundary.x = 0.;
crossLambdaSum}
#if dimension ==2
.z = 0.;
lambdasumint.z = 0.;
lambdasumboundary.z = 0;
lambdasum
.z = 0.;
crossLambdaSumInt.z = 0.;
crossLambdaSumBoundary.z = 0.;
crossLambdaSum#endif
/* Interior domain of the particle */
[k] = &(p[k].Interior);
Interior
/* Boundary domain of the particle */
[k] = &(p[k].reduced_domain);
Boundary= &(p[k].g);
gci = &(p[k].s);
sbm ;
coord lambdapos#if DLM_Moving_particle
double rho_s = p[k].rho_s;
#if TRANSLATION
double M = p[k].M;
= p[k].Unm1;
coord Unm1 = p[k].U;
coord U #endif
#if ROTATION
= p[k].wnm1;
coord wnm1 = p[k].w;
coord w , omIom, Idomdt;
coord Iom#endif
#endif
// Particule's interior multipliers
foreach_cache((*Interior[k])) {
if (Flagfield[] < 1 && k == Index_lambda.y[]) {
/* Compute Fh = <lambda,V>_P */
/* For moving particles the additional term +
(rho_f/rho_s).M.dU/dt is added after the mpi_calls below */
foreach_dimension() {
.x += Lambda.x[];
lambdasumint}
/* Compute Mh = <lambda,xi^GM>_P */
/* For moving particles, the additional term +
(rho_f/rho_s).(I.dom/dt + om ^ (I.om)) is added after mpi
calls below */
/* Modify temporerly the particle center position for periodic boundary condition */
foreach_dimension()
(*gci).center.x += pshift.x[];
.x += (Lambda.z[]*(y - (*gci).center.y) - Lambda.y[]*(z - (*gci).center.z));
crossLambdaSumInt.y += (Lambda.x[]*(z - (*gci).center.z) - Lambda.z[]*(x - (*gci).center.x));
crossLambdaSumInt.z += (Lambda.y[]*(x - (*gci).center.x) - Lambda.x[]*(y - (*gci).center.y));
crossLambdaSumIntforeach_dimension()
(*gci).center.x -= pshift.x[];
}
}//end foreach_cache()
// Particle's boundary multipliers
foreach_cache((*Boundary[k])) {
if ((Index_lambda.x[] > -1) && (p[k].pnum == (int)Index_lambda.y[])) {
.x = (*sbm).x[(int)Index_lambda.x[]];
lambdapos.y = (*sbm).y[(int)Index_lambda.x[]];
lambdapos.z = 0.;
lambdapos#if dimension == 3
.z = (*sbm).z[(int)Index_lambda.x[]];
lambdapos#endif
/* Compute Fh = <lambda,V>_P */
foreach_dimension() {
.x += Lambda.x[];
lambdasumboundary}
/* Modify temporerly the particle center position for periodic boundary condition */
foreach_dimension()
(*gci).center.x += pshift.x[];
/* Compute Mh = <lambda,xi^GM>_P */
.x += (Lambda.z[]*(lambdapos.y - (*gci).center.y) - Lambda.y[]*(lambdapos.z - (*gci).center.z));
crossLambdaSumBoundary.y += (Lambda.x[]*(lambdapos.z - (*gci).center.z) - Lambda.z[]*(lambdapos.x - (*gci).center.x));
crossLambdaSumBoundary.z += (Lambda.y[]*(lambdapos.x - (*gci).center.x) - Lambda.x[]*(lambdapos.y - (*gci).center.y));
crossLambdaSumBoundary
foreach_dimension()
(*gci).center.x -= pshift.x[];
}
}
#if _MPI
foreach_dimension() {
(lambdasumint.x, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce (lambdasumboundary.x, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce (crossLambdaSumInt.x, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce (crossLambdaSumBoundary.x, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce }
#if dimension == 2
(crossLambdaSumInt.z, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce (crossLambdaSumBoundary.z, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce #endif
#endif
/* The Force term (rho_f/rho_s)MdU/dt is added here for
translating particles */
#if DLM_Moving_particle
#if TRANSLATION
foreach_dimension()
.x += (rho_f/rho_s)*M*(U.x - Unm1.x)/dt;
lambdasumint#endif
/* The Torque term (rho_f/rho_s).(Idom/dt + om ^ (I.om)) is added
here for rotating particles */
#if ROTATION
/* I.om term */
.x = p[k].Ip[0]*w.x + p[k].Ip[3]*w.y + p[k].Ip[4]*w.z;
Iom.y = p[k].Ip[3]*w.x + p[k].Ip[1]*w.y + p[k].Ip[5]*w.z;
Iom.z = p[k].Ip[4]*w.x + p[k].Ip[5]*w.y + p[k].Ip[2]*w.z;
Iom
/* om^(I.om) term */
.x = w.y*Iom.z - w.z*Iom.y;
omIom.y = w.z*Iom.x - w.x*Iom.z;
omIom.z = w.x*Iom.y - w.y*Iom.x;
omIom
/* Idom/dt term; */
.x = p[k].Ip[0]*(w.x - wnm1.x) + p[k].Ip[3]*(w.y - wnm1.y) + p[k].Ip[4]*(w.z - wnm1.z);
Idomdt.y = p[k].Ip[3]*(w.x - wnm1.x) + p[k].Ip[1]*(w.y - wnm1.y) + p[k].Ip[5]*(w.z - wnm1.z);
Idomdt.z = p[k].Ip[4]*(w.x - wnm1.x) + p[k].Ip[5]*(w.y - wnm1.y) + p[k].Ip[2]*(w.z - wnm1.z);
Idomdt
.x += (rho_f/rho_s)*((Idomdt.x)/dt + omIom.x);
crossLambdaSumInt.y += (rho_f/rho_s)*((Idomdt.y)/dt + omIom.y);
crossLambdaSumInt.z += (rho_f/rho_s)*((Idomdt.z)/dt + omIom.z);
crossLambdaSumInt#endif
#endif
foreach_dimension() {
.x = lambdasumint.x + lambdasumboundary.x;
lambdasum.x = crossLambdaSumInt.x + crossLambdaSumBoundary.x;
crossLambdaSum}
#if dimension == 2
.z = crossLambdaSumInt.z + crossLambdaSumBoundary.z;
crossLambdaSum
if(pid() == 0) {
fprintf(sl[k], "%f\t %20.18f\t %20.18f\t %20.18f\n", t, lambdasum.x, lambdasum.y, crossLambdaSum.z);
fflush(sl[k]);
}
#elif dimension == 3
if(pid() == 0) {
fprintf(sl[k], "%20.18f\t %20.18f\t %20.18f\t %20.18f\t %20.18f\t %20.18f\t %20.18f\n", t, lambdasum.x, lambdasum.y, lambdasum.z,
.x, crossLambdaSum.y, crossLambdaSum.z);
crossLambdaSumfflush(sl[k]);
}
#endif
}
return lambdasum;
}
void init_file_pointers (FILE ** p, FILE ** d, const size_t rflag) {
char name[800];
char name2[800];
#if _MPI
if (pid() == 0)
#endif
{
for (int k = 0; k < NPARTICLES; k++) {
sprintf (name, "particle-data-%d", k);
sprintf (name2, "sum_lambda-%d", k);
if (!rflag) {
[k] = fopen (name, "w");
p[k] = fopen (name2, "w");
d
/* if (k == (NPARTICLES - 1)) { */
/* printf ("pointer sum lambda= %p\n", (void *)d[k]); */
/* printf ("pointer particle data = %p\n", (void *)p[k]); */
/* } */
/* Write headers in these files */
writer_headers (p[k], d[k]);
}
else {
[k] = fopen (name, "a");
p[k] = fopen (name2, "a");
d}
}
}
}
void vorticity_3D (const vector u, vector omega) {
foreach()
foreach_dimension()
.x[] = ( (u.z[0,1,0] - u.z[0,-1,0]) - (u.y[0,0,1] - u.y[0,0,-1]) )/2.*Delta;
omega
boundary((scalar *){omega});
}
void compute_flowrate_right (FILE * pf, const vector u, const int level) {
= {0., 0., 0.};
coord velo
foreach_dimension()
.x = 0.;
velo
#if !adaptive
Cache intDomain = {0};
;
Point lpointforeach() {
if (x > (L0 - Delta)) {
= locate(x, y, z);
lpoint cache_append(&intDomain, lpoint, 0);
}
}
cache_shrink(&intDomain);
foreach_cache(intDomain){
foreach_dimension()
.x += sq(Delta)*u.x[];
velo}
free(intDomain.p);
#endif
#if adaptive
double hh = L0/pow(2,level);
double xi = 0., yj = 0., zval = 0.;
int ii = 0, jj = 0;
(level) {
foreach_level= L0 - 0.5*Delta + Z0;
zval }
/* printf("zz = %f, h = %f\n", zval, hh); */
for (ii = 0; ii < pow(2,level); ii++) {
= 0.5*hh + ii*hh + X0;
xi for (jj = 0; jj < pow(2,level); jj++) {
= 0.5*hh + jj*hh + Y0;
yj = {0., 0., 0.};
coord uu foreach_dimension() {
.x = interpolate (u.x, xi, yj, zval);
uuif (uu.x < nodata)
.x += sq(hh)*uu.x;
velo}
/* printf("thread %d, u = (%f,%f,%f)\n",pid(), interpolate(u.x, xi, yj, zz), interpolate(u.y, xi, yj, zz), interpolate(u.z, xi, yj, zz)); */
}
}
#endif
/* printf("thread %d, velo = (%f,%f,%f)\n",pid(), velo.x, velo.y, velo.z); */
#if _MPI
foreach_dimension ()
(velo.x, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce #endif
fprintf(pf, "%f\t %20.18f\t %20.18f\t %20.18f\n", t, velo.x, velo.y, velo.z);
fflush(pf);
}
void pressure_law (scalar pres, FILE * ppf, const coord hv, const double t) {
double plaw = 0.;
= interpolate (pres, hv.x, hv.y, hv.z);
plaw
#if _MPI
(MPI_COMM_WORLD);
MPI_Barrierif (plaw == nodata)
= 0.;
plaw (MPI_COMM_WORLD);
MPI_Barrier
if (plaw != nodata)
(plaw, MPI_DOUBLE, MPI_SUM);
mpi_all_reduce#endif
if (pid() == 0) {
fprintf(ppf, "%20.18f\t %20.18f\n", t, plaw);
fflush(ppf);
}
}
dump/resto particle’s structure functions
void dump_particle (particle * p) {
FILE * fp;
char * file = "dump_particle";
if (file && (fp = fopen (file, "w")) == NULL) {
(file);
perror exit (1);
}
assert (fp);
(p, sizeof(*p), NPARTICLES, fp);
fwritefclose(fp);
}
bool restore_particle (particle * p) {
FILE * fp;
char * file = "dump_particle";
if (file && (fp = fopen (file, "r")) == NULL)
return false;
assert (fp);
if (fread (p, sizeof(*p), NPARTICLES, fp) < 1) {
fprintf (ferr, "restore_particle(): error reading particle data\n");
exit (1);
}
fclose(fp);
return true;
}
void inverse3by3matrix(double oldMatrix[3][3], double ** inversedMatrix) {
double block1 = oldMatrix[1][1]*oldMatrix[2][2] - oldMatrix[1][2]*oldMatrix[2][1];
double block2 = oldMatrix[1][2]*oldMatrix[2][0] - oldMatrix[1][0]*oldMatrix[2][2];
double block3 = oldMatrix[1][0]*oldMatrix[2][1] - oldMatrix[1][1]*oldMatrix[2][0];
double determinat = oldMatrix[0][0]*block1 + oldMatrix[0][1]*block2 + oldMatrix[0][2]*block3;
/* m[i][j], *(*(m + i) + j) */
*(*(inversedMatrix + 0) + 0) = block1/determinat;
*(*(inversedMatrix + 0) + 1) = (oldMatrix[0][2]*oldMatrix[2][1] - oldMatrix[0][1]*oldMatrix[2][2])/determinat;
*(*(inversedMatrix + 0) + 2) = (oldMatrix[0][1]*oldMatrix[1][2] - oldMatrix[0][2]*oldMatrix[1][1])/determinat;
*(*(inversedMatrix + 1) + 0) = block2 / determinat;
*(*(inversedMatrix + 1) + 1) = (oldMatrix[0][0]*oldMatrix[2][2] - oldMatrix[0][2]*oldMatrix[2][0])/determinat;
*(*(inversedMatrix + 1) + 2) = (oldMatrix[0][2]*oldMatrix[1][0] - oldMatrix[0][0]*oldMatrix[1][2])/determinat;
*(*(inversedMatrix + 2) + 0) = block3/determinat;
*(*(inversedMatrix + 2) + 1) = (oldMatrix[0][1]*oldMatrix[2][0] - oldMatrix[0][0]*oldMatrix[2][1])/determinat;
*(*(inversedMatrix + 2) + 2) = (oldMatrix[0][0]*oldMatrix[1][1] - oldMatrix[0][1]*oldMatrix[1][0])/determinat ;
}
int totalcells() {
int t = 0;
foreach() {
++;
t}
#if _MPI
(t, MPI_INTEGER, MPI_SUM);
mpi_all_reduce #endif
return t;
}
int total_dlmfd_cells (particle * p, const int np) {
int apts = 0;
for (int k = 0; k < np; k++) {
#if debugInterior == 0
+= p[k].Interior.n;
apts #endif
#if debugBD == 0
+= p[k].reduced_domain.n;
apts #endif
}
#if _MPI
(apts, MPI_INTEGER, MPI_SUM);
mpi_all_reduce #endif
return apts;
}
int total_dlmfd_multipliers (particle * p, const int np) {
int apts = 0;
for (int k = 0; k < np; k++) {
#if debugInterior == 0
+= p[k].Interior.n;
apts #endif
}
#if _MPI
(apts, MPI_INTEGER, MPI_SUM);
mpi_all_reduce #endif
for (int k = 0; k < np; k++) {
#if debugBD == 0
SolidBodyBoundary * bla;
= &(p[k].s);
bla += bla->m;
apts #endif
}
return apts;
}
double getDelta() {
/* Return the smallest grid size */
/* ----------------------------- */
int ii = 0;
double dd = 0.;
(depth()) {
foreach_level++;
ii= Delta;
dd if (ii > 0)
break;
}
#if _MPI
(dd, MPI_DOUBLE, MPI_MIN);
mpi_all_reduce #endif
return dd;
}