Gowdy solver
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
grid/gridDriver.h
Go to the documentation of this file.
00001 /**
00002  *  @file      gridDriver.h
00003  *  @brief     Implements a spatially cell-centered uniform grid.
00004  *  @author    Mikica Kocic
00005  *  @copyright GNU General Public License (GPLv3).
00006  *
00007  *  @page fdm Finite Difference Approximation
00008  *
00009  *  At the core of finite difference approximation is a discretization of the
00010  *  spacetime, or a numerical grid (shown below).\ Then, a function `f(t,r)` is
00011  *  represented by values at a discrete set of points `(m,n)`.
00012  *
00013  *  <pre>
00014  *                p in M          <-->     (t,r)      <-->        (m,n)
00015  *         (point in a manifold)        (in a chart)        (discretized point)
00016  *                                           |                      |
00017  *                                           V                      V
00018  *                                         f(t,r)                 f(m,n)    </pre>
00019  *
00020  *  The points `(m,n)` are called the grid points or nodes. The grid points are chosen
00021  *  to reside at the center of grid cells (the other approach would be to associate the
00022  *  grid points with the vertices of the grid cells).&nbsp;
00023  *
00024  *  The data structure GridPoint contains the set of fields `{f,...}` that are kept
00025  *  in the memory for the point `(m,n)`. The numerical grid is an array of grid points
00026  *  `grid[m][n]` where a field `f` is directly accessible as `grid[m][n].f`, or using
00027  *  a macro as `f(m,n)`.&nbsp;
00028  *
00029  *  The grid consists of the *interior points*, and the *virtual points* at the boundary.
00030  *  The virtual points are used to impose the boundary conditions.&nbsp;
00031  *
00032  *  A cell-centered uniform grid with `nLen` grid points in each grid row is shown below
00033  *  (see also @cite Baumgarte:2010nr, p.192).
00034  *
00035  *  <pre>
00036  *         left virtual                grid cell        grid point     right virtual
00037  *            point(s)                 .---^---.            |             point(s)
00038  *      .        |               n-1  '    n    '  n+1      |                |
00039  *      :   +----|----+-------+-------+---------+-------+---|---+-------+----|----+
00040  *     m+1  |    O    |       |       | (m+1,n) |       |   X   |       |    O    |
00041  *          +---------+-------+-------.=========.-------+-------+-------+---------+
00042  *      m   |         |       |(m,n-1)|  (m,n)  |(m,n+1)|       |       |         |
00043  *          +---------+-------+-------'========='-------+-------+-------+---------+
00044  *     m-1  |         |       |       |         |       |       |       |         |
00045  *      .   +---------'-------+-------+---------+-------+-------+-------'---------+
00046  *      :        0    |   1       2      . . .                    nLen  |  nLen+1
00047  *                    ^                                                 ^
00048  *                   r_min                                            r_max       </pre>
00049  *
00050  *  The cell-centered uniform grid implies:
00051  *   @code
00052  *     r = r_min + ( n - 1/2 ) delta_r
00053  *     delta_r = ( r_max - r_min ) / nLen
00054  *   @endcode
00055  *   @li if `nGhost = 1`, `n` ranges between 1 and `nLen`;
00056  *       the boundary virtual points are `grid[m][0]` and `grid[m][nLen+1]`
00057  *
00058  *   @li `m` ranges between 1 and mLen, and wraps around;
00059  *       the slices `grid[mLen+1]`... are used for intermediate integration steps.
00060  *
00061  *  In parallel simulations, the grid is split across processes using MPI,
00062  *  allowing storage of large grid functions and parallel work on each part.
00063  *
00064  */
00065 
00066 /////////////////////////////////////////////////////////////////////////////////////////
00067 /** @defgroup g4 Grid driver                                                           */
00068 /////////////////////////////////////////////////////////////////////////////////////////
00069                                                                                    /*@{*/
00070 /** Uniform grid of grid functions.
00071  */
00072 class UniformGrid
00073     : public MPIWorld
00074 {
00075     /** Allocates memory for the numerical grid.
00076      *
00077      *  We allocate `mExtra` extra m grid rows for the intermediate steps.
00078      *  We also allocate 2*nGhost n-cells as the L/R spatial boundary.
00079      */
00080     void createGrid ()
00081     {
00082         size_t mDim = mLen + mExtra;
00083         size_t nDim = nLen + 2 * nGhost;
00084 
00085         grid = new GridPoint* [ mDim ];
00086         grid[0] = new GridPoint[ mDim * nDim ];
00087 
00088         for( size_t m = 0; m < mDim - 1; ++m ) {
00089             grid[m+1] = grid[m] + nDim;
00090         }
00091 
00092         slog << "    Allocated " << mDim << " * " << nDim
00093              << " * " << sizeof(GridPoint) / sizeof(Real)
00094              << " * Real" << 8 * sizeof(Real)
00095              << " = " << mDim * nDim * sizeof(GridPoint)
00096              << " bytes" << std::endl
00097              << "    Tracking " << GFCNT << " grid functions at a point"
00098              << std::endl << std::endl;
00099     }
00100 
00101     /** Releases memory allocated for the numerical grid.
00102      */
00103     void deleteGrid ()
00104     {
00105         if ( ! grid ) return;
00106 
00107         delete[] grid[0];
00108         delete[] grid;
00109         grid = NULL;
00110     }
00111 
00112 protected:
00113 
00114     GridPoint** grid;      //!< The grid storage
00115                            //   Spatial discretization:
00116     Int         nLen;      //!< Number of cells in `r`-direction
00117     Int         nGhost;    //!< Number of virtual (ghost) cells on the `r`-boundary
00118     Real        delta_r;   //!< The grid spacing accross `r`
00119                            //   Temporal discretization:
00120     Int         mLen;      //!< Number of cached cells in `t`-direction
00121     Int         mExtra;    //!< Number of extra cells (for integration substeps)
00122 
00123 public:
00124 
00125     GridPoint** get_grid () { return grid; }
00126 
00127     Int  get_nLen    () const { return nLen;    }
00128     Int  get_nGhost  () const { return nGhost;  }
00129     Int  get_mLen    () const { return mLen;    }
00130     Real get_delta_r () const { return delta_r; }
00131 
00132     Int  mpiSize     () const { return size (); }
00133     Int  mpiRank     () const { return rank (); }
00134 
00135     /** Constructs the uniform grid as specified in the parameter file.
00136      */
00137     UniformGrid( Parameters& params )
00138     {
00139         params.get( "grid.nLen",    nLen,     10  );
00140         params.get( "grid.nGhost",  nGhost,   10  );
00141         params.get( "grid.delta_r", delta_r,  0.1 );
00142         params.get( "grid.mLen",    mLen,     5   );
00143         params.get( "grid.mExtra",  mExtra,   9   );
00144 
00145         // Split the data equally among all the ranks in the MPI world
00146         nLen = nLen / size();
00147 
00148         slog << "Uniform Grid Driver:" << std::endl << std::endl
00149              << "    nLen = " << nLen << ",  nGhost = " << nGhost
00150              << ",  delta_r = " << delta_r
00151              << ",  mLen = " << mLen << ",  mExtra = " << mExtra << std::endl
00152              << "    Compile-time: CFDS_ORDER = " << CFDS_ORDER << std::endl;
00153 
00154         #if _OPENMP
00155              slog << "    Using OpenMP: #procs = "
00156                   << omp_get_num_procs() << ", max #threads = "
00157                   << omp_get_max_threads() << std::endl;
00158         #endif
00159 
00160         // Sanity check that nGhost > CFDS_ORDER/2
00161         //
00162         if( nGhost < CFDS_ORDER/2 ) {
00163             slog << "Error: Ghost region does not fit the FD order." << std::endl;
00164             exit( -1 );
00165         }
00166 
00167         createGrid ();
00168     }
00169 
00170     /** Exchange the boundaries at the given time slice.
00171      */
00172     void exchangeBoundaries( Int m )
00173     {
00174         MPIWorld::exchangeBoundaries(
00175             &grid[m][ 0                      ],  // Left ghost (received)
00176             &grid[m][ nGhost                 ],  // Left edge (sent)
00177             &grid[m][ nGhost + nLen - nGhost ],  // Right_edge (sent)
00178             &grid[m][ nGhost + nLen          ],  // Right ghost (received)
00179             nGhost * GFCNT                       // Exchanged size of Reals
00180         );
00181     }
00182 };
00183 
00184 /////////////////////////////////////////////////////////////////////////////////////////
00185 
00186 /** Access the given grid function data (a utility macro for the grid users).
00187  */
00188 #define GF(f,m,n)  grid[m][n][f]
00189 
00190 /** `emitField` is a macro that emits a method encapsulating
00191  *  a grid function that access data in a grid at a point given by
00192  *  `m` (discretized t-coordinate) and `n` (discretized r-coordinate).
00193  *  For example, `emitField(r)` defines `r(m,n)`.
00194  */
00195 #define emitField(gf) \
00196     inline Real& gf( Int m, Int n ) { return grid[m][n][fld::gf]; }
00197 
00198 /** GridUser contains cached variables from the grid-driver.
00199  *  @note Finite differences are defined for the grid users.
00200  */
00201 struct GridUser
00202 {
00203     UniformGrid* gridDriver;  //!< Grid object
00204     GridPoint** grid;         //!< Actual grid data
00205 
00206     Int nLen;           //!< Number of cells in `r`-direction
00207     Int mLen;           //!< Number of cells in `t`-direction
00208     Int nGhost;         //!< Number of virtual (ghost) cells on the `r`-boundary
00209 
00210     Real delta_r;       //!< The grid spacing accross `r`
00211     Real inv_delta_r;   //!< `1 / delta_r`
00212     Real inv_delta_rr;  //!< `1 / delta_r^2`
00213 
00214     emitField(t)
00215     emitField(r)
00216 
00217     GridUser( UniformGrid& ug )
00218     {
00219         grid    = ug.get_grid ();
00220         nLen    = ug.get_nLen ();
00221         mLen    = ug.get_mLen ();
00222         nGhost  = ug.get_nGhost ();
00223         delta_r = ug.get_delta_r ();
00224 
00225         // Calculate various constants involving 1/delta_r
00226         //
00227         inv_delta_r  = 1 / ug.get_delta_r ();
00228         inv_delta_rr = 1 / ( ug.get_delta_r () * ug.get_delta_r () );
00229     }
00230 
00231     /** Cubic spline smoother of a grid function.
00232      */
00233     void cubicSplineShmooth( Int m, Int gf, Int lin2n, Int cub2n )
00234     {
00235         // The accuracy is very low at low r. Assume that a few first cells are linear.
00236         //
00237         if( lin2n > 0 )
00238         {
00239             Real dydx = delta_r * GF(gf,m,nGhost+lin2n) / r(m,nGhost+lin2n);
00240             for ( Int i = 0; i < lin2n; ++i ) {
00241                 GF(gf,m,nGhost+i) = ( i + 0.5 ) * dydx;
00242             }
00243         }
00244 
00245         // A six-point cubic spline to smooth the region around r = 0.
00246         //
00247         if( cub2n > 0 )
00248         {
00249             static CubicSpline spline( 6 );
00250 
00251             Real pts[6][2] = {
00252                 { r(m,nGhost           ),   GF(gf,m,nGhost           ) },
00253                 { r(m,nGhost + 3       ),   GF(gf,m,nGhost + 3       ) },
00254                 { r(m,nGhost + cub2n/2 ),   GF(gf,m,nGhost + cub2n/2 ) },
00255                 { r(m,nGhost + cub2n-6 ),   GF(gf,m,nGhost + cub2n-6 ) },
00256                 { r(m,nGhost + cub2n-3 ),   GF(gf,m,nGhost + cub2n-3 ) },
00257                 { r(m,nGhost + cub2n   ),   GF(gf,m,nGhost + cub2n   ) }
00258             };
00259             spline.initialize( pts );
00260 
00261             for( Int i = 0; i < cub2n; ++i ) {
00262                 GF(gf,m,nGhost+i) = spline( r(m,nGhost+i) );
00263             }
00264         }
00265     }
00266 };
00267                                                                                    /*@}*/
00268 /////////////////////////////////////////////////////////////////////////////////////////