/* mesh.hh - This file is part of MUSIC - a code to generate multi-scale initial conditions for cosmological simulations Copyright (C) 2010 Oliver Hahn This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef __MESH_HH #define __MESH_HH #include #include #include #include #include #include "config_file.hh" //! base class for all things that have rectangular mesh structure template class Meshvar{ public: typedef T real_t; unsigned m_nx, //!< x-extent of the rectangular mesh m_ny, //!< y-extent of the rectangular mesh m_nz; //!< z-extent of the rectangular mesh unsigned m_offx, //!< x-offset of the grid (just as a helper, not used inside the class) m_offy, //!< y-offset of the grid (just as a helper, not used inside the class) m_offz; //!< z-offset of the grid (just as a helper, not used inside the class) real_t * m_pdata; //!< pointer to the dynamic data array //! constructor for cubic mesh explicit Meshvar( unsigned n, unsigned offx, unsigned offy, unsigned offz ) : m_nx( n ), m_ny( n ), m_nz( n ), m_offx( offx ), m_offy( offy ), m_offz( offz ) { m_pdata = new real_t[m_nx*m_ny*m_nz]; } //! constructor for rectangular mesh Meshvar( unsigned nx, unsigned ny, unsigned nz, unsigned offx, unsigned offy, unsigned offz ) : m_nx( nx ), m_ny( ny ), m_nz( nz ), m_offx( offx ), m_offy( offy ), m_offz( offz ) { m_pdata = new real_t[m_nx*m_ny*m_nz]; } //! variant copy constructor with optional copying of the actual data Meshvar( const Meshvar& m, bool copy_over=true ) { m_nx = m.m_nx; m_ny = m.m_ny; m_nz = m.m_nz; m_offx = m.m_offx; m_offy = m.m_offy; m_offz = m.m_offz; m_pdata = new real_t[m_nx*m_ny*m_nz]; if( copy_over ) for( unsigned i=0; i& m ) { m_nx = m.m_nx; m_ny = m.m_ny; m_nz = m.m_nz; m_offx = m.m_offx; m_offy = m.m_offy; m_offz = m.m_offz; m_pdata = new real_t[m_nx*m_ny*m_nz]; for( unsigned i=0; i& operator*=( real_t x ) { for( unsigned i=0; i& operator+=( real_t x ) { for( unsigned i=0; i& operator/=( real_t x ) { for( unsigned i=0; i& operator-=( real_t x ) { for( unsigned i=0; i& operator*=( const Meshvar& v ) { if( v.m_nx*v.m_ny*v.m_nz != m_nx*m_ny*m_nz ) throw std::runtime_error("Meshvar::operator*= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator/=( const Meshvar& v ) { if( v.m_nx*v.m_ny*v.m_nz != m_nx*m_ny*m_nz ) throw std::runtime_error("Meshvar::operator/= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator+=( const Meshvar& v ) { if( v.m_nx*v.m_ny*v.m_nz != m_nx*m_ny*m_nz ) throw std::runtime_error("Meshvar::operator+= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator-=( const Meshvar& v ) { if( v.m_nx*v.m_ny*v.m_nz != m_nx*m_ny*m_nz ) throw std::runtime_error("Meshvar::operator-= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator=( const Meshvar& m ) { m_nx = m.m_nx; m_ny = m.m_ny; m_nz = m.m_nz; m_offx = m.m_offx; m_offy = m.m_offy; m_offz = m.m_offz; if( m_pdata != NULL ) delete m_pdata; m_pdata = new real_t[m_nx*m_ny*m_nz]; for( unsigned i=0; i class MeshvarBnd : public Meshvar< T >{ using Meshvar::m_nx; using Meshvar::m_ny; using Meshvar::m_nz; using Meshvar::m_pdata; public: typedef T real_t; unsigned m_nbnd; //! most general constructor MeshvarBnd( unsigned nbnd, unsigned nx, unsigned ny, unsigned nz, unsigned xoff, unsigned yoff, unsigned zoff ) : Meshvar( nx+2*nbnd, ny+2*nbnd, nz+2*nbnd, xoff, yoff, zoff ), m_nbnd( nbnd ) { } //! zero-offset constructor MeshvarBnd( unsigned nbnd, unsigned nx, unsigned ny, unsigned nz ) : Meshvar( nx+2*nbnd, ny+2*nbnd, nz+2*nbnd, 0, 0, 0 ), m_nbnd( nbnd ) { } //! constructor for cubic meshes MeshvarBnd( unsigned nbnd, unsigned n, unsigned xoff, unsigned yoff, unsigned zoff ) : Meshvar( n+2*nbnd, xoff, yoff, zoff ), m_nbnd( nbnd ) { } //! constructor for cubic meshes with zero offset MeshvarBnd( unsigned nbnd, unsigned n ) : Meshvar( n+2*nbnd, 0, 0, 0 ), m_nbnd( nbnd ) { } //! modified copy constructor, allows to avoid copying actual data MeshvarBnd( const MeshvarBnd& v, bool copyover ) : Meshvar( v, copyover ), m_nbnd( v.m_nbnd ) { } //! copy constructor explicit MeshvarBnd( const MeshvarBnd& v ) : Meshvar( v, true ), m_nbnd( v.m_nbnd ) { } //! get extent of the mesh along a specified dimension inline unsigned size( unsigned dim=0 ) const { if( dim == 0 ) return m_nx-2*m_nbnd; if( dim == 1 ) return m_ny-2*m_nbnd; return m_nz-2*m_nbnd; } //! 3D random access to the data block via index 3-tuples inline real_t& operator()(const int ix, const int iy, const int iz ) { int iix(ix+m_nbnd), iiy(iy+m_nbnd), iiz(iz+m_nbnd); return m_pdata[ (iix*m_ny+iiy)*m_nz + iiz ]; } //! 3D random access to the data block via index 3-tuples (const) inline const real_t& operator()(const int ix, const int iy, const int iz ) const { int iix(ix+m_nbnd), iiy(iy+m_nbnd), iiz(iz+m_nbnd); return m_pdata[ (iix*m_ny+iiy)*m_nz + iiz ]; } //! assignment operator for rectangular meshes with ghost zones MeshvarBnd& operator=( const MeshvarBnd& m ) { this->m_nx = m.m_nx; this->m_ny = m.m_ny; this->m_nz = m.m_nz; if( m_pdata != NULL ) delete[] m_pdata; m_pdata = new real_t[m_nx*m_ny*m_nz]; for( unsigned i=0; im_pdata[i] = m.m_pdata[i]; return *this; } //! sets the value of all ghost zones to zero void zero_bnd( void ) { int nx,ny,nz; nx = this->size(0); ny = this->size(1); nz = this->size(2); for( int j=-m_nbnd; jsize(0) << ", " << this->size(1) << ", " << this->size(2) << "]\n"; std::cout << "ghost region has length of " << nbnd << std::endl; std::cout.precision(3); for(int i=-nbnd; i<(int)this->size(0)+nbnd; ++i ) { std::cout << "ix = " << i << ": \n"; for (int j=-nbnd; j<(int)this->size(1)+nbnd; ++j) { for (int k=-nbnd; k<(int)this->size(2)+nbnd; ++k) { if( i<0||i>=this->size(0)||j<0||j>=this->size(1)||k<0||k>=this->size(2)) std::cout << "[" << std::setw(6) << (*this)(i,j,k) << "] "; else std::cout << std::setw(8) << (*this)(i,j,k) << " "; } std::cout << std::endl; } std::cout << std::endl; } } }; //! class that subsumes a nested grid collection template< typename T > class GridHierarchy { public: //! number of ghost cells on boundary unsigned m_nbnd; //! highest level without adaptive refinement unsigned m_levelmin; //! vector of pointers to the underlying rectangular mesh data for each level std::vector< MeshvarBnd* > m_pgrids; std::vector m_xoffabs, //!< vector of x-offsets of a level mesh relative to the coarser level m_yoffabs, //!< vector of x-offsets of a level mesh relative to the coarser level m_zoffabs; //!< vector of x-offsets of a level mesh relative to the coarser level protected: //! check whether a given grid has identical hierarchy, dimensions to this bool is_consistent( const GridHierarchy& gh ) { if( gh.levelmax()!=levelmax() ) return false; if( gh.levelmin()!=levelmin() ) return false; for( unsigned i=levelmin(); i<=levelmax(); ++i ) for( int j=0; j<3; ++j ) { if( size(i,j) != gh.size(i,j) ) return false; if( offset(i,j) != gh.offset(i,j) ) return false; } return true; } public: //! return a pointer to the MeshvarBnd object representing data for one level MeshvarBnd *get_grid( unsigned ilevel ) { if( ilevel >= m_pgrids.size() ) { std::cerr << "Attempt to access level " << ilevel << " but maxlevel = " << m_pgrids.size()-1 << std::endl; throw std::runtime_error("Fatal: attempt to access non-existent grid"); } return m_pgrids[ilevel]; } //! return a pointer to the MeshvarBnd object representing data for one level (const) const MeshvarBnd *get_grid( unsigned ilevel ) const { if( ilevel >= m_pgrids.size() ) { std::cerr << "Attempt to access level " << ilevel << " but maxlevel = " << m_pgrids.size()-1 << std::endl; throw std::runtime_error("Fatal: attempt to access non-existent grid"); } return m_pgrids[ilevel]; } //! constructor for a collection of rectangular grids representing a multi-level hierarchy /*! creates an empty hierarchy, levelmin is initially zero, no grids are stored * @param nbnd number of ghost zones added at the boundary */ explicit GridHierarchy( unsigned nbnd ) : m_nbnd( nbnd ), m_levelmin( 0 ) { m_pgrids.clear(); } //! copy constructor explicit GridHierarchy( const GridHierarchy & gh ) { for( unsigned i=0; i<=gh.levelmax(); ++i ) m_pgrids.push_back( new MeshvarBnd( *gh.get_grid(i) ) ); m_nbnd = gh.m_nbnd; m_levelmin = gh.m_levelmin; m_xoffabs = gh.m_xoffabs; m_yoffabs = gh.m_yoffabs; m_zoffabs = gh.m_zoffabs; } //! destructor ~GridHierarchy() { this->deallocate(); } //! free all memory occupied by the grid hierarchy void deallocate() { for( unsigned i=0; ioffset(idim); } //! get size of a grid at specified refinement level /*! the size describes the number of cells along one dimension of a grid * @param ilevel the level for which the size is to be determined * @param idim the dimension along which the size is to be determined * @return integer value denoting the size of refinement grid at level ilevel along dimension idim */ int size( int ilevel, int idim ) const { return m_pgrids[ilevel]->size(idim); } //! get the absolute offset of a grid at specified refinement level /*! the absolute offset describes the shift of a refinement grid with respect to the simulation volume * @param ilevel the level for which the offset is to be determined * @param idim the dimension along which the offset is to be determined * @return integer value denoting the absolute offset in units of fine grid cells * @sa offset */ int offset_abs( int ilevel, int idim ) const { if( idim == 0 ) return m_xoffabs[ilevel]; if( idim == 1 ) return m_yoffabs[ilevel]; return m_zoffabs[ilevel]; } //! get the coordinate posisition of a grid cell /*! returns the position of a grid cell at specified level relative to the simulation volume * @param ilevel the refinement level of the grid cell * @param i the x-index of the cell in the level grid * @param j the y-index of the cell in the level grid * @param k the z-index of the cell in the level grid * @param ppos pointer to a double[3] array to which the coordinates are written * @return none */ void cell_pos( unsigned ilevel, int i, int j, int k, double* ppos ) const { double h = 1.0/pow(2,ilevel);//, htop = h*2.0; ppos[0] = h*((double)offset_abs(ilevel,0)+(double)i+0.5); ppos[1] = h*((double)offset_abs(ilevel,1)+(double)j+0.5); ppos[2] = h*((double)offset_abs(ilevel,2)+(double)k+0.5); if( ppos[0] >= 1.0 || ppos[1] >= 1.0 || ppos[2] >= 1.0 ) std::cerr << " - Cell seems outside domain! : (" << ppos[0] << ", " << ppos[1] << ", " << ppos[2] << "\n"; } //! checks whether a given grid cell is refined /*! a grid cell counts as refined if it is divided into 8 cells at the next higher level * @param ilevel the refinement level of the grid cell * @param i the x-index of the cell in the level grid * @param j the y-index of the cell in the level grid * @param k the z-index of the cell in the level grid * @return true if cell is refined, false otherwise */ bool is_refined( unsigned ilevel, int i, int j, int k ) const { if( ilevel == levelmax() ) return false; if( i < offset(ilevel+1,0) || i >= offset(ilevel+1, 0)+size(ilevel+1,0)/2 || j < offset(ilevel+1,1) || j >= offset(ilevel+1, 1)+size(ilevel+1,1)/2 || k < offset(ilevel+1,2) || k >= offset(ilevel+1, 2)+size(ilevel+1,2)/2 ) return false; return true; } //! sets the values of all grids on all levels to zero void zero( void ) { for( unsigned i=0; izero(); } //! count the number of cells that are not further refined (=leafs) /*! for allocation purposes it is useful to query the number of cells to be expected * @param lmin the minimum refinement level to consider * @param lmax the maximum refinement level to consider * @return the integer number of cells between lmin and lmax that are not further refined */ unsigned count_leaf_cells( unsigned lmin, unsigned lmax ) const { unsigned npcount = 0; for( int ilevel=lmax; ilevel>=(int)lmin; --ilevel ) for( unsigned i=0; isize(0); ++i ) for( unsigned j=0; jsize(1); ++j ) for( unsigned k=0; ksize(2); ++k ) if( ! is_refined(ilevel,i,j,k) ) ++npcount; return npcount; } //! count the number of cells that are not further refined (=leafs) /*! for allocation purposes it is useful to query the number of cells to be expected * @return the integer number of cells in the hierarchy that are not further refined */ unsigned count_leaf_cells( void ) const { return count_leaf_cells( levelmin(), levelmax() ); } //! creates a hierarchy of coextensive grids, refined by factors of 2 /*! creates a hierarchy of lmax grids, each extending over the whole simulation volume with * grid length 2^n for level 0<=n<=lmax * @param lmax the maximum refinement level to be added (sets the resolution to 2^lmax for each dim) * @return none */ void create_base_hierarchy( unsigned lmax ) { unsigned n=1; m_pgrids.clear(); for( unsigned i=0; i<= lmax; ++i ) { //std::cout << "....adding level " << i << " (" << n << ", " << n << ", " << n << ")" << std::endl; m_pgrids.push_back( new MeshvarBnd( m_nbnd, n, n, n, 0, 0, 0 ) ); m_pgrids[i]->zero(); n *= 2; m_xoffabs.push_back( 0 ); m_yoffabs.push_back( 0 ); m_zoffabs.push_back( 0 ); } m_levelmin = lmax; } GridHierarchy& operator*=( T x ) { for( unsigned i=0; i& operator/=( T x ) { for( unsigned i=0; i& operator+=( T x ) { for( unsigned i=0; i& operator-=( T x ) { for( unsigned i=0; i& operator*=( const GridHierarchy& gh ) { if( !is_consistent(gh) ) throw std::runtime_error("GridHierarchy::operator*= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator/=( const GridHierarchy& gh ) { if( !is_consistent(gh) ) throw std::runtime_error("GridHierarchy::operator/= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator+=( const GridHierarchy& gh ) { if( !is_consistent(gh) ) throw std::runtime_error("GridHierarchy::operator+= : attempt to operate on incompatible data"); for( unsigned i=0; i& operator-=( const GridHierarchy& gh ) { if( !is_consistent(gh) ) throw std::runtime_error("GridHierarchy::operator-= : attempt to operate on incompatible data"); for( unsigned i=0; i( m_nbnd, nx, ny, nz, xoff, yoff, zoff ) ); m_pgrids.back()->zero(); //.. add absolute offsets (in units of current level grid cells) m_xoffabs.push_back( 2*(m_xoffabs.back() + xoff) ); m_yoffabs.push_back( 2*(m_yoffabs.back() + yoff) ); m_zoffabs.push_back( 2*(m_zoffabs.back() + zoff) ); } void cut_patch( unsigned ilevel, unsigned xoff, unsigned yoff, unsigned zoff, unsigned nx, unsigned ny, unsigned nz) { unsigned dx,dy,dz,dxtop,dytop,dztop; dx = xoff-m_xoffabs[ilevel]; dy = yoff-m_yoffabs[ilevel]; dz = zoff-m_zoffabs[ilevel]; dxtop = m_pgrids[ilevel]->offset(0)+dx/2; dytop = m_pgrids[ilevel]->offset(1)+dy/2; dztop = m_pgrids[ilevel]->offset(2)+dz/2; MeshvarBnd *mnew = new MeshvarBnd( m_nbnd, nx, ny, nz, dxtop, dytop, dztop ); //... copy data for( unsigned i=0; ioffset(0) -= dx;//xoff; m_pgrids[ilevel+1]->offset(1) -= dy;//yoff; m_pgrids[ilevel+1]->offset(2) -= dz;//zoff; } find_new_levelmin(); } void find_new_levelmin( void ) { for( unsigned i=0; i<=levelmax(); ++i ) { unsigned n = (unsigned)pow(2,i); if( m_pgrids[i]->size(0) == n && m_pgrids[i]->size(1) == n && m_pgrids[i]->size(2) == n ) { m_levelmin=i; } } } unsigned levelmax( void ) const { return m_pgrids.size()-1; } unsigned levelmin( void ) const { return m_levelmin; } GridHierarchy& operator=( const GridHierarchy& gh ) { for( unsigned i=0; i( *gh.get_grid(i) ) ); m_levelmin = gh.levelmin(); m_nbnd = gh.m_nbnd; m_xoffabs = gh.m_xoffabs; m_yoffabs = gh.m_yoffabs; m_zoffabs = gh.m_zoffabs; return *this; } }; //! class that computes the refinement structure given parameters class refinement_hierarchy { std::vector x0_,y0_,z0_,xl_,yl_,zl_; std::vector ox_,oy_,oz_,oax_,oay_,oaz_; std::vector nx_,ny_,nz_; unsigned levelmin_, levelmax_, padding_; config_file& cf_; bool align_top_; float x0ref_[3], lxref_[3]; int xshift_[3]; public: refinement_hierarchy( const refinement_hierarchy& rh ) : cf_( rh.cf_ ) { *this = rh; } explicit refinement_hierarchy( config_file& cf ) : cf_( cf ) { //... query the parameter data we need levelmin_ = cf_.getValue("setup","levelmin"); levelmax_ = cf_.getValue("setup","levelmax"); padding_ = cf_.getValue("setup","padding"); align_top_ = cf_.getValue("setup","align_top"); bool bnoshift = cf_.getValueSafe("setup","no_shift",false); std::string temp; temp = cf_.getValue( "setup", "ref_offset" ); sscanf( temp.c_str(), "%g,%g,%g", &x0ref_[0], &x0ref_[1], &x0ref_[2] ); temp = cf_.getValue( "setup", "ref_extent" ); sscanf( temp.c_str(), "%g,%g,%g", &lxref_[0],&lxref_[1],&lxref_[2] ); unsigned ncoarse = (unsigned)pow(2,levelmin_); //... determine shift double xc[3]; xc[0] = fmod(x0ref_[0]+0.5*lxref_[0],1.0); xc[1] = fmod(x0ref_[1]+0.5*lxref_[1],1.0); xc[2] = fmod(x0ref_[2]+0.5*lxref_[2],1.0); if( levelmin_ != levelmax_ && !bnoshift) { xshift_[0] = (int)((0.5-xc[0])*ncoarse); xshift_[1] = (int)((0.5-xc[1])*ncoarse); xshift_[2] = (int)((0.5-xc[2])*ncoarse); }else{ xshift_[0] = 0; xshift_[1] = 0; xshift_[2] = 0; } char strtmp[32]; sprintf( strtmp, "%d", xshift_[0] ); cf_.insertValue( "setup", "shift_x", strtmp ); sprintf( strtmp, "%d", xshift_[1] ); cf_.insertValue( "setup", "shift_y", strtmp ); sprintf( strtmp, "%d", xshift_[2] ); cf_.insertValue( "setup", "shift_z", strtmp ); x0ref_[0] += (double)xshift_[0]/ncoarse; x0ref_[1] += (double)xshift_[1]/ncoarse; x0ref_[2] += (double)xshift_[2]/ncoarse; //... initialize arrays x0_.assign(levelmax_+1,0.0); xl_.assign(levelmax_+1,1.0); y0_.assign(levelmax_+1,0.0); yl_.assign(levelmax_+1,1.0); z0_.assign(levelmax_+1,0.0); zl_.assign(levelmax_+1,1.0); ox_.assign(levelmax_+1,0); nx_.assign(levelmax_+1,0); oy_.assign(levelmax_+1,0); ny_.assign(levelmax_+1,0); oz_.assign(levelmax_+1,0); nz_.assign(levelmax_+1,0); oax_.assign(levelmax_+1,0); oay_.assign(levelmax_+1,0); oaz_.assign(levelmax_+1,0); nx_[levelmin_] = ncoarse; ny_[levelmin_] = ncoarse; nz_[levelmin_] = ncoarse; //... determine the position of the refinement region on the finest grid int il,jl,kl,ir,jr,kr; int nresmax = (int)pow(2,levelmax_); il = (int)(x0ref_[0] * nresmax); jl = (int)(x0ref_[1] * nresmax); kl = (int)(x0ref_[2] * nresmax); ir = (int)((x0ref_[0]+lxref_[0]) * nresmax + 1.0); jr = (int)((x0ref_[0]+lxref_[0]) * nresmax + 1.0); kr = (int)((x0ref_[0]+lxref_[0]) * nresmax + 1.0); //... align with coarser grids ... if( align_top_ ) { //... require alignment with top grid unsigned nref = (unsigned)pow(2,levelmax_-levelmin_)*2; il = (int)((double)il/nref)*nref; jl = (int)((double)jl/nref)*nref; kl = (int)((double)kl/nref)*nref; ir = (int)((double)ir/nref+1.0)*nref; jr = (int)((double)jr/nref+1.0)*nref; kr = (int)((double)kr/nref+1.0)*nref; }else{ //... require alignment with coarser grid il -= il%2; jl -= jl%2; kl -= kl%2; ir += ir%2; jr += jr%2; kr += kr%2; } if( levelmin_ != levelmax_ ) { oax_[levelmax_] = (il+nresmax)%nresmax; oay_[levelmax_] = (jl+nresmax)%nresmax; oaz_[levelmax_] = (kl+nresmax)%nresmax; nx_[levelmax_] = ir-il; ny_[levelmax_] = jr-jl; nz_[levelmax_] = kr-kl; } //... determine position of coarser grids for( unsigned ilevel=levelmax_-1; ilevel> levelmin_; --ilevel ) { il = (int)((double)il * 0.5 - padding_); jl = (int)((double)jl * 0.5 - padding_); kl = (int)((double)kl * 0.5 - padding_); ir = (int)((double)ir * 0.5 + padding_); jr = (int)((double)jr * 0.5 + padding_); kr = (int)((double)kr * 0.5 + padding_); //... align with coarser grids ... if( align_top_ ) { //... require alignment with top grid unsigned nref = (unsigned)pow(2,ilevel-levelmin_); il = (int)((double)il/nref)*nref; jl = (int)((double)jl/nref)*nref; kl = (int)((double)kl/nref)*nref; ir = (int)((double)ir/nref+1.0)*nref; jr = (int)((double)jr/nref+1.0)*nref; kr = (int)((double)kr/nref+1.0)*nref; }else{ //... require alignment with coarser grid il -= il%2; jl -= jl%2; kl -= kl%2; ir += ir%2; jr += jr%2; kr += kr%2; } oax_[ilevel] = il; oay_[ilevel] = jl; oaz_[ilevel] = kl; nx_[ilevel] = ir-il; ny_[ilevel] = jr-jl; nz_[ilevel] = kr-kl; } //... determine relative offsets between grids for( unsigned ilevel=levelmax_; ilevel>levelmin_; --ilevel ) { ox_[ilevel] = (oax_[ilevel]/2 - oax_[ilevel-1]); oy_[ilevel] = (oay_[ilevel]/2 - oay_[ilevel-1]); oz_[ilevel] = (oaz_[ilevel]/2 - oaz_[ilevel-1]); } for( unsigned ilevel=levelmin_+1; ilevel<=levelmax_; ++ilevel ) { double h = 1.0/pow(2,ilevel); x0_[ilevel] = h*(double)oax_[ilevel]; y0_[ilevel] = h*(double)oay_[ilevel]; z0_[ilevel] = h*(double)oaz_[ilevel]; xl_[ilevel] = h*(double)nx_[ilevel]; yl_[ilevel] = h*(double)ny_[ilevel]; zl_[ilevel] = h*(double)nz_[ilevel]; } for( unsigned ilevel=0; ilevel <=levelmin_; ++ilevel ) { unsigned n = (unsigned)pow(2,ilevel); xl_[ilevel] = yl_[ilevel] = zl_[ilevel] = 1.0; nx_[ilevel] = ny_[ilevel] = nz_[ilevel] = n; } } refinement_hierarchy& operator=( const refinement_hierarchy& o ) { levelmin_ = o.levelmin_; levelmax_ = o.levelmax_; padding_ = o.padding_; cf_ = o.cf_; align_top_ = o.align_top_; for( int i=0; i<3; ++i ) { x0ref_[i] = o.x0ref_[i]; lxref_[i] = o.lxref_[i]; xshift_[i] = o.xshift_[i]; } x0_ = o.x0_; y0_ = o.y0_; z0_ = o.z0_; xl_ = o.xl_; yl_ = o.yl_; zl_ = o.zl_; ox_ = o.ox_; oy_ = o.oy_; oz_ = o.oz_; oax_= o.oax_; oay_ = o.oay_; oaz_ = o.oaz_; nx_ = o.nx_; ny_=o.ny_; nz_=o.nz_; return *this; } void adjust_level( unsigned ilevel, int nx, int ny, int nz, int oax, int oay, int oaz ) { double h = 1.0/pow(2,ilevel); int dx,dy,dz; dx = oax_[ilevel] - oax; dy = oay_[ilevel] - oay; dz = oaz_[ilevel] - oaz; ox_[ilevel] -= dx/2; oy_[ilevel] -= dy/2; oz_[ilevel] -= dz/2; oax_[ilevel] = oax; oay_[ilevel] = oay; oaz_[ilevel] = oaz; nx_[ilevel] = nx; ny_[ilevel] = ny; nz_[ilevel] = nz; x0_[ilevel] = h*oax; y0_[ilevel] = h*oay; z0_[ilevel] = h*oaz; xl_[ilevel] = h*nx; yl_[ilevel] = h*ny; zl_[ilevel] = h*nz; if( ilevel < levelmax_ ) { ox_[ilevel+1] += dx; oy_[ilevel+1] += dy; oz_[ilevel+1] += dz; } find_new_levelmin(); } void find_new_levelmin( bool print=false ) { unsigned old_levelmin( levelmin_ ); for( unsigned i=0; i<=levelmax(); ++i ) { unsigned n = (unsigned)pow(2,i); if( oax_[i]==0 && oay_[i]==0 && oaz_[i]==0 && nx_[i]==n && ny_[i]==n && nz_[i]==n ) { levelmin_=i; } } if( old_levelmin != levelmin_ ) std::cerr << " - refinement_hierarchy: set new levelmin to " << levelmin_ << std::endl; } unsigned offset_abs( unsigned ilevel, int dim ) const { if( dim==0 ) return oax_.at(ilevel); if( dim==1 ) return oay_.at(ilevel); return oaz_.at(ilevel); } unsigned offset( unsigned ilevel, int dim ) const { if( dim==0 ) return ox_.at(ilevel); if( dim==1 ) return oy_.at(ilevel); return oz_.at(ilevel); } unsigned size( unsigned ilevel, int dim ) const { if( dim==0 ) return nx_.at(ilevel); if( dim==1 ) return ny_.at(ilevel); return nz_.at(ilevel); } unsigned levelmin( void ) const { return levelmin_; } unsigned levelmax( void ) const { return levelmax_; } void output( void ) { std::cout << "-------------------------------------------------------------\n"; if( xshift_[0]!=0||xshift_[1]!=0||xshift_[2]!=0 ) std::cout << " - Domain will be shifted by (" << xshift_[0] << ", " << xshift_[1] << ", " << xshift_[2] << ")\n" << std::endl; std::cout << " - Grid structure:\n"; for( unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel ) { std::cout << " Level " << std::setw(3) << ilevel << " : offset = (" << std::setw(5) << ox_[ilevel] << ", " << std::setw(5) << oy_[ilevel] << ", " << std::setw(5) << oz_[ilevel] << ")\n" << " size = (" << std::setw(5) << nx_[ilevel] << ", " << std::setw(5) << ny_[ilevel] << ", " << std::setw(5) << nz_[ilevel] << ")\n"; } std::cout << "-------------------------------------------------------------\n"; } }; #endif