/*
 *    vmg - a versatile multigrid solver
 *    Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn
 *
 *  vmg 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.
 *
 *  vmg 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 .
 */
/**
 * @file   multigrid.cpp
 * @author Julian Iseringhausen 
 * @date   Mon Apr 18 12:54:37 2011
 *
 * @brief  VMG::Multigrid
 *
 */
#ifdef HAVE_CONFIG_H
#include 
#endif
#include 
#include "base/helper.hpp"
#include "base/index.hpp"
#include "base/interface.hpp"
#include "comm/comm.hpp"
#include "comm/domain_decomposition.hpp"
#include "grid/grid.hpp"
#include "grid/grid_properties.hpp"
#include "grid/multigrid.hpp"
using namespace VMG;
Multigrid::Multigrid(const Comm& comm, const Interface& interface)
{
  Index points, remainder;
  LocalIndices local_l;
  const std::vector& extent = interface.Extent();
  const std::vector& global_separated = comm.DecomposedGlobalMe();
  for (unsigned int i=0; i 0) {
      /*
       * Initialize some properties with zero
       */
      local_l.HaloBegin1() = 0;
      local_l.HaloEnd1() = 0;
      local_l.HaloBegin2() = 0;
      local_l.HaloEnd2() = 0;
      local_l.BoundaryBegin1() = 0;
      local_l.BoundaryEnd1() = 0;
      local_l.BoundaryBegin2() = 0;
      local_l.BoundaryEnd2() = 0;
      /*
       * Set boundary dependant properties
       */
      for (int j=0; j<3; ++j) {
        if (comm.BoundaryConditions()[j] == Dirichlet ||
            comm.BoundaryConditions()[j] == Open) {
          local_l.SizeTotal()[j] = global_separated[i].LocalSize()[j];
          /*
           * We have a boundary at the ends of the process grids
           * and halo grid points otherwise
           */
          if (global_separated[i].LocalBegin()[j] == global_separated[i].GlobalBegin()[j]) {
            local_l.BoundaryBegin1()[j] = 0;
            local_l.BoundaryEnd1()[j] = 1;
          }else {
            ++local_l.SizeTotal()[j];
            local_l.HaloBegin1()[j] = 0;
            local_l.HaloEnd1()[j] = 1;
          }
          if (global_separated[i].LocalEnd()[j] == global_separated[i].GlobalEnd()[j]) {
            local_l.BoundaryBegin2()[j] = local_l.SizeTotal()[j] - 1;
            local_l.BoundaryEnd2()[j] = local_l.SizeTotal()[j];
          }else {
            ++local_l.SizeTotal()[j];
            local_l.HaloBegin2()[j] = local_l.SizeTotal()[j] - 1;
            local_l.HaloEnd2()[j] = local_l.SizeTotal()[j];
          }
        }else if (comm.BoundaryConditions()[j] == Periodic) {
          local_l.SizeTotal()[j] = global_separated[i].LocalSize()[j] + 2;
          /*
           * No boundary
           */
          local_l.BoundaryBegin1()[j] = local_l.BoundaryEnd1()[j] = 0;
          local_l.BoundaryBegin2()[j] = local_l.BoundaryEnd2()[j] = 0;
          /*
           * Halo grid points on all processes
           */
          local_l.HaloBegin1()[j] = 0;
          local_l.HaloEnd1()[j] = 1;
          local_l.HaloBegin2()[j] = local_l.SizeTotal()[j] - 1;
          local_l.HaloEnd2()[j] = local_l.SizeTotal()[j];
        }
      }
      local_l.Begin() = 1;
      local_l.End() = local_l.SizeTotal() - 1;
      local_l.Size() = local_l.End() - local_l.Begin();
      local_l.HaloSize1() = local_l.HaloEnd1() - local_l.HaloBegin1();
      local_l.HaloSize2() = local_l.HaloEnd2() - local_l.HaloBegin2();
      local_l.BoundarySize1() = local_l.BoundaryEnd1() - local_l.BoundaryBegin1();
      local_l.BoundarySize2() = local_l.BoundaryEnd2() - local_l.BoundaryBegin2();
    }else {
      local_l.Begin() = 0;
      local_l.End() = 0;
      local_l.Size() = 0;
      local_l.SizeTotal() = 0;
      local_l.HaloBegin1() = 0;
      local_l.HaloEnd1() = 0;
      local_l.HaloSize1() = 0;
      local_l.HaloBegin2() = 0;
      local_l.HaloEnd2() = 0;
      local_l.HaloSize2() = 0;
      local_l.BoundaryBegin1() = 0;
      local_l.BoundaryEnd1() = 0;
      local_l.BoundarySize1() = 0;
      local_l.BoundaryBegin2() = 0;
      local_l.BoundaryEnd2() = 0;
      local_l.BoundarySize2() = 0;
    }
    grids.push_back(new Grid(global_separated[i], local_l, extent[i], interface.MaxLevel()-i, this));
  }
  numLevels = grids.size();
  levelMax = interface.MaxLevel();
  levelMin = levelMax - numLevels + 1;
  levelIndex = 0;
  levelCurrent = levelMax;
}
void Multigrid::SetLevel(int level)
{
  assert(level >= levelMin && level <= levelMax);
  levelCurrent = level;
  levelIndex = levelMax - level;
}
void Multigrid::ToCoarserLevel()
{
  assert(levelCurrent-1 >= levelMin);
  --levelCurrent;
  ++levelIndex;
}
void Multigrid::ToFinerLevel()
{
  assert(levelCurrent+1 <= levelMax);
  ++levelCurrent;
  --levelIndex;
}
void Multigrid::ClearAll()
{
  for (int i=MinLevel(); i<=MaxLevel(); ++i)
    (*this)(i).Clear();
}
// TODO: diff that in case that breaks QP
void Multigrid::ClearAllCoarseLevels()
{
  for (int i=MinLevel(); iMinLevel(); --i) {
    Grid& grid_f = (*this)(i);
    Grid& grid_c = (*this)(i-1);
    i_c.X() = grid_c.Local().BoundaryBegin1().X();
    i_f.X() = grid_f.Local().BoundaryBegin1().X();
    for (i_c.Y()=grid_c.Local().Begin().Y(); i_c.Y()