diff options
Diffstat (limited to 'src/ConfMetric.c')
-rw-r--r-- | src/ConfMetric.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/src/ConfMetric.c b/src/ConfMetric.c new file mode 100644 index 0000000..be9b0d2 --- /dev/null +++ b/src/ConfMetric.c @@ -0,0 +1,546 @@ + /*@@ + @file ConfMetric.c + @date Tue Sep 26 11:29:18 2000 + @author Gerd Lanfermann + @desc + Provides sor solver engine routines + @enddesc + @@*/ + +#include <stdlib.h> +#include <stdio.h> +#include <math.h> +#include <string.h> + +#include "cctk.h" +#include "cctk_Arguments.h" +#include "cctk_Parameters.h" + +#include "Boundary.h" +#include "Symmetry.h" +#include "Ell_DBstructure.h" +#include "EllBase.h" + +static const char *rcsid = "$Header$"; + +CCTK_FILEVERSION(CactusElliptic_EllSOR_ConfMetric_c) + +#define SQR(a) ((a)*(a)) + +static int firstcall = 1; + +int SORConfMetric3D(cGH *GH, int *MetricPsiI, int conformal, + int FieldIndex, int MIndex, int NIndex, + CCTK_REAL *AbsTol, CCTK_REAL *RelTol); + + /*@@ + @routine SORConfMetric3D + @date Tue Sep 26 11:28:08 2000 + @author Joan Masso, Paul Walker, Gerd Lanfermann + @desc + This is a standalone sor solver engine, + called by the wrapper functions + @enddesc + @calls + @calledby + @history + + @endhistory + +@@*/ + +int SORConfMetric3D(cGH *GH, int *MetricPsiI, int conformal, + int FieldIndex, int MIndex, int NIndex, + CCTK_REAL *AbsTol, CCTK_REAL *RelTol) +{ + DECLARE_CCTK_PARAMETERS + + int retval = ELL_SUCCESS; + int timelevel; + int origin_sign; + + /* The pointer to the metric fields */ + CCTK_REAL *gxx =NULL, *gxy =NULL; + CCTK_REAL *gxz =NULL, *gyy =NULL; + CCTK_REAL *gyz =NULL, *gzz =NULL; + CCTK_REAL *psi =NULL; + CCTK_REAL *Mlin=NULL, *Nlin=NULL; + CCTK_REAL *var =NULL; + + /* The inverse metric, allocated here */ + CCTK_REAL *uxx=NULL, *uyy=NULL, + *uzz=NULL, *uxz=NULL, + *uxy=NULL, *uyz=NULL; + + /* shortcuts for metric, psi, deltas, etc. */ + CCTK_REAL pm4, p12, det; + + CCTK_REAL dx,dy,dz; + CCTK_REAL dxdx, dydy, dzdz, + dxdy, dxdz, dydz; + + /* Some physical variables */ + CCTK_REAL omega, resnorm=0.0, residual=0.0; + CCTK_REAL glob_residual=0.0, rjacobian=0.0; + CCTK_REAL finf; + CCTK_INT npow; + CCTK_REAL tol; + + /* Iteration / stepping variables */ + int sorit, maxit; + int i,j,k; + int nxyz; + + /* 19 point stencil index */ + int ijk; + int ipjk, ijpk, ijkp, imjk, ijmk, ijkm; + int ipjpk, ipjmk, imjpk, imjmk; + int ipjkp, ipjkm, imjkp, imjkm; + int ijpkp, ijpkm, ijmkp, ijmkm; + + /* 19 point stencil coefficients */ + CCTK_REAL ac; + CCTK_REAL ae,aw,an,as,at,ab; + CCTK_REAL ane, anw, ase, asw, ate, atw, abe, abw; + CCTK_REAL atn, ats, abn, absol; + + /* Miscellaneous */ + int sum_handle=-1; + int sw[3], ierr; + int Mstorage=0, Nstorage=0; + size_t varsize; + CCTK_REAL detrec_pm4, sqrtdet; + char *robin=NULL; + char *sor_accel=NULL; + + + /* Get the reduction handle */ + sum_handle = CCTK_ReductionArrayHandle("sum"); + if (sum_handle<0) + { + CCTK_WARN(1,"SORConfMetric3D: " + "Cannot get handle for sum reduction"); + retval = ELL_FAILURE; + } + + /* If Robin BCs are set, prepare for a boundary call: + setup stencil width and get Robin constants (set by the routine + which is calling the solver interface) */ + if (Ell_GetStrKey(&robin, "EllLinConfMetric::Bnd::Robin")< 0) + { + CCTK_WARN(1,"SORConfMetric3D: Robin keys not set"); + } + + if (CCTK_EQUALS(robin,"yes")) + { + sw[0]=1; + sw[1]=1; + sw[2]=1; + + ierr = Ell_GetRealKey(&finf, "EllLinConfMetric::Bnd::Robin::inf"); + ierr = Ell_GetIntKey (&npow, "EllLinConfMetric::Bnd::Robin::falloff"); + } + + /* Get the maximum number of iterations allowed. */ + if (Ell_GetIntKey(&maxit, "Ell::SORmaxit") == ELLGET_NOTSET) + { + CCTK_WARN(1,"SORConfMetric3D: Ell::SORmaxit not set. " + "Maximum allowed iterations being set to 100."); + maxit = 100; + } + + /* Only supports absolute tolerance */ + tol = AbsTol[0]; + + /* Get the type of acceleration to use. */ + if (Ell_GetStrKey(&sor_accel, "Ell::SORaccel") == ELLGET_NOTSET) + { + const char tmpstr[6] = "const"; + CCTK_WARN(1,"SORConfMetric3D: Ell::SORaccel not set. " + "Omega being set to a constant value of 1.8."); + sor_accel = strdup(tmpstr); + } + + /* Things to do only once! */ + if (firstcall==1) + { + if (CCTK_Equals(elliptic_verbose, "yes")) + { + if (CCTK_Equals(sor_accel, "cheb")) + { + CCTK_INFO("SOR with Chebyshev acceleration"); + } + else if (CCTK_Equals(sor_accel, "const")) + { + CCTK_INFO("SOR with hardcoded omega = 1.8"); + } + else if (CCTK_Equals(sor_accel, "none")) + { + CCTK_INFO("SOR with unaccelerated relaxation (omega = 1)"); + } + else + { + CCTK_WARN(0, "SORConfMetric3D: sor_accel not set"); + } + } + firstcall = 0; + } + + /* + Get the data ptr of these GFs. + They all have to be on the same timelevel. + Derive the metric data pointer from the index array. + Note the ordering in the metric + */ + + timelevel = 0; + var = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, FieldIndex); + + timelevel = 0; + gxx = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[0]); + gxy = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[1]); + gxz = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[2]); + gyy = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[3]); + gyz = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[4]); + gzz = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[5]); + + if (conformal) + { + timelevel = 0; + psi = (CCTK_REAL*) CCTK_VarDataPtrI(GH, timelevel, MetricPsiI[6]); + } + + /* if we have a negative index for M/N, this GF is not needed, + there for don't even look for it. when index positive, + set flag Mstorage=1, dito for N */ + if (MIndex>=0) + { + timelevel = 0; + Mlin = (CCTK_REAL*) CCTK_VarDataPtrI(GH,timelevel,MIndex); + if (Mlin) + { + Mstorage = 1; + } + else + { + CCTK_WARN(0, "SORConfMetric3D: Unable to get pointer to M."); + } + } + if (NIndex>=0) + { + timelevel = 0; + Nlin = (CCTK_REAL*) CCTK_VarDataPtrI(GH,timelevel,NIndex); + if (Nlin) + { + Nstorage = 1; + } + else + { + CCTK_WARN(0, "SORConfMetric3D: Unable to get pointer to N."); + } + } + + /* Shortcuts */ + dx = GH->cctk_delta_space[0]; + dy = GH->cctk_delta_space[1]; + dz = GH->cctk_delta_space[2]; + nxyz = GH->cctk_lsh[0]*GH->cctk_lsh[1]*GH->cctk_lsh[2]; + + /* Allocate the inverse metric */ + varsize = (size_t)CCTK_VarTypeSize(CCTK_VarTypeI(FieldIndex))*nxyz; + uxx = (CCTK_REAL*) malloc(varsize); + uxy = (CCTK_REAL*) malloc(varsize); + uxz = (CCTK_REAL*) malloc(varsize); + uyy = (CCTK_REAL*) malloc(varsize); + uyz = (CCTK_REAL*) malloc(varsize); + uzz = (CCTK_REAL*) malloc(varsize); + + if (!uxx || !uxy || !uxz || !uyy || !uyz || !uzz) + { + CCTK_WARN(0,"SORConfMetric3D: Memory allocation failed for upper metric"); + } + + /* calculate the differential coefficient */ + dxdx = 0.5/(dx*dx); + dydy = 0.5/(dy*dy); + dzdz = 0.5/(dz*dz); + dxdy = 0.25/(dx*dy); + dxdz = 0.25/(dx*dz); + dydz = 0.25/(dy*dz); + + /* Calculate the inverse metric */ + for (ijk=0; ijk<nxyz; ijk++) + { + det = -(SQR(gxz[ijk])*gyy[ijk]) + + 2*gxy[ijk]*gxz[ijk]*gyz[ijk] - + gxx[ijk]*SQR(gyz[ijk]) - + SQR(gxy[ijk])*gzz[ijk] + + gxx[ijk]*gyy[ijk]*gzz[ijk]; + + if (conformal) + { + pm4 = 1.0/pow(psi[ijk],4.0); + p12 = pow(psi[ijk],12.0); + } + else + { + pm4 = 1.0; + p12 = 1.0; + } + + /* try to avoid constly division */ + detrec_pm4 = 1.0/det*pm4; + sqrtdet = sqrt(det); + + uxx[ijk]=(-SQR(gyz[ijk]) + gyy[ijk]*gzz[ijk])*detrec_pm4; + uxy[ijk]=( gxz[ijk]*gyz[ijk] - gxy[ijk]*gzz[ijk])*detrec_pm4; + uxz[ijk]=(-gxz[ijk]*gyy[ijk] + gxy[ijk]*gyz[ijk])*detrec_pm4; + uyy[ijk]=(-SQR(gxz[ijk]) + gxx[ijk]*gzz[ijk])*detrec_pm4; + uyz[ijk]=( gxy[ijk]*gxz[ijk] - gxx[ijk]*gyz[ijk])*detrec_pm4; + uzz[ijk]=(-SQR(gxy[ijk]) + gxx[ijk]*gyy[ijk])*detrec_pm4; + + det = det*p12; + sqrtdet= sqrt(det); + + /* Rescaling for the uppermetric solver */ + if (Mstorage) + { + Mlin[ijk] = Mlin[ijk]*sqrt(det); + } + if (Nstorage) + { + Nlin[ijk] = Nlin[ijk]*sqrt(det); + } + + uxx[ijk]=uxx[ijk]*dxdx*sqrtdet; + uyy[ijk]=uyy[ijk]*dydy*sqrtdet; + uzz[ijk]=uzz[ijk]*dzdz*sqrtdet; + uxy[ijk]=uxy[ijk]*dxdy*sqrtdet; + uxz[ijk]=uxz[ijk]*dxdz*sqrtdet; + uyz[ijk]=uyz[ijk]*dydz*sqrtdet; + + } + + /* Initialize omega. */ + /* TODO: Make it so that the value of the constant omega can be set. */ + if (CCTK_Equals(sor_accel, "const")) + { + omega = 1.8; + } + else + { + omega = 1.; + } + + /* Set the spectral radius of the Jacobi iteration. */ + rjacobian = 0.999; + + /* Compute whether the origin of this processor's + sub grid is "red" or "black". */ + + origin_sign = (GH->cctk_lbnd[0] + GH->cctk_lbnd[1] + GH->cctk_lbnd[2])%2; + + /* start at 1 for historic (Fortran) reasons */ + for (sorit=1; sorit<=maxit; sorit++) + { + resnorm = 0.0; + + for (k=1; k<GH->cctk_lsh[2]-1; k++) + { + for (j=1; j<GH->cctk_lsh[1]-1; j++) + { + for (i=1; i<GH->cctk_lsh[0]-1; i++) + { + if ((origin_sign+i+j+k)%2 == sorit%2) + { + ijk = CCTK_GFINDEX3D(GH,i ,j ,k ); + + ipjk = CCTK_GFINDEX3D(GH,i+1,j ,k ); + imjk = CCTK_GFINDEX3D(GH,i-1,j ,k ); + ijpk = CCTK_GFINDEX3D(GH,i ,j+1,k ); + ijmk = CCTK_GFINDEX3D(GH,i ,j-1,k ); + ijkp = CCTK_GFINDEX3D(GH,i ,j ,k+1); + ijkm = CCTK_GFINDEX3D(GH,i ,j ,k-1); + + ipjpk = CCTK_GFINDEX3D(GH,i+1,j+1,k ); + ipjmk = CCTK_GFINDEX3D(GH,i+1,j-1,k ); + imjpk = CCTK_GFINDEX3D(GH,i-1,j+1,k ); + imjmk = CCTK_GFINDEX3D(GH,i-1,j-1,k ); + + ijpkp = CCTK_GFINDEX3D(GH,i ,j+1,k+1); + ijpkm = CCTK_GFINDEX3D(GH,i ,j+1,k-1); + ijmkp = CCTK_GFINDEX3D(GH,i ,j-1,k+1); + ijmkm = CCTK_GFINDEX3D(GH,i ,j-1,k-1); + + ipjkp = CCTK_GFINDEX3D(GH,i+1,j ,k+1); + ipjkm = CCTK_GFINDEX3D(GH,i+1,j ,k-1); + imjkp = CCTK_GFINDEX3D(GH,i-1,j ,k+1); + imjkm = CCTK_GFINDEX3D(GH,i-1,j ,k-1); + + ac = -1.0*uxx[ipjk] - 2.0*uxx[ijk] - 1.0*uxx[imjk] + -1.0*uyy[ijpk] - 2.0*uyy[ijk] - 1.0*uyy[ijmk] + -1.0*uzz[ijkp] - 2.0*uzz[ijk] - 1.0*uzz[ijkm]; + + if (Mstorage) + { + ac += Mlin[ijk]; + } + + ae = uxx[ipjk]+uxx[ijk]; + aw = uxx[imjk]+uxx[ijk]; + an = uyy[ijpk]+uyy[ijk]; + as = uyy[ijmk]+uyy[ijk]; + at = uzz[ijkp]+uzz[ijk]; + ab = uzz[ijkm]+uzz[ijk]; + + ane = uxy[ijpk]+uxy[ipjk]; + anw =-uxy[imjk]-uxy[ijpk]; + ase =-uxy[ipjk]-uxy[ijmk]; + asw = uxy[imjk]+uxy[ijmk]; + + ate = uxz[ijkp]+uxz[ipjk]; + atw =-uxz[imjk]-uxz[ijkp]; + abe =-uxz[ipjk]-uxz[ijkm]; + abw = uxz[imjk]+uxz[ijkm]; + + atn = uyz[ijpk]+uyz[ijkp]; + ats =-uyz[ijkp]-uyz[ijmk]; + abn =-uyz[ijkm]-uyz[ijpk]; + absol = uyz[ijkm]+uyz[ijmk]; + + residual = ac * var[ijk] + + ae *var[ipjk] + aw*var[imjk] + + an *var[ijpk] + as*var[ijmk] + + at *var[ijkp] + ab*var[ijkm]; + + residual = residual + + ane*var[ipjpk] + anw*var[imjpk]; + + residual = residual + + ase*var[ipjmk] + asw*var[imjmk]; + + residual = residual + + ate*var[ipjkp] + atw*var[imjkp] + + abe*var[ipjkm] + abw*var[imjkm] + + atn*var[ijpkp] + ats*var[ijmkp] + + abn*var[ijpkm] + absol*var[ijmkm]; + + if (Nstorage) + { + residual +=Nlin[ijk]; + } + + resnorm = resnorm + fabs(residual); + + var[ijk] = var[ijk] - omega*residual/ac; + + } + } + } + } + + /* reduction operation on processor-local residual values */ + if (CCTK_ReduceLocScalar(GH, -1, sum_handle, + &resnorm, &glob_residual, CCTK_VARIABLE_REAL)<0) + { + CCTK_WARN(1,"SORConfMetric3D: Reduction of residual failed"); + } + + glob_residual = glob_residual / + (GH->cctk_gsh[0]*GH->cctk_gsh[1]*GH->cctk_gsh[2]); + + /* apply symmetry boundary conditions within loop */ + if (CartSymVI(GH,FieldIndex)<0) + { + CCTK_WARN(1,"SORConfMetric3D: CartSymVI failed in EllSOR loop"); + } + + /* apply Robin boundary conditions within loop */ + if (CCTK_EQUALS(robin,"yes")) + { + if (BndRobinVI(GH, sw, finf, npow, FieldIndex)<0) + { + CCTK_WARN(1, "SORConfMetric3D: BndRobinVI failed in EllSOR loop"); + break; + } + } + + /* synchronization of grid variable */ + ierr = CCTK_SyncGroupWithVarI(GH, FieldIndex); + if (ierr < 0) + { + CCTK_VWarn(1,__LINE__,__FILE__,CCTK_THORNSTRING, + "ConfMetric3D: Synchronization of %s failed (Error: %d)", + CCTK_VarName(FieldIndex),ierr); + } + + /* Leave iteration loop if tolerance criterium is met */ + if (glob_residual<tol) + { + break; + } + + /* Update omega if using Chebyshev acceleration. */ + if (CCTK_Equals(sor_accel, "cheb")) + { + if (sorit == 1) + { + omega = 1. / (1. - 0.5 * rjacobian * rjacobian); + } + else + { + omega = 1. / (1. - 0.25 * rjacobian * rjacobian * omega); + } + } + + } + + if (elliptic_verbose) + { + CCTK_VInfo(CCTK_THORNSTRING,"Required SOR tolerence was set at %f",tol); + CCTK_VInfo(CCTK_THORNSTRING,"Achieved SOR residual was %f",glob_residual); + CCTK_VInfo(CCTK_THORNSTRING, + "Number of iterations was %d (max: %d)",sorit,maxit); + } + + if (glob_residual>tol) + { + CCTK_WARN(1, "SORConfMetric3D: SOR Solver did not converge"); + retval = ELL_NOCONVERGENCE; + } + + if (uxx) + { + free(uxx); + } + if (uyy) + { + free(uyy); + } + if (uzz) + { + free(uzz); + } + if (uxy) + { + free(uxy); + } + if (uxz) + { + free(uxz); + } + if (uyz) + { + free(uyz); + } + if (robin) + { + free(robin); + } + if (sor_accel) + { + free(sor_accel); + } + + return retval; +} |