/*@@ @file SymmetryWrappers.c @date April 2000 @author Gerd Lanfermann @desc Routines to apply the 1/2/3D Symmetries for all symmetry domains (octant/bitant/quadrant). @enddesc @history @hdate Sat 02 Nov 2002 @hauthor Thomas Radke @hdesc routines generalized for applying to arbitrary CCTK data types @endhistory @version $Id$ @@*/ #include #include "cctk.h" #include "cctk_Arguments.h" #include "cctk_Parameters.h" #include "Symmetry.h" /* the rcs ID and its dummy function to use it */ static const char *rcsid = "$Header$"; CCTK_FILEVERSION(CactusBase_CartGrid3D_Symmetry_c) /******************************************************************** ********************* Local Routine Prototypes ********************* ********************************************************************/ static int ApplySymmetry (const cGH *GH, int gindex, int first_vindex, int numvars); /******************************************************************** ******************* Fortran Wrapper Prototypes ********************* ********************************************************************/ void CCTK_FCALL CCTK_FNAME (CartSymGI) (int *ierr, const cGH **GH, int *gindex); void CCTK_FCALL CCTK_FNAME (CartSymGN) (int *ierr, const cGH **GH, ONE_FORTSTRING_ARG); void CCTK_FCALL CCTK_FNAME (CartSymVI) (int *ierr, const cGH **GH, int *vindex); void CCTK_FCALL CCTK_FNAME (CartSymVN) (int *ierr, const cGH **GH, ONE_FORTSTRING_ARG); /******************************************************************** ****************** External Routine Prototypes ********************* ********************************************************************/ void DecodeSymParameters3D (int sym[6]); void CartGrid3D_ApplyBC (CCTK_ARGUMENTS); /*@@ @routine CartSymGI @date April 2000 @author Gerd Lanfermann @desc Apply symmetry boundary routines by group index @enddesc @calls ApplySymmetry @var GH @vdesc Pointer to CCTK grid hierarchy @vtype const cGH * @vio in @endvar @var gindex @vdesc index of group to apply symmetry BC @vtype int @vio in @endvar @returntype int @returndesc return code of @seeroutine ApplySymmetry
-1 if invalid group index was given @endreturndesc @@*/ int CartSymGI (const cGH *GH, int gindex) { int numvars, first_vindex, retval; numvars = CCTK_NumVarsInGroupI (gindex); first_vindex = CCTK_FirstVarIndexI (gindex); if (numvars > 0 && first_vindex >= 0) { char * groupname = CCTK_GroupName (gindex); if (!groupname) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error returned from function CCTK_GroupName"); CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, "You should not call the symmetry boundary condition routines for the group \"%s\" through the CartSym* routines any more. The symmetry boundary conditions are now applied automatically when a physical boundary condition is applied.", groupname); free (groupname); retval = ApplySymmetry (GH, gindex, first_vindex, numvars); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Invalid group index %d in CartSymGI", gindex); retval = -1; } return (retval); } void CCTK_FCALL CCTK_FNAME (CartSymGI) (int *ierr, const cGH **GH, int *gindex) { *ierr = CartSymGI (*GH, *gindex); } /*@@ @routine CartSymGN @date April 2000 @author Gerd Lanfermann @desc Apply symmetry boundary routines by group name @enddesc @calls ApplySymmetry @var GH @vdesc Pointer to CCTK grid hierarchy @vtype const cGH * @vio in @endvar @var gname @vdesc name of group to apply symmetry BC @vtype const char * @vio in @endvar @returntype int @returndesc return code of @seeroutine ApplySymmetry
-1 if invalid group name was given @endreturndesc @@*/ int CartSymGN (const cGH *GH, const char *gname) { int gindex, retval; gindex = CCTK_GroupIndex (gname); if (gindex >= 0) { retval = CartSymGI (GH, gindex); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Invalid group name '%s' in CartSymGN", gname); retval = -1; } return (retval); } void CCTK_FCALL CCTK_FNAME (CartSymGN) (int *ierr, const cGH **GH, ONE_FORTSTRING_ARG) { ONE_FORTSTRING_CREATE (gname) *ierr = CartSymGN (*GH, gname); free (gname); } /*@@ @routine CartSymVI @date April 2000 @author Gerd Lanfermann @desc Apply symmetry boundary routines by variable index @enddesc @calls ApplySymmetry @var GH @vdesc Pointer to CCTK grid hierarchy @vtype const cGH * @vio in @endvar @var gindex @vdesc index of variable to apply symmetry BC @vtype int @vio in @endvar @returntype int @returndesc return code of @seeroutine ApplySymmetry
-1 if invalid variable index was given @endreturndesc @@*/ int CartSymVI (const cGH *GH, int vindex) { int retval, gindex; gindex = CCTK_GroupIndexFromVarI (vindex); if (gindex >= 0) { char * fullname = CCTK_FullName (vindex); if (!fullname) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error returned from function CCTK_FullName"); CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING, "You should not call the symmetry boundary condition routines for the variable \"%s\" through the CartSym* routines any more. The symmetry boundary conditions are now applied automatically when a physical boundary condition is applied.", fullname); free (fullname); retval = ApplySymmetry (GH, gindex, vindex, 1); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Invalid variable index %d in CartSymVI", vindex); retval = -1; } return (retval); } void CCTK_FCALL CCTK_FNAME (CartSymVI) (int *ierr, const cGH **GH, int *vindex) { *ierr = CartSymVI (*GH, *vindex); } /*@@ @routine CartSymVN @date April 2000 @author Gerd Lanfermann @desc Apply symmetry boundary routines by variable name @enddesc @calls ApplySymmetry @var GH @vdesc Pointer to CCTK grid hierarchy @vtype const cGH * @vio in @endvar @var gname @vdesc name of variable to apply symmetry BC @vtype const char * @vio in @endvar @returntype int @returndesc return code of @seeroutine ApplySymmetry
-1 if invalid variable name was given @endreturndesc @@*/ int CartSymVN (const cGH *GH, const char *vname) { int vindex, retval; vindex = CCTK_VarIndex (vname); if (vindex >= 0) { retval = CartSymVI (GH, vindex); } else { CCTK_VWarn (1,__LINE__,__FILE__,CCTK_THORNSTRING, "Invalid variable name '%s' in CartSymVN", vname); retval = -1; } return (retval); } void CCTK_FCALL CCTK_FNAME (CartSymVN) (int *ierr, const cGH **GH, ONE_FORTSTRING_ARG) { ONE_FORTSTRING_CREATE (vname) *ierr = CartSymVN (*GH, vname); free (vname); } /******************************************************************** ********************* Local Routines ************************* ********************************************************************/ /* macro to compute the linear index of a 3D point */ #define INDEX_3D(lsh, i, j, k) ((i) + (lsh)[0]*((j) + (lsh)[1]*(k))) /*@@ @routine SYMMETRY_BOUNDARY @date Sat 02 Nov 2002 @author Thomas Radke @desc Macro to apply symmetry boundary conditions to a variable of given datatype Currently it is limited up to 3D variables only. @enddesc @var cctk_type @vdesc CCTK datatype of the variable @vtype @vio in @endvar @@*/ #define APPLY_LOWER(dir, ii, jj, kk, jjend, kkend, iii, jjj, kkk) \ { \ for (kk = 0; kk < kkend; kk++) \ { \ for (jj = 0; jj < jjend; jj++) \ { \ for (ii = 0; ii < gdata.nghostzones[dir/2]; ii++) \ { \ _var[INDEX_3D (lsh, i, j, k)] NUMBER_PART = GFSym[vindex][dir] * \ _var[INDEX_3D (lsh, iii, jjj, kkk)] NUMBER_PART; \ } \ } \ } \ } #define APPLY_UPPER(dir, ii, jj, kk, jjend, kkend, iii, jjj, kkk) \ { \ for (kk = 0; kk < kkend; kk++) \ { \ for (jj = 0; jj < jjend; jj++) \ { \ for (ii = lsh[dir/2]-gdata.nghostzones[dir/2]; ii < lsh[dir/2]; ii++) \ { \ _var[INDEX_3D (lsh, i, j, k)] NUMBER_PART = GFSym[vindex][dir] * \ _var[INDEX_3D (lsh, iii, jjj, kkk)] NUMBER_PART; \ } \ } \ } \ } #define SYMMETRY_BOUNDARY(cctk_type) \ { \ cctk_type *_var = GH->data[vindex][0]; \ \ switch (group_static_data.dim) \ { \ case 3: \ /* apply symmetry to the z faces */ \ if (doSym[4] == GFSYM_REFLECTION) \ { \ APPLY_LOWER (4, k, j, i, lssh[1], lssh[0], i, j, offset[4]-k); \ } \ if (doSym[5] == GFSYM_REFLECTION) \ { \ APPLY_UPPER (5, k, j, i, lssh[1], lssh[0], i, j, offset[5]-k); \ } \ if (doSym[4] == GFSYM_ROTATION_X) \ { \ APPLY_LOWER (4, k, j, i, lssh[1], lssh[0], i, lssh[1]-j-1, offset[4]-k); \ } \ if (doSym[5] == GFSYM_ROTATION_X) \ { \ APPLY_UPPER (5, k, j, i, lssh[1], lssh[0], i, lssh[1]-j-1, offset[5]-k); \ } \ if (doSym[4] == GFSYM_ROTATION_Y) \ { \ APPLY_LOWER (4, k, j, i, lssh[1], lssh[0], lssh[0]-i-1, j, offset[4]-k); \ } \ if (doSym[5] == GFSYM_ROTATION_Y) \ { \ APPLY_UPPER (5, k, j, i, lssh[1], lssh[0], lssh[0]-i-1, j, offset[5]-k); \ } \ /* FALL THROUGH */ \ case 2: \ /* apply symmetry to the y faces */ \ if (doSym[2] == GFSYM_REFLECTION) \ { \ APPLY_LOWER (2, j, k, i, lssh[2], lssh[0], i, offset[2]-j, k); \ } \ if (doSym[3] == GFSYM_REFLECTION) \ { \ APPLY_UPPER (3, j, k, i, lssh[2], lssh[0], i, offset[3]-j, k); \ } \ if (doSym[2] == GFSYM_ROTATION_Z) \ { \ APPLY_LOWER (2, j, k, i, lssh[2], lssh[0], lssh[0]-i-1, offset[2]-j, k); \ } \ if (doSym[3] == GFSYM_ROTATION_Z) \ { \ APPLY_UPPER (3, j, k, i, lssh[2], lssh[0], lssh[0]-i-1, offset[3]-j, k); \ } \ if (group_static_data.dim > 2) \ { \ if (doSym[2] == GFSYM_ROTATION_X) \ { \ APPLY_LOWER (2, j, k, i, lssh[2], lssh[0], i, offset[2]-j, lssh[2]-k-1);\ } \ if (doSym[3] == GFSYM_ROTATION_X) \ { \ APPLY_UPPER (3, j, k, i, lssh[2], lssh[0], i, offset[3]-j, lssh[2]-k-1);\ } \ } \ /* FALL THROUGH */ \ case 1: \ /* apply symmetry to the x faces */ \ if (doSym[0] == GFSYM_REFLECTION) \ { \ APPLY_LOWER (0, i, j, k, lssh[1], lssh[2], offset[0]-i, j, k); \ } \ if (doSym[1] == GFSYM_REFLECTION) \ { \ APPLY_UPPER (1, i, j, k, lssh[1], lssh[2], offset[1]-i, j, k); \ } \ if (group_static_data.dim > 1) \ { \ if (doSym[0] == GFSYM_ROTATION_Z) \ { \ APPLY_LOWER (0, i, j, k, lssh[1], lssh[2], offset[0]-i, lssh[1]-j-1, k);\ } \ if (doSym[1] == GFSYM_ROTATION_Z) \ { \ APPLY_UPPER (1, i, j, k, lssh[1], lssh[2], offset[1]-i, lssh[1]-j-1, k);\ } \ } \ if (group_static_data.dim > 2) \ { \ if (doSym[0] == GFSYM_ROTATION_Y) \ { \ APPLY_LOWER (0, i, j, k, lssh[1], lssh[2], offset[0]-i, j, lssh[2]-k-1);\ } \ if (doSym[1] == GFSYM_ROTATION_Y) \ { \ APPLY_UPPER (1, i, j, k, lssh[1], lssh[2], offset[1]-i, j, lssh[2]-k-1);\ } \ } \ /* FALL THROUGH */ \ default: \ ; \ } \ } /* Function to apply above macros. */ #define SYMMETRY_FUNCTION(cctk_type,SUFFIX) \ static void cctk_type ## _SymBC ## SUFFIX(const cGH *GH, const int vindex, const int *doSym, const int *offset, const int *lsh, const int *lssh, const cGroup group_static_data, const cGroupDynamicData gdata, int **GFSym) { int i,j,k; SYMMETRY_BOUNDARY(cctk_type); } /* Create functions to apply macros. * This is much easier for the optiser to deal with. * E.g. on some machines we can't compile this file if we use the macros * directly in the switch statement in ApplySymmetry. */ #define NUMBER_PART .Re SYMMETRY_FUNCTION(CCTK_COMPLEX,R) #ifdef HAVE_CCTK_COMPLEX8 SYMMETRY_FUNCTION(CCTK_COMPLEX8,R) #endif #ifdef HAVE_CCTK_COMPLEX16 SYMMETRY_FUNCTION(CCTK_COMPLEX16,R) #endif #ifdef HAVE_CCTK_COMPLEX32 SYMMETRY_FUNCTION(CCTK_COMPLEX32,R) #endif #undef NUMBER_PART #define NUMBER_PART .Im SYMMETRY_FUNCTION(CCTK_COMPLEX,I) #ifdef HAVE_CCTK_COMPLEX8 SYMMETRY_FUNCTION(CCTK_COMPLEX8,I) #endif #ifdef HAVE_CCTK_COMPLEX16 SYMMETRY_FUNCTION(CCTK_COMPLEX16,I) #endif #ifdef HAVE_CCTK_COMPLEX32 SYMMETRY_FUNCTION(CCTK_COMPLEX32,I) #endif #undef NUMBER_PART #define NUMBER_PART SYMMETRY_FUNCTION(CCTK_CHAR,R) SYMMETRY_FUNCTION(CCTK_INT,R) #ifdef HAVE_CCTK_INT1 SYMMETRY_FUNCTION(CCTK_INT1,R) #endif #ifdef HAVE_CCTK_INT2 SYMMETRY_FUNCTION(CCTK_INT2,R) #endif #ifdef HAVE_CCTK_INT4 SYMMETRY_FUNCTION(CCTK_INT4,R) #endif #ifdef HAVE_CCTK_INT8 SYMMETRY_FUNCTION(CCTK_INT8,R) #endif SYMMETRY_FUNCTION(CCTK_REAL,R) #ifdef HAVE_CCTK_REAL4 SYMMETRY_FUNCTION(CCTK_REAL4,R) #endif #ifdef HAVE_CCTK_REAL8 SYMMETRY_FUNCTION(CCTK_REAL8,R) #endif #ifdef HAVE_CCTK_REAL16 SYMMETRY_FUNCTION(CCTK_REAL16,R) #endif #undef NUMBER_PART #define CALL_SYMBC(cctk_type,SUFFIX) cctk_type ## _SymBC ## SUFFIX(GH, vindex, doSym, offset, lsh, lssh, group_static_data, gdata, GFSym) /*@@ @routine ApplySymmetry @date Thu Mar 2 11:02:10 2000 @author Gerd Lanfermann @desc Apply symmetry boundary conditions to a group of grid variables This routine is called by the various CartSymXXX wrappers. @enddesc @var GH @vdesc Pointer to CCTK grid hierarchy @vtype const cGH * @vio in @endvar @var gindex @vdesc group index of the variables to apply symmetry BCs @vtype int @vio in @endvar @var first_var @vdesc index of first variable to apply symmetry BCs @vtype int @vio in @endvar @var num_vars @vdesc number of variables @vtype int @vio in @endvar @calls CCTK_GroupData CCTK_GroupDynamicData CCTK_StaggerDirArray SYMMETRY_BOUNDARY @history @hdate Sat 02 Nov 2002 @hauthor Thomas Radke @hdesc Merged separate routines for 1D, 2D, and 3D into a single generic routine @endhistory @returntype int @returndesc 0 for success, or
-1 if group dimension is not supported
-2 if group datatype is not supported @endreturndesc @@*/ static int ApplySymmetry (const cGH *GH, int gindex, int first_vindex, int numvars) { int i, j, k, dim, vindex, retval; int **GFSym; int domainsym[2*MAX_DIM], doSym[2*MAX_DIM], offset[2*MAX_DIM]; int dstag[MAX_DIM], lsh[MAX_DIM], lssh[MAX_DIM], cntstag[MAX_DIM]; cGroup group_static_data; cGroupDynamicData gdata; DECLARE_CCTK_PARAMETERS DecodeSymParameters3D (domainsym); /* check if any symmetries are to be applied */ for (i = 0; i < 2*MAX_DIM; i++) { if (domainsym[i]) { break; } } if (i == 2*MAX_DIM) { return (0); } /* get the group's static and dynamic data structure */ CCTK_GroupData (gindex, &group_static_data); CCTK_GroupDynamicData (GH, gindex, &gdata); if (group_static_data.dim <= 0 || group_static_data.dim > MAX_DIM) { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "ApplySymmetry: group dimension must 1, 2, or 3"); return (-1); } /* Avoid origin? Default is yes */ cntstag[0] = no_origin && no_originx && avoid_origin && avoid_originx; cntstag[1] = no_origin && no_originy && avoid_origin && avoid_originy; cntstag[2] = no_origin && no_originz && avoid_origin && avoid_originz; /* get the directional staggering of the group */ CCTK_StaggerDirArray (dstag, group_static_data.dim, group_static_data.stagtype); /* initialize array for variables with less dimensions than MAX_DIM so that we can use the INDEX_3D macro later on */ for (i = 0; i < MAX_DIM; i++) { if (i < group_static_data.dim) { lsh[i] = gdata.lsh[i]; lssh[i] = GH->cctk_lssh[CCTK_LSSH_IDX (dstag[i], i)]; } else { lsh[i] = lssh[i] = 1; } offset[2*i+0] = 2*gdata.nghostzones[i] - cntstag[i]; offset[2*i+1] = 2*(lsh[i]-1) - offset[2*i+0]; } GFSym = ((SymmetryGHex *) CCTK_GHExtension (GH, "Symmetry"))->GFSym; /* Apply Symmetries if: + the Symmetry is activated (== NOT NOSYM) + the Symmetry is set (== NOT UNSET) + the length in the direction is more than 1 grid point + the processor has a lower/upper physical boundary. Whether a grid allows a symmetry along a direction (e.g. octant=all) is part if the Symmetry Setup process. */ retval = 0; for (vindex = first_vindex; vindex < first_vindex + numvars; vindex++) { for (dim = 0; dim < 2*group_static_data.dim; dim++) { if (GFSym[vindex][dim] == GFSYM_UNSET) { CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING, "Symmetries unspecified for '%s'", CCTK_VarName (vindex)); } doSym[dim] = (GFSym[vindex][dim] != GFSYM_NOSYM && GFSym[vindex][dim] != GFSYM_UNSET && lssh[dim/2] > 1 && GH->cctk_bbox[dim]) ? domainsym[dim] : 0; } switch (group_static_data.vartype) { case CCTK_VARIABLE_CHAR: CALL_SYMBC(CCTK_CHAR,R); break; case CCTK_VARIABLE_INT: CALL_SYMBC(CCTK_INT,R); break; case CCTK_VARIABLE_REAL: CALL_SYMBC(CCTK_REAL,R); break; case CCTK_VARIABLE_COMPLEX: CALL_SYMBC(CCTK_COMPLEX,R); CALL_SYMBC(CCTK_COMPLEX,I); break; #ifdef CCTK_INT1 case CCTK_VARIABLE_INT1: CALL_SYMBC(CCTK_INT1,R); break; #endif #ifdef CCTK_INT2 case CCTK_VARIABLE_INT2: CALL_SYMBC(CCTK_INT2,R); break; #endif #ifdef CCTK_INT4 case CCTK_VARIABLE_INT4: CALL_SYMBC(CCTK_INT4,R); break; #endif #ifdef CCTK_INT8 case CCTK_VARIABLE_INT8: CALL_SYMBC(CCTK_INT8,R); break; #endif #ifdef CCTK_REAL4 case CCTK_VARIABLE_REAL4: CALL_SYMBC(CCTK_REAL4,R); break; case CCTK_VARIABLE_COMPLEX8: CALL_SYMBC(CCTK_COMPLEX8,R); CALL_SYMBC(CCTK_COMPLEX8,I); break; #endif #ifdef CCTK_REAL8 case CCTK_VARIABLE_REAL8: CALL_SYMBC(CCTK_REAL8,R); break; case CCTK_VARIABLE_COMPLEX16: CALL_SYMBC(CCTK_COMPLEX16,R); CALL_SYMBC(CCTK_COMPLEX16,I); break; #endif #ifdef CCTK_REAL16 case CCTK_VARIABLE_REAL16: CALL_SYMBC(CCTK_REAL16,R); break; case CCTK_VARIABLE_COMPLEX32: CALL_SYMBC(CCTK_COMPLEX32,R); CALL_SYMBC(CCTK_COMPLEX32,I); break; #endif default: CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, "Unsupported variable type %d for variable '%s'", CCTK_VarTypeI (vindex), CCTK_VarName (vindex)); retval = -2; } } return (retval); } /*@@ @routine CartGrid3D_ApplyBC @date Sat Feb 07 @author Erik Schnetter @desc Apply the symmetry boundary conditions @enddesc @@*/ void CartGrid3D_ApplyBC (CCTK_ARGUMENTS) { DECLARE_CCTK_ARGUMENTS; int nvars; CCTK_INT * restrict indices; CCTK_INT * restrict faces; CCTK_INT * restrict widths; CCTK_INT * restrict tables; int vi; int gi; int i; int ierr; if (!cctkGH) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "cctkGH undeclared"); nvars = Boundary_SelectedGVs (cctkGH, 0, 0, 0, 0, 0, 0); if (nvars<0) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error returned from function Boundary_selectedGVs"); indices = malloc (nvars * sizeof *indices); if(! (nvars==0 || indices)) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error in function CartGrid3D_ApplyBC"); faces = malloc (nvars * sizeof *faces); if(! (nvars==0 || faces)) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error in function CartGrid3D_ApplyBC"); widths = malloc (nvars * sizeof *widths); if(! (nvars==0 || widths)) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error in function CartGrid3D_ApplyBC"); tables = malloc (nvars * sizeof *tables); if(! (nvars==0 || tables)) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error in function CartGrid3D_ApplyBC"); ierr = Boundary_SelectedGVs (cctkGH, nvars, indices, faces, widths, tables, 0); if(! (ierr == nvars)) CCTK_VWarn ( 0, __LINE__, __FILE__, "CartGrid3D", "error in function CartGrid3D_ApplyBC"); for (i=0; i=0 && vi