/* * 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 solver_singular.cpp * @author Julian Iseringhausen * @date Mon Apr 18 13:12:02 2011 * * @brief VMG::SolverSingular * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "base/discretization.hpp" #include "base/stencil.hpp" #include "comm/comm.hpp" #include "grid/multigrid.hpp" #include "solver/solver_singular.hpp" #include "mg.hpp" using namespace VMG; //TODO: Implement global MPI communication here void SolverSingular::AssembleMatrix(const Grid& rhs) { Grid::iterator grid_iter; Stencil::iterator stencil_iter; Index i; int index, index2; vmg_float row_sum; Comm* comm = MG::GetComm(); const vmg_float prefactor = MG::GetDiscretization()->OperatorPrefactor(rhs); const Stencil& A = MG::GetDiscretization()->GetStencil(); // Make sure that arrays are big enough to hold expanded system of equations this->Realloc(rhs.Global().GlobalSize().Product() + 1); for (grid_iter = rhs.Iterators().Local().Begin(); grid_iter != rhs.Iterators().Local().End(); ++grid_iter) { // Compute 1-dimensional index from 3-dimensional grid index = rhs.GlobalLinearIndex(*grid_iter - rhs.Local().Begin() + rhs.Global().LocalBegin()); // Check if we computed the index correctly assert(index >= 0 && index < this->Size()-1); // Set solution and right hand side vectors this->Sol(index) = 0.0; this->Rhs(index) = rhs.GetVal(*grid_iter); // Initialize matrix with zeros and then set entries according to the stencil for (int l=0; lSize(); l++) this->Mat(index,l) = 0.0; this->Mat(index,index) = prefactor * A.GetDiag(); for (stencil_iter = A.begin(); stencil_iter != A.end(); ++stencil_iter) { i = *grid_iter - rhs.Local().Begin() + rhs.Global().LocalBegin() + stencil_iter->Disp(); for (int j=0; j<3; ++j) if (comm->BoundaryConditions()[j] == Periodic) { if (i[j] < rhs.Global().GlobalBegin()[j]) i[j] += rhs.Global().GlobalSize()[j]; else if (i[j] >= rhs.Global().GlobalEnd()[j]) i[j] -= rhs.Global().GlobalSize()[j]; } // Compute global 1-dimensional index index2 = rhs.GlobalLinearIndex(i); // Set matrix entry this->Mat(index,index2) += prefactor * stencil_iter->Val(); } } // Check if matrix has zero row sum (i.e. (1,1,...,1) is an Eigenvector to the Eigenvalue 0) row_sum = A.GetDiag(); for (Stencil::iterator iter=A.begin(); iter!=A.end(); iter++) row_sum += iter->Val(); if (std::abs(row_sum) <= (A.size()+1) * std::numeric_limits::epsilon()) { // Expand equation system in order to make the system regular. // The last entry of the solution vector will hold a correction to the right hand side, // ensuring that the discrete compatibility condition holds. (Compare Trottenberg) for (int i=0; iSize()-1; i++) this->Mat(this->Size()-1, i) = this->Mat(i, this->Size()-1) = 1.0; this->Mat(this->Size()-1, this->Size()-1) = 0.0; this->Sol(this->Size()-1) = 0.0; this->Rhs(this->Size()-1) = 0.0; }else { //TODO: Implement this assert(0 == "At the first glance your stencil does not seem to be singular. Try SolverRegular instead."); } } void SolverSingular::ExportSol(Grid& sol, Grid& rhs) { int index; const vmg_float correction = this->Sol(this->Size()-1); for (int i=0; i= 0 && index < sol.Global().GlobalSize().Product()); // Set solution sol(sol.Local().Begin().X()+i, sol.Local().Begin().Y()+j, sol.Local().Begin().Z()+k) = this->Sol(index) - correction; } }