IncompFlowSolverHybrid.hpp
Go to the documentation of this file.
1// -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set ts=8 sw=4 et sts=4:
3//===========================================================================
4//
5// File: IncompFlowSolverHybrid.hpp
6//
7// Created: Tue Jun 30 10:25:40 2009
8//
9// Author(s): B�rd Skaflestad <bard.skaflestad@sintef.no>
10// Atgeirr F Rasmussen <atgeirr@sintef.no>
11//
12// $Date$
13//
14// $Revision$
15//
16//===========================================================================
17
18/*
19 Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
20 Copyright 2009, 2010 Statoil ASA.
21
22 This file is part of The Open Reservoir Simulator Project (OpenRS).
23
24 OpenRS is free software: you can redistribute it and/or modify
25 it under the terms of the GNU General Public License as published by
26 the Free Software Foundation, either version 3 of the License, or
27 (at your option) any later version.
28
29 OpenRS is distributed in the hope that it will be useful,
30 but WITHOUT ANY WARRANTY; without even the implied warranty of
31 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
32 GNU General Public License for more details.
33
34 You should have received a copy of the GNU General Public License
35 along with OpenRS. If not, see <http://www.gnu.org/licenses/>.
36*/
37
38#ifndef OPENRS_INCOMPFLOWSOLVERHYBRID_HEADER
39#define OPENRS_INCOMPFLOWSOLVERHYBRID_HEADER
40
41#include <boost/unordered_map.hpp>
42
43#include <boost/bind.hpp>
44#include <boost/scoped_ptr.hpp>
45#include <boost/lexical_cast.hpp>
46
47#include <dune/common/fvector.hh>
48#include <dune/common/fmatrix.hh>
49#include <opm/common/ErrorMacros.hpp>
50#include <opm/core/utility/SparseTable.hpp>
51
52#include <dune/istl/bvector.hh>
53#include <dune/istl/bcrsmatrix.hh>
54#include <dune/istl/operators.hh>
55#include <dune/istl/io.hh>
56
57#include <dune/istl/overlappingschwarz.hh>
58#include <dune/istl/schwarz.hh>
59#include <dune/istl/preconditioners.hh>
60#include <dune/istl/solvers.hh>
61#include <dune/istl/owneroverlapcopy.hh>
62#include <dune/istl/paamg/amg.hh>
63#include <dune/common/version.hh>
64#if DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
65#include <dune/istl/paamg/fastamg.hh>
66#endif
67#include <dune/istl/paamg/kamg.hh>
68#include <dune/istl/paamg/pinfo.hh>
69
72
73#include <algorithm>
74#include <functional>
75#include <map>
76#include <numeric>
77#include <ostream>
78#include <stdexcept>
79#include <utility>
80#include <vector>
81#include <iostream>
82
83namespace Opm {
84 namespace {
108 template<class GI>
109 bool topologyIsSane(const GI& g)
110 {
111 typedef typename GI::CellIterator CI;
112 typedef typename CI::FaceIterator FI;
113
114 bool sane = g.numberOfCells() >= 0;
115
116 for (CI c = g.cellbegin(); sane && c != g.cellend(); ++c) {
117 std::vector<int> n;
118
119 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
120 if (!f->boundary()) {
121 n.push_back(f->neighbourCellIndex());
122 }
123 }
124 std::sort(n.begin(), n.end());
125
126 sane = std::unique(n.begin(), n.end()) == n.end();
127 }
128
129 return sane;
130 }
131
132
158 template<typename T>
159 class axpby : public std::binary_function<T,T,T> {
160 public:
166 axpby(const T& a, const T& b) : a_(a), b_(b) {}
167
180 T operator()(const T& x, const T& y)
181 {
182 return a_*x + b_*y;
183 }
184 private:
185 T a_, b_;
186 };
187 }
188
189
362 template <class GridInterface,
363 class RockInterface,
364 class BCInterface,
365 template <class GridIF, class RockIF> class InnerProduct>
372 typedef typename GridInterface::Scalar Scalar;
373
378 enum FaceType { Internal, Dirichlet, Neumann, Periodic };
379
382 class FlowSolution {
383 public:
389 typedef typename GridInterface::Scalar Scalar;
390
394 typedef typename GridInterface::CellIterator CI;
395
398 typedef typename CI ::FaceIterator FI;
399
400 friend class IncompFlowSolverHybrid;
401
411 Scalar pressure(const CI& c) const
412 {
413 return pressure_[cellno_[c->index()]];
414 }
415
426 Scalar outflux (const FI& f) const
427 {
428 return outflux_[cellno_[f->cellIndex()]][f->localIndex()];
429 }
430 Scalar outflux (int hf) const
431 {
432 return outflux_.data(hf);
433 }
434 private:
435 std::vector< int > cellno_;
436 Opm::SparseTable< int > cellFaces_;
437 std::vector<Scalar> pressure_;
438 Opm::SparseTable<Scalar> outflux_;
439
440 void clear() {
441 std::vector<int>().swap(cellno_);
442 cellFaces_.clear();
443
444 std::vector<Scalar>().swap(pressure_);
445 outflux_.clear();
446 }
447 };
448
449 public:
476 template<class Point>
477 void init(const GridInterface& g,
478 const RockInterface& r,
479 const Point& grav,
480 const BCInterface& bc)
481 {
482 clear();
483
484 if (g.numberOfCells() > 0) {
485 initSystemStructure(g, bc);
486 computeInnerProducts(r, grav);
487 }
488 }
489
490
498 void clear()
499 {
500 pgrid_ = 0;
501 max_ncf_ = -1;
502 num_internal_faces_ = 0;
503 total_num_faces_ = 0;
504 matrix_structure_valid_ = false;
505 do_regularization_ = true; // Assume pure Neumann by default.
506
507 bdry_id_map_.clear();
508
509 std::vector<Scalar>().swap(L_);
510 std::vector<Scalar>().swap(g_);
511 F_.clear();
512
513 flowSolution_.clear();
514
515 cleared_state_ = true;
516 }
517
518
534 void initSystemStructure(const GridInterface& g,
535 const BCInterface& bc)
536 {
537 // You must call clear() prior to initSystemStructure()
538 assert (cleared_state_);
539
540 assert (topologyIsSane(g));
541
542 enumerateDof(g, bc);
543 allocateConnections(bc);
544 setConnections(bc);
545 }
546
547
564 template<class Point>
565 void computeInnerProducts(const RockInterface& r,
566 const Point& grav)
567 {
568 // You must call connectionsCompleted() prior to computeInnerProducts()
569 assert (matrix_structure_valid_);
570
571 typedef typename GridInterface::CellIterator CI;
572 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
573
574 int i = 0;
575 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c, ++i) {
576 ip_.buildStaticContrib(c, r, grav, cf.rowSize(i));
577 }
578 }
579
580
657 template<class FluidInterface>
658 void solve(const FluidInterface& r ,
659 const std::vector<double>& sat,
660 const BCInterface& bc ,
661 const std::vector<double>& src,
662 double residual_tolerance = 1e-8,
663 int linsolver_verbosity = 1,
664 int linsolver_type = 1,
665 bool same_matrix = false,
666 int linsolver_maxit = 0,
667 double prolongate_factor = 1.6,
668 int smooth_steps = 1)
669 {
670 assembleDynamic(r, sat, bc, src);
671// static int count = 0;
672// ++count;
673// printSystem(std::string("linsys_mimetic-") + boost::lexical_cast<std::string>(count));
674 switch (linsolver_type) {
675 case 0: // ILU0 preconditioned CG
676 solveLinearSystem(residual_tolerance, linsolver_verbosity, linsolver_maxit);
677 break;
678 case 1: // AMG preconditioned CG
679 solveLinearSystemAMG(residual_tolerance, linsolver_verbosity,
680 linsolver_maxit, prolongate_factor, same_matrix, smooth_steps);
681 break;
682
683 case 2: // KAMG preconditioned CG
684 solveLinearSystemKAMG(residual_tolerance, linsolver_verbosity,
685 linsolver_maxit, prolongate_factor, same_matrix,smooth_steps);
686 break;
687 case 3: // CG preconditioned with AMG that uses less memory badwidth
688#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
689 solveLinearSystemFastAMG(residual_tolerance, linsolver_verbosity,
690 linsolver_maxit, prolongate_factor, same_matrix,smooth_steps);
691#else
692 if(linsolver_verbosity)
693 std::cerr<<"Fast AMG is not available; falling back to CG preconditioned with the normal one."<<std::endl;
694 solveLinearSystemAMG(residual_tolerance, linsolver_verbosity,
695 linsolver_maxit, prolongate_factor, same_matrix, smooth_steps);
696#endif
697 break;
698 default:
699 std::cerr << "Unknown linsolver_type: " << linsolver_type << '\n';
700 throw std::runtime_error("Unknown linsolver_type");
701 }
702 computePressureAndFluxes(r, sat);
703 }
704
705 private:
707 class FaceFluxes
708 {
709 public:
710 FaceFluxes(int sz)
711 : fluxes_(sz, 0.0), visited_(sz, 0), max_modification_(0.0)
712 {
713 }
714 void put(double flux, int f_ix) {
715 assert(visited_[f_ix] == 0 || visited_[f_ix] == 1);
716 double sign = visited_[f_ix] ? -1.0 : 1.0;
717 fluxes_[f_ix] += sign*flux;
718 ++visited_[f_ix];
719 }
720 void get(double& flux, int f_ix) {
721 assert(visited_[f_ix] == 0 || visited_[f_ix] == 1);
722 double sign = visited_[f_ix] ? -1.0 : 1.0;
723 double new_flux = 0.5*sign*fluxes_[f_ix];
724 double diff = std::fabs(flux - new_flux);
725 max_modification_ = std::max(max_modification_, diff);
726 flux = new_flux;
727 ++visited_[f_ix];
728 }
729 void resetVisited()
730 {
731 std::fill(visited_.begin(), visited_.end(), 0);
732 }
733
734 double maxMod() const
735 {
736 return max_modification_;
737 }
738 private:
739 std::vector<double> fluxes_;
740 std::vector<int> visited_;
741 double max_modification_;
742
743 };
744
745 public:
755 {
756 typedef typename GridInterface::CellIterator CI;
757 typedef typename CI ::FaceIterator FI;
758 const std::vector<int>& cell = flowSolution_.cellno_;
759 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
760 Opm::SparseTable<double>& cflux = flowSolution_.outflux_;
761
762 FaceFluxes face_fluxes(pgrid_->numberOfFaces());
763 // First pass: compute projected fluxes.
764 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
765 const int cell_index = cell[c->index()];
766 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
767 int f_ix = cf[cell_index][f->localIndex()];
768 double flux = cflux[cell_index][f->localIndex()];
769 if (f->boundary()) {
770 if (ppartner_dof_.empty()) {
771 continue;
772 }
773 int partner_f_ix = ppartner_dof_[f_ix];
774 if (partner_f_ix != -1) {
775 face_fluxes.put(flux, f_ix);
776 face_fluxes.put(flux, partner_f_ix);
777 }
778 } else {
779 face_fluxes.put(flux, f_ix);
780 }
781 }
782 }
783 face_fluxes.resetVisited();
784 // Second pass: set all fluxes to the projected ones.
785 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
786 const int cell_index = cell[c->index()];
787 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
788 int f_ix = cf[cell_index][f->localIndex()];
789 double& flux = cflux[cell_index][f->localIndex()];
790 if (f->boundary()) {
791 if (ppartner_dof_.empty()) {
792 continue;
793 }
794 int partner_f_ix = ppartner_dof_[f_ix];
795 if (partner_f_ix != -1) {
796 face_fluxes.get(flux, f_ix);
797 double dummy = flux;
798 face_fluxes.get(dummy, partner_f_ix);
799 assert(dummy == flux);
800 }
801 } else {
802 face_fluxes.get(flux, f_ix);
803 }
804 }
805 }
806 return face_fluxes.maxMod();
807 }
808
809
818 typedef const FlowSolution& SolutionType;
819
829 {
830 return flowSolution_;
831 }
832
833
848 template<typename charT, class traits>
849 void printStats(std::basic_ostream<charT,traits>& os)
850 {
851 os << "IncompFlowSolverHybrid<>:\n"
852 << "\tMaximum number of cell faces = " << max_ncf_ << '\n'
853 << "\tNumber of internal faces = " << num_internal_faces_ << '\n'
854 << "\tTotal number of faces = " << total_num_faces_ << '\n';
855
856 const std::vector<int>& cell = flowSolution_.cellno_;
857 os << "cell index map = [";
858 std::copy(cell.begin(), cell.end(),
859 std::ostream_iterator<int>(os, " "));
860 os << "\b]\n";
861
862 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
863 os << "cell faces =\n";
864 for (int i = 0; i < cf.size(); ++i)
865 {
866 os << "\t[" << i << "] -> [";
867 std::copy(cf[i].begin(), cf[i].end(),
868 std::ostream_iterator<int>(os, ","));
869 os << "\b]\n";
870 }
871 }
872
873
895 void printSystem(const std::string& prefix)
896 {
897 writeMatrixToMatlab(S_, prefix + "-mat.dat");
898
899 std::string rhsfile(prefix + "-rhs.dat");
900 std::ofstream rhs(rhsfile.c_str());
901 rhs.precision(15);
902 rhs.setf(std::ios::scientific | std::ios::showpos);
903 std::copy(rhs_.begin(), rhs_.end(),
904 std::ostream_iterator<VectorBlockType>(rhs, "\n"));
905 }
906
907 private:
908 typedef std::pair<int,int> DofID;
909 typedef boost::unordered_map<int,DofID> BdryIdMapType;
910 typedef BdryIdMapType::const_iterator BdryIdMapIterator;
911
912 const GridInterface* pgrid_;
913 BdryIdMapType bdry_id_map_;
914 std::vector<int> ppartner_dof_;
915
916 InnerProduct<GridInterface, RockInterface> ip_;
917
918 // ----------------------------------------------------------------
919 bool cleared_state_;
920 int max_ncf_;
921 int num_internal_faces_;
922 int total_num_faces_;
923
924 // ----------------------------------------------------------------
925 std::vector<Scalar> L_, g_;
926 Opm::SparseTable<Scalar> F_ ;
927
928 // ----------------------------------------------------------------
929 // Actual, assembled system of linear equations
930 typedef Dune::FieldVector<Scalar, 1 > VectorBlockType;
931 typedef Dune::FieldMatrix<Scalar, 1, 1> MatrixBlockType;
932
933 Dune::BCRSMatrix <MatrixBlockType> S_; // System matrix
934 Dune::BlockVector<VectorBlockType> rhs_; // System RHS
935 Dune::BlockVector<VectorBlockType> soln_; // System solution (contact pressure)
936 bool matrix_structure_valid_;
937 bool do_regularization_;
938
939 // ----------------------------------------------------------------
940 // Physical quantities (derived)
941 FlowSolution flowSolution_;
942
943
944 // ----------------------------------------------------------------
945 void enumerateDof(const GridInterface& g, const BCInterface& bc)
946 // ----------------------------------------------------------------
947 {
948 enumerateGridDof(g);
949 enumerateBCDof(g, bc);
950
951 pgrid_ = &g;
952 cleared_state_ = false;
953 }
954
955 // ----------------------------------------------------------------
956 void enumerateGridDof(const GridInterface& g)
957 // ----------------------------------------------------------------
958 {
959 typedef typename GridInterface::CellIterator CI;
960 typedef typename CI ::FaceIterator FI;
961
962 const int nc = g.numberOfCells();
963 std::vector<int> fpos ; fpos.reserve(nc + 1);
964 std::vector<int> num_cf(nc) ;
965 std::vector<int> faces ;
966
967 // Allocate cell structures.
968 std::vector<int>(nc, -1).swap(flowSolution_.cellno_);
969
970 std::vector<int>& cell = flowSolution_.cellno_;
971
972 // First pass: enumerate internal faces.
973 int cellno = 0; fpos.push_back(0);
974 int tot_ncf = 0, tot_ncf2 = 0;
975 for (CI c = g.cellbegin(); c != g.cellend(); ++c, ++cellno) {
976 const int c0 = c->index();
977 assert((0 <= c0) && (c0 < nc) && (cell[c0] == -1));
978
979 cell[c0] = cellno;
980
981 int& ncf = num_cf[c0];
982
983 for (FI f = c->facebegin(); f != c-> faceend(); ++f) {
984 if (!f->boundary()) {
985 const int c1 = f->neighbourCellIndex();
986 assert((0 <= c1) && (c1 < nc) && (c1 != c0));
987
988 if (cell[c1] == -1) {
989 // Previously undiscovered internal face.
990 faces.push_back(c1);
991 }
992 }
993 ++ncf;
994 }
995
996 fpos.push_back(int(faces.size()));
997 max_ncf_ = std::max(max_ncf_, ncf);
998 tot_ncf += ncf;
999 tot_ncf2 += ncf * ncf;
1000 }
1001 assert (cellno == nc);
1002
1003 total_num_faces_ = num_internal_faces_ = int(faces.size());
1004
1005 ip_.init(max_ncf_); ip_.reserveMatrices(num_cf);
1006 F_ .reserve(nc, tot_ncf);
1007
1008 flowSolution_.cellFaces_.reserve(nc, tot_ncf);
1009 flowSolution_.outflux_ .reserve(nc, tot_ncf);
1010
1011 Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1012
1013 // Avoid (most) allocation(s) inside 'c' loop.
1014 std::vector<int> l2g; l2g .reserve(max_ncf_);
1015 std::vector<Scalar> F_alloc; F_alloc .reserve(max_ncf_);
1016
1017 // Second pass: build cell-to-face mapping, including boundary.
1018 typedef std::vector<int>::iterator VII;
1019 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1020 const int c0 = c->index();
1021
1022 assert ((0 <= c0 ) && ( c0 < nc) &&
1023 (0 <= cell[c0]) && (cell[c0] < nc));
1024
1025 const int ncf = num_cf[cell[c0]];
1026 l2g .resize(ncf , 0 );
1027 F_alloc .resize(ncf , Scalar(0.0));
1028
1029 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1030 if (f->boundary()) {
1031 // External, not counted before. Add new face...
1032 l2g[f->localIndex()] = total_num_faces_++;
1033 } else {
1034 // Internal face. Need to determine during
1035 // traversal of which cell we discovered this
1036 // face first, and extract the face number
1037 // from the 'faces' table range of that cell.
1038
1039 // Note: std::find() below is potentially
1040 // *VERY* expensive (e.g., large number of
1041 // seeks in moderately sized data in case of
1042 // faulted cells).
1043
1044 const int c1 = f->neighbourCellIndex();
1045 assert ((0 <= c1 ) && ( c1 < nc) &&
1046 (0 <= cell[c1]) && (cell[c1] < nc));
1047
1048 int t = c0, seek = c1;
1049 if (cell[seek] < cell[t])
1050 std::swap(t, seek);
1051
1052 int s = fpos[cell[t]], e = fpos[cell[t] + 1];
1053
1054 VII p = std::find(faces.begin() + s, faces.begin() + e, seek);
1055 assert(p != faces.begin() + e);
1056
1057 l2g[f->localIndex()] = s + (p - (faces.begin() + s));
1058 }
1059 }
1060
1061 cf.appendRow (l2g .begin(), l2g .end());
1062 F_.appendRow (F_alloc.begin(), F_alloc.end());
1063
1064 flowSolution_.outflux_
1065 .appendRow(F_alloc.begin(), F_alloc.end());
1066 }
1067 }
1068
1069
1070 // ----------------------------------------------------------------
1071 void enumerateBCDof(const GridInterface& g, const BCInterface& bc)
1072 // ----------------------------------------------------------------
1073 {
1074 typedef typename GridInterface::CellIterator CI;
1075 typedef typename CI ::FaceIterator FI;
1076
1077 const std::vector<int>& cell = flowSolution_.cellno_;
1078 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1079
1080 bdry_id_map_.clear();
1081 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1082 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1083 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1084 const int bid = f->boundaryId();
1085 DofID dof(cell[c->index()], f->localIndex());
1086 bdry_id_map_.insert(std::make_pair(bid, dof));
1087 }
1088 }
1089 }
1090
1091 ppartner_dof_.clear();
1092 if (!bdry_id_map_.empty()) {
1093 ppartner_dof_.assign(total_num_faces_, -1);
1094 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1095 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1096 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1097 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1098
1099 BdryIdMapIterator j =
1100 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1101 assert (j != bdry_id_map_.end());
1102 const int dof2 = cf[j->second.first][j->second.second];
1103
1104 ppartner_dof_[dof1] = dof2;
1105 ppartner_dof_[dof2] = dof1;
1106 }
1107 }
1108 }
1109 }
1110 }
1111
1112
1113
1114 // ----------------------------------------------------------------
1115 void allocateConnections(const BCInterface& bc)
1116 // ----------------------------------------------------------------
1117 {
1118 // You must call enumerateDof() prior to allocateConnections()
1119 assert(!cleared_state_);
1120
1121 assert (!matrix_structure_valid_);
1122
1123 // Clear any residual data, prepare for assembling structure.
1124 S_.setSize(total_num_faces_, total_num_faces_);
1125 S_.setBuildMode(Dune::BCRSMatrix<MatrixBlockType>::random);
1126
1127 // Compute row sizes
1128 for (int f = 0; f < total_num_faces_; ++f) {
1129 S_.setrowsize(f, 1);
1130 }
1131
1132 allocateGridConnections();
1133 allocateBCConnections(bc);
1134
1135 S_.endrowsizes();
1136
1137 rhs_ .resize(total_num_faces_);
1138 soln_.resize(total_num_faces_);
1139 }
1140
1141
1142 // ----------------------------------------------------------------
1143 void allocateGridConnections()
1144 // ----------------------------------------------------------------
1145 {
1146 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1147 typedef Opm::SparseTable<int>::row_type::const_iterator fi;
1148
1149 for (int c = 0; c < cf.size(); ++c) {
1150 const int nf = cf[c].size();
1151 fi fb = cf[c].begin(), fe = cf[c].end();
1152
1153 for (fi f = fb; f != fe; ++f) {
1154 S_.incrementrowsize(*f, nf - 1);
1155 }
1156 }
1157 }
1158
1159
1160 // ----------------------------------------------------------------
1161 void allocateBCConnections(const BCInterface& bc)
1162 // ----------------------------------------------------------------
1163 {
1164 // Include system connections for periodic boundary
1165 // conditions, if any. We make an arbitrary choice in
1166 // that the face/degree-of-freedom with the minimum
1167 // numerical id of the two periodic partners represents
1168 // the coupling. Suppose <i_p> is this minimum dof-id.
1169 // We then need to introduce a *symmetric* coupling to
1170 // <i_p> to each of the dof's of the cell *NOT* containing
1171 // <i_p>. This choice is implemented in the following
1172 // loop by introducing couplings only when dof1 (self) is
1173 // less than dof2 (other).
1174 //
1175 // See also: setBCConnections() and addCellContrib().
1176 //
1177 typedef typename GridInterface::CellIterator CI;
1178 typedef typename CI ::FaceIterator FI;
1179
1180 const std::vector<int>& cell = flowSolution_.cellno_;
1181 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1182
1183 if (!bdry_id_map_.empty()) {
1184 // At least one periodic BC. Allocate corresponding
1185 // connections.
1186 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1187 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1188 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1189 // dof-id of self
1190 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1191
1192 // dof-id of other
1193 BdryIdMapIterator j =
1194 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1195 assert (j != bdry_id_map_.end());
1196 const int c2 = j->second.first;
1197 const int dof2 = cf[c2][j->second.second];
1198
1199 if (dof1 < dof2) {
1200 // Allocate storage for the actual
1201 // couplings.
1202 //
1203 const int ndof = cf.rowSize(c2);
1204 S_.incrementrowsize(dof1, ndof); // self->other
1205 for (int dof = 0; dof < ndof; ++dof) {
1206 int ii = cf[c2][dof];
1207 int pp = ppartner_dof_[ii];
1208 if ((pp != -1) && (pp != dof1) && (pp < ii)) {
1209 S_.incrementrowsize(pp, 1);
1210 }
1211 S_.incrementrowsize(ii, 1); // other->self
1212 }
1213 }
1214 }
1215 }
1216 }
1217 }
1218 }
1219
1220
1221
1222 // ----------------------------------------------------------------
1223 void setConnections(const BCInterface& bc)
1224 // ----------------------------------------------------------------
1225 {
1226 setGridConnections();
1227 setBCConnections(bc);
1228
1229 S_.endindices();
1230
1231 const int nc = pgrid_->numberOfCells();
1232 std::vector<Scalar>(nc).swap(flowSolution_.pressure_);
1233 std::vector<Scalar>(nc).swap(g_);
1234 std::vector<Scalar>(nc).swap(L_);
1235
1236 matrix_structure_valid_ = true;
1237 }
1238
1239
1240 // ----------------------------------------------------------------
1241 void setGridConnections()
1242 // ----------------------------------------------------------------
1243 {
1244 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1245 typedef Opm::SparseTable<int>::row_type::const_iterator fi;
1246
1247 // Compute actual connections (the non-zero structure).
1248 for (int c = 0; c < cf.size(); ++c) {
1249 fi fb = cf[c].begin(), fe = cf[c].end();
1250
1251 for (fi i = fb; i != fe; ++i) {
1252 for (fi j = fb; j != fe; ++j) {
1253 S_.addindex(*i, *j);
1254 }
1255 }
1256 }
1257 }
1258
1259
1260 // ----------------------------------------------------------------
1261 void setBCConnections(const BCInterface& bc)
1262 // ----------------------------------------------------------------
1263 {
1264 // Include system connections for periodic boundary
1265 // conditions, if any. We make an arbitrary choice in
1266 // that the face/degree-of-freedom with the minimum
1267 // numerical id of the two periodic partners represents
1268 // the coupling. Suppose <i_p> is this minimum dof-id.
1269 // We then need to introduce a *symmetric* coupling to
1270 // <i_p> to each of the dof's of the cell *NOT* containing
1271 // <i_p>. This choice is implemented in the following
1272 // loop by introducing couplings only when dof1 (self) is
1273 // less than dof2 (other).
1274 //
1275 // See also: allocateBCConnections() and addCellContrib().
1276 //
1277 typedef typename GridInterface::CellIterator CI;
1278 typedef typename CI ::FaceIterator FI;
1279
1280 const std::vector<int>& cell = flowSolution_.cellno_;
1281 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1282
1283 if (!bdry_id_map_.empty()) {
1284 // At least one periodic BC. Assign periodic
1285 // connections.
1286 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1287 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1288 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1289 // dof-id of self
1290 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1291
1292 // dof-id of other
1293 BdryIdMapIterator j =
1294 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1295 assert (j != bdry_id_map_.end());
1296 const int c2 = j->second.first;
1297 const int dof2 = cf[c2][j->second.second];
1298
1299 if (dof1 < dof2) {
1300 // Assign actual couplings.
1301 //
1302 const int ndof = cf.rowSize(c2);
1303 for (int dof = 0; dof < ndof; ++dof) {
1304 int ii = cf[c2][dof];
1305 int pp = ppartner_dof_[ii];
1306 if ((pp != -1) && (pp != dof1) && (pp < ii)) {
1307 ii = pp;
1308 }
1309 S_.addindex(dof1, ii); // self->other
1310 S_.addindex(ii, dof1); // other->self
1311 S_.addindex(dof2, ii);
1312 S_.addindex(ii, dof2);
1313 }
1314 }
1315 }
1316 }
1317 }
1318 }
1319 }
1320
1321
1322
1323 // ----------------------------------------------------------------
1324 template<class FluidInterface>
1325 void assembleDynamic(const FluidInterface& fl ,
1326 const std::vector<double>& sat,
1327 const BCInterface& bc ,
1328 const std::vector<double>& src)
1329 // ----------------------------------------------------------------
1330 {
1331 typedef typename GridInterface::CellIterator CI;
1332
1333 const std::vector<int>& cell = flowSolution_.cellno_;
1334 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1335
1336 std::vector<Scalar> data_store(max_ncf_ * max_ncf_);
1337 std::vector<Scalar> e (max_ncf_);
1338 std::vector<Scalar> rhs (max_ncf_);
1339 std::vector<Scalar> gflux (max_ncf_);
1340
1341 std::vector<FaceType> facetype (max_ncf_);
1342 std::vector<Scalar> condval (max_ncf_);
1343 std::vector<int> ppartner (max_ncf_);
1344
1345 // Clear residual data
1346 S_ = 0.0;
1347 rhs_ = 0.0;
1348
1349 std::fill(g_.begin(), g_.end(), Scalar(0.0));
1350 std::fill(L_.begin(), L_.end(), Scalar(0.0));
1351 std::fill(e .begin(), e .end(), Scalar(1.0));
1352
1353 // We will have to regularize resulting system if there
1354 // are no prescribed pressures (i.e., Dirichlet BC's).
1355 do_regularization_ = true;
1356
1357 // Assemble dynamic contributions for each cell
1358 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1359 const int ci = c->index();
1360 const int c0 = cell[ci]; assert (c0 < cf.size());
1361 const int nf = cf[c0].size();
1362
1363 rhs .resize(nf);
1364 gflux.resize(nf);
1365
1366 setExternalContrib(c, c0, bc, src[ci], rhs,
1367 facetype, condval, ppartner);
1368
1369 ip_.computeDynamicParams(c, fl, sat);
1370
1371 SharedFortranMatrix S(nf, nf, &data_store[0]);
1372 ip_.getInverseMatrix(c, S);
1373
1374 std::fill(gflux.begin(), gflux.end(), Scalar(0.0));
1375 ip_.gravityFlux(c, gflux);
1376
1377 ImmutableFortranMatrix one(nf, 1, &e[0]);
1378 buildCellContrib(c0, one, gflux, S, rhs);
1379
1380 addCellContrib(S, rhs, facetype, condval, ppartner, cf[c0]);
1381 }
1382 }
1383
1384
1385
1386 // ----------------------------------------------------------------
1387 void solveLinearSystem(double residual_tolerance, int verbosity_level, int maxit)
1388 // ----------------------------------------------------------------
1389 {
1390 // Adapted from DuMux...
1391 Scalar residTol = residual_tolerance;
1392
1393 typedef Dune::BCRSMatrix <MatrixBlockType> Matrix;
1394 typedef Dune::BlockVector<VectorBlockType> Vector;
1395 typedef Dune::MatrixAdapter<Matrix,Vector,Vector> Adapter;
1396
1397 // Regularize the matrix (only for pure Neumann problems...)
1398 if (do_regularization_) {
1399 S_[0][0] *= 2;
1400 }
1401 Adapter opS(S_);
1402
1403 // Construct preconditioner.
1404 Dune::SeqILU0<Matrix,Vector,Vector> precond(S_, 1.0);
1405
1406 // Construct solver for system of linear equations.
1407 Dune::CGSolver<Vector> linsolve(opS, precond, residTol,
1408 (maxit>0)?maxit:S_.N(), verbosity_level);
1409
1410 Dune::InverseOperatorResult result;
1411 soln_ = 0.0;
1412
1413 // Solve system of linear equations to recover
1414 // face/contact pressure values (soln_).
1415 linsolve.apply(soln_, rhs_, result);
1416 if (!result.converged) {
1417 OPM_THROW(std::runtime_error, "Linear solver failed to converge in " << result.iterations << " iterations.\n"
1418 << "Residual reduction achieved is " << result.reduction << '\n');
1419 }
1420 }
1421
1422
1423
1424 // ------------------ AMG typedefs --------------------
1425
1426 // Representation types for linear system.
1427 typedef Dune::BCRSMatrix <MatrixBlockType> Matrix;
1428 typedef Dune::BlockVector<VectorBlockType> Vector;
1429 typedef Dune::MatrixAdapter<Matrix,Vector,Vector> Operator;
1430
1431 // AMG specific types.
1432 // Old: FIRST_DIAGONAL 1, SYMMETRIC 1, SMOOTHER_ILU 1, ANISOTROPIC_3D 0
1433 // SPE10: FIRST_DIAGONAL 0, SYMMETRIC 1, SMOOTHER_ILU 0, ANISOTROPIC_3D 1
1434#ifndef FIRST_DIAGONAL
1435#define FIRST_DIAGONAL 1
1436#endif
1437#ifndef SYMMETRIC
1438#define SYMMETRIC 1
1439#endif
1440#ifndef SMOOTHER_ILU
1441#define SMOOTHER_ILU 1
1442#endif
1443#ifndef SMOOTHER_BGS
1444#define SMOOTHER_BGS 0
1445#endif
1446#ifndef ANISOTROPIC_3D
1447#define ANISOTROPIC_3D 0
1448#endif
1449
1450#if FIRST_DIAGONAL
1451 typedef Dune::Amg::FirstDiagonal CouplingMetric;
1452#else
1453 typedef Dune::Amg::RowSum CouplingMetric;
1454#endif
1455
1456#if SYMMETRIC
1457 typedef Dune::Amg::SymmetricCriterion<Matrix,CouplingMetric> CriterionBase;
1458#else
1459 typedef Dune::Amg::UnSymmetricCriterion<Matrix,CouplingMetric> CriterionBase;
1460#endif
1461
1462#if SMOOTHER_BGS
1463 typedef Dune::SeqOverlappingSchwarz<Matrix,Vector,Dune::MultiplicativeSchwarzMode> Smoother;
1464#else
1465#if SMOOTHER_ILU
1466 typedef Dune::SeqILU0<Matrix,Vector,Vector> Smoother;
1467#else
1468 typedef Dune::SeqSSOR<Matrix,Vector,Vector> Smoother;
1469#endif
1470#endif
1471 typedef Dune::Amg::CoarsenCriterion<CriterionBase> Criterion;
1472
1473
1474 // --------- storing the AMG operator and preconditioner --------
1475 boost::scoped_ptr<Operator> opS_;
1476 typedef Dune::Preconditioner<Vector,Vector> PrecondBase;
1477 boost::scoped_ptr<PrecondBase> precond_;
1478
1479
1480 // ----------------------------------------------------------------
1481 void solveLinearSystemAMG(double residual_tolerance, int verbosity_level,
1482 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1483 // ----------------------------------------------------------------
1484 {
1485 typedef Dune::Amg::AMG<Operator,Vector,Smoother,Dune::Amg::SequentialInformation>
1486 Precond;
1487
1488 // Adapted from upscaling.cc by Arne Rekdal, 2009
1489 Scalar residTol = residual_tolerance;
1490
1491 if (!same_matrix) {
1492 // Regularize the matrix (only for pure Neumann problems...)
1493 if (do_regularization_) {
1494 S_[0][0] *= 2;
1495 }
1496 opS_.reset(new Operator(S_));
1497
1498 // Construct preconditioner.
1499 double relax = 1;
1500 typename Precond::SmootherArgs smootherArgs;
1501 smootherArgs.relaxationFactor = relax;
1502#if SMOOTHER_BGS
1503 smootherArgs.overlap = Precond::SmootherArgs::none;
1504 smootherArgs.onthefly = false;
1505#endif
1506 Criterion criterion;
1507 criterion.setDebugLevel(verbosity_level);
1508#if ANISOTROPIC_3D
1509 criterion.setDefaultValuesAnisotropic(3, 2);
1510#endif
1511 criterion.setProlongationDampingFactor(prolong_factor);
1512 criterion.setBeta(1e-10);
1513 precond_.reset(new Precond(*opS_, criterion, smootherArgs,
1514 1, smooth_steps, smooth_steps));
1515 }
1516 // Construct solver for system of linear equations.
1517 Dune::CGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1518
1519 Dune::InverseOperatorResult result;
1520 soln_ = 0.0;
1521 // Adapt initial guess such Dirichlet boundary conditions are
1522 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1523 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1524 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1525 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1526 bool isDirichlet=true;
1527 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1528 if(ci.index()!=ri.index() && *ci!=0.0)
1529 isDirichlet=false;
1530 if(isDirichlet)
1531 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1532 }
1533 // Solve system of linear equations to recover
1534 // face/contact pressure values (soln_).
1535 linsolve.apply(soln_, rhs_, result);
1536 if (!result.converged) {
1537 OPM_THROW(std::runtime_error, "Linear solver failed to converge in " << result.iterations << " iterations.\n"
1538 << "Residual reduction achieved is " << result.reduction << '\n');
1539 }
1540
1541 }
1542
1543#if defined(HAS_DUNE_FAST_AMG) || DUNE_VERSION_NEWER(DUNE_ISTL, 2, 3)
1544
1545 // ----------------------------------------------------------------
1546 void solveLinearSystemFastAMG(double residual_tolerance, int verbosity_level,
1547 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1548 // ----------------------------------------------------------------
1549 {
1550 typedef Dune::Amg::FastAMG<Operator,Vector> Precond;
1551
1552 // Adapted from upscaling.cc by Arne Rekdal, 2009
1553 Scalar residTol = residual_tolerance;
1554
1555 if (!same_matrix) {
1556 // Regularize the matrix (only for pure Neumann problems...)
1557 if (do_regularization_) {
1558 S_[0][0] *= 2;
1559 }
1560 opS_.reset(new Operator(S_));
1561
1562 // Construct preconditioner.
1563 typedef Dune::Amg::AggregationCriterion<Dune::Amg::SymmetricMatrixDependency<Matrix,CouplingMetric> > CriterionBase;
1564
1565 typedef Dune::Amg::CoarsenCriterion<CriterionBase> Criterion;
1566 Criterion criterion;
1567 criterion.setDebugLevel(verbosity_level);
1568#if ANISOTROPIC_3D
1569 criterion.setDefaultValuesAnisotropic(3, 2);
1570#endif
1571 criterion.setProlongationDampingFactor(prolong_factor);
1572 criterion.setBeta(1e-10);
1573 Dune::Amg::Parameters parms;
1574 parms.setDebugLevel(verbosity_level);
1575 parms.setNoPreSmoothSteps(smooth_steps);
1576 parms.setNoPostSmoothSteps(smooth_steps);
1577 precond_.reset(new Precond(*opS_, criterion, parms));
1578 }
1579 // Construct solver for system of linear equations.
1580 Dune::GeneralizedPCGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1581
1582 Dune::InverseOperatorResult result;
1583 soln_ = 0.0;
1584
1585 // Adapt initial guess such Dirichlet boundary conditions are
1586 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1587 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1588 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1589 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1590 bool isDirichlet=true;
1591 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1592 if(ci.index()!=ri.index() && *ci!=0.0)
1593 isDirichlet=false;
1594 if(isDirichlet)
1595 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1596 }
1597 // Solve system of linear equations to recover
1598 // face/contact pressure values (soln_).
1599 linsolve.apply(soln_, rhs_, result);
1600 if (!result.converged) {
1601 OPM_THROW(std::runtime_error, "Linear solver failed to converge in " << result.iterations << " iterations.\n"
1602 << "Residual reduction achieved is " << result.reduction << '\n');
1603 }
1604
1605 }
1606#endif
1607
1608 // ----------------------------------------------------------------
1609 void solveLinearSystemKAMG(double residual_tolerance, int verbosity_level,
1610 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1611 // ----------------------------------------------------------------
1612 {
1613
1614 typedef Dune::Amg::KAMG<Operator,Vector,Smoother,Dune::Amg::SequentialInformation,
1615 Dune::CGSolver<Vector> > Precond;
1616 // Adapted from upscaling.cc by Arne Rekdal, 2009
1617 Scalar residTol = residual_tolerance;
1618 if (!same_matrix) {
1619 // Regularize the matrix (only for pure Neumann problems...)
1620 if (do_regularization_) {
1621 S_[0][0] *= 2;
1622 }
1623 opS_.reset(new Operator(S_));
1624
1625 // Construct preconditioner.
1626 double relax = 1;
1627 typename Precond::SmootherArgs smootherArgs;
1628 smootherArgs.relaxationFactor = relax;
1629#if SMOOTHER_BGS
1630 smootherArgs.overlap = Precond::SmootherArgs::none;
1631 smootherArgs.onthefly = false;
1632#endif
1633 Criterion criterion;
1634 criterion.setDebugLevel(verbosity_level);
1635#if ANISOTROPIC_3D
1636 criterion.setDefaultValuesAnisotropic(3, 2);
1637#endif
1638 criterion.setProlongationDampingFactor(prolong_factor);
1639 criterion.setBeta(1e-10);
1640 precond_.reset(new Precond(*opS_, criterion, smootherArgs, 2, smooth_steps, smooth_steps));
1641 }
1642 // Construct solver for system of linear equations.
1643 Dune::CGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1644
1645 Dune::InverseOperatorResult result;
1646 soln_ = 0.0;
1647 // Adapt initial guess such Dirichlet boundary conditions are
1648 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1649 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1650 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1651 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1652 bool isDirichlet=true;
1653 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1654 if(ci.index()!=ri.index() && *ci!=0.0)
1655 isDirichlet=false;
1656 if(isDirichlet)
1657 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1658 }
1659 // Solve system of linear equations to recover
1660 // face/contact pressure values (soln_).
1661 linsolve.apply(soln_, rhs_, result);
1662 if (!result.converged) {
1663 OPM_THROW(std::runtime_error, "Linear solver failed to converge in " << result.iterations << " iterations.\n"
1664 << "Residual reduction achieved is " << result.reduction << '\n');
1665 }
1666
1667 }
1668
1669
1670
1671 // ----------------------------------------------------------------
1672 template<class FluidInterface>
1673 void computePressureAndFluxes(const FluidInterface& r ,
1674 const std::vector<double>& sat)
1675 // ----------------------------------------------------------------
1676 {
1677 typedef typename GridInterface::CellIterator CI;
1678
1679 const std::vector<int>& cell = flowSolution_.cellno_;
1680 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1681
1682 std::vector<Scalar>& p = flowSolution_.pressure_;
1683 Opm::SparseTable<Scalar>& v = flowSolution_.outflux_;
1684
1685 //std::vector<double> mob(FluidInterface::NumberOfPhases);
1686 std::vector<double> pi (max_ncf_);
1687 std::vector<double> gflux(max_ncf_);
1688 std::vector<double> Binv_storage(max_ncf_ * max_ncf_);
1689
1690 // Assemble dynamic contributions for each cell
1691 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1692 const int c0 = cell[c->index()];
1693 const int nf = cf.rowSize(c0);
1694
1695 pi .resize(nf);
1696 gflux.resize(nf);
1697
1698 // Extract contact pressures for cell 'c'.
1699 for (int i = 0; i < nf; ++i) {
1700 pi[i] = soln_[cf[c0][i]];
1701 }
1702
1703 // Compute cell pressure in cell 'c'.
1704 p[c0] = (g_[c0] +
1705 std::inner_product(F_[c0].begin(), F_[c0].end(),
1706 pi.begin(), 0.0)) / L_[c0];
1707
1708 std::transform(pi.begin(), pi.end(),
1709 pi.begin(),
1710 boost::bind(std::minus<Scalar>(), p[c0], _1));
1711
1712 // Recover fluxes from local system
1713 // Bv = Bv_g + Cp - D\pi
1714 //
1715 // 1) Solve system Bv = Cp - D\pi
1716 //
1717 ip_.computeDynamicParams(c, r, sat);
1718
1719 SharedFortranMatrix Binv(nf, nf, &Binv_storage[0]);
1720 ip_.getInverseMatrix(c, Binv);
1721 vecMulAdd_N(Scalar(1.0), Binv, &pi[0], Scalar(0.0), &v[c0][0]);
1722
1723 // 2) Add gravity flux contributions (v <- v + v_g)
1724 //
1725 ip_.gravityFlux(c, gflux);
1726 std::transform(gflux.begin(), gflux.end(), v[c0].begin(),
1727 v[c0].begin(),
1728 std::plus<Scalar>());
1729 }
1730 }
1731
1732
1733
1734
1735 // ----------------------------------------------------------------
1736 void setExternalContrib(const typename GridInterface::CellIterator c,
1737 const int c0, const BCInterface& bc,
1738 const double src,
1739 std::vector<Scalar>& rhs,
1740 std::vector<FaceType>& facetype,
1741 std::vector<double>& condval,
1742 std::vector<int>& ppartner)
1743 // ----------------------------------------------------------------
1744 {
1745 typedef typename GridInterface::CellIterator::FaceIterator FI;
1746
1747 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1748
1749 std::fill(rhs .begin(), rhs .end(), Scalar(0.0));
1750 std::fill(facetype.begin(), facetype.end(), Internal );
1751 std::fill(condval .begin(), condval .end(), Scalar(0.0));
1752 std::fill(ppartner.begin(), ppartner.end(), -1 );
1753
1754 g_[c0] = src;
1755
1756 int k = 0;
1757 for (FI f = c->facebegin(); f != c->faceend(); ++f, ++k) {
1758 if (f->boundary()) {
1759 const FlowBC& bcond = bc.flowCond(*f);
1760 if (bcond.isDirichlet()) {
1761 facetype[k] = Dirichlet;
1762 condval[k] = bcond.pressure();
1763 do_regularization_ = false;
1764 } else if (bcond.isPeriodic()) {
1765 BdryIdMapIterator j =
1766 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1767 assert (j != bdry_id_map_.end());
1768
1769 facetype[k] = Periodic;
1770 condval[k] = bcond.pressureDifference();
1771 ppartner[k] = cf[j->second.first][j->second.second];
1772 } else {
1773 assert (bcond.isNeumann());
1774 facetype[k] = Neumann;
1775 rhs[k] = bcond.outflux();
1776 }
1777 }
1778 }
1779 }
1780
1781
1782
1783
1784 // ----------------------------------------------------------------
1785 void buildCellContrib(const int c ,
1786 const ImmutableFortranMatrix& one ,
1787 const std::vector<Scalar>& gflux,
1789 std::vector<Scalar>& rhs)
1790 // ----------------------------------------------------------------
1791 {
1792 // Ft <- B^{-t} * ones([size(S,2),1])
1793 SharedFortranMatrix Ft(S.numRows(), 1, &F_[c][0]);
1794 matMulAdd_TN(Scalar(1.0), S, one, Scalar(0.0), Ft);
1795
1796 L_[c] = std::accumulate(Ft.data(), Ft.data() + Ft.numRows(), 0.0);
1797 g_[c] -= std::accumulate(gflux.begin(), gflux.end(), Scalar(0.0));
1798
1799 // rhs <- v_g - rhs (== v_g - h)
1800 std::transform(gflux.begin(), gflux.end(), rhs.begin(),
1801 rhs.begin(),
1802 std::minus<Scalar>());
1803
1804 // rhs <- rhs + g_[c]/L_[c]*F
1805 std::transform(rhs.begin(), rhs.end(), Ft.data(),
1806 rhs.begin(),
1807 axpby<Scalar>(Scalar(1.0), Scalar(g_[c] / L_[c])));
1808
1809 // S <- S - F'*F/L_c
1810 symmetricUpdate(-Scalar(1.0)/L_[c], Ft, Scalar(1.0), S);
1811 }
1812
1813
1814
1815 // ----------------------------------------------------------------
1817 template<class L2G>
1818 void addCellContrib(const SharedFortranMatrix& S ,
1819 const std::vector<Scalar>& rhs ,
1820 const std::vector<FaceType>& facetype,
1821 const std::vector<Scalar>& condval ,
1822 const std::vector<int>& ppartner,
1823 const L2G& l2g)
1824 // ----------------------------------------------------------------
1825 {
1826 typedef typename L2G::const_iterator it;
1827
1828 int r = 0;
1829 for (it i = l2g.begin(); i != l2g.end(); ++i, ++r) {
1830 // Indirection for periodic BC handling.
1831 int ii = *i;
1832
1833 switch (facetype[r]) {
1834 case Dirichlet:
1835 // Pressure is already known. Assemble trivial
1836 // equation of the form: a*x = a*p where 'p' is
1837 // the known pressure value (i.e., condval[r]).
1838 //
1839 S_ [ii][ii] = S(r,r);
1840 rhs_[ii] = S(r,r) * condval[r];
1841 continue;
1842 case Periodic:
1843 // Periodic boundary condition. Contact pressures
1844 // linked by relations of the form
1845 //
1846 // a*(x0 - x1) = a*pd
1847 //
1848 // where 'pd' is the known pressure difference
1849 // x0-x1 (condval[r]). Preserve matrix symmetry
1850 // by assembling both of the equations
1851 //
1852 // a*(x0-x1) = a* pd, and (1)
1853 // a*(x1-x0) = a*(-pd) (2)
1854 //
1855 assert ((0 <= ppartner[r]) && (ppartner[r] < int(rhs_.size())));
1856 assert (ii != ppartner[r]);
1857
1858 {
1859 const double a = S(r,r), b = a * condval[r];
1860
1861 // Equation (1)
1862 S_ [ ii][ ii] += a;
1863 S_ [ ii][ppartner[r]] -= a;
1864 rhs_[ ii] += b;
1865
1866 // Equation (2)
1867 S_ [ppartner[r]][ ii] -= a;
1868 S_ [ppartner[r]][ppartner[r]] += a;
1869 rhs_[ppartner[r]] -= b;
1870 }
1871
1872 ii = std::min(ii, ppartner[r]);
1873
1874 // INTENTIONAL FALL-THROUGH!
1875 // IOW: Don't insert <break;> here!
1876 //
1877 default:
1878 int c = 0;
1879 for (it j = l2g.begin(); j != l2g.end(); ++j, ++c) {
1880 // Indirection for periodic BC handling.
1881 int jj = *j;
1882
1883 if (facetype[c] == Dirichlet) {
1884 rhs_[ii] -= S(r,c) * condval[c];
1885 continue;
1886 }
1887 if (facetype[c] == Periodic) {
1888 assert ((0 <= ppartner[c]) && (ppartner[c] < int(rhs_.size())));
1889 assert (jj != ppartner[c]);
1890 if (ppartner[c] < jj) {
1891 rhs_[ii] -= S(r,c) * condval[c];
1892 jj = ppartner[c];
1893 }
1894 }
1895 S_[ii][jj] += S(r,c);
1896 }
1897 break;
1898 }
1899 rhs_[ii] += rhs[r];
1900 }
1901 }
1902 };
1903} // namespace Opm
1904
1905#endif // OPENRS_INCOMPFLOWSOLVERHYBRID_HEADER
Solve mixed formulation of incompressible flow modelled by Darcy's law.
Definition: IncompFlowSolverHybrid.hpp:366
double postProcessFluxes()
Postprocess the solution fluxes. This method modifies the solution object so that out-fluxes of twin ...
Definition: IncompFlowSolverHybrid.hpp:754
SolutionType getSolution()
Recover the solution to the problem defined by the parameters to method.
Definition: IncompFlowSolverHybrid.hpp:828
void solve(const FluidInterface &r, const std::vector< double > &sat, const BCInterface &bc, const std::vector< double > &src, double residual_tolerance=1e-8, int linsolver_verbosity=1, int linsolver_type=1, bool same_matrix=false, int linsolver_maxit=0, double prolongate_factor=1.6, int smooth_steps=1)
Construct and solve system of linear equations for the pressure values on each interface/contact betw...
Definition: IncompFlowSolverHybrid.hpp:658
const FlowSolution & SolutionType
Type representing the solution to the problem defined by the parameters to.
Definition: IncompFlowSolverHybrid.hpp:818
void printSystem(const std::string &prefix)
Output current system of linear equations to permanent storage in files. One file for the coefficient...
Definition: IncompFlowSolverHybrid.hpp:895
void computeInnerProducts(const RockInterface &r, const Point &grav)
Compute static (i.e., independent of saturation) parts of the spatially varying inner products for e...
Definition: IncompFlowSolverHybrid.hpp:565
void clear()
Clear all topologic, geometric and rock-dependent information currently held in internal data structu...
Definition: IncompFlowSolverHybrid.hpp:498
void printStats(std::basic_ostream< charT, traits > &os)
Print statistics about the connections in the current model. This is mostly for debugging purposes an...
Definition: IncompFlowSolverHybrid.hpp:849
void init(const GridInterface &g, const RockInterface &r, const Point &grav, const BCInterface &bc)
All-in-one initialization routine. Enumerates all grid connections, allocates sufficient space,...
Definition: IncompFlowSolverHybrid.hpp:477
void initSystemStructure(const GridInterface &g, const BCInterface &bc)
Compute structure of coefficient matrix in final system of linear equations for this flow problem....
Definition: IncompFlowSolverHybrid.hpp:534
Definition: BlackoilFluid.hpp:32
void symmetricUpdate(const T &a1, const FullMatrix< T, StoragePolicy, FortranOrdering > &A, const T &a2, FullMatrix< T, StoragePolicy, FortranOrdering > &C)
Symmetric, rank update of symmetric matrix. Specifically, .
Definition: Matrix.hpp:830
const FullMatrix< double, ImmutableSharedData, FortranOrdering > ImmutableFortranMatrix
Definition: Matrix.hpp:591
void vecMulAdd_N(const T &a1, const FullMatrix< T, SP, FortranOrdering > &A, const std::vector< T > &x, const T &a2, std::vector< T > &y)
GEneral Matrix-Vector product (GAXPY operation). Specifically, .
Definition: Matrix.hpp:914
FullMatrix< double, SharedData, FortranOrdering > SharedFortranMatrix
Definition: Matrix.hpp:590
void matMulAdd_TN(const T &a1, const FullMatrix< T, SP1, FortranOrdering > &A, const FullMatrix< T, SP2, FortranOrdering > &B, const T &a2, FullMatrix< T, SP3, FortranOrdering > &C)
GEneral Matrix-Matrix product update of other matrix. Specificlly, .
Definition: Matrix.hpp:1253