| 1 | /*
 | 
|---|
| 2 |  *    vmg - a versatile multigrid solver
 | 
|---|
| 3 |  *    Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn
 | 
|---|
| 4 |  *
 | 
|---|
| 5 |  *  vmg is free software: you can redistribute it and/or modify
 | 
|---|
| 6 |  *  it under the terms of the GNU General Public License as published by
 | 
|---|
| 7 |  *  the Free Software Foundation, either version 3 of the License, or
 | 
|---|
| 8 |  *  (at your option) any later version.
 | 
|---|
| 9 |  *
 | 
|---|
| 10 |  *  vmg is distributed in the hope that it will be useful,
 | 
|---|
| 11 |  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
| 12 |  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
| 13 |  *  GNU General Public License for more details.
 | 
|---|
| 14 |  *
 | 
|---|
| 15 |  *  You should have received a copy of the GNU General Public License
 | 
|---|
| 16 |  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
| 17 |  */
 | 
|---|
| 18 | 
 | 
|---|
| 19 | /**
 | 
|---|
| 20 |  * @file   mg.cpp
 | 
|---|
| 21 |  * @author Julian Iseringhausen <isering@ins.uni-bonn.de>
 | 
|---|
| 22 |  * @date   Sat Jun 12 20:36:24 2010
 | 
|---|
| 23 |  *
 | 
|---|
| 24 |  * @brief  A multigrid solver
 | 
|---|
| 25 |  *
 | 
|---|
| 26 |  * This file contains the implementation of the main class for
 | 
|---|
| 27 |  * a multigrid solver.
 | 
|---|
| 28 |  *
 | 
|---|
| 29 |  */
 | 
|---|
| 30 | 
 | 
|---|
| 31 | #ifdef HAVE_CONFIG_H
 | 
|---|
| 32 | #include <libvmg_config.h>
 | 
|---|
| 33 | #endif
 | 
|---|
| 34 | 
 | 
|---|
| 35 | #ifdef OUTPUT_TIMING
 | 
|---|
| 36 | #ifdef HAVE_MPI
 | 
|---|
| 37 | #include <mpi.h>
 | 
|---|
| 38 | #ifdef HAVE_MARMOT
 | 
|---|
| 39 | #include <enhancempicalls.h>
 | 
|---|
| 40 | #include <sourceinfompicalls.h>
 | 
|---|
| 41 | #endif
 | 
|---|
| 42 | #endif
 | 
|---|
| 43 | #endif
 | 
|---|
| 44 | 
 | 
|---|
| 45 | #include <cmath>
 | 
|---|
| 46 | #include <cstdio>
 | 
|---|
| 47 | #include <cfloat>
 | 
|---|
| 48 | #include <ctime>
 | 
|---|
| 49 | #include <string>
 | 
|---|
| 50 | #include <fstream>
 | 
|---|
| 51 | #include <sstream>
 | 
|---|
| 52 | 
 | 
|---|
| 53 | #include "base/command_list.hpp"
 | 
|---|
| 54 | #include "base/discretization.hpp"
 | 
|---|
| 55 | #include "base/factory.hpp"
 | 
|---|
| 56 | #include "base/interface.hpp"
 | 
|---|
| 57 | #include "base/timer.hpp"
 | 
|---|
| 58 | #include "comm/comm.hpp"
 | 
|---|
| 59 | #include "discretization/boundary_value_setter_open.hpp"
 | 
|---|
| 60 | #include "cycles/cycle.hpp"
 | 
|---|
| 61 | #include "grid/grid.hpp"
 | 
|---|
| 62 | #include "grid/tempgrid.hpp"
 | 
|---|
| 63 | #include "level/level_operator.hpp"
 | 
|---|
| 64 | #include "smoother/smoother.hpp"
 | 
|---|
| 65 | #include "solver/solver.hpp"
 | 
|---|
| 66 | #include "mg.hpp"
 | 
|---|
| 67 | 
 | 
|---|
| 68 | using namespace VMG;
 | 
|---|
| 69 | 
 | 
|---|
| 70 | #define REGISTER_COMMAND(a) extern void Initialize##a();Initialize##a();
 | 
|---|
| 71 | 
 | 
|---|
| 72 | VMG::CommandFactory MG::command_factory;
 | 
|---|
| 73 | 
 | 
|---|
| 74 | static void VMGRegisterBuiltinCommands()
 | 
|---|
| 75 | {
 | 
|---|
| 76 |   REGISTER_COMMAND(VMGCommandCheckConsistency);
 | 
|---|
| 77 |   REGISTER_COMMAND(VMGCommandCheckIterationCounter);
 | 
|---|
| 78 |   REGISTER_COMMAND(VMGCommandCheckRelativeResidual);
 | 
|---|
| 79 |   REGISTER_COMMAND(VMGCommandCheckResidual);
 | 
|---|
| 80 |   REGISTER_COMMAND(VMGCommandClearCoarseLevels);
 | 
|---|
| 81 |   REGISTER_COMMAND(VMGCommandClearGrid);
 | 
|---|
| 82 |   REGISTER_COMMAND(VMGCommandComputeResidualNorm);
 | 
|---|
| 83 |   REGISTER_COMMAND(VMGCommandCopyBoundary);
 | 
|---|
| 84 |   REGISTER_COMMAND(VMGCommandExecuteCycle);
 | 
|---|
| 85 |   REGISTER_COMMAND(VMGCommandExecuteCycleLoop);
 | 
|---|
| 86 |   REGISTER_COMMAND(VMGCommandExecuteFullCycle);
 | 
|---|
| 87 |   REGISTER_COMMAND(VMGCommandExecuteFullCycleLoop);
 | 
|---|
| 88 |   REGISTER_COMMAND(VMGCommandExportSolution);
 | 
|---|
| 89 |   REGISTER_COMMAND(VMGCommandForceDiscreteCompatibility);
 | 
|---|
| 90 |   REGISTER_COMMAND(VMGCommandImportRightHandSide);
 | 
|---|
| 91 |   REGISTER_COMMAND(VMGCommandInterpolateFMG);
 | 
|---|
| 92 |   REGISTER_COMMAND(VMGCommandInitializeIterationCounter);
 | 
|---|
| 93 |   REGISTER_COMMAND(VMGCommandInitializeResidualNorm);
 | 
|---|
| 94 |   REGISTER_COMMAND(VMGCommandNOP);
 | 
|---|
| 95 |   REGISTER_COMMAND(VMGCommandPrintAllSettings);
 | 
|---|
| 96 |   REGISTER_COMMAND(VMGCommandPrintDefect);
 | 
|---|
| 97 |   REGISTER_COMMAND(VMGCommandPrintGridStructure);
 | 
|---|
| 98 |   REGISTER_COMMAND(VMGCommandPrintGrid);
 | 
|---|
| 99 |   REGISTER_COMMAND(VMGCommandPrintResidualNorm);
 | 
|---|
| 100 |   REGISTER_COMMAND(VMGCommandPrintRunningTime);
 | 
|---|
| 101 |   REGISTER_COMMAND(VMGCommandProlongate);
 | 
|---|
| 102 |   REGISTER_COMMAND(VMGCommandRestrict);
 | 
|---|
| 103 |   REGISTER_COMMAND(VMGCommandSetAverageToZero);
 | 
|---|
| 104 |   REGISTER_COMMAND(VMGCommandSetCoarserDirichletValues);
 | 
|---|
| 105 |   REGISTER_COMMAND(VMGCommandSetLevel);
 | 
|---|
| 106 |   REGISTER_COMMAND(VMGCommandSmooth);
 | 
|---|
| 107 |   REGISTER_COMMAND(VMGCommandSolve);
 | 
|---|
| 108 | }
 | 
|---|
| 109 | 
 | 
|---|
| 110 | MG::MG()
 | 
|---|
| 111 | {
 | 
|---|
| 112 |   state = 0;
 | 
|---|
| 113 |   VMGRegisterBuiltinCommands();
 | 
|---|
| 114 | }
 | 
|---|
| 115 | 
 | 
|---|
| 116 | MG::~MG()
 | 
|---|
| 117 | {
 | 
|---|
| 118 |   MG::Destroy();
 | 
|---|
| 119 | }
 | 
|---|
| 120 | 
 | 
|---|
| 121 | // Brings Multigrid back to starting state.
 | 
|---|
| 122 | void MG::Destroy()
 | 
|---|
| 123 | {
 | 
|---|
| 124 |   MG::Instance()->factories.clear();
 | 
|---|
| 125 |   MG::Instance()->state = 0;
 | 
|---|
| 126 |   Timer::Clear();
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | /*
 | 
|---|
| 130 |  * Post init communication class
 | 
|---|
| 131 |  */
 | 
|---|
| 132 | void MG::PostInit()
 | 
|---|
| 133 | {
 | 
|---|
| 134 |   if (GetFactory().TestObject("COMM") && GetFactory().TestObject("INTERFACE")) {
 | 
|---|
| 135 | 
 | 
|---|
| 136 |     Comm& comm = *GetComm();
 | 
|---|
| 137 |     Interface& interface = *GetInterface();
 | 
|---|
| 138 | 
 | 
|---|
| 139 |     comm.ComputeDomainDecomposition(interface);
 | 
|---|
| 140 | 
 | 
|---|
| 141 |     Multigrid* sol = new Multigrid(comm, interface);
 | 
|---|
| 142 |     sol->Register("SOL");
 | 
|---|
| 143 | 
 | 
|---|
| 144 |     Multigrid* rhs = new Multigrid(comm, interface);
 | 
|---|
| 145 |     rhs->Register("RHS");
 | 
|---|
| 146 | 
 | 
|---|
| 147 |     TempGrid* temp = new TempGrid();
 | 
|---|
| 148 |     temp->Register("TEMPGRID");
 | 
|---|
| 149 | 
 | 
|---|
| 150 |     new ObjectStorage<int>("GLOBAL_MAXLEVEL", sol->GlobalMaxLevel());
 | 
|---|
| 151 |     new ObjectStorage<int>("MINLEVEL", sol->MinLevel());
 | 
|---|
| 152 |     new ObjectStorage<int>("MAXLEVEL", sol->MaxLevel());
 | 
|---|
| 153 | 
 | 
|---|
| 154 |     if (GetFactory().TestObject("CYCLE"))
 | 
|---|
| 155 |       GetCycle()->Generate();
 | 
|---|
| 156 | 
 | 
|---|
| 157 |     if (comm.BoundaryConditions()[0] == Open &&
 | 
|---|
| 158 |         comm.BoundaryConditions()[1] == Open &&
 | 
|---|
| 159 |         comm.BoundaryConditions()[2] == Open) {
 | 
|---|
| 160 |       new BoundaryValueSetterOpen();
 | 
|---|
| 161 |     }
 | 
|---|
| 162 | 
 | 
|---|
| 163 |     comm.PostInit(*GetSol(), *GetRhs());
 | 
|---|
| 164 | 
 | 
|---|
| 165 |   }
 | 
|---|
| 166 | }
 | 
|---|
| 167 | 
 | 
|---|
| 168 | /**
 | 
|---|
| 169 |  * Solves a given system with a multigrid method
 | 
|---|
| 170 |  *
 | 
|---|
| 171 |  */
 | 
|---|
| 172 | void MG::Solve()
 | 
|---|
| 173 | {
 | 
|---|
| 174 | #ifdef OUTPUT_TIMING
 | 
|---|
| 175 |   GetComm()->Barrier();
 | 
|---|
| 176 |   Timer::Start("CompleteRunningTime");
 | 
|---|
| 177 | #endif
 | 
|---|
| 178 | 
 | 
|---|
| 179 |   CommandList* cl_init = MG::GetFactory().Get("COMMANDLIST_INIT")->Cast<CommandList>();
 | 
|---|
| 180 |   CommandList* cl_loop = MG::GetFactory().Get("COMMANDLIST_LOOP")->Cast<CommandList>();
 | 
|---|
| 181 |   CommandList* cl_finalize = MG::GetFactory().Get("COMMANDLIST_FINALIZE")->Cast<CommandList>();
 | 
|---|
| 182 | 
 | 
|---|
| 183 |   cl_init->ExecuteList();
 | 
|---|
| 184 | 
 | 
|---|
| 185 |   while (cl_loop->ExecuteList() == Continue);
 | 
|---|
| 186 | 
 | 
|---|
| 187 |   cl_finalize->ExecuteList();
 | 
|---|
| 188 | 
 | 
|---|
| 189 | #ifdef OUTPUT_TIMING
 | 
|---|
| 190 |   GetComm()->Barrier();
 | 
|---|
| 191 |   Timer::Stop("CompleteRunningTime");
 | 
|---|
| 192 | #ifdef HAVE_MPI
 | 
|---|
| 193 |   Timer::PrintGlobal();
 | 
|---|
| 194 | #else
 | 
|---|
| 195 |   Timer::Print();
 | 
|---|
| 196 | #endif
 | 
|---|
| 197 | #endif
 | 
|---|
| 198 | }
 | 
|---|
| 199 | 
 | 
|---|
| 200 | void MG::SetState(const int& state_)
 | 
|---|
| 201 | {
 | 
|---|
| 202 |   MG::Instance()->state = state_;
 | 
|---|
| 203 | }
 | 
|---|
| 204 | 
 | 
|---|
| 205 | VMG::Factory& MG::GetFactory()
 | 
|---|
| 206 | {
 | 
|---|
| 207 |   std::map<int, VMG::Factory>::iterator iter = MG::Instance()->factories.find(MG::Instance()->state);
 | 
|---|
| 208 | 
 | 
|---|
| 209 |   if (iter == MG::Instance()->factories.end())
 | 
|---|
| 210 |     iter = MG::Instance()->factories.insert(std::make_pair(MG::Instance()->state, Factory())).first;
 | 
|---|
| 211 | 
 | 
|---|
| 212 |   assert(iter != MG::Instance()->factories.end());
 | 
|---|
| 213 | 
 | 
|---|
| 214 |   return iter->second;
 | 
|---|
| 215 | }
 | 
|---|
| 216 | 
 | 
|---|
| 217 | VMG::CommandFactory& MG::GetCommands()
 | 
|---|
| 218 | {
 | 
|---|
| 219 |   return MG::command_factory;
 | 
|---|
| 220 | }
 | 
|---|
| 221 | 
 | 
|---|
| 222 | Comm* MG::GetComm()
 | 
|---|
| 223 | {
 | 
|---|
| 224 |   return MG::GetFactory().Get("COMM")->Cast<VMG::Comm>();
 | 
|---|
| 225 | }
 | 
|---|
| 226 | 
 | 
|---|
| 227 | Cycle* MG::GetCycle()
 | 
|---|
| 228 | {
 | 
|---|
| 229 |   return MG::GetFactory().Get("CYCLE")->Cast<VMG::Cycle>();
 | 
|---|
| 230 | }
 | 
|---|
| 231 | 
 | 
|---|
| 232 | Discretization* MG::GetDiscretization()
 | 
|---|
| 233 | {
 | 
|---|
| 234 |   return MG::GetFactory().Get("DISCRETIZATION")->Cast<VMG::Discretization>();
 | 
|---|
| 235 | }
 | 
|---|
| 236 | 
 | 
|---|
| 237 | LevelOperator* MG::GetLevelOperator()
 | 
|---|
| 238 | {
 | 
|---|
| 239 |   return MG::GetFactory().Get("LEVEL_OPERATOR")->Cast<VMG::LevelOperator>();
 | 
|---|
| 240 | }
 | 
|---|
| 241 | 
 | 
|---|
| 242 | Multigrid* MG::GetRhs()
 | 
|---|
| 243 | {
 | 
|---|
| 244 |   return MG::GetFactory().Get("RHS")->Cast<VMG::Multigrid>();
 | 
|---|
| 245 | }
 | 
|---|
| 246 | 
 | 
|---|
| 247 | Multigrid* MG::GetSol()
 | 
|---|
| 248 | {
 | 
|---|
| 249 |   return MG::GetFactory().Get("SOL")->Cast<VMG::Multigrid>();
 | 
|---|
| 250 | }
 | 
|---|
| 251 | 
 | 
|---|
| 252 | VMG::Grid& MG::GetRhsMaxLevel()
 | 
|---|
| 253 | {
 | 
|---|
| 254 |   return (*MG::GetRhs())(MG::GetRhs()->MaxLevel());
 | 
|---|
| 255 | }
 | 
|---|
| 256 | 
 | 
|---|
| 257 | VMG::Grid& MG::GetSolMaxLevel()
 | 
|---|
| 258 | {
 | 
|---|
| 259 |   return (*MG::GetSol())(MG::GetSol()->MaxLevel());
 | 
|---|
| 260 | }
 | 
|---|
| 261 | 
 | 
|---|
| 262 | Smoother* MG::GetSmoother()
 | 
|---|
| 263 | {
 | 
|---|
| 264 |   return MG::GetFactory().Get("SMOOTHER")->Cast<VMG::Smoother>();
 | 
|---|
| 265 | }
 | 
|---|
| 266 | 
 | 
|---|
| 267 | Solver* MG::GetSolver()
 | 
|---|
| 268 | {
 | 
|---|
| 269 |   return MG::GetFactory().Get("SOLVER")->Cast<VMG::Solver>();
 | 
|---|
| 270 | }
 | 
|---|
| 271 | 
 | 
|---|
| 272 | TempGrid* MG::GetTempGrid()
 | 
|---|
| 273 | {
 | 
|---|
| 274 |   return MG::GetFactory().Get("TEMPGRID")->Cast<VMG::TempGrid>();
 | 
|---|
| 275 | }
 | 
|---|
| 276 | 
 | 
|---|
| 277 | Interface* MG::GetInterface()
 | 
|---|
| 278 | {
 | 
|---|
| 279 |   return MG::GetFactory().Get("INTERFACE")->Cast<VMG::Interface>();
 | 
|---|
| 280 | }
 | 
|---|
| 281 | 
 | 
|---|
| 282 | BoundaryValueSetter* MG::GetBoundaryValueSetter()
 | 
|---|
| 283 | {
 | 
|---|
| 284 |   return MG::GetFactory().Get("BOUNDARY_VALUE_SETTER")->Cast<VMG::BoundaryValueSetter>();
 | 
|---|
| 285 | }
 | 
|---|
| 286 | 
 | 
|---|
| 287 | bool MG::IsInitialized()
 | 
|---|
| 288 | {
 | 
|---|
| 289 |   const Factory& f = GetFactory();
 | 
|---|
| 290 | 
 | 
|---|
| 291 |   bool init = true;
 | 
|---|
| 292 | 
 | 
|---|
| 293 |   init &= f.TestObject("COMM");
 | 
|---|
| 294 |   init &= f.TestObject("LEVEL_OPERATOR");
 | 
|---|
| 295 |   init &= f.TestObject("RHS");
 | 
|---|
| 296 |   init &= f.TestObject("SOL");
 | 
|---|
| 297 |   init &= f.TestObject("SOLVER");
 | 
|---|
| 298 |   init &= f.TestObject("SMOOTHER");
 | 
|---|
| 299 |   init &= f.TestObject("DISCRETIZATION");
 | 
|---|
| 300 |   init &= f.TestObject("MAX_ITERATION");
 | 
|---|
| 301 |   init &= f.TestObject("PRECISION");
 | 
|---|
| 302 |   init &= f.TestObject("PRESMOOTHSTEPS");
 | 
|---|
| 303 |   init &= f.TestObject("POSTSMOOTHSTEPS");
 | 
|---|
| 304 |   init &= f.TestObject("COMMANDLIST_INIT");
 | 
|---|
| 305 |   init &= f.TestObject("COMMANDLIST_LOOP");
 | 
|---|
| 306 |   init &= f.TestObject("COMMANDLIST_FINALIZE");
 | 
|---|
| 307 |   init &= f.TestObject("MINLEVEL");
 | 
|---|
| 308 |   init &= f.TestObject("MAXLEVEL");
 | 
|---|
| 309 |   init &= f.TestObject("GLOBAL_MAXLEVEL");
 | 
|---|
| 310 |   init &= f.TestObject("INTERFACE");
 | 
|---|
| 311 | 
 | 
|---|
| 312 |   return init;
 | 
|---|
| 313 | }
 | 
|---|