/*
* 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 grid.cpp
* @author Julian Iseringhausen
* @date Mon Apr 18 12:53:27 2011
*
* @brief VMG::Grid
*
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include "base/helper.hpp"
#include "base/stencil.hpp"
#include "comm/comm.hpp"
#include "grid/grid.hpp"
#include "grid/tempgrid.hpp"
#include "mg.hpp"
using namespace VMG;
void Grid::InitGrid()
{
grid = new vmg_float[local.SizeTotal().Product()];
}
Grid::~Grid()
{
delete [] grid;
}
Grid& Grid::operator=(const Grid& rhs)
{
if (this != &rhs) {
global = rhs.Global();
local = rhs.Local();
extent = rhs.Extent();
iterators = rhs.Iterators();
father = rhs.Father();
level = rhs.Level();
delete [] grid;
grid = new vmg_float[local.SizeTotal().Product()];
SetGrid(rhs);
}
return *this;
}
void Grid::Clear()
{
for (int i=0; iGlobalSum(avg) / Global().GlobalSize().Product();
MG::GetComm()->PrintOnce(Info, "Global constraint enforcement: %e", avg);
if (std::abs(avg) > std::numeric_limits::epsilon())
for (iter = Iterators().Local().Begin(); iter != Iterators().Local().End(); ++iter)
(*this)(*iter) -= avg;
}
void Grid::ForceDiscreteCompatibilityCondition()
{
Grid::iterator iter;
vmg_float val = 0.0;
for (iter = Iterators().Local().Begin(); iter != Iterators().Local().End(); ++iter)
val += GetVal(*iter);
val = MG::GetComm()->GlobalSum(val) / Global().GlobalSize().Product();
if (std::abs(val) > std::numeric_limits::epsilon()) {
MG::GetComm()->PrintOnce(Info, "Right hand side does not satisfy the compatibility condition. Trying to enforce.");
for (iter = Iterators().Local().Begin(); iter != Iterators().Local().End(); ++iter)
(*this)(*iter) -= val;
#ifdef OUPUT_DEBUG
val = 0.0;
for (iter = Iterators().Local().Begin(); iter != Iterators().Local().End(); ++iter)
val += GetVal(*iter);
val = MG::GetComm()->GlobalSumRoot(val);
MG::GetComm()->PrintOnce(Debug, "Sum of grid charges after forcing the discrete compatibility condition: %e", val);
#endif
}
}
void Grid::SetGrid(const Grid& rhs)
{
#ifdef DEBUG
IsCompatible(rhs);
#endif
std::memcpy(grid, rhs.grid, local.SizeTotal().Product()*sizeof(vmg_float));
}
void Grid::SetBoundary(const Grid& rhs)
{
#ifdef DEBUG
IsCompatible(rhs);
#endif
Grid::iterator iter;
for (int i=0; i<3; ++i) {
for (iter = Iterators().Boundary1()[i].Begin(); iter != Iterators().Boundary1()[i].End(); ++iter)
(*this)(*iter) = rhs.GetVal(*iter);
for (iter = Iterators().Boundary2()[i].Begin(); iter != Iterators().Boundary2()[i].End(); ++iter)
(*this)(*iter) = rhs.GetVal(*iter);
}
}
void Grid::AddGrid(const Grid& rhs)
{
#ifdef DEBUG_MATRIX_CHECKS
IsCompatible(rhs);
#endif
for (Grid::iterator iter = Iterators().CompleteGrid().Begin(); iter != Iterators().CompleteGrid().End(); ++iter)
(*this)(*iter) += rhs.GetVal(*iter);
}
void Grid::SubtractGrid(const Grid& rhs)
{
#ifdef DEBUG_MATRIX_CHECKS
IsCompatible(rhs);
#endif
for (Grid::iterator iter = Iterators().CompleteGrid().Begin(); iter != Iterators().CompleteGrid().End(); ++iter)
(*this)(*iter) -= rhs.GetVal(*iter);
}
void Grid::MultiplyScalar(const vmg_float& scalar)
{
for (Grid::iterator iter = Iterators().CompleteGrid().Begin(); iter != Iterators().CompleteGrid().End(); ++iter)
(*this)(*iter) *= scalar;
}
void Grid::ApplyStencil(const Stencil& stencil)
{
Grid::iterator grid_iter;
Stencil::iterator stencil_iter;
TempGrid *temp = MG::GetTempGrid();
temp->SetProperties(*this);
temp->SetGrid(*this);
MG::GetComm()->CommToGhosts(*temp);
for (grid_iter = Iterators().Local().Begin(); grid_iter != Iterators().Local().End(); ++grid_iter) {
(*this)(*grid_iter) = stencil.GetDiag() * temp->GetVal(*grid_iter);
for (stencil_iter=stencil.begin(); stencil_iter!=stencil.end(); ++stencil_iter)
(*this)(*grid_iter) += stencil_iter->Val() * temp->GetVal(*grid_iter + stencil_iter->Disp());
}
}
bool Grid::IsCompatible(const Grid& rhs) const
{
bool eq = true;
eq &= Helper::IsEq(Local().Begin(), rhs.Local().Begin(), "Local().Begin");
eq &= Helper::IsEq(Local().End(), rhs.Local().End(), "Local().End");
eq &= Helper::IsEq(Local().Size(), rhs.Local().Size(), "Local().Size");
eq &= Helper::IsEq(Local().SizeTotal(), rhs.Local().SizeTotal(), "Local().SizeTotal");
eq &= Helper::IsEq(Global().LocalBegin(), rhs.Global().LocalBegin(), "Global().LocalBegin");
eq &= Helper::IsEq(Global().LocalEnd(), rhs.Global().LocalEnd(), "Global().LocalEnd");
eq &= Helper::IsEq(Global().LocalSize(), rhs.Global().LocalSize(), "Global().LocalSize");
eq &= Helper::IsEq(Global().GlobalSizeFinest(), rhs.Global().GlobalSizeFinest(), "Global().GlobalSizeFinest");
eq &= Helper::IsEq(Local().HaloBegin1(), rhs.Local().HaloBegin1(), "Local().HaloBegin1");
eq &= Helper::IsEq(Local().HaloBegin2(), rhs.Local().HaloBegin2(), "Local().HaloBegin2");
eq &= Helper::IsEq(Local().HaloEnd1(), rhs.Local().HaloEnd1(), "Local().HaloEnd1");
eq &= Helper::IsEq(Local().HaloEnd2(), rhs.Local().HaloEnd2(), "Local().HaloEnd2");
eq &= Helper::IsEq(Extent().MeshWidth(), rhs.Extent().MeshWidth(), "MeshWidth");
return eq;
}
bool Grid::IsConsistent() const
{
bool consistent = true;
for (Grid::iterator iter=Iterators().Local().Begin(); iter!=Iterators().Local().End(); ++iter)
consistent &= Helper::CheckNumber(GetVal(*iter));
return consistent;
}
Vector Grid::GetSpatialPos(const Index& index_local) const
{
return Extent().Begin() + Extent().MeshWidth() * (index_local - Local().HaloSize1() + Global().LocalBegin() - Global().GlobalBegin());
}
Vector Grid::GetSpatialPosGlobal(const Index& index_global) const
{
return Extent().Begin() + Extent().MeshWidth() * (index_global - Global().GlobalBegin());
}
Index Grid::GetGlobalIndex(const Vector& pos) const
{
const Index index = (pos - Extent().Begin()) / Extent().MeshWidth() + 0.5;
return index + (Global().BoundaryType() == LocallyRefined ? 1 : 0);
}