/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2012 University of Bonn. All rights reserved.
 * 
 *
 *   This file is part of MoleCuilder.
 *
 *    MoleCuilder 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 2 of the License, or
 *    (at your option) any later version.
 *
 *    MoleCuilder 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 MoleCuilder.  If not, see .
 */
/*
 * VMGDebugGridJob.cpp
 *
 *  Created on: Jul 13, 2012
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#ifdef HAVE_MPI
#include "mpi.h"
#endif
// include headers that implement a archive in simple text format
// otherwise BOOST_CLASS_EXPORT_IMPLEMENT has no effect
#include 
#include 
#include "mg.hpp"
#include "base/object.hpp"
#include "base/defs.hpp"
#ifdef HAVE_MPI
#include "comm/comm_mpi.hpp"
#include "comm/domain_decomposition_mpi.hpp"
#include "units/particle/comm_mpi_particle.hpp"
#else
#include "comm/comm_serial.hpp"
#endif
#include "grid/multigrid.hpp"
//#include "grid/tempgrid.hpp"
#include "level/stencils.hpp"
#include "solver/givens.hpp"
// periodic boundary conditions
#include "cycles/cycle_cs_periodic.hpp"
#include "discretization/discretization_poisson_fd.hpp"
#include "level/level_operator_cs.hpp"
#include "smoother/gsrb_poisson_4.hpp"
#include "solver/solver_singular.hpp"
// open boundary conditions
#ifndef NDEBUG
#include "cycles/cycle_fas_dirichlet_debug.hpp"
#else
#include "cycles/cycle_fas_dirichlet.hpp"
#endif
#include "discretization/discretization_poisson_fv.hpp"
#include "level/level_operator_fas.hpp"
#include "smoother/gsrb_poisson_2.hpp"
#include "solver/solver_regular.hpp"
//#include "CodePatterns/MemDebug.hpp"
#include "Jobs/VMGDebugGridJob.hpp"
#include "LinearAlgebra/defs.hpp"
#include "Jobs/InterfaceVMGDebugGridJob.hpp"
using namespace VMG;
VMGDebugGridJob::VMGDebugGridJob(
    const JobId_t _JobId,
    const SamplingGrid &_density_grid,
    const bool _OpenBoundaryConditions) :
  FragmentJob(_JobId),
  density_grid(_density_grid),
  OpenBoundaryConditions(_OpenBoundaryConditions)
{}
VMGDebugGridJob::VMGDebugGridJob() :
  FragmentJob(JobId::IllegalJob),
  OpenBoundaryConditions(false)
{}
VMGDebugGridJob::~VMGDebugGridJob()
{}
FragmentResult::ptr VMGDebugGridJob::Work()
{
  // initialize VMG library solver
  InitVMG();
  /*
   * Start the multigrid solver,
   * hence calling InterfaceVMGDebugGridJob::ImportRightHandSide()
   */
  MG::Solve();
  /*
   * Delete all data.
   */
  MG::Destroy();
  std::stringstream returnstream;
  boost::archive::text_oarchive oa(returnstream);
  std::string message("Sampled Grid");
  oa << message;
  FragmentResult::ptr ptr( new FragmentResult(getId(), returnstream.str()) );
  return ptr;
}
/** Initialization of VMG library.
 *
 * The contents is heavily inspired from interface_fcs.cpp: VMG_fcs_init() of
 * the ScaFaCoS project.
 *
 */
void VMGDebugGridJob::InitVMG()
{
  Boundary *boundary= NULL;
  if (OpenBoundaryConditions)
    boundary = new Boundary(Open, Open, Open);
  else
    boundary = new Boundary(Periodic, Periodic, Periodic);
#ifdef HAVE_MPI
  new Particle::CommMPI(*boundary, new DomainDecompositionMPI());
#else
  new CommSerial(*boundary);
#endif
  if (OpenBoundaryConditions)
    new DiscretizationPoissonFV(2);
  else
    new DiscretizationPoissonFD(4);
  new VMGInterfaces::InterfaceVMGDebugGridJob(
      density_grid,
      *boundary,
      2,
      density_grid.level,
      Vector(density_grid.begin),
      density_grid.end[0]-density_grid.begin[0],
      5);
  const int cycle_type = 1; // V-type
  if (OpenBoundaryConditions) {
    new LevelOperatorFAS(Stencils::RestrictionFullWeight, Stencils::Injection, Stencils::InterpolationTrilinear);
    new Givens();
#ifndef NDEBUG
    new CycleFASDirichletDebug(cycle_type);
#else
    new CycleFASDirichlet(cycle_type);
#endif
    new GaussSeidelRBPoisson2();
  } else {
    new LevelOperatorCS(Stencils::RestrictionFullWeight, Stencils::InterpolationTrilinear);
    new Givens();
    new CycleCSPeriodic(cycle_type);
    new GaussSeidelRBPoisson4();
  }
  delete boundary;
  /*
   * Register required parameters
   */
  new ObjectStorage("PRESMOOTHSTEPS", 3);
  new ObjectStorage("POSTSMOOTHSTEPS", 3);
  new ObjectStorage("PRECISION", 1.0e-10);
  new ObjectStorage("MAX_ITERATION", 15);
  new ObjectStorage("PARTICLE_NEAR_FIELD_CELLS", 5);
  new ObjectStorage("PARTICLE_INTERPOLATION_DEGREE", 3);
  /*
   * Post init
   */
  MG::PostInit();
  /*
   * Check whether the library is correctly initialized now.
   */
  MG::IsInitialized();
}
// we need to explicitly instantiate the serialization functions as
// its is only serialized through its base class FragmentJob
BOOST_CLASS_EXPORT_IMPLEMENT(VMGDebugGridJob)