/* * 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 mg.cpp * @author Julian Iseringhausen * @date Sat Jun 12 20:36:24 2010 * * @brief A multigrid solver * * This file contains the implementation of the main class for * a multigrid solver. * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef OUTPUT_TIMING #ifdef HAVE_MPI #include #ifdef HAVE_MARMOT #include #include #endif #endif #endif #include #include #include #include #include #include #include #include "base/command_list.hpp" #include "base/discretization.hpp" #include "base/factory.hpp" #include "base/interface.hpp" #include "base/timer.hpp" #include "comm/comm.hpp" #include "discretization/boundary_value_setter_open.hpp" #include "cycles/cycle.hpp" #include "grid/grid.hpp" #include "grid/tempgrid.hpp" #include "level/level_operator.hpp" #include "smoother/smoother.hpp" #include "solver/solver.hpp" #include "mg.hpp" using namespace VMG; #define REGISTER_COMMAND(a) extern void Initialize##a();Initialize##a(); VMG::CommandFactory MG::command_factory; static void VMGRegisterBuiltinCommands() { REGISTER_COMMAND(VMGCommandCheckConsistency); REGISTER_COMMAND(VMGCommandCheckIterationCounter); REGISTER_COMMAND(VMGCommandCheckRelativeResidual); REGISTER_COMMAND(VMGCommandCheckResidual); REGISTER_COMMAND(VMGCommandClearCoarseLevels); REGISTER_COMMAND(VMGCommandClearGrid); REGISTER_COMMAND(VMGCommandComputeResidualNorm); REGISTER_COMMAND(VMGCommandCopyBoundary); REGISTER_COMMAND(VMGCommandExecuteCycle); REGISTER_COMMAND(VMGCommandExecuteCycleLoop); REGISTER_COMMAND(VMGCommandExecuteFullCycle); REGISTER_COMMAND(VMGCommandExecuteFullCycleLoop); REGISTER_COMMAND(VMGCommandExportSolution); REGISTER_COMMAND(VMGCommandForceDiscreteCompatibility); REGISTER_COMMAND(VMGCommandImportRightHandSide); REGISTER_COMMAND(VMGCommandInterpolateFMG); REGISTER_COMMAND(VMGCommandInitializeIterationCounter); REGISTER_COMMAND(VMGCommandInitializeResidualNorm); REGISTER_COMMAND(VMGCommandNOP); REGISTER_COMMAND(VMGCommandPrintAllSettings); REGISTER_COMMAND(VMGCommandPrintDefect); REGISTER_COMMAND(VMGCommandPrintGridStructure); REGISTER_COMMAND(VMGCommandPrintGrid); REGISTER_COMMAND(VMGCommandPrintResidualNorm); REGISTER_COMMAND(VMGCommandPrintRunningTime); REGISTER_COMMAND(VMGCommandProlongate); REGISTER_COMMAND(VMGCommandRestrict); REGISTER_COMMAND(VMGCommandSetAverageToZero); REGISTER_COMMAND(VMGCommandSetCoarserDirichletValues); REGISTER_COMMAND(VMGCommandSetLevel); REGISTER_COMMAND(VMGCommandSmooth); REGISTER_COMMAND(VMGCommandSolve); } MG::MG() { state = 0; VMGRegisterBuiltinCommands(); } MG::~MG() { MG::Destroy(); } // Brings Multigrid back to starting state. void MG::Destroy() { MG::Instance()->factories.clear(); MG::Instance()->state = 0; Timer::Clear(); } /* * Post init communication class */ void MG::PostInit() { if (GetFactory().TestObject("COMM") && GetFactory().TestObject("INTERFACE")) { Comm& comm = *GetComm(); Interface& interface = *GetInterface(); comm.ComputeDomainDecomposition(interface); Multigrid* sol = new Multigrid(comm, interface); sol->Register("SOL"); Multigrid* rhs = new Multigrid(comm, interface); rhs->Register("RHS"); TempGrid* temp = new TempGrid(); temp->Register("TEMPGRID"); new ObjectStorage("GLOBAL_MAXLEVEL", sol->GlobalMaxLevel()); new ObjectStorage("MINLEVEL", sol->MinLevel()); new ObjectStorage("MAXLEVEL", sol->MaxLevel()); if (GetFactory().TestObject("CYCLE")) GetCycle()->Generate(); if (comm.BoundaryConditions()[0] == Open && comm.BoundaryConditions()[1] == Open && comm.BoundaryConditions()[2] == Open) { new BoundaryValueSetterOpen(); } comm.PostInit(*GetSol(), *GetRhs()); } } /** * Solves a given system with a multigrid method * */ void MG::Solve() { #ifdef OUTPUT_TIMING GetComm()->Barrier(); Timer::Start("CompleteRunningTime"); #endif CommandList* cl_init = MG::GetFactory().Get("COMMANDLIST_INIT")->Cast(); CommandList* cl_loop = MG::GetFactory().Get("COMMANDLIST_LOOP")->Cast(); CommandList* cl_finalize = MG::GetFactory().Get("COMMANDLIST_FINALIZE")->Cast(); cl_init->ExecuteList(); while (cl_loop->ExecuteList() == Continue); cl_finalize->ExecuteList(); #ifdef OUTPUT_TIMING GetComm()->Barrier(); Timer::Stop("CompleteRunningTime"); #ifdef HAVE_MPI Timer::PrintGlobal(); #else Timer::Print(); #endif #endif } void MG::SetState(const int& state_) { MG::Instance()->state = state_; } VMG::Factory& MG::GetFactory() { std::map::iterator iter = MG::Instance()->factories.find(MG::Instance()->state); if (iter == MG::Instance()->factories.end()) iter = MG::Instance()->factories.insert(std::make_pair(MG::Instance()->state, Factory())).first; assert(iter != MG::Instance()->factories.end()); return iter->second; } VMG::CommandFactory& MG::GetCommands() { return MG::command_factory; } Comm* MG::GetComm() { return MG::GetFactory().Get("COMM")->Cast(); } Cycle* MG::GetCycle() { return MG::GetFactory().Get("CYCLE")->Cast(); } Discretization* MG::GetDiscretization() { return MG::GetFactory().Get("DISCRETIZATION")->Cast(); } LevelOperator* MG::GetLevelOperator() { return MG::GetFactory().Get("LEVEL_OPERATOR")->Cast(); } Multigrid* MG::GetRhs() { return MG::GetFactory().Get("RHS")->Cast(); } Multigrid* MG::GetSol() { return MG::GetFactory().Get("SOL")->Cast(); } VMG::Grid& MG::GetRhsMaxLevel() { return (*MG::GetRhs())(MG::GetRhs()->MaxLevel()); } VMG::Grid& MG::GetSolMaxLevel() { return (*MG::GetSol())(MG::GetSol()->MaxLevel()); } Smoother* MG::GetSmoother() { return MG::GetFactory().Get("SMOOTHER")->Cast(); } Solver* MG::GetSolver() { return MG::GetFactory().Get("SOLVER")->Cast(); } TempGrid* MG::GetTempGrid() { return MG::GetFactory().Get("TEMPGRID")->Cast(); } Interface* MG::GetInterface() { return MG::GetFactory().Get("INTERFACE")->Cast(); } BoundaryValueSetter* MG::GetBoundaryValueSetter() { return MG::GetFactory().Get("BOUNDARY_VALUE_SETTER")->Cast(); } bool MG::IsInitialized() { const Factory& f = GetFactory(); bool init = true; init &= f.TestObject("COMM"); init &= f.TestObject("LEVEL_OPERATOR"); init &= f.TestObject("RHS"); init &= f.TestObject("SOL"); init &= f.TestObject("SOLVER"); init &= f.TestObject("SMOOTHER"); init &= f.TestObject("DISCRETIZATION"); init &= f.TestObject("MAX_ITERATION"); init &= f.TestObject("PRECISION"); init &= f.TestObject("PRESMOOTHSTEPS"); init &= f.TestObject("POSTSMOOTHSTEPS"); init &= f.TestObject("COMMANDLIST_INIT"); init &= f.TestObject("COMMANDLIST_LOOP"); init &= f.TestObject("COMMANDLIST_FINALIZE"); init &= f.TestObject("MINLEVEL"); init &= f.TestObject("MAXLEVEL"); init &= f.TestObject("GLOBAL_MAXLEVEL"); init &= f.TestObject("INTERFACE"); return init; }