EulerUpstreamImplicit_impl.hpp
Go to the documentation of this file.
1//===========================================================================
2//
3// File: EulerUpstreamImplicit_impl.hpp
4//
5// Created: Tue Jun 16 14:25:24 2009
6//
7// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
8// B�rd Skaflestad <bard.skaflestad@sintef.no>
9// Halvor M Nilsen <hnil@sintef.no>
10//
11// $Date$
12//
13// $Revision$
14//
15//===========================================================================
16
17/*
18 Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
19 Copyright 2009, 2010 Statoil ASA.
20
21 This file is part of The Open Reservoir Simulator Project (OpenRS).
22
23 OpenRS is free software: you can redistribute it and/or modify
24 it under the terms of the GNU General Public License as published by
25 the Free Software Foundation, either version 3 of the License, or
26 (at your option) any later version.
27
28 OpenRS is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
32
33 You should have received a copy of the GNU General Public License
34 along with OpenRS. If not, see <http://www.gnu.org/licenses/>.
35*/
36
37#ifndef OPENRS_EULERUPSTREAMIMPLICIT_IMPL_HEADER
38#define OPENRS_EULERUPSTREAMIMPLICIT_IMPL_HEADER
39
40#include <opm/common/ErrorMacros.hpp>
42#include <opm/input/eclipse/Units/Units.hpp>
43#include <opm/grid/common/Volumes.hpp>
44#include <opm/grid/utility/StopWatch.hpp>
46#include <opm/grid/transmissibility/trans_tpfa.h>
47
48#include <cmath>
49#include <algorithm>
50#include <limits>
51#include <vector>
52#include <array>
53#include <iostream>
54
55namespace Opm
56{
57
58
59 template <class GI, class RP, class BC>
61 {
62 check_sat_ = true;
63 clamp_sat_ = false;
64 }
65 template <class GI, class RP, class BC>
66 inline EulerUpstreamImplicit<GI, RP, BC>::EulerUpstreamImplicit(const GI& g, const RP& r, const BC& b)
67 {
68 check_sat_ = true;
69 clamp_sat_ = false;
70 initObj(g, r, b);
71 }
72
73 template <class GI, class RP, class BC>
74 inline void EulerUpstreamImplicit<GI, RP, BC>::init(const Opm::ParameterGroup& param)
75 {
76 check_sat_ = param.getDefault("check_sat", check_sat_);
77 clamp_sat_ = param.getDefault("clamp_sat", clamp_sat_);
78 //Opm::ImplicitTransportDetails::NRControl ctrl_;
79 ctrl_.max_it = param.getDefault("transport_nr_max_it", 10);
80 max_repeats_ = param.getDefault("transport_max_rep", 10);
81 ctrl_.atol = param.getDefault("transport_atol", 1.0e-6);
82 ctrl_.rtol = param.getDefault("transport_rtol", 5.0e-7);
83 ctrl_.max_it_ls = param.getDefault("transport_max_it_ls", 20);
84 ctrl_.dxtol = param.getDefault("transport_dxtol", 1e-6);
85 ctrl_.verbosity = param.getDefault("transport_verbosity", 0);
86 }
87
88 template <class GI, class RP, class BC>
89 inline void EulerUpstreamImplicit<GI, RP, BC>::init(const Opm::ParameterGroup& param,
90 const GI& g, const RP& r, const BC& b)
91 {
92 init(param);
93 initObj(g, r, b);
94 }
95
96
97 template <class GI, class RP, class BC>
98 inline void EulerUpstreamImplicit<GI, RP, BC>::initObj(const GI& g, const RP& r, const BC& b)
99 {
100 //residual_computer_.initObj(g, r, b);
101
102 mygrid_.init(g.grid());
103 porevol_.resize(mygrid_.numCells());
104 for (int i = 0; i < mygrid_.numCells(); ++i){
105 porevol_[i]= mygrid_.cellVolume(i)*r.porosity(i);
106 }
107 // int numf=mygrid_.numFaces();
108 int num_cells = mygrid_.numCells();
109 int ngconn = mygrid_.c_grid()->cell_facepos[num_cells];
110 //std::vector<double> htrans_(ngconn);
111 htrans_.resize(ngconn);
112 const double* perm = &(r.permeability(0)(0,0));
113 tpfa_htrans_compute(mygrid_.c_grid(), perm, &htrans_[0]);
114 // int count = 0;
115
116 myrp_= r;
117
118 typedef typename GI::CellIterator CIt;
119 typedef typename CIt::FaceIterator FIt;
120 std::vector<FIt> bid_to_face;
121 int maxbid = 0;
122 for (CIt c = g.cellbegin(); c != g.cellend(); ++c) {
123 for (FIt f = c->facebegin(); f != c->faceend(); ++f) {
124 int bid = f->boundaryId();
125 maxbid = std::max(maxbid, bid);
126 }
127 }
128
129 bid_to_face.resize(maxbid + 1);
130 std::vector<int> egf_cf(mygrid_.numFaces());
131 int cix=0;
132 for (CIt c = g.cellbegin(); c != g.cellend(); ++c) {
133 int loc_fix=0;
134 for (FIt f = c->facebegin(); f != c->faceend(); ++f) {
135 if (f->boundary() && b.satCond(*f).isPeriodic()) {
136 bid_to_face[f->boundaryId()] = f;
137 }
138 int egf=f->index();
139 int cf=mygrid_.cellFace(cix,loc_fix);
140 egf_cf[egf]=cf;
141 loc_fix+=1;
142 }
143 cix+=1;
144 }
145
146#ifndef NDEBUG
147 const UnstructuredGrid& c_grid=*mygrid_.c_grid();
148#endif
149 int hf_ind=0;
150 periodic_cells_.resize(0);
151 periodic_faces_.resize(0);
152 periodic_hfaces_.resize(0);
153 periodic_nbfaces_.resize(0);
154 //cell1 = cell0;
155 direclet_cells_.resize(0);
156 direclet_sat_.resize(0);
157 direclet_sat_.resize(0);
158 direclet_hfaces_.resize(0);
159
160 assert(periodic_cells_.size()==0);
161 for (CIt c = g.cellbegin(); c != g.cellend(); ++c) {
162 int cell0 = c->index();
163 for (FIt f = c->facebegin(); f != c->faceend(); ++f) {
164 // Neighbour face, will be changed if on a periodic boundary.
165 // Compute cell[1], cell_sat[1]
166 FIt nbface = f;
167 if (f->boundary()) {
168 if (b.satCond(*f).isPeriodic()) {
169 nbface = bid_to_face[b.getPeriodicPartner(f->boundaryId())];
170 assert(nbface != f);
171 int cell1 = nbface->cellIndex();
172 assert(cell0 != cell1);
173
174 int f_ind=f->index();
175
176 int fn_ind=nbface->index();
177 // mapping face indices
178 f_ind=egf_cf[f_ind];
179 fn_ind=egf_cf[fn_ind];
180 assert((c_grid.face_cells[2*f_ind]==-1) || (c_grid.face_cells[2*f_ind+1]==-1));
181 assert((c_grid.face_cells[2*fn_ind]==-1) || (c_grid.face_cells[2*fn_ind+1]==-1));
182 assert((c_grid.face_cells[2*f_ind]==cell0) || (c_grid.face_cells[2*f_ind+1]==cell0));
183 assert((c_grid.face_cells[2*fn_ind]==cell1) || (c_grid.face_cells[2*fn_ind+1]==cell1));
184 periodic_cells_.push_back(cell0);
185 periodic_cells_.push_back(cell1);
186 periodic_faces_.push_back(f_ind);
187 periodic_hfaces_.push_back(hf_ind);
188 periodic_nbfaces_.push_back(fn_ind);
189 } else if (!( b.flowCond(*f).isNeumann() && b.flowCond(*f).outflux() == 0.0)) {
190 //cell1 = cell0;
191 direclet_cells_.push_back(cell0);
192 direclet_sat_.push_back(b.satCond(*f).saturation());
193 direclet_sat_.push_back(1-b.satCond(*f).saturation());//only work for 2 phases
194 direclet_hfaces_.push_back(hf_ind);
195 }
196 }
197 hf_ind+=1;
198 }
199 }
200
201 mygrid_.makeQPeriodic(periodic_hfaces_,periodic_cells_);
202 // use fractional flow instead of saturation as src
203 TwophaseFluid myfluid(myrp_);
204 int num_b=direclet_cells_.size();
205 for(int i=0; i <num_b; ++i){
206 std::array<double,2> sat = {{direclet_sat_[2*i] ,direclet_sat_[2*i+1] }};
207 std::array<double,2> mob;
208 std::array<double,2*2> dmob;
209 myfluid.mobility(direclet_cells_[i], sat, mob, dmob);
210 double fl = mob[0]/(mob[0]+mob[1]);
211 direclet_sat_[2*i] = fl;
212 direclet_sat_[2*i+1] = 1-fl;
213 }
214 }
215
216 template <class GI, class RP, class BC>
218 {
219 using namespace std;
220 cout << endl;
221 cout <<"Displaying some members of EulerUpstreamImplicit" << endl;
222 cout << endl;
223 }
224
225 template <class GI, class RP, class BC>
226 template <class PressureSolution>
227 bool EulerUpstreamImplicit<GI, RP, BC>::transportSolve(std::vector<double>& saturation,
228 const double time,
229 const typename GI::Vector& /* gravity */,
230 const PressureSolution& pressure_sol,
231 const Opm::SparseVector<double>& /* injection_rates */) const
232 {
233
234 Opm::ReservoirState<2> state(mygrid_.c_grid());
235 {
236 std::vector<double>& sat = state.saturation();
237 for (int i=0; i < mygrid_.numCells(); ++i){
238 sat[2*i] = saturation[i];
239 sat[2*i+1] = 1-saturation[i];
240 }
241 }
242
243 //int count=0;
244 const UnstructuredGrid* cgrid = mygrid_.c_grid();
245 int numhf = cgrid->cell_facepos[cgrid->number_of_cells];
246
247 std::vector<double> faceflux(numhf);
248
249 {
250 auto i = grid_size_t(0);
251 for (int c = 0; c < cgrid->number_of_cells; ++c){
252 for (; i < cgrid->cell_facepos[c + 1]; ++i) {
253 int f= cgrid->cell_faces[i];
254 double outflux = pressure_sol.outflux(i);
255 double sgn = 2.0*(cgrid->face_cells[2*f + 0] == c) - 1;
256 faceflux[f] = sgn * outflux;
257 }
258 }
259 }
260 int num_db=direclet_hfaces_.size();
261 std::vector<double> sflux(num_db);
262 for (int i=0; i < num_db;++i){
263 sflux[i]=-pressure_sol.outflux(direclet_hfaces_[i]);
264 }
265 state.faceflux()=faceflux;
266
267 double dt_transport = time;
268 int nr_transport_steps = 1;
269 Opm::time::StopWatch clock;
270 int repeats = 0;
271 bool finished = false;
272 clock.start();
273
274 TwophaseFluid myfluid(myrp_);
275 double* tmp_grav=0;
276 const UnstructuredGrid& c_grid=*mygrid_.c_grid();
277 TransportModel model(myfluid,c_grid,porevol_,tmp_grav);
278 model.makefhfQPeriodic(periodic_faces_,periodic_hfaces_, periodic_nbfaces_);
279 model.initGravityTrans(*mygrid_.c_grid(),htrans_);
280 TransportSolver tsolver(model);
281 LinearSolver linsolve_;
283
284 Opm::TransportSource tsrc;//create_transport_source(0, 2);
285 // the input flux is assumed to be the saturation times the flux in the transport solver
286
287 tsrc.nsrc =direclet_cells_.size();
288 tsrc.saturation = direclet_sat_;
289 tsrc.cell = direclet_cells_;
290 tsrc.flux = sflux;
291
292 while (!finished) {
293 for (int q = 0; q < nr_transport_steps; ++q) {
294 tsolver.solve(*mygrid_.c_grid(), &tsrc, dt_transport, ctrl_, state, linsolve_, rpt_);
295 if(rpt_.flag<0){
296 break;
297 }
298 }
299 if(!(rpt_.flag<0) ){
300 finished =true;
301 }else{
302 if(repeats >max_repeats_){
303 finished=true;
304 }else{
305 OPM_MESSAGE("Warning: Transport failed, retrying with more steps.");
306 nr_transport_steps *= 2;
307 dt_transport = time/nr_transport_steps;
308 if (ctrl_.verbosity){
309 std::cout << "Warning: Transport failed, retrying with more steps. dt = "
310 << dt_transport/Opm::unit::year << " year.\n";
311 }
312
313 std::vector<double>& sat = state.saturation();
314 for (int i=0; i < mygrid_.numCells(); ++i){
315 sat[2*i] = saturation[i];
316 sat[2*i+1] = 1-saturation[i];
317 }
318 }
319 }
320 repeats +=1;
321 }
322 clock.stop();
323 std::cout << "EulerUpstreamImplicite used " << repeats
324 << " repeats and " << nr_transport_steps <<" steps"<< std::endl;
325#ifdef VERBOSE
326 std::cout << "Seconds taken by transport solver: " << clock.secsSinceStart() << std::endl;
327#endif // VERBOSE
328 {
329 const std::vector<double>& sat = state.saturation();
330 for (int i=0; i < mygrid_.numCells(); ++i){
331 saturation[i] = sat[2*i];
332 }
333 }
334 if((rpt_.flag<0)){
335 std::cerr << "EulerUpstreamImplicit did not converge" << std::endl;
336 return false;
337 }else{
338 return true;
339 }
340 }
341
342 template <class GI, class RP, class BC>
343 inline void EulerUpstreamImplicit<GI, RP, BC>::checkAndPossiblyClampSat(std::vector<double>& s) const
344 {
345 int num_cells = s.size();
346 for (int cell = 0; cell < num_cells; ++cell) {
347 if (s[cell] > 1.0 || s[cell] < 0.0) {
348 if (clamp_sat_) {
349 s[cell] = std::max(std::min(s[cell], 1.0), 0.0);
350 } else if (s[cell] > 1.001 || s[cell] < -0.001) {
351 OPM_THROW(std::runtime_error,
352 "Saturation out of range in EulerUpstreamImplicit: "
353 "Cell " + std::to_string(cell) +
354 " sat " + std::to_string(s[cell]));
355 }
356 }
357 }
358 }
359
360}
361
362
363
364#endif // OPENRS_EULERUPSTREAM_IMPL_HEADER
EulerUpstreamImplicit()
Definition: EulerUpstreamImplicit_impl.hpp:60
void checkAndPossiblyClampSat(std::vector< double > &s) const
Definition: EulerUpstreamImplicit_impl.hpp:343
void initObj(const GridInterface &grid, const ReservoirProperties &resprop, const BoundaryConditions &boundary)
Definition: EulerUpstreamImplicit_impl.hpp:98
bool transportSolve(std::vector< double > &saturation, const double time, const typename GridInterface::Vector &gravity, const PressureSolution &pressure_sol, const Opm::SparseVector< double > &injection_rates) const
Solve transport equation, evolving.
void display()
Definition: EulerUpstreamImplicit_impl.hpp:217
void init(const Opm::ParameterGroup &param)
Definition: EulerUpstreamImplicit_impl.hpp:74
Definition: ImplicitTransport.hpp:105
void solve(const Grid &g, const SourceTerms *src, const double dt, const ImplicitTransportDetails::NRControl &ctrl, ReservoirState &state, LinearSolver &linsolve, ImplicitTransportDetails::NRReport &rpt)
Definition: ImplicitTransport.hpp:116
Definition: ImplicitTransportDefs.hpp:162
Definition: ImplicitTransportDefs.hpp:52
::std::vector< double > & faceflux()
Definition: ImplicitTransportDefs.hpp:63
::std::vector< double > & saturation()
Definition: ImplicitTransportDefs.hpp:64
Definition: SinglePointUpwindTwoPhase.hpp:278
void initGravityTrans(const Grid &g, const std::vector< double > &htrans)
Definition: SinglePointUpwindTwoPhase.hpp:475
void makefhfQPeriodic(const std::vector< int > &p_faces, const std::vector< int > &hf_faces, const std::vector< int > &nb_faces)
Definition: SinglePointUpwindTwoPhase.hpp:312
Definition: ImplicitTransportDefs.hpp:196
::std::vector< double > saturation
Definition: ImplicitTransportDefs.hpp:205
::std::vector< int > cell
Definition: ImplicitTransportDefs.hpp:202
int nsrc
Definition: ImplicitTransportDefs.hpp:200
::std::vector< double > flux
Definition: ImplicitTransportDefs.hpp:204
Definition: ImplicitTransportDefs.hpp:115
void mobility(int c, const Sat &s, Mob &mob, DMob &dmob) const
Definition: ImplicitTransportDefs.hpp:125
min[0]
Definition: elasticity_upscale_impl.hpp:146
Dune::BlockVector< Dune::FieldVector< double, 1 > > Vector
A vector holding our RHS.
Definition: matrixops.hpp:33
Definition: ImplicitAssembly.hpp:43
Definition: ImplicitTransport.hpp:63
int flag
Definition: ImplicitTransport.hpp:65