/** @file grid.h * @brief Definitions for working with general grids. */ #ifndef _GRID_H_ #ifndef _TREE_H_ # include "tree.h" #endif #define RECT_COORDS int r0, r1, z0, z1, ntheta /*!< Coordinate names for the grids */ #define BND_AT_R 0 #define BND_AT_Z 2 #define BND_MIN 0 #define BND_MAX 1 #define BND_LEFT (BND_AT_R | BND_MIN) #define BND_RIGHT (BND_AT_R | BND_MAX) #define BND_BOTTOM (BND_AT_Z | BND_MIN) #define BND_TOP (BND_AT_Z | BND_MAX) #define BND_MASK(B_) (1 << (B_)) #define BND_NONE 0 #define BND_MASK_LEFT BND_MASK(BND_LEFT) #define BND_MASK_RIGHT BND_MASK(BND_RIGHT) #define BND_MASK_BOTTOM BND_MASK(BND_BOTTOM) #define BND_MASK_TOP BND_MASK(BND_TOP) #define BND_MASK_ALL (BND_MASK_LEFT | BND_MASK_RIGHT\ | BND_MASK_BOTTOM | BND_MASK_TOP) #define GRID_INSIDE (1 << (BND_TOP + 1)) /* Locations of the cell centers. */ #define r_at(r_, level_) (((double) (r_) + 0.5) * dr[level_]) #define z_at(z_, level_) (((double) (z_) + 0.5) * dz[level_]) #define theta_at(theta_) ((double) (theta_) * dtheta) /* Locations of the electric field. */ #define er_r_at(i_, level_) ((i_ + 1) * dr[level_]) #define er_z_at(j_, level_) (((double) (j_) + 0.5) * dz[level_]) #define ez_r_at(i_, level_) (((double) (i_) + 0.5) * dr[level_]) #define ez_z_at(j_, level_) ((j_ + 1) * dz[level_]) #define etheta_theta_at(i_) (((double) (i_) + 0.5) * dtheta) /** We can produce easily a true 2d code by replacing r when it appears * due to the cylindrical coordinates by this macros. This has a rather * large performance penalty, so it is better to do that in compile time */ /* Locations of the electric field. */ #ifdef TRUE2D # define cyl_q(X_) 1 # define cyl_er_r_at(i_, level_) 1 # define cyl_r_at(r_, level_) 1 #else # define cyl_q(X_) (X_) # define cyl_er_r_at(i_, level_) er_r_at(i_, level_) # define cyl_r_at(r_, level_) r_at(r_, level_) #endif /* These are shortcuts to make the iteration over grid cells easier. * Note that it is important that the inner loop has the smallest * stride to minimize the cache faults. */ #define iter_grid_z(grid_, iz_) \ for(iz_ = grid_->z0; iz_ < grid_->z1; iz_++) #define iter_grid_r(grid_, ir_) \ for(ir_ = grid_->r0; ir_ < grid_->r1; ir_++) #define iter_grid_theta(grid_, it_) \ for(it_ = 0; it_ < grid_->ntheta; it_++) #define iter_grid(grid_, ir_, iz_) \ iter_grid_z(grid_, iz_) \ iter_grid_r(grid_, ir_) #define iter_grid_3d(grid_, ir_, iz_, it_) \ iter_grid_theta(grid_, it_) \ iter_grid_z(grid_, iz_) \ iter_grid_r(grid_, ir_) /* Functions to iterate over the grids _including_ 1 extra boundary */ #define iter_grid_z_1(grid_, iz_) \ for(iz_ = grid_->z0 - 1; iz_ < grid_->z1 + 1; iz_++) #define iter_grid_r_1(grid_, ir_) \ for(ir_ = grid_->r0 - 1; ir_ < grid_->r1 + 1; ir_++) #define iter_grid_1(grid_, ir_, iz_) \ iter_grid_z_1(grid_, iz_) \ iter_grid_r(grid_, ir_) #define iter_grid_3d_1(grid_, ir_, iz_, it_) \ iter_grid_theta(grid_, it_) \ iter_grid_z_1(grid_, iz_) \ iter_grid_r_1(grid_, ir_) /* These include n extra cells in the boundary. We avoid that when * ntheta == 1 because we are in the 2D case and there are no boundaries * in theta*/ #define iter_grid_theta_n(grid_, it_, n_) \ for(it_ = (grid_->ntheta == 1? 0: -n_); it_ < grid_->ntheta \ + (grid_->ntheta == 1? 0: n_); it_++) #define iter_grid_z_n(grid_, iz_, n_) \ for(iz_ = grid_->z0 - n_; iz_ < grid_->z1 + n_; iz_++) #define iter_grid_r_n(grid_, ir_, n_) \ for(ir_ = grid_->r0 - n_; ir_ < grid_->r1 + n_; ir_++) #define iter_grid_n(grid_, ir_, iz_, n_) \ iter_grid_z_n(grid_, iz_, n_) \ iter_grid_r_n(grid_, ir_, n_) #define iter_grid_3d_n(grid_, ir_, iz_, it_, n_) \ iter_grid_theta_n(grid_, it_, n_) \ iter_grid_z_n(grid_, iz_, n_) \ iter_grid_r_n(grid_, ir_, n_) /* Iter through the parent indices that fill one grid. */ #define iter_grid_parent(grid_, ir_, iz_) \ for(ir_ = (grid_->r0 >> 1) + (grid_->r0 % 2); \ ir_ < (grid_->r1 >> 1); ir_++) \ for(iz_ = (grid_->z0 >> 1) + (grid_->z0 % 2); \ iz_ < (grid_->z1 >> 1); iz_++) /** @brief The cdr grids and poisson grids types are cdr_grid_t and * pois_grid_t, defined in cdr.h and poisson.h. * * This structure contains the common parts of both structures and * thus can be used in general routines that accept any kind of grid. * The C standard promises that we can du this. */ typedef struct grid_t grid_t; struct grid_t { RECT_COORDS; LEAF_FIELDS(grid_t); /* ext_bound indicates which boundaries are external boundaries. e.g. ext_bound & BND_LEFT_TOP tells us whether the left-top boundary is an external one. */ int ext_bound; }; /** @brief To ease typing, you can write e.g. * printf ("Solving grid (" grid_printf_str ")\n", grid_printf_args(grid)); */ #define grid_printf_str "{r0 = %d, z0 = %d, r1 = %d, z1 = %d, level = %d}" #define grid_printf_args(G_) (G_)->r0, (G_)->z0, (G_)->r1, (G_)->z1, \ (G_)->level #define _GRID_H_ #endif