| [dfed1c] | 1 | /**
|
|---|
| 2 | * @file solver_singular.cpp
|
|---|
| 3 | * @author Julian Iseringhausen <isering@ins.uni-bonn.de>
|
|---|
| 4 | * @date Mon Apr 18 13:12:02 2011
|
|---|
| 5 | *
|
|---|
| 6 | * @brief VMG::SolverSingular
|
|---|
| 7 | *
|
|---|
| 8 | */
|
|---|
| 9 |
|
|---|
| 10 | #ifdef HAVE_CONFIG_H
|
|---|
| 11 | #include <config.h>
|
|---|
| 12 | #endif
|
|---|
| 13 |
|
|---|
| 14 | #include <cmath>
|
|---|
| 15 | #include <cassert>
|
|---|
| 16 | #include <iostream>
|
|---|
| 17 | #include <limits>
|
|---|
| 18 |
|
|---|
| 19 | #include "base/discretization.hpp"
|
|---|
| 20 | #include "base/stencil.hpp"
|
|---|
| 21 | #include "comm/comm.hpp"
|
|---|
| 22 | #include "grid/multigrid.hpp"
|
|---|
| 23 | #include "solver/solver_singular.hpp"
|
|---|
| 24 | #include "mg.hpp"
|
|---|
| 25 |
|
|---|
| 26 | using namespace VMG;
|
|---|
| 27 |
|
|---|
| 28 | //TODO: Implement global MPI communication here
|
|---|
| 29 |
|
|---|
| 30 | void SolverSingular::AssembleMatrix(const Grid& rhs)
|
|---|
| 31 | {
|
|---|
| 32 | Grid::iterator grid_iter;
|
|---|
| 33 | Stencil::iterator stencil_iter;
|
|---|
| 34 | Index i;
|
|---|
| 35 | int index, index2;
|
|---|
| 36 | vmg_float row_sum;
|
|---|
| 37 |
|
|---|
| 38 | Comm* comm = MG::GetComm();
|
|---|
| 39 |
|
|---|
| 40 | const vmg_float prefactor = MG::GetDiscretization()->OperatorPrefactor(rhs);
|
|---|
| 41 | const Stencil& A = MG::GetDiscretization()->GetStencil();
|
|---|
| 42 |
|
|---|
| 43 | // Make sure that arrays are big enough to hold expanded system of equations
|
|---|
| [ac6d04] | 44 | this->Realloc(rhs.Global().GlobalSize().Product() + 1);
|
|---|
| [dfed1c] | 45 |
|
|---|
| 46 | for (grid_iter = rhs.Iterators().Local().Begin(); grid_iter != rhs.Iterators().Local().End(); ++grid_iter) {
|
|---|
| 47 |
|
|---|
| 48 | // Compute 1-dimensional index from 3-dimensional grid
|
|---|
| [ac6d04] | 49 | index = rhs.GlobalLinearIndex(*grid_iter - rhs.Local().Begin() + rhs.Global().LocalBegin());
|
|---|
| [dfed1c] | 50 |
|
|---|
| 51 | // Check if we computed the index correctly
|
|---|
| 52 | assert(index >= 0 && index < this->Size()-1);
|
|---|
| 53 |
|
|---|
| 54 | // Set solution and right hand side vectors
|
|---|
| 55 | this->Sol(index) = 0.0;
|
|---|
| 56 | this->Rhs(index) = rhs.GetVal(*grid_iter);
|
|---|
| 57 |
|
|---|
| 58 | // Initialize matrix with zeros and then set entries according to the stencil
|
|---|
| 59 | for (int l=0; l<this->Size(); l++)
|
|---|
| 60 | this->Mat(index,l) = 0.0;
|
|---|
| 61 |
|
|---|
| 62 | this->Mat(index,index) = prefactor * A.GetDiag();
|
|---|
| 63 |
|
|---|
| 64 | for (stencil_iter = A.begin(); stencil_iter != A.end(); ++stencil_iter) {
|
|---|
| 65 |
|
|---|
| [ac6d04] | 66 | i = *grid_iter - rhs.Local().Begin() + rhs.Global().LocalBegin() + stencil_iter->Disp();
|
|---|
| [dfed1c] | 67 |
|
|---|
| 68 | for (int j=0; j<3; ++j)
|
|---|
| 69 | if (comm->BoundaryConditions()[j] == Periodic) {
|
|---|
| 70 | if (i[j] < 0)
|
|---|
| [ac6d04] | 71 | i[j] += rhs.Global().GlobalSize()[j];
|
|---|
| 72 | else if (i[j] >= rhs.Global().GlobalSize()[j])
|
|---|
| 73 | i[j] -= rhs.Global().GlobalSize()[j];
|
|---|
| [dfed1c] | 74 | }
|
|---|
| 75 |
|
|---|
| 76 | // Compute global 1-dimensional index
|
|---|
| 77 | index2 = rhs.GlobalLinearIndex(i);
|
|---|
| 78 |
|
|---|
| 79 | // Set matrix entry
|
|---|
| 80 | this->Mat(index,index2) += prefactor * stencil_iter->Val();
|
|---|
| 81 | }
|
|---|
| 82 | }
|
|---|
| 83 |
|
|---|
| 84 | // Check if matrix has zero row sum (i.e. (1,1,...,1) is an Eigenvector to the Eigenvalue 0)
|
|---|
| 85 | row_sum = A.GetDiag();
|
|---|
| 86 | for (Stencil::iterator iter=A.begin(); iter!=A.end(); iter++)
|
|---|
| 87 | row_sum += iter->Val();
|
|---|
| 88 |
|
|---|
| [ac6d04] | 89 | if (std::abs(row_sum) <= (A.size()+1) * std::numeric_limits<vmg_float>::epsilon()) {
|
|---|
| [dfed1c] | 90 |
|
|---|
| 91 | // Expand equation system in order to make the system regular.
|
|---|
| 92 | // The last entry of the solution vector will hold a correction to the right hand side,
|
|---|
| 93 | // ensuring that the discrete compatibility condition holds. (Compare Trottenberg)
|
|---|
| 94 | for (int i=0; i<this->Size()-1; i++)
|
|---|
| 95 | this->Mat(this->Size()-1, i) = this->Mat(i, this->Size()-1) = 1.0;
|
|---|
| 96 |
|
|---|
| 97 | this->Mat(this->Size()-1, this->Size()-1) = 0.0;
|
|---|
| 98 | this->Sol(this->Size()-1) = 0.0;
|
|---|
| 99 | this->Rhs(this->Size()-1) = 0.0;
|
|---|
| 100 |
|
|---|
| 101 | }else {
|
|---|
| 102 | //TODO: Implement this
|
|---|
| 103 | assert(0 == "At the first glance your stencil does not seem to be singular. Try SolverRegular instead.");
|
|---|
| 104 | }
|
|---|
| 105 | }
|
|---|
| 106 |
|
|---|
| 107 | void SolverSingular::ExportSol(Grid& sol, Grid& rhs)
|
|---|
| 108 | {
|
|---|
| 109 | int index;
|
|---|
| [ac6d04] | 110 | const vmg_float correction = this->Sol(this->Size()-1);
|
|---|
| [dfed1c] | 111 |
|
|---|
| 112 | for (int i=0; i<sol.Local().Size().X(); i++)
|
|---|
| 113 | for (int j=0; j<sol.Local().Size().Y(); j++)
|
|---|
| 114 | for (int k=0; k<sol.Local().Size().Z(); k++) {
|
|---|
| 115 |
|
|---|
| 116 | // Compute global 1-dimensional index
|
|---|
| [ac6d04] | 117 | index = sol.GlobalLinearIndex(sol.Global().LocalBegin().X()+i,
|
|---|
| 118 | sol.Global().LocalBegin().Y()+j,
|
|---|
| 119 | sol.Global().LocalBegin().Z()+k);
|
|---|
| [dfed1c] | 120 |
|
|---|
| 121 | // Set solution
|
|---|
| [ac6d04] | 122 | sol(sol.Local().Begin().X()+i, sol.Local().Begin().Y()+j, sol.Local().Begin().Z()+k) = this->Sol(index) - correction;
|
|---|
| [dfed1c] | 123 |
|
|---|
| 124 | }
|
|---|
| 125 |
|
|---|
| 126 | // Set correction
|
|---|
| 127 | Grid::Correction() = this->Sol(this->Size()-1);
|
|---|
| 128 | }
|
|---|