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