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 <opm/common/ErrorMacros.hpp>
42#include <opm/grid/utility/SparseTable.hpp>
45
46#include <opm/common/utility/platform_dependent/disable_warnings.h>
47
48#include <unordered_map>
49
50#include <dune/common/fvector.hh>
51#include <dune/common/fmatrix.hh>
52
53#include <dune/istl/bvector.hh>
54#include <dune/istl/bcrsmatrix.hh>
55#include <dune/istl/operators.hh>
56#include <dune/istl/io.hh>
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#include <dune/istl/paamg/fastamg.hh>
65#include <dune/istl/paamg/kamg.hh>
66#include <dune/istl/paamg/pinfo.hh>
67
68#include <opm/common/utility/platform_dependent/reenable_warnings.h>
69
70
71#include <algorithm>
72#include <functional>
73#include <map>
74#include <memory>
75#include <numeric>
76#include <ostream>
77#include <stdexcept>
78#include <utility>
79#include <vector>
80#include <iostream>
81
82namespace Opm {
83 namespace {
107 template<class GI>
108 bool topologyIsSane(const GI& g)
109 {
110 typedef typename GI::CellIterator CI;
111 typedef typename CI::FaceIterator FI;
112
113 bool sane = g.numberOfCells() >= 0;
114
115 for (CI c = g.cellbegin(); sane && c != g.cellend(); ++c) {
116 std::vector<int> n;
117
118 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
119 if (!f->boundary()) {
120 n.push_back(f->neighbourCellIndex());
121 }
122 }
123 std::sort(n.begin(), n.end());
124
125 sane = std::unique(n.begin(), n.end()) == n.end();
126 }
127
128 return sane;
129 }
130
131
157 template<typename T>
158 class axpby {
159 public:
165 axpby(const T& a, const T& b) : a_(a), b_(b) {}
166
179 T operator()(const T& x, const T& y)
180 {
181 return a_*x + b_*y;
182 }
183 private:
184 T a_, b_;
185 };
186 }
187
188
361 template <class GridInterface,
362 class RockInterface,
363 class BCInterface,
364 template <class GridIF, class RockIF> class InnerProduct>
371 typedef typename GridInterface::Scalar Scalar;
372
377 enum FaceType { Internal, Dirichlet, Neumann, Periodic };
378
381 class FlowSolution {
382 public:
388 typedef typename GridInterface::Scalar Scalar;
389
393 typedef typename GridInterface::CellIterator CI;
394
397 typedef typename CI ::FaceIterator FI;
398
399 friend class IncompFlowSolverHybrid;
400
410 Scalar pressure(const CI& c) const
411 {
412 return pressure_[cellno_[c->index()]];
413 }
414
425 Scalar outflux (const FI& f) const
426 {
427 return outflux_[cellno_[f->cellIndex()]][f->localIndex()];
428 }
429 Scalar outflux (int hf) const
430 {
431 return outflux_.data(hf);
432 }
433 private:
434 std::vector< int > cellno_;
435 Opm::SparseTable< int > cellFaces_;
436 std::vector<Scalar> pressure_;
437 Opm::SparseTable<Scalar> outflux_;
438
439 void clear() {
440 std::vector<int>().swap(cellno_);
441 cellFaces_.clear();
442
443 std::vector<Scalar>().swap(pressure_);
444 outflux_.clear();
445 }
446 };
447
448 public:
475 template<class Point>
476 void init(const GridInterface& g,
477 const RockInterface& r,
478 const Point& grav,
479 const BCInterface& bc)
480 {
481 clear();
482
483 if (g.numberOfCells() > 0) {
484 initSystemStructure(g, bc);
485 computeInnerProducts(r, grav);
486 }
487 }
488
489
497 void clear()
498 {
499 pgrid_ = 0;
500 max_ncf_ = -1;
501 num_internal_faces_ = 0;
502 total_num_faces_ = 0;
503 matrix_structure_valid_ = false;
504 do_regularization_ = true; // Assume pure Neumann by default.
505
506 bdry_id_map_.clear();
507
508 std::vector<Scalar>().swap(L_);
509 std::vector<Scalar>().swap(g_);
510 F_.clear();
511
512 flowSolution_.clear();
513
514 cleared_state_ = true;
515 }
516
517
533 void initSystemStructure(const GridInterface& g,
534 const BCInterface& bc)
535 {
536 // You must call clear() prior to initSystemStructure()
537 assert (cleared_state_);
538
539 assert (topologyIsSane(g));
540
541 enumerateDof(g, bc);
542 allocateConnections(bc);
543 setConnections(bc);
544 }
545
546
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-") + std::to_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 solveLinearSystemFastAMG(residual_tolerance, linsolver_verbosity,
689 linsolver_maxit, prolongate_factor, same_matrix,smooth_steps);
690 break;
691 default:
692 std::cerr << "Unknown linsolver_type: " << linsolver_type << '\n';
693 throw std::runtime_error("Unknown linsolver_type");
694 }
695 computePressureAndFluxes(r, sat);
696 }
697
698 private:
700 class FaceFluxes
701 {
702 public:
703 explicit FaceFluxes(int sz)
704 : fluxes_(sz, 0.0), visited_(sz, 0), max_modification_(0.0)
705 {
706 }
707 void put(double flux, int f_ix) {
708 assert(visited_[f_ix] == 0 || visited_[f_ix] == 1);
709 double sign = visited_[f_ix] ? -1.0 : 1.0;
710 fluxes_[f_ix] += sign*flux;
711 ++visited_[f_ix];
712 }
713 void get(double& flux, int f_ix) {
714 assert(visited_[f_ix] == 0 || visited_[f_ix] == 1);
715 double sign = visited_[f_ix] ? -1.0 : 1.0;
716 double new_flux = 0.5*sign*fluxes_[f_ix];
717 double diff = std::fabs(flux - new_flux);
718 max_modification_ = std::max(max_modification_, diff);
719 flux = new_flux;
720 ++visited_[f_ix];
721 }
722 void resetVisited()
723 {
724 std::fill(visited_.begin(), visited_.end(), 0);
725 }
726
727 double maxMod() const
728 {
729 return max_modification_;
730 }
731 private:
732 std::vector<double> fluxes_;
733 std::vector<int> visited_;
734 double max_modification_;
735
736 };
737
738 public:
748 {
749 typedef typename GridInterface::CellIterator CI;
750 typedef typename CI ::FaceIterator FI;
751 const std::vector<int>& cell = flowSolution_.cellno_;
752 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
753 Opm::SparseTable<double>& cflux = flowSolution_.outflux_;
754
755 FaceFluxes face_fluxes(pgrid_->numberOfFaces());
756 // First pass: compute projected fluxes.
757 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
758 const int cell_index = cell[c->index()];
759 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
760 int f_ix = cf[cell_index][f->localIndex()];
761 double flux = cflux[cell_index][f->localIndex()];
762 if (f->boundary()) {
763 if (ppartner_dof_.empty()) {
764 continue;
765 }
766 int partner_f_ix = ppartner_dof_[f_ix];
767 if (partner_f_ix != -1) {
768 face_fluxes.put(flux, f_ix);
769 face_fluxes.put(flux, partner_f_ix);
770 }
771 } else {
772 face_fluxes.put(flux, f_ix);
773 }
774 }
775 }
776 face_fluxes.resetVisited();
777 // Second pass: set all fluxes to the projected ones.
778 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
779 const int cell_index = cell[c->index()];
780 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
781 int f_ix = cf[cell_index][f->localIndex()];
782 double& flux = cflux[cell_index][f->localIndex()];
783 if (f->boundary()) {
784 if (ppartner_dof_.empty()) {
785 continue;
786 }
787 int partner_f_ix = ppartner_dof_[f_ix];
788 if (partner_f_ix != -1) {
789 face_fluxes.get(flux, f_ix);
790 double dummy = flux;
791 face_fluxes.get(dummy, partner_f_ix);
792 assert(dummy == flux);
793 }
794 } else {
795 face_fluxes.get(flux, f_ix);
796 }
797 }
798 }
799 return face_fluxes.maxMod();
800 }
801
802
811 typedef const FlowSolution& SolutionType;
812
822 {
823 return flowSolution_;
824 }
825
826
841 template<typename charT, class traits>
842 void printStats(std::basic_ostream<charT,traits>& os)
843 {
844 os << "IncompFlowSolverHybrid<>:\n"
845 << "\tMaximum number of cell faces = " << max_ncf_ << '\n'
846 << "\tNumber of internal faces = " << num_internal_faces_ << '\n'
847 << "\tTotal number of faces = " << total_num_faces_ << '\n';
848
849 const std::vector<int>& cell = flowSolution_.cellno_;
850 os << "cell index map = [";
851 std::copy(cell.begin(), cell.end(),
852 std::ostream_iterator<int>(os, " "));
853 os << "\b]\n";
854
855 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
856 os << "cell faces =\n";
857 for (int i = 0; i < cf.size(); ++i)
858 {
859 os << "\t[" << i << "] -> [";
860 std::copy(cf[i].begin(), cf[i].end(),
861 std::ostream_iterator<int>(os, ","));
862 os << "\b]\n";
863 }
864 }
865
866
888 void printSystem(const std::string& prefix)
889 {
890 writeMatrixToMatlab(S_, prefix + "-mat.dat");
891
892 std::string rhsfile(prefix + "-rhs.dat");
893 std::ofstream rhs(rhsfile.c_str());
894 rhs.precision(15);
895 rhs.setf(std::ios::scientific | std::ios::showpos);
896 std::copy(rhs_.begin(), rhs_.end(),
897 std::ostream_iterator<VectorBlockType>(rhs, "\n"));
898 }
899
900 private:
901 typedef std::pair<int,int> DofID;
902 typedef std::unordered_map<int,DofID> BdryIdMapType;
903 typedef BdryIdMapType::const_iterator BdryIdMapIterator;
904
905 const GridInterface* pgrid_;
906 BdryIdMapType bdry_id_map_;
907 std::vector<int> ppartner_dof_;
908
909 InnerProduct<GridInterface, RockInterface> ip_;
910
911 // ----------------------------------------------------------------
912 bool cleared_state_;
913 int max_ncf_;
914 int num_internal_faces_;
915 int total_num_faces_;
916
917 // ----------------------------------------------------------------
918 std::vector<Scalar> L_, g_;
919 Opm::SparseTable<Scalar> F_ ;
920
921 // ----------------------------------------------------------------
922 // Actual, assembled system of linear equations
923 typedef Dune::FieldVector<Scalar, 1 > VectorBlockType;
924 typedef Dune::FieldMatrix<Scalar, 1, 1> MatrixBlockType;
925
926 Dune::BCRSMatrix <MatrixBlockType> S_; // System matrix
927 Dune::BlockVector<VectorBlockType> rhs_; // System RHS
928 Dune::BlockVector<VectorBlockType> soln_; // System solution (contact pressure)
929 bool matrix_structure_valid_;
930 bool do_regularization_;
931
932 // ----------------------------------------------------------------
933 // Physical quantities (derived)
934 FlowSolution flowSolution_;
935
936
937 // ----------------------------------------------------------------
938 void enumerateDof(const GridInterface& g, const BCInterface& bc)
939 // ----------------------------------------------------------------
940 {
941 enumerateGridDof(g);
942 enumerateBCDof(g, bc);
943
944 pgrid_ = &g;
945 cleared_state_ = false;
946 }
947
948 // ----------------------------------------------------------------
949 void enumerateGridDof(const GridInterface& g)
950 // ----------------------------------------------------------------
951 {
952 typedef typename GridInterface::CellIterator CI;
953 typedef typename CI ::FaceIterator FI;
954
955 const int nc = g.numberOfCells();
956 std::vector<int> fpos ; fpos.reserve(nc + 1);
957 std::vector<int> num_cf(nc) ;
958 std::vector<int> faces ;
959
960 // Allocate cell structures.
961 std::vector<int>(nc, -1).swap(flowSolution_.cellno_);
962
963 std::vector<int>& cell = flowSolution_.cellno_;
964
965 // First pass: enumerate internal faces.
966 int cellno = 0; fpos.push_back(0);
967 int tot_ncf = 0;
968 for (CI c = g.cellbegin(); c != g.cellend(); ++c, ++cellno) {
969 const int c0 = c->index();
970 assert((0 <= c0) && (c0 < nc) && (cell[c0] == -1));
971
972 cell[c0] = cellno;
973
974 int& ncf = num_cf[c0];
975
976 for (FI f = c->facebegin(); f != c-> faceend(); ++f) {
977 if (!f->boundary()) {
978 const int c1 = f->neighbourCellIndex();
979 assert((0 <= c1) && (c1 < nc) && (c1 != c0));
980
981 if (cell[c1] == -1) {
982 // Previously undiscovered internal face.
983 faces.push_back(c1);
984 }
985 }
986 ++ncf;
987 }
988
989 fpos.push_back(int(faces.size()));
990 max_ncf_ = std::max(max_ncf_, ncf);
991 tot_ncf += ncf;
992 }
993 assert (cellno == nc);
994
995 total_num_faces_ = num_internal_faces_ = int(faces.size());
996
997 ip_.init(max_ncf_); ip_.reserveMatrices(num_cf);
998 F_ .reserve(nc, tot_ncf);
999
1000 flowSolution_.cellFaces_.reserve(nc, tot_ncf);
1001 flowSolution_.outflux_ .reserve(nc, tot_ncf);
1002
1003 Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1004
1005 // Avoid (most) allocation(s) inside 'c' loop.
1006 std::vector<int> l2g; l2g .reserve(max_ncf_);
1007 std::vector<Scalar> F_alloc; F_alloc .reserve(max_ncf_);
1008
1009 // Second pass: build cell-to-face mapping, including boundary.
1010 typedef std::vector<int>::iterator VII;
1011 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1012 const int c0 = c->index();
1013
1014 assert ((0 <= c0 ) && ( c0 < nc) &&
1015 (0 <= cell[c0]) && (cell[c0] < nc));
1016
1017 const int ncf = num_cf[cell[c0]];
1018 l2g .resize(ncf , 0 );
1019 F_alloc .resize(ncf , Scalar(0.0));
1020
1021 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1022 if (f->boundary()) {
1023 // External, not counted before. Add new face...
1024 l2g[f->localIndex()] = total_num_faces_++;
1025 } else {
1026 // Internal face. Need to determine during
1027 // traversal of which cell we discovered this
1028 // face first, and extract the face number
1029 // from the 'faces' table range of that cell.
1030
1031 // Note: std::find() below is potentially
1032 // *VERY* expensive (e.g., large number of
1033 // seeks in moderately sized data in case of
1034 // faulted cells).
1035
1036 const int c1 = f->neighbourCellIndex();
1037 assert ((0 <= c1 ) && ( c1 < nc) &&
1038 (0 <= cell[c1]) && (cell[c1] < nc));
1039
1040 int t = c0, seek = c1;
1041 if (cell[seek] < cell[t])
1042 std::swap(t, seek);
1043
1044 int s = fpos[cell[t]], e = fpos[cell[t] + 1];
1045
1046 VII p = std::find(faces.begin() + s, faces.begin() + e, seek);
1047 assert(p != faces.begin() + e);
1048
1049 l2g[f->localIndex()] = s + (p - (faces.begin() + s));
1050 }
1051 }
1052
1053 cf.appendRow (l2g .begin(), l2g .end());
1054 F_.appendRow (F_alloc.begin(), F_alloc.end());
1055
1056 flowSolution_.outflux_
1057 .appendRow(F_alloc.begin(), F_alloc.end());
1058 }
1059 }
1060
1061
1062 // ----------------------------------------------------------------
1063 void enumerateBCDof(const GridInterface& g, const BCInterface& bc)
1064 // ----------------------------------------------------------------
1065 {
1066 typedef typename GridInterface::CellIterator CI;
1067 typedef typename CI ::FaceIterator FI;
1068
1069 const std::vector<int>& cell = flowSolution_.cellno_;
1070 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1071
1072 bdry_id_map_.clear();
1073 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1074 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1075 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1076 const int bid = f->boundaryId();
1077 DofID dof(cell[c->index()], f->localIndex());
1078 bdry_id_map_.insert(std::make_pair(bid, dof));
1079 }
1080 }
1081 }
1082
1083 ppartner_dof_.clear();
1084 if (!bdry_id_map_.empty()) {
1085 ppartner_dof_.assign(total_num_faces_, -1);
1086 for (CI c = g.cellbegin(); c != g.cellend(); ++c) {
1087 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1088 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1089 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1090
1091 BdryIdMapIterator j =
1092 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1093 assert (j != bdry_id_map_.end());
1094 const int dof2 = cf[j->second.first][j->second.second];
1095
1096 ppartner_dof_[dof1] = dof2;
1097 ppartner_dof_[dof2] = dof1;
1098 }
1099 }
1100 }
1101 }
1102 }
1103
1104
1105
1106 // ----------------------------------------------------------------
1107 void allocateConnections(const BCInterface& bc)
1108 // ----------------------------------------------------------------
1109 {
1110 // You must call enumerateDof() prior to allocateConnections()
1111 assert(!cleared_state_);
1112
1113 assert (!matrix_structure_valid_);
1114
1115 // Clear any residual data, prepare for assembling structure.
1116 S_.setSize(total_num_faces_, total_num_faces_);
1117 S_.setBuildMode(Dune::BCRSMatrix<MatrixBlockType>::random);
1118
1119 // Compute row sizes
1120 for (int f = 0; f < total_num_faces_; ++f) {
1121 S_.setrowsize(f, 1);
1122 }
1123
1124 allocateGridConnections();
1125 allocateBCConnections(bc);
1126
1127 S_.endrowsizes();
1128
1129 rhs_ .resize(total_num_faces_);
1130 soln_.resize(total_num_faces_);
1131 }
1132
1133
1134 // ----------------------------------------------------------------
1135 void allocateGridConnections()
1136 // ----------------------------------------------------------------
1137 {
1138 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1139
1140 for (int c = 0; c < cf.size(); ++c) {
1141 const int nf = cf[c].size();
1142 for (auto& f : cf[c]) {
1143 S_.incrementrowsize(f, nf - 1);
1144 }
1145 }
1146 }
1147
1148
1149 // ----------------------------------------------------------------
1150 void allocateBCConnections(const BCInterface& bc)
1151 // ----------------------------------------------------------------
1152 {
1153 // Include system connections for periodic boundary
1154 // conditions, if any. We make an arbitrary choice in
1155 // that the face/degree-of-freedom with the minimum
1156 // numerical id of the two periodic partners represents
1157 // the coupling. Suppose <i_p> is this minimum dof-id.
1158 // We then need to introduce a *symmetric* coupling to
1159 // <i_p> to each of the dof's of the cell *NOT* containing
1160 // <i_p>. This choice is implemented in the following
1161 // loop by introducing couplings only when dof1 (self) is
1162 // less than dof2 (other).
1163 //
1164 // See also: setBCConnections() and addCellContrib().
1165 //
1166 typedef typename GridInterface::CellIterator CI;
1167 typedef typename CI ::FaceIterator FI;
1168
1169 const std::vector<int>& cell = flowSolution_.cellno_;
1170 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1171
1172 if (!bdry_id_map_.empty()) {
1173 // At least one periodic BC. Allocate corresponding
1174 // connections.
1175 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1176 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1177 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1178 // dof-id of self
1179 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1180
1181 // dof-id of other
1182 BdryIdMapIterator j =
1183 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1184 assert (j != bdry_id_map_.end());
1185 const int c2 = j->second.first;
1186 const int dof2 = cf[c2][j->second.second];
1187
1188 if (dof1 < dof2) {
1189 // Allocate storage for the actual
1190 // couplings.
1191 //
1192 const int ndof = cf.rowSize(c2);
1193 S_.incrementrowsize(dof1, ndof); // self->other
1194 for (int dof = 0; dof < ndof; ++dof) {
1195 int ii = cf[c2][dof];
1196 int pp = ppartner_dof_[ii];
1197 if ((pp != -1) && (pp != dof1) && (pp < ii)) {
1198 S_.incrementrowsize(pp, 1);
1199 }
1200 S_.incrementrowsize(ii, 1); // other->self
1201 }
1202 }
1203 }
1204 }
1205 }
1206 }
1207 }
1208
1209
1210
1211 // ----------------------------------------------------------------
1212 void setConnections(const BCInterface& bc)
1213 // ----------------------------------------------------------------
1214 {
1215 setGridConnections();
1216 setBCConnections(bc);
1217
1218 S_.endindices();
1219
1220 const int nc = pgrid_->numberOfCells();
1221 std::vector<Scalar>(nc).swap(flowSolution_.pressure_);
1222 std::vector<Scalar>(nc).swap(g_);
1223 std::vector<Scalar>(nc).swap(L_);
1224
1225 matrix_structure_valid_ = true;
1226 }
1227
1228
1229 // ----------------------------------------------------------------
1230 void setGridConnections()
1231 // ----------------------------------------------------------------
1232 {
1233 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1234
1235 // Compute actual connections (the non-zero structure).
1236 for (int c = 0; c < cf.size(); ++c) {
1237 auto fb = cf[c].begin(), fe = cf[c].end();
1238
1239 for (auto i = fb; i != fe; ++i) {
1240 for (auto j = fb; j != fe; ++j) {
1241 S_.addindex(*i, *j);
1242 }
1243 }
1244 }
1245 }
1246
1247
1248 // ----------------------------------------------------------------
1249 void setBCConnections(const BCInterface& bc)
1250 // ----------------------------------------------------------------
1251 {
1252 // Include system connections for periodic boundary
1253 // conditions, if any. We make an arbitrary choice in
1254 // that the face/degree-of-freedom with the minimum
1255 // numerical id of the two periodic partners represents
1256 // the coupling. Suppose <i_p> is this minimum dof-id.
1257 // We then need to introduce a *symmetric* coupling to
1258 // <i_p> to each of the dof's of the cell *NOT* containing
1259 // <i_p>. This choice is implemented in the following
1260 // loop by introducing couplings only when dof1 (self) is
1261 // less than dof2 (other).
1262 //
1263 // See also: allocateBCConnections() and addCellContrib().
1264 //
1265 typedef typename GridInterface::CellIterator CI;
1266 typedef typename CI ::FaceIterator FI;
1267
1268 const std::vector<int>& cell = flowSolution_.cellno_;
1269 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1270
1271 if (!bdry_id_map_.empty()) {
1272 // At least one periodic BC. Assign periodic
1273 // connections.
1274 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1275 for (FI f = c->facebegin(); f != c->faceend(); ++f) {
1276 if (f->boundary() && bc.flowCond(*f).isPeriodic()) {
1277 // dof-id of self
1278 const int dof1 = cf[cell[c->index()]][f->localIndex()];
1279
1280 // dof-id of other
1281 BdryIdMapIterator j =
1282 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1283 assert (j != bdry_id_map_.end());
1284 const int c2 = j->second.first;
1285 const int dof2 = cf[c2][j->second.second];
1286
1287 if (dof1 < dof2) {
1288 // Assign actual couplings.
1289 //
1290 const int ndof = cf.rowSize(c2);
1291 for (int dof = 0; dof < ndof; ++dof) {
1292 int ii = cf[c2][dof];
1293 int pp = ppartner_dof_[ii];
1294 if ((pp != -1) && (pp != dof1) && (pp < ii)) {
1295 ii = pp;
1296 }
1297 S_.addindex(dof1, ii); // self->other
1298 S_.addindex(ii, dof1); // other->self
1299 S_.addindex(dof2, ii);
1300 S_.addindex(ii, dof2);
1301 }
1302 }
1303 }
1304 }
1305 }
1306 }
1307 }
1308
1309
1310
1311 // ----------------------------------------------------------------
1312 template<class FluidInterface>
1313 void assembleDynamic(const FluidInterface& fl ,
1314 const std::vector<double>& sat,
1315 const BCInterface& bc ,
1316 const std::vector<double>& src)
1317 // ----------------------------------------------------------------
1318 {
1319 typedef typename GridInterface::CellIterator CI;
1320
1321 const std::vector<int>& cell = flowSolution_.cellno_;
1322 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1323
1324 std::vector<Scalar> data_store(max_ncf_ * max_ncf_);
1325 std::vector<Scalar> e (max_ncf_);
1326 std::vector<Scalar> rhs (max_ncf_);
1327 std::vector<Scalar> gflux (max_ncf_);
1328
1329 std::vector<FaceType> facetype (max_ncf_);
1330 std::vector<Scalar> condval (max_ncf_);
1331 std::vector<int> ppartner (max_ncf_);
1332
1333 // Clear residual data
1334 S_ = 0.0;
1335 rhs_ = 0.0;
1336
1337 std::fill(g_.begin(), g_.end(), Scalar(0.0));
1338 std::fill(L_.begin(), L_.end(), Scalar(0.0));
1339 std::fill(e .begin(), e .end(), Scalar(1.0));
1340
1341 // We will have to regularize resulting system if there
1342 // are no prescribed pressures (i.e., Dirichlet BC's).
1343 do_regularization_ = true;
1344
1345 // Assemble dynamic contributions for each cell
1346 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1347 const int ci = c->index();
1348 const int c0 = cell[ci]; assert (c0 < cf.size());
1349 const int nf = cf[c0].size();
1350
1351 rhs .resize(nf);
1352 gflux.resize(nf);
1353
1354 setExternalContrib(c, c0, bc, src[ci], rhs,
1355 facetype, condval, ppartner);
1356
1357 ip_.computeDynamicParams(c, fl, sat);
1358
1359 SharedFortranMatrix S(nf, nf, &data_store[0]);
1360 ip_.getInverseMatrix(c, S);
1361
1362 std::fill(gflux.begin(), gflux.end(), Scalar(0.0));
1363 ip_.gravityFlux(c, gflux);
1364
1365 ImmutableFortranMatrix one(nf, 1, &e[0]);
1366 buildCellContrib(c0, one, gflux, S, rhs);
1367
1368 addCellContrib(S, rhs, facetype, condval, ppartner, cf[c0]);
1369 }
1370 }
1371
1372
1373
1374 // ----------------------------------------------------------------
1375 void solveLinearSystem(double residual_tolerance, int verbosity_level, int maxit)
1376 // ----------------------------------------------------------------
1377 {
1378 // Adapted from DuMux...
1379 Scalar residTol = residual_tolerance;
1380
1381 typedef Dune::BCRSMatrix <MatrixBlockType> MatrixT;
1382 typedef Dune::BlockVector<VectorBlockType> VectorT;
1383 typedef Dune::MatrixAdapter<Matrix,Vector,Vector> Adapter;
1384
1385 // Regularize the matrix (only for pure Neumann problems...)
1386 if (do_regularization_) {
1387 S_[0][0] *= 2;
1388 }
1389 Adapter opS(S_);
1390
1391 // Construct preconditioner.
1392 Dune::SeqILU<MatrixT,VectorT,VectorT> precond(S_, 1.0);
1393
1394 // Construct solver for system of linear equations.
1395 Dune::CGSolver<VectorT> linsolve(opS, precond, residTol,
1396 (maxit>0)?maxit:S_.N(), verbosity_level);
1397
1398 Dune::InverseOperatorResult result;
1399 soln_ = 0.0;
1400
1401 // Solve system of linear equations to recover
1402 // face/contact pressure values (soln_).
1403 linsolve.apply(soln_, rhs_, result);
1404 if (!result.converged) {
1405 OPM_THROW(std::runtime_error,
1406 "Linear solver failed to converge in " +
1407 std::to_string(result.iterations) + " iterations.\n"
1408 "Residual reduction achieved is " +
1409 std::to_string(result.reduction) + '\n');
1410 }
1411 }
1412
1413
1414
1415 // ------------------ AMG typedefs --------------------
1416
1417 // Representation types for linear system.
1418 typedef Dune::BCRSMatrix <MatrixBlockType> Matrix;
1419 typedef Dune::BlockVector<VectorBlockType> Vector;
1420 typedef Dune::MatrixAdapter<Matrix,Vector,Vector> Operator;
1421
1422 // AMG specific types.
1423 // Old: FIRST_DIAGONAL 1, SYMMETRIC 1, SMOOTHER_ILU 1, ANISOTROPIC_3D 0
1424 // SPE10: FIRST_DIAGONAL 0, SYMMETRIC 1, SMOOTHER_ILU 0, ANISOTROPIC_3D 1
1425#ifndef FIRST_DIAGONAL
1426#define FIRST_DIAGONAL 1
1427#endif
1428#ifndef SYMMETRIC
1429#define SYMMETRIC 1
1430#endif
1431#ifndef SMOOTHER_ILU
1432#define SMOOTHER_ILU 1
1433#endif
1434#ifndef SMOOTHER_BGS
1435#define SMOOTHER_BGS 0
1436#endif
1437#ifndef ANISOTROPIC_3D
1438#define ANISOTROPIC_3D 0
1439#endif
1440
1441#if FIRST_DIAGONAL
1442 typedef Dune::Amg::FirstDiagonal CouplingMetric;
1443#else
1444 typedef Dune::Amg::RowSum CouplingMetric;
1445#endif
1446
1447#if SYMMETRIC
1448 typedef Dune::Amg::SymmetricCriterion<Matrix,CouplingMetric> CriterionBase;
1449#else
1450 typedef Dune::Amg::UnSymmetricCriterion<Matrix,CouplingMetric> CriterionBase;
1451#endif
1452
1453#if SMOOTHER_BGS
1454 typedef Dune::SeqOverlappingSchwarz<Matrix,Vector,Dune::MultiplicativeSchwarzMode> Smoother;
1455#else
1456#if SMOOTHER_ILU
1457 typedef Dune::SeqILU<Matrix,Vector,Vector> Smoother;
1458#else
1459 typedef Dune::SeqSSOR<Matrix,Vector,Vector> Smoother;
1460#endif
1461#endif
1462 typedef Dune::Amg::CoarsenCriterion<CriterionBase> Criterion;
1463
1464
1465 // --------- storing the AMG operator and preconditioner --------
1466 std::unique_ptr<Operator> opS_;
1467 typedef Dune::Preconditioner<Vector,Vector> PrecondBase;
1468 std::unique_ptr<PrecondBase> precond_;
1469
1470
1471 // ----------------------------------------------------------------
1472 void solveLinearSystemAMG(double residual_tolerance, int verbosity_level,
1473 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1474 // ----------------------------------------------------------------
1475 {
1476 typedef Dune::Amg::AMG<Operator,Vector,Smoother,Dune::Amg::SequentialInformation>
1477 Precond;
1478
1479 // Adapted from upscaling.cc by Arne Rekdal, 2009
1480 Scalar residTol = residual_tolerance;
1481
1482 if (!same_matrix) {
1483 // Regularize the matrix (only for pure Neumann problems...)
1484 if (do_regularization_) {
1485 S_[0][0] *= 2;
1486 }
1487 opS_.reset(new Operator(S_));
1488
1489 // Construct preconditioner.
1490 double relax = 1;
1491 typename Precond::SmootherArgs smootherArgs;
1492 smootherArgs.relaxationFactor = relax;
1493#if SMOOTHER_BGS
1494 smootherArgs.overlap = Precond::SmootherArgs::none;
1495 smootherArgs.onthefly = false;
1496#endif
1497 Criterion criterion;
1498 criterion.setDebugLevel(verbosity_level);
1499#if ANISOTROPIC_3D
1500 criterion.setDefaultValuesAnisotropic(3, 2);
1501#endif
1502 criterion.setProlongationDampingFactor(prolong_factor);
1503 criterion.setBeta(1e-10);
1504 criterion.setNoPreSmoothSteps(smooth_steps);
1505 criterion.setNoPostSmoothSteps(smooth_steps);
1506 criterion.setGamma(1); // V-cycle; this is the default
1507 precond_.reset(new Precond(*opS_, criterion, smootherArgs));
1508 }
1509 // Construct solver for system of linear equations.
1510 Dune::CGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1511
1512 Dune::InverseOperatorResult result;
1513 soln_ = 0.0;
1514 // Adapt initial guess such Dirichlet boundary conditions are
1515 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1516 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1517 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1518 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1519 bool isDirichlet=true;
1520 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1521 if(ci.index()!=ri.index() && *ci!=0.0)
1522 isDirichlet=false;
1523 if(isDirichlet)
1524 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1525 }
1526 // Solve system of linear equations to recover
1527 // face/contact pressure values (soln_).
1528 linsolve.apply(soln_, rhs_, result);
1529 if (!result.converged) {
1530 OPM_THROW(std::runtime_error,
1531 "Linear solver failed to converge in " +
1532 std::to_string(result.iterations) + " iterations.\n"
1533 "Residual reduction achieved is " +
1534 std::to_string(result.reduction) + '\n');
1535 }
1536
1537 }
1538
1539
1540 // ----------------------------------------------------------------
1541 void solveLinearSystemFastAMG(double residual_tolerance, int verbosity_level,
1542 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1543 // ----------------------------------------------------------------
1544 {
1545 typedef Dune::Amg::FastAMG<Operator,Vector> Precond;
1546
1547 // Adapted from upscaling.cc by Arne Rekdal, 2009
1548 Scalar residTol = residual_tolerance;
1549
1550 if (!same_matrix) {
1551 // Regularize the matrix (only for pure Neumann problems...)
1552 if (do_regularization_) {
1553 S_[0][0] *= 2;
1554 }
1555 opS_.reset(new Operator(S_));
1556
1557 // Construct preconditioner.
1558 typedef Dune::Amg::AggregationCriterion<Dune::Amg::SymmetricMatrixDependency<Matrix,CouplingMetric> > CritBase;
1559
1560 typedef Dune::Amg::CoarsenCriterion<CritBase> Crit;
1561 Crit criterion;
1562 criterion.setDebugLevel(verbosity_level);
1563#if ANISOTROPIC_3D
1564 criterion.setDefaultValuesAnisotropic(3, 2);
1565#endif
1566 criterion.setProlongationDampingFactor(prolong_factor);
1567 criterion.setBeta(1e-10);
1568 Dune::Amg::Parameters parms;
1569 parms.setDebugLevel(verbosity_level);
1570 parms.setNoPreSmoothSteps(smooth_steps);
1571 parms.setNoPostSmoothSteps(smooth_steps);
1572 precond_.reset(new Precond(*opS_, criterion, parms));
1573 }
1574 // Construct solver for system of linear equations.
1575 Dune::GeneralizedPCGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1576
1577 Dune::InverseOperatorResult result;
1578 soln_ = 0.0;
1579
1580 // Adapt initial guess such Dirichlet boundary conditions are
1581 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1582 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1583 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1584 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1585 bool isDirichlet=true;
1586 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1587 if(ci.index()!=ri.index() && *ci!=0.0)
1588 isDirichlet=false;
1589 if(isDirichlet)
1590 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1591 }
1592 // Solve system of linear equations to recover
1593 // face/contact pressure values (soln_).
1594 linsolve.apply(soln_, rhs_, result);
1595 if (!result.converged) {
1596 OPM_THROW(std::runtime_error,
1597 "Linear solver failed to converge in " +
1598 std::to_string(result.iterations) + " iterations.\n"
1599 "Residual reduction achieved is " +
1600 std::to_string(result.reduction) + '\n');
1601 }
1602
1603 }
1604
1605 // ----------------------------------------------------------------
1606 void solveLinearSystemKAMG(double residual_tolerance, int verbosity_level,
1607 int maxit, double prolong_factor, bool same_matrix, int smooth_steps)
1608 // ----------------------------------------------------------------
1609 {
1610
1611 typedef Dune::Amg::KAMG<Operator,Vector,Smoother,Dune::Amg::SequentialInformation> Precond;
1612 // Adapted from upscaling.cc by Arne Rekdal, 2009
1613 Scalar residTol = residual_tolerance;
1614 if (!same_matrix) {
1615 // Regularize the matrix (only for pure Neumann problems...)
1616 if (do_regularization_) {
1617 S_[0][0] *= 2;
1618 }
1619 opS_.reset(new Operator(S_));
1620
1621 // Construct preconditioner.
1622 double relax = 1;
1623 typename Precond::SmootherArgs smootherArgs;
1624 smootherArgs.relaxationFactor = relax;
1625#if SMOOTHER_BGS
1626 smootherArgs.overlap = Precond::SmootherArgs::none;
1627 smootherArgs.onthefly = false;
1628#endif
1629 Criterion criterion;
1630 criterion.setDebugLevel(verbosity_level);
1631#if ANISOTROPIC_3D
1632 criterion.setDefaultValuesAnisotropic(3, 2);
1633#endif
1634 criterion.setProlongationDampingFactor(prolong_factor);
1635 criterion.setBeta(1e-10);
1636 criterion.setNoPreSmoothSteps(smooth_steps);
1637 criterion.setNoPostSmoothSteps(smooth_steps);
1638 criterion.setGamma(2);
1639 precond_.reset(new Precond(*opS_, criterion, smootherArgs));
1640 }
1641 // Construct solver for system of linear equations.
1642 Dune::CGSolver<Vector> linsolve(*opS_, dynamic_cast<Precond&>(*precond_), residTol, (maxit>0)?maxit:S_.N(), verbosity_level);
1643
1644 Dune::InverseOperatorResult result;
1645 soln_ = 0.0;
1646 // Adapt initial guess such Dirichlet boundary conditions are
1647 // represented, i.e. soln_i=A_{ii}^-1 rhs_i
1648 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstRowIterator RowIter;
1649 typedef typename Dune::BCRSMatrix <MatrixBlockType>::ConstColIterator ColIter;
1650 for(RowIter ri=S_.begin(); ri!=S_.end(); ++ri){
1651 bool isDirichlet=true;
1652 for(ColIter ci=ri->begin(); ci!=ri->end(); ++ci)
1653 if(ci.index()!=ri.index() && *ci!=0.0)
1654 isDirichlet=false;
1655 if(isDirichlet)
1656 soln_[ri.index()]=rhs_[ri.index()]/S_[ri.index()][ri.index()];
1657 }
1658 // Solve system of linear equations to recover
1659 // face/contact pressure values (soln_).
1660 linsolve.apply(soln_, rhs_, result);
1661 if (!result.converged) {
1662 OPM_THROW(std::runtime_error,
1663 "Linear solver failed to converge in " +
1664 std::to_string(result.iterations) + " iterations.\n"
1665 "Residual reduction achieved is " +
1666 std::to_string(result.reduction) + '\n');
1667 }
1668
1669 }
1670
1671
1672
1673 // ----------------------------------------------------------------
1674 template<class FluidInterface>
1675 void computePressureAndFluxes(const FluidInterface& r ,
1676 const std::vector<double>& sat)
1677 // ----------------------------------------------------------------
1678 {
1679 typedef typename GridInterface::CellIterator CI;
1680
1681 const std::vector<int>& cell = flowSolution_.cellno_;
1682 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1683
1684 std::vector<Scalar>& p = flowSolution_.pressure_;
1685 Opm::SparseTable<Scalar>& v = flowSolution_.outflux_;
1686
1687 //std::vector<double> mob(FluidInterface::NumberOfPhases);
1688 std::vector<double> pi (max_ncf_);
1689 std::vector<double> gflux(max_ncf_);
1690 std::vector<double> Binv_storage(max_ncf_ * max_ncf_);
1691
1692 // Assemble dynamic contributions for each cell
1693 for (CI c = pgrid_->cellbegin(); c != pgrid_->cellend(); ++c) {
1694 const int c0 = cell[c->index()];
1695 const int nf = cf.rowSize(c0);
1696
1697 pi .resize(nf);
1698 gflux.resize(nf);
1699
1700 // Extract contact pressures for cell 'c'.
1701 for (int i = 0; i < nf; ++i) {
1702 pi[i] = soln_[cf[c0][i]];
1703 }
1704
1705 // Compute cell pressure in cell 'c'.
1706 p[c0] = (g_[c0] +
1707 std::inner_product(F_[c0].begin(), F_[c0].end(),
1708 pi.begin(), 0.0)) / L_[c0];
1709
1710 std::transform(pi.begin(), pi.end(),
1711 pi.begin(),
1712 [&p, c0](const double& input) { return p[c0] - input; });
1713
1714 // Recover fluxes from local system
1715 // Bv = Bv_g + Cp - D\pi
1716 //
1717 // 1) Solve system Bv = Cp - D\pi
1718 //
1719 ip_.computeDynamicParams(c, r, sat);
1720
1721 SharedFortranMatrix Binv(nf, nf, &Binv_storage[0]);
1722 ip_.getInverseMatrix(c, Binv);
1723 vecMulAdd_N(Scalar(1.0), Binv, &pi[0], Scalar(0.0), &v[c0][0]);
1724
1725 // 2) Add gravity flux contributions (v <- v + v_g)
1726 //
1727 ip_.gravityFlux(c, gflux);
1728 std::transform(gflux.begin(), gflux.end(), v[c0].begin(),
1729 v[c0].begin(),
1730 std::plus<Scalar>());
1731 }
1732 }
1733
1734
1735
1736
1737 // ----------------------------------------------------------------
1738 void setExternalContrib(const typename GridInterface::CellIterator c,
1739 const int c0, const BCInterface& bc,
1740 const double src,
1741 std::vector<Scalar>& rhs,
1742 std::vector<FaceType>& facetype,
1743 std::vector<double>& condval,
1744 std::vector<int>& ppartner)
1745 // ----------------------------------------------------------------
1746 {
1747 typedef typename GridInterface::CellIterator::FaceIterator FI;
1748
1749 const Opm::SparseTable<int>& cf = flowSolution_.cellFaces_;
1750
1751 std::fill(rhs .begin(), rhs .end(), Scalar(0.0));
1752 std::fill(facetype.begin(), facetype.end(), Internal );
1753 std::fill(condval .begin(), condval .end(), Scalar(0.0));
1754 std::fill(ppartner.begin(), ppartner.end(), -1 );
1755
1756 g_[c0] = src;
1757
1758 int k = 0;
1759 for (FI f = c->facebegin(); f != c->faceend(); ++f, ++k) {
1760 if (f->boundary()) {
1761 const FlowBC& bcond = bc.flowCond(*f);
1762 if (bcond.isDirichlet()) {
1763 facetype[k] = Dirichlet;
1764 condval[k] = bcond.pressure();
1765 do_regularization_ = false;
1766 } else if (bcond.isPeriodic()) {
1767 BdryIdMapIterator j =
1768 bdry_id_map_.find(bc.getPeriodicPartner(f->boundaryId()));
1769 assert (j != bdry_id_map_.end());
1770
1771 facetype[k] = Periodic;
1772 condval[k] = bcond.pressureDifference();
1773 ppartner[k] = cf[j->second.first][j->second.second];
1774 } else {
1775 assert (bcond.isNeumann());
1776 facetype[k] = Neumann;
1777 rhs[k] = bcond.outflux();
1778 }
1779 }
1780 }
1781 }
1782
1783
1784
1785
1786 // ----------------------------------------------------------------
1787 void buildCellContrib(const int c ,
1788 const ImmutableFortranMatrix& one ,
1789 const std::vector<Scalar>& gflux,
1791 std::vector<Scalar>& rhs)
1792 // ----------------------------------------------------------------
1793 {
1794 // Ft <- B^{-t} * ones([size(S,2),1])
1795 SharedFortranMatrix Ft(S.numRows(), 1, &F_[c][0]);
1796 matMulAdd_TN(Scalar(1.0), S, one, Scalar(0.0), Ft);
1797
1798 L_[c] = std::accumulate(Ft.data(), Ft.data() + Ft.numRows(), 0.0);
1799 g_[c] -= std::accumulate(gflux.begin(), gflux.end(), Scalar(0.0));
1800
1801 // rhs <- v_g - rhs (== v_g - h)
1802 std::transform(gflux.begin(), gflux.end(), rhs.begin(),
1803 rhs.begin(),
1804 std::minus<Scalar>());
1805
1806 // rhs <- rhs + g_[c]/L_[c]*F
1807 std::transform(rhs.begin(), rhs.end(), Ft.data(),
1808 rhs.begin(),
1809 axpby<Scalar>(Scalar(1.0), Scalar(g_[c] / L_[c])));
1810
1811 // S <- S - F'*F/L_c
1812 symmetricUpdate(-Scalar(1.0)/L_[c], Ft, Scalar(1.0), S);
1813 }
1814
1815
1816
1817 // ----------------------------------------------------------------
1819 template<class L2G>
1820 void addCellContrib(const SharedFortranMatrix& S ,
1821 const std::vector<Scalar>& rhs ,
1822 const std::vector<FaceType>& facetype,
1823 const std::vector<Scalar>& condval ,
1824 const std::vector<int>& ppartner,
1825 const L2G& l2g)
1826 // ----------------------------------------------------------------
1827 {
1828 int r = 0;
1829 for (auto 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 (auto 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:365
double postProcessFluxes()
Postprocess the solution fluxes. This method modifies the solution object so that out-fluxes of twin ...
Definition: IncompFlowSolverHybrid.hpp:747
SolutionType getSolution()
Recover the solution to the problem defined by the parameters to method.
Definition: IncompFlowSolverHybrid.hpp:821
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:811
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:888
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:497
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:842
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:476
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:533
Dune::MatrixAdapter< Matrix, Vector, Vector > Operator
A linear operator.
Definition: elasticity_preconditioners.hpp:49
min[0]
Definition: elasticity_upscale_impl.hpp:146
int j
Definition: elasticity_upscale_impl.hpp:658
Definition: ImplicitAssembly.hpp:43
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:829
const FullMatrix< double, ImmutableSharedData, FortranOrdering > ImmutableFortranMatrix
Definition: Matrix.hpp:590
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:913
FullMatrix< double, SharedData, FortranOrdering > SharedFortranMatrix
Definition: Matrix.hpp:589
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:1252