• Main Page
  • Classes
  • Files
  • File List
  • File Members

prob/linear_wave3d.c

Go to the documentation of this file.
00001 #include "copyright.h"
00002 /*============================================================================*/
00003 /*! \file linear_wave3d.c
00004  *  \brief Linear wave problem generator for 3D problems.
00005  *
00006  * PURPOSE: Linear wave problem generator for 3D problems. The generalization
00007  *   of linear_wave.c to handle 1D, 2D, and 3D problems seemed more complex
00008  *   than neccessary, so this special routine has been written to handle only
00009  *   3D problems.  This routine automatically sets the wavevector along the
00010  *   domain diagonal (cannot run grid-aligned waves).
00011  *
00012  *   Can be used for either standing (problem/vflow=1.0) or travelling
00013  *   (problem/vflow=0.0) waves.
00014  *
00015  *   Configure --with-gravity=fft to check Jeans stability of plane waves
00016  *   propagating parallel to grid.
00017  *
00018  *   Configure --enable-resistivity and/or --with-viscosity=ns to check
00019  *   damping of linear waves by resistivity/ambipolar diffusion and/or viscosity
00020  *
00021  * This code is most easily understood in terms of a one dimensional
00022  * problem in the coordinate system (x,y,z).  Two coordinate rotations are
00023  * applied to obtain a new wave vector in a 3D space in the (x1,x2,x3)
00024  * coordinate system.
00025  *
00026  *   First rotate about the y axis:
00027  *   - x' = x*cos(ang_2) - z*sin(ang_2)
00028  *   - y' = y
00029  *   - z' = x*sin(ang_2) + z*cos(ang_2)
00030  *
00031  *   Next rotate about the z' axis:
00032  *   - x = x'*cos(ang_3) - y'*sin(ang_3)
00033  *   - y = x'*sin(ang_3) + y'*cos(ang_3)
00034  *   - z = z'
00035  *
00036  *   Expanding this out we get:
00037  *   - x1 = x*cos(ang_2)*cos(ang_3) - y*sin(ang_3) - z*sin(ang_2)*cos(ang_3)
00038  *   - x2 = x*cos(ang_2)*sin(ang_3) - y*cos(ang_3) - z*sin(ang_2)*sin(ang_3)
00039  *   - x3 = x*sin(ang_2)                           + z*cos(ang_2)
00040  *
00041  *   This inverts to:
00042  *   - x =  x1*cos(ang_2)*cos(ang_3) + x2*cos(ang_2)*sin(ang_3) + x3*sin(ang_2)
00043  *   - y = -x1*sin(ang_3)            + x2*cos(ang_3)
00044  *   - z = -x1*sin(ang_2)*cos(ang_3) - x2*sin(ang_2)*sin(ang_3) + x3*cos(ang_2)
00045  *
00046  *   The magnetic field is given by:
00047  *   - B_x = b_par
00048  *   - B_y = b_perp*cos(k*x)
00049  *   - B_z = b_perp*sin(k*x)
00050  *   where k = 2.0*PI/lambda
00051  *
00052  * PRIVATE FUNCTION PROTOTYPES:
00053  * - A1() - 1-component of vector potential for initial conditions
00054  * - A2() - 2-component of vector potential for initial conditions
00055  * - A3() - 3-component of vector potential for initial conditions
00056  *
00057  * USERWORK_AFTER_LOOP function computes L1 error norm in solution by comparing
00058  *   to initial conditions.  Problem must be evolved for an integer number of
00059  *   wave periods for this to work (only works for ideal MHD).                */
00060 /*============================================================================*/
00061 
00062 #include <math.h>
00063 #include <stdio.h>
00064 #include <stdlib.h>
00065 #include "defs.h"
00066 #include "athena.h"
00067 #include "globals.h"
00068 #include "prototypes.h"
00069 
00070 /* Initial solution, shared with Userwork_after_loop to compute L1 error */
00071 static ConsS ***RootSoln=NULL;
00072 
00073 /* Parameters which define initial solution -- made global so that they can be
00074  * shared with functions A1,2,3 which compute vector potentials */
00075 #ifdef MHD
00076 static Real bx0, by0, bz0, dby, dbz;
00077 #endif
00078 static int wave_flag;
00079 static Real ang_2, ang_3; /* Rotation angles about the y and z' axis */
00080 static Real sin_a2, cos_a2, sin_a3, cos_a3;
00081 static Real lambda, k_par; /* Wavelength, 2*PI/wavelength */
00082 
00083 /*=============================================================================
00084  * PRIVATE FUNCTION PROTOTYPES:
00085  * A1() - 1-component of vector potential for initial conditions
00086  * A2() - 2-component of vector potential for initial conditions
00087  * A3() - 3-component of vector potential for initial conditions
00088  *============================================================================*/
00089 
00090 #ifdef MHD
00091 static Real A1(const Real x1, const Real x2, const Real x3);
00092 static Real A2(const Real x1, const Real x2, const Real x3);
00093 static Real A3(const Real x1, const Real x2, const Real x3);
00094 #endif /* MHD */
00095 
00096 /*=========================== PUBLIC FUNCTIONS ===============================*/
00097 /*----------------------------------------------------------------------------*/
00098 /* problem:  */
00099 
00100 void problem(DomainS *pDomain)
00101 {
00102   GridS *pGrid=(pDomain->Grid);
00103   ConsS ***Soln;
00104   int i=0,j=0,k=0;
00105   int is,ie,js,je,ks,ke,n,m,nx1,nx2,nx3;
00106   Real amp,vflow;
00107   Real d0,p0,u0,v0,w0,h0;
00108   Real x,x1,x2,x3,sn;
00109   Real Mx, My, Mz;
00110   Real ev[NWAVE],rem[NWAVE][NWAVE],lem[NWAVE][NWAVE];
00111   Real x1size, x2size, x3size;
00112 #ifdef MHD
00113   Real xfact,yfact;
00114   Real ***a1,***a2,***a3;
00115 #endif /* MHD */
00116 
00117   is = pGrid->is; ie = pGrid->ie;
00118   js = pGrid->js; je = pGrid->je;
00119   ks = pGrid->ks; ke = pGrid->ke;
00120 
00121   nx1 = (ie-is)+1 + 2*nghost;
00122   nx2 = (je-js)+1 + 2*nghost;
00123   nx3 = (ke-ks)+1 + 2*nghost;
00124 
00125   if (nx3 <= 1)
00126     ath_error("[linear_wave3d]: Only true 3D problems can be run\n");
00127 
00128 /* allocate memory for solution and vector potential */
00129 
00130 #ifdef MHD
00131   if ((a1 = (Real***)calloc_3d_array(nx3, nx2, nx1, sizeof(Real))) == NULL)
00132     ath_error("[problem]: Error allocating memory for \"a1\"\n");
00133 
00134   if ((a2 = (Real***)calloc_3d_array(nx3, nx2, nx1, sizeof(Real))) == NULL)
00135     ath_error("[problem]: Error allocating memory for \"a2\"\n");
00136 
00137   if ((a3 = (Real***)calloc_3d_array(nx3, nx2, nx1, sizeof(Real))) == NULL)
00138     ath_error("[problem]: Error allocating memory for \"a3\"\n");
00139 #endif /* MHD */
00140 
00141   if ((Soln = (ConsS***)calloc_3d_array(nx3,nx2,nx1,sizeof(ConsS)))==NULL)
00142     ath_error("[problem]: Error allocating memory for \"Soln\"\n");
00143 
00144   if (pDomain->Level == 0){
00145     if ((RootSoln = (ConsS***)calloc_3d_array(nx3,nx2,nx1,sizeof(ConsS)))
00146       == NULL) ath_error("[problem]: Error alloc memory for RootSoln\n");
00147   }
00148 
00149 
00150 /* Read initial conditions */
00151 
00152   wave_flag = par_geti("problem","wave_flag");
00153   amp = par_getd("problem","amp");
00154   vflow = par_getd("problem","vflow");
00155 
00156 /* Imposing periodicity and one wavelength along each grid direction */
00157 
00158   x1size = pDomain->RootMaxX[0] - pDomain->RootMinX[0];
00159   x2size = pDomain->RootMaxX[1] - pDomain->RootMinX[1];
00160   x3size = pDomain->RootMaxX[2] - pDomain->RootMinX[2];
00161 
00162   ang_3 = atan(x1size/x2size);
00163   sin_a3 = sin(ang_3);
00164   cos_a3 = cos(ang_3);
00165 
00166   ang_2 = atan(0.5*(x1size*cos_a3 + x2size*sin_a3)/x3size);
00167   sin_a2 = sin(ang_2);
00168   cos_a2 = cos(ang_2);
00169 
00170   x1 = x1size*cos_a2*cos_a3;
00171   x2 = x2size*cos_a2*sin_a3;
00172   x3 = x3size*sin_a2;
00173 
00174 /* For lambda choose the smaller of the 3 */
00175   lambda = x1;
00176   lambda = MIN(lambda,x2);
00177   lambda = MIN(lambda,x3);
00178 
00179 /* Initialize k_parallel */
00180   k_par = 2.0*PI/lambda;
00181 
00182 /* Get eigenmatrix, where the quantities u0 and bx0 are parallel to the
00183  * wavevector, and v0,w0,by0,bz0 are perpendicular. */
00184 
00185   d0 = 1.0;
00186 #ifndef ISOTHERMAL
00187   p0 = 1.0/Gamma;
00188   u0 = vflow*sqrt(Gamma*p0/d0);
00189 #else
00190   u0 = vflow*Iso_csound;
00191 #endif
00192   v0 = 0.0;
00193   w0 = 0.0;
00194 #ifdef MHD
00195   bx0 = 1.0;
00196   by0 = sqrt(2.0);
00197   bz0 = 0.5;
00198   xfact = 0.0;
00199   yfact = 1.0;
00200 #endif
00201 
00202   for (n=0; n<NWAVE; n++) {
00203     for (m=0; m<NWAVE; m++) {
00204       rem[n][m] = 0.0;
00205       lem[n][m] = 0.0;
00206     }
00207   }
00208 
00209 #ifdef HYDRO
00210 #ifdef ISOTHERMAL
00211   esys_roe_iso_hyd(u0,v0,w0,   ev,rem,lem);
00212 #else
00213   h0 = ((p0/Gamma_1 + 0.5*d0*(u0*u0+v0*v0+w0*w0)) + p0)/d0;
00214   esys_roe_adb_hyd(u0,v0,w0,h0,ev,rem,lem);
00215   ath_pout(0,"Ux - Cs = %e, %e\n",ev[0],rem[0][wave_flag]);
00216   ath_pout(0,"Ux      = %e, %e\n",ev[1],rem[1][wave_flag]);
00217   ath_pout(0,"Ux + Cs = %e, %e\n",ev[4],rem[4][wave_flag]);
00218 #endif /* ISOTHERMAL */
00219 #endif /* HYDRO */
00220 
00221 #ifdef MHD
00222 #if defined(ISOTHERMAL)
00223   esys_roe_iso_mhd(d0,u0,v0,w0,bx0,by0,bz0,xfact,yfact,ev,rem,lem);
00224   ath_pout(0,"Ux - Cf = %e, %e\n",ev[0],rem[0][wave_flag]);
00225   ath_pout(0,"Ux - Ca = %e, %e\n",ev[1],rem[1][wave_flag]);
00226   ath_pout(0,"Ux - Cs = %e, %e\n",ev[2],rem[2][wave_flag]);
00227   ath_pout(0,"Ux + Cs = %e, %e\n",ev[3],rem[3][wave_flag]);
00228   ath_pout(0,"Ux + Ca = %e, %e\n",ev[4],rem[4][wave_flag]);
00229   ath_pout(0,"Ux + Cf = %e, %e\n",ev[5],rem[5][wave_flag]);
00230 #else
00231   h0 = ((p0/Gamma_1+0.5*(bx0*bx0+by0*by0+bz0*bz0)+0.5*d0*(u0*u0+v0*v0+w0*w0))
00232                + (p0+0.5*(bx0*bx0+by0*by0+bz0*bz0)))/d0;
00233   esys_roe_adb_mhd(d0,u0,v0,w0,h0,bx0,by0,bz0,xfact,yfact,ev,rem,lem);
00234   ath_pout(0,"Ux - Cf = %e, %e\n",ev[0],rem[0][wave_flag]);
00235   ath_pout(0,"Ux - Ca = %e, %e\n",ev[1],rem[1][wave_flag]);
00236   ath_pout(0,"Ux - Cs = %e, %e\n",ev[2],rem[2][wave_flag]);
00237   ath_pout(0,"Ux      = %e, %e\n",ev[3],rem[3][wave_flag]);
00238   ath_pout(0,"Ux + Cs = %e, %e\n",ev[4],rem[4][wave_flag]);
00239   ath_pout(0,"Ux + Ca = %e, %e\n",ev[5],rem[5][wave_flag]);
00240   ath_pout(0,"Ux + Cf = %e, %e\n",ev[6],rem[6][wave_flag]);
00241 #endif /* ISOTHERMAL */
00242 #endif /* MHD */
00243 
00244 
00245 /* Now initialize wave at appropriate angle to grid */
00246 /* Fields are initialized using vector potentials */
00247 
00248 #ifdef MHD
00249 /* Initialize the wave amplitudes for By and Bz */
00250   dby = amp*rem[NWAVE-2][wave_flag];
00251   dbz = amp*rem[NWAVE-1][wave_flag];
00252 
00253 /* Initialize the Vector potential */
00254   for (k=ks; k<=ke+1; k++) {
00255     for (j=js; j<=je+1; j++) {
00256       for (i=is; i<=ie+1; i++) {
00257         cc_pos(pGrid,i,j,k,&x1,&x2,&x3);
00258 
00259         a1[k][j][i] = A1(x1, x2-0.5*pGrid->dx2, x3-0.5*pGrid->dx3);
00260 
00261         a2[k][j][i] = A2(x1-0.5*pGrid->dx1, x2, x3-0.5*pGrid->dx3);
00262 
00263         a3[k][j][i] = A3(x1-0.5*pGrid->dx1, x2-0.5*pGrid->dx2, x3);
00264       }
00265     }
00266   }
00267 
00268 /* Initialize the interface fields in the Grid */
00269   for (k=ks; k<=ke; k++) {
00270     for (j=js; j<=je; j++) {
00271       for (i=is; i<=ie+1; i++) {
00272         pGrid->B1i[k][j][i] = (a3[k  ][j+1][i] - a3[k][j][i])/pGrid->dx2 -
00273                               (a2[k+1][j  ][i] - a2[k][j][i])/pGrid->dx3;
00274       }
00275     }
00276   }
00277 
00278   for (k=ks; k<=ke; k++) {
00279     for (j=js; j<=je+1; j++) {
00280       for (i=is; i<=ie; i++) {
00281         pGrid->B2i[k][j][i] = (a1[k+1][j][i  ] - a1[k][j][i])/pGrid->dx3 -
00282                               (a3[k  ][j][i+1] - a3[k][j][i])/pGrid->dx1;
00283       }
00284     }
00285   }
00286 
00287   for (k=ks; k<=ke+1; k++) {
00288     for (j=js; j<=je; j++) {
00289       for (i=is; i<=ie; i++) {
00290         pGrid->B3i[k][j][i] = (a2[k][j  ][i+1] - a2[k][j][i])/pGrid->dx1 -
00291                               (a1[k][j+1][i  ] - a1[k][j][i])/pGrid->dx2;
00292       }
00293     }
00294   }
00295 
00296 /* compute cell-centered B-fields */
00297   for (k=ks; k<=ke; k++) {
00298     for (j=js; j<=je; j++) {
00299       for (i=is; i<=ie; i++) {
00300         Soln[k][j][i].B1c = 0.5*(pGrid->B1i[k][j][i]+pGrid->B1i[k  ][j  ][i+1]);
00301         Soln[k][j][i].B2c = 0.5*(pGrid->B2i[k][j][i]+pGrid->B2i[k  ][j+1][i  ]);
00302         Soln[k][j][i].B3c = 0.5*(pGrid->B3i[k][j][i]+pGrid->B3i[k+1][j  ][i  ]);
00303       }
00304     }
00305   }
00306 #endif /* MHD */
00307 
00308 /* The initial solution is stored into global 3D arrays so the error norm can
00309  * be computed at the end of the run.  After calculating these arrays, the
00310  * conserved variables are set equal to them */
00311 
00312   for (k=ks; k<=ke; k++) {
00313     for (j=js; j<=je; j++) {
00314       for (i=is; i<=ie; i++) {
00315         cc_pos(pGrid,i,j,k,&x1,&x2,&x3);
00316 
00317         x = cos_a2*(x1*cos_a3 + x2*sin_a3) + x3*sin_a2;
00318 
00319         sn = sin(k_par*x);
00320 
00321         Soln[k][j][i].d = d0 + amp*sn*rem[0][wave_flag];
00322 
00323         Mx = d0*vflow + amp*sn*rem[1][wave_flag];
00324         My = amp*sn*rem[2][wave_flag];
00325         Mz = amp*sn*rem[3][wave_flag];
00326 
00327         Soln[k][j][i].M1 = Mx*cos_a2*cos_a3 - My*sin_a3 - Mz*sin_a2*cos_a3;
00328         Soln[k][j][i].M2 = Mx*cos_a2*sin_a3 + My*cos_a3 - Mz*sin_a2*sin_a3;
00329         Soln[k][j][i].M3 = Mx*sin_a2                    + Mz*cos_a2;
00330 
00331 #ifndef ISOTHERMAL
00332         Soln[k][j][i].E = p0/Gamma_1 + 0.5*d0*u0*u0 +
00333 #ifdef MHD
00334           0.5*(bx0*bx0 + by0*by0 + bz0*bz0) +
00335 #endif /* MHD */
00336           amp*sn*rem[4][wave_flag];
00337 #endif /* ISOTHERMAL */
00338       }
00339     }
00340   }
00341 
00342 /* Now set initial conditions to 3d wave solution */ 
00343 
00344   for (k=ks; k<=ke; k++) {
00345     for (j=js; j<=je; j++) {
00346       for (i=is; i<=ie; i++) {
00347         pGrid->U[k][j][i].d = Soln[k][j][i].d;
00348 #ifndef ISOTHERMAL
00349         pGrid->U[k][j][i].E = Soln[k][j][i].E;
00350 #endif /* ISOTHERMAL */
00351         pGrid->U[k][j][i].M1 = Soln[k][j][i].M1;
00352         pGrid->U[k][j][i].M2 = Soln[k][j][i].M2;
00353         pGrid->U[k][j][i].M3 = Soln[k][j][i].M3;
00354 #ifdef MHD
00355         pGrid->U[k][j][i].B1c = Soln[k][j][i].B1c;
00356         pGrid->U[k][j][i].B2c = Soln[k][j][i].B2c;
00357         pGrid->U[k][j][i].B3c = Soln[k][j][i].B3c;
00358 #endif /* MHD */
00359       }
00360     }
00361   }
00362 
00363 #ifdef MHD
00364   free_3d_array((void***)a1);
00365   free_3d_array((void***)a2);
00366   free_3d_array((void***)a3);
00367 #endif /* MHD */
00368 
00369 /* For self-gravitating problems, read 4\piG and compute mean density */
00370 
00371 #ifdef SELF_GRAVITY
00372   four_pi_G = par_getd("problem","four_pi_G");
00373   grav_mean_rho = d0;
00374 #endif /* SELF_GRAVITY */
00375 
00376 /* With viscosity and/or resistivity, read eta_R and nu_V */
00377 
00378 #ifdef RESISTIVITY 
00379   eta_Ohm = par_getd("problem","eta_O");
00380   Q_AD    = par_getd_def("problem","Q_AD",0.0);
00381   d_ind   = par_getd_def("problem","d_ind",0.0);
00382 #endif
00383 #ifdef NAVIER_STOKES
00384   nu_V = par_getd("problem","nu");
00385 #endif
00386 
00387 /* save solution on root grid */
00388 
00389   if (pDomain->Level == 0) {
00390     for (k=ks; k<=ke; k++) {
00391     for (j=js; j<=je; j++) {
00392     for (i=is; i<=ie; i++) {
00393       RootSoln[k][j][i].d  = Soln[k][j][i].d ;
00394       RootSoln[k][j][i].M1 = Soln[k][j][i].M1;
00395       RootSoln[k][j][i].M2 = Soln[k][j][i].M2;
00396       RootSoln[k][j][i].M3 = Soln[k][j][i].M3;
00397 #ifndef ISOTHERMAL
00398       RootSoln[k][j][i].E  = Soln[k][j][i].E ;
00399 #endif /* ISOTHERMAL */
00400 #ifdef MHD
00401       RootSoln[k][j][i].B1c = Soln[k][j][i].B1c;
00402       RootSoln[k][j][i].B2c = Soln[k][j][i].B2c;
00403       RootSoln[k][j][i].B3c = Soln[k][j][i].B3c;
00404 #endif
00405 #if (NSCALARS > 0)
00406       for (n=0; n<NSCALARS; n++)
00407         RootSoln[k][j][i].s[n] = Soln[k][j][i].s[n];
00408 #endif
00409     }}}
00410   }
00411 
00412   return;
00413 }
00414 
00415 /*==============================================================================
00416  * PROBLEM USER FUNCTIONS:
00417  * problem_write_restart() - writes problem-specific user data to restart files
00418  * problem_read_restart()  - reads problem-specific user data from restart files
00419  * get_usr_expr()          - sets pointer to expression for special output data
00420  * get_usr_out_fun()       - returns a user defined output function pointer
00421  * get_usr_par_prop()      - returns a user defined particle selection function
00422  * Userwork_in_loop        - problem specific work IN     main loop
00423  * Userwork_after_loop     - problem specific work AFTER  main loop
00424  *----------------------------------------------------------------------------*/
00425 
00426 void problem_write_restart(MeshS *pM, FILE *fp)
00427 {
00428   return;
00429 }
00430 
00431 void problem_read_restart(MeshS *pM, FILE *fp)
00432 {
00433   return;
00434 }
00435 
00436 ConsFun_t get_usr_expr(const char *expr)
00437 {
00438   return NULL;
00439 }
00440 
00441 VOutFun_t get_usr_out_fun(const char *name){
00442   return NULL;
00443 }
00444 
00445 #ifdef RESISTIVITY
00446 void get_eta_user(GridS *pG, int i, int j, int k,
00447                              Real *eta_O, Real *eta_H, Real *eta_A)
00448 {
00449   *eta_O = 0.0;
00450   *eta_H = 0.0;
00451   *eta_A = 0.0;
00452 
00453   return;
00454 }
00455 #endif
00456 
00457 void Userwork_in_loop(MeshS *pM)
00458 {
00459 }
00460 
00461 /*---------------------------------------------------------------------------
00462  * Userwork_after_loop: computes L1-error in linear waves,
00463  * ASSUMING WAVE HAS PROPAGATED AN INTEGER NUMBER OF PERIODS
00464  * Must set parameters in input file appropriately so that this is true
00465  */
00466 
00467 void Userwork_after_loop(MeshS *pM)
00468 {
00469   GridS *pGrid;
00470   int i=0,j=0,k=0;
00471   int is,ie,js,je,ks,ke;
00472   Real rms_error=0.0;
00473   ConsS error,total_error;
00474   FILE *fp;
00475   char *fname;
00476   int Nx1, Nx2, Nx3, count;
00477 #if defined MPI_PARALLEL
00478   double err[8], tot_err[8];
00479   int ierr,myID;
00480 #endif
00481 
00482   total_error.d = 0.0;
00483   total_error.M1 = 0.0;
00484   total_error.M2 = 0.0;
00485   total_error.M3 = 0.0;
00486 #ifdef MHD
00487   total_error.B1c = 0.0;
00488   total_error.B2c = 0.0;
00489   total_error.B3c = 0.0;
00490 #endif /* MHD */
00491 #ifndef ISOTHERMAL
00492   total_error.E = 0.0;
00493 #endif /* ISOTHERMAL */
00494 
00495 /* Compute error only on root Grid, which is in Domain[0][0] */
00496 
00497   pGrid=pM->Domain[0][0].Grid;
00498   if (pGrid == NULL) return;
00499 
00500 /* compute L1 error in each variable, and rms total error */
00501 
00502   is = pGrid->is; ie = pGrid->ie;
00503   js = pGrid->js; je = pGrid->je;
00504   ks = pGrid->ks; ke = pGrid->ke;
00505   for (k=ks; k<=ke; k++) {
00506   for (j=js; j<=je; j++) {
00507     error.d = 0.0;
00508     error.M1 = 0.0;
00509     error.M2 = 0.0;
00510     error.M3 = 0.0;
00511 #ifdef MHD
00512     error.B1c = 0.0;
00513     error.B2c = 0.0;
00514     error.B3c = 0.0;
00515 #endif /* MHD */
00516 #ifndef ISOTHERMAL
00517     error.E = 0.0;
00518 #endif /* ISOTHERMAL */
00519 
00520     for (i=is; i<=ie; i++) {
00521       error.d   += fabs(pGrid->U[k][j][i].d   - RootSoln[k][j][i].d );
00522       error.M1  += fabs(pGrid->U[k][j][i].M1  - RootSoln[k][j][i].M1);
00523       error.M2  += fabs(pGrid->U[k][j][i].M2  - RootSoln[k][j][i].M2);
00524       error.M3  += fabs(pGrid->U[k][j][i].M3  - RootSoln[k][j][i].M3); 
00525 #ifdef MHD
00526       error.B1c += fabs(pGrid->U[k][j][i].B1c - RootSoln[k][j][i].B1c);
00527       error.B2c += fabs(pGrid->U[k][j][i].B2c - RootSoln[k][j][i].B2c);
00528       error.B3c += fabs(pGrid->U[k][j][i].B3c - RootSoln[k][j][i].B3c);
00529 #endif /* MHD */
00530 #ifndef ISOTHERMAL
00531       error.E   += fabs(pGrid->U[k][j][i].E   - RootSoln[k][j][i].E );
00532 #endif /* ISOTHERMAL */
00533     }
00534 
00535     total_error.d += error.d;
00536     total_error.M1 += error.M1;
00537     total_error.M2 += error.M2;
00538     total_error.M3 += error.M3;
00539 #ifdef MHD
00540     total_error.B1c += error.B1c;
00541     total_error.B2c += error.B2c;
00542     total_error.B3c += error.B3c;
00543 #endif /* MHD */
00544 #ifndef ISOTHERMAL
00545     total_error.E += error.E;
00546 #endif /* ISOTHERMAL */
00547   }}
00548 
00549 #ifdef MPI_PARALLEL
00550   Nx1 = pM->Domain[0][0].Nx[0];
00551   Nx2 = pM->Domain[0][0].Nx[1];
00552   Nx3 = pM->Domain[0][0].Nx[2];
00553 #else
00554   Nx1 = ie - is + 1;
00555   Nx2 = je - js + 1;
00556   Nx3 = ke - ks + 1;
00557 #endif
00558   count = Nx1*Nx2*Nx3;
00559 
00560 #ifdef MPI_PARALLEL 
00561 /* Now we have to use an All_Reduce to get the total error over all the MPI
00562  * grids.  Begin by copying the error into the err[] array */
00563 
00564   err[0] = total_error.d;
00565   err[1] = total_error.M1;
00566   err[2] = total_error.M2;
00567   err[3] = total_error.M3;
00568 #ifdef MHD
00569   err[4] = total_error.B1c;
00570   err[5] = total_error.B2c;
00571   err[6] = total_error.B3c;
00572 #endif /* MHD */
00573 #ifndef ISOTHERMAL
00574   err[7] = total_error.E;
00575 #endif /* ISOTHERMAL */
00576 
00577   /* Sum up the Computed Error */
00578   ierr = MPI_Reduce(err,tot_err,8,MPI_DOUBLE,MPI_SUM,0,
00579     pM->Domain[0][0].Comm_Domain);
00580 
00581 /* If I'm the parent, copy the sum back to the total_error variable */
00582 
00583   ierr = MPI_Comm_rank(pM->Domain[0][0].Comm_Domain, &myID);
00584   if(myID == 0){ /* I'm the parent */
00585     total_error.d   = tot_err[0];
00586     total_error.M1  = tot_err[1];
00587     total_error.M2  = tot_err[2];
00588     total_error.M3  = tot_err[3];
00589 #ifdef MHD
00590     total_error.B1c = tot_err[4];
00591     total_error.B2c = tot_err[5];
00592     total_error.B3c = tot_err[6];
00593 #endif /* MHD */
00594 #ifndef ISOTHERMAL
00595     total_error.E   = tot_err[7];
00596 #endif /* ISOTHERMAL */
00597   }
00598   else return; /* The child grids do not do any of the following code */
00599 
00600 #endif /* MPI_PARALLEL */
00601 
00602 /* Compute RMS error over all variables, and print out */
00603 
00604   rms_error = SQR(total_error.d) + SQR(total_error.M1) + SQR(total_error.M2)
00605                 + SQR(total_error.M3);
00606 #ifdef MHD
00607   rms_error += SQR(total_error.B1c) + SQR(total_error.B2c) 
00608                + SQR(total_error.B3c);
00609 #endif /* MHD */
00610 #ifndef ISOTHERMAL
00611   rms_error += SQR(total_error.E);
00612 #endif /* ISOTHERMAL */
00613   rms_error = sqrt(rms_error)/(double)count;
00614 
00615 /* Print error to file "LinWave-errors.#.dat", where #=wave_flag  */
00616 
00617 #ifdef MPI_PARALLEL
00618   fname = ath_fname("../","LinWave-errors",NULL,NULL,1,wave_flag,NULL,"dat");
00619 #else
00620   fname = ath_fname(NULL,"LinWave-errors",NULL,NULL,1,wave_flag,NULL,"dat");
00621 #endif
00622 
00623 /* The file exists -- reopen the file in append mode */
00624   if((fp=fopen(fname,"r")) != NULL){
00625     if((fp = freopen(fname,"a",fp)) == NULL){
00626       ath_perr(-1,"[Userwork_after_loop]: Unable to reopen file.\n");
00627       free(fname);
00628       return;
00629     }
00630   }
00631 /* The file does not exist -- open the file in write mode */
00632   else{
00633     if((fp = fopen(fname,"w")) == NULL){
00634       ath_perr(-1,"[Userwork_after_loop]: Unable to open file.\n");
00635       free(fname);
00636       return;
00637     }
00638 /* Now write out some header information */
00639     fprintf(fp,"# Nx1  Nx2  Nx3  RMS-Error  d  M1  M2  M3");
00640 #ifndef ISOTHERMAL
00641     fprintf(fp,"  E");
00642 #endif /* ISOTHERMAL */
00643 #ifdef MHD
00644     fprintf(fp,"  B1c  B2c  B3c");
00645 #endif /* MHD */
00646     fprintf(fp,"\n#\n");
00647   }
00648 
00649   fprintf(fp,"%d  %d  %d  %e",Nx1,Nx2,Nx3,rms_error);
00650 
00651   fprintf(fp,"  %e  %e  %e  %e",
00652           (total_error.d/(double)count),
00653           (total_error.M1/(double)count),
00654           (total_error.M2/(double)count),
00655           (total_error.M3/(double)count) );
00656 
00657 #ifndef ISOTHERMAL
00658   fprintf(fp,"  %e",(total_error.E/(double)count) );
00659 #endif /* ISOTHERMAL */
00660 
00661 #ifdef MHD
00662   fprintf(fp,"  %e  %e  %e",
00663           (total_error.B1c/(double)count),
00664           (total_error.B2c/(double)count),
00665           (total_error.B3c/(double)count));
00666 #endif /* MHD */
00667 
00668   fprintf(fp,"\n");
00669 
00670   fclose(fp);
00671   free(fname);
00672 
00673   return;
00674 }
00675 
00676 /*=========================== PRIVATE FUNCTIONS ==============================*/
00677 
00678 /*----------------------------------------------------------------------------*/
00679 /*! \fn static Real A1(const Real x1, const Real x2, const Real x3)
00680  *  \brief A1: 1-component of vector potential, using a gauge such that Ax = 0,
00681  * and Ay, Az are functions of x and y alone.
00682  */
00683 
00684 #ifdef MHD
00685 static Real A1(const Real x1, const Real x2, const Real x3)
00686 {
00687   Real x, y;
00688   Real Ay, Az;
00689 
00690   x =  x1*cos_a2*cos_a3 + x2*cos_a2*sin_a3 + x3*sin_a2;
00691   y = -x1*sin_a3        + x2*cos_a3;
00692 
00693   Ay =  bz0*x - (dbz/k_par)*cos(k_par*x);
00694   Az = -by0*x + (dby/k_par)*cos(k_par*x) + bx0*y;
00695 
00696   return -Ay*sin_a3 - Az*sin_a2*cos_a3;
00697 }
00698 
00699 /*----------------------------------------------------------------------------*/
00700 /*! \fn static Real A2(const Real x1, const Real x2, const Real x3)
00701  *  \brief A2: 2-component of vector potential
00702  */
00703 
00704 static Real A2(const Real x1, const Real x2, const Real x3)
00705 {
00706   Real x, y;
00707   Real Ay, Az;
00708 
00709   x =  x1*cos_a2*cos_a3 + x2*cos_a2*sin_a3 + x3*sin_a2;
00710   y = -x1*sin_a3        + x2*cos_a3;
00711 
00712   Ay =  bz0*x - (dbz/k_par)*cos(k_par*x);
00713   Az = -by0*x + (dby/k_par)*cos(k_par*x) + bx0*y;
00714 
00715   return Ay*cos_a3 - Az*sin_a2*sin_a3;
00716 }
00717 
00718 /*----------------------------------------------------------------------------*/
00719 /*! \fn static Real A3(const Real x1, const Real x2, const Real x3)
00720  *  \brief A3: 3-component of vector potential
00721  */
00722 
00723 static Real A3(const Real x1, const Real x2, const Real x3)
00724 {
00725   Real x, y;
00726   Real Az;
00727 
00728   x =  x1*cos_a2*cos_a3 + x2*cos_a2*sin_a3 + x3*sin_a2;
00729   y = -x1*sin_a3        + x2*cos_a3;
00730 
00731   Az = -by0*x + (dby/k_par)*cos(k_par*x) + bx0*y;
00732 
00733   return Az*cos_a2;
00734 }
00735 #endif /* MHD */

Generated on Mon Sep 27 2010 23:03:08 for Athena by  doxygen 1.7.1