SinglePointUpwindTwoPhase.hpp
Go to the documentation of this file.
1/*===========================================================================
2//
3// File: SinglePointUpwindTwoPhase.hpp
4//
5// Created: 2011-09-28 14:21:34+0200
6//
7// Authors: Ingeborg S. Ligaarden <Ingeborg.Ligaarden@sintef.no>
8// Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
9// Halvor M. Nilsen <HalvorMoll.Nilsen@sintef.no>
10// Atgeirr F. Rasmussen <atgeirr@sintef.no>
11// Bård Skaflestad <Bard.Skaflestad@sintef.no>
12//
13//==========================================================================*/
14
15
16/*
17 Copyright 2011 SINTEF ICT, Applied Mathematics.
18 Copyright 2011 Statoil ASA.
19
20 This file is part of the Open Porous Media Project (OPM).
21
22 OPM is free software: you can redistribute it and/or modify
23 it under the terms of the GNU General Public License as published by
24 the Free Software Foundation, either version 3 of the License, or
25 (at your option) any later version.
26
27 OPM is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public License
33 along with OPM. If not, see <http://www.gnu.org/licenses/>.
34*/
35
42#ifndef OPM_SINGLEPOINTUPWINDTWOPHASE_HPP_HEADER
43#define OPM_SINGLEPOINTUPWINDTWOPHASE_HPP_HEADER
44
45#include <cassert>
46#include <cstddef>
47
48#include <algorithm>
49#include <vector>
50#include <iostream>
51
52namespace Opm {
53 namespace spu_2p {
83 public:
91 ModelParameterStorage(int nc, int totconn)
92 : drho_(0.0), mob_(0), dmob_(0),
93 porevol_(0), dg_(0), ds_(0), pc_(0), dpc_(0), trans_(0),
94 data_()
95 {
96 std::size_t alloc_sz;
97
98 alloc_sz = 2 * nc; // mob_
99 alloc_sz += 2 * nc; // dmob_
100 alloc_sz += 1 * nc; // porevol_
101 alloc_sz += 1 * totconn; // dg_
102 alloc_sz += 1 * nc; // ds_
103 alloc_sz += 1 * nc; // pc_
104 alloc_sz += 1 * nc; // dpc_
105 alloc_sz += 1 * totconn; // dtrans
106 data_.resize(alloc_sz);
107
108 mob_ = &data_[0];
109 dmob_ = mob_ + (2 * nc );
110 porevol_ = dmob_ + (2 * nc );
111 dg_ = porevol_ + (1 * nc );
112 ds_ = dg_ + (1 * totconn);
113 pc_ = ds_ + (1 * nc );
114 dpc_ = pc_ + (1 * nc );
115 trans_ = dpc_ + (1 * nc );
116 }
117
123 double& drho () { return drho_ ; }
128 double drho () const { return drho_ ; }
129
136 double* mob (int c) { return mob_ + (2*c + 0); }
143 const double* mob (int c) const { return mob_ + (2*c + 0); }
144
152 double* dmob (int c) { return dmob_ + (2*c + 0); }
160 const double* dmob (int c) const { return dmob_ + (2*c + 0); }
161
166 double* porevol() { return porevol_ ; }
172 double porevol(int c) const { return porevol_[c] ; }
173
182 double& dg(int i) { return dg_[i] ; }
190 double dg(int i) const { return dg_[i] ; }
191
199 double& ds(int c) { return ds_[c] ; }
207 double ds(int c) const { return ds_[c] ; }
208
215 double& pc(int c) { return pc_[c] ; }
222 double pc(int c) const { return pc_[c] ; }
223
231 double& dpc(int c) { return dpc_[c] ; }
239 double dpc(int c) const { return dpc_[c] ; }
240
248 double& trans(int f) { return trans_[f] ; }
256 double trans(int f) const { return trans_[f] ; }
257
258 private:
259 double drho_ ;
260 double *mob_ ;
261 double *dmob_ ;
262 double *porevol_;
263 double *dg_ ;
264 double *ds_ ;
265 double *pc_ ;
266 double *dpc_ ;
267 double *trans_ ;
272 std::vector<double> data_;
273 };
274 }
275
276
277 template <class TwophaseFluid>
279 public:
280 template <class Grid>
281 SinglePointUpwindTwoPhase(const TwophaseFluid& fluid ,
282 const Grid& g ,
283 const std::vector<double>& porevol ,
284 const double* grav = 0,
285 const bool guess_previous = true)
286 : fluid_ (fluid) ,
287 gravity_(grav) ,
288 f2hf_ (2 * g.number_of_faces, -1) ,
289 store_ (g.number_of_cells,
290 g.cell_facepos[ g.number_of_cells ]),
291 init_step_use_previous_sol_(guess_previous),
292 sat_tol_(1e-5)
293 {
294
295 if (gravity_) {
296 store_.drho() = fluid_.density(0) - fluid_.density(1);
297 }
298
299 auto i = grid_size_t(0);
300 for (int c = 0; c < g.number_of_cells; ++c) {
301 for (; i < g.cell_facepos[c + 1]; ++i) {
302 const int f = g.cell_faces[i];
303 const int p = 1 - (g.face_cells[2*f + 0] == c);
304 f2hf_[2*f + p] = i;
305 }
306 }
307
308 std::copy(porevol.begin(), porevol.end(), store_.porevol());
309 }
310
311 void
312 makefhfQPeriodic(const std::vector<int>& p_faces ,
313 const std::vector<int>& hf_faces,
314 const std::vector<int>& nb_faces)
315 {
316 if (p_faces.empty()) {
317 return;
318 }
319 assert (p_faces.size() == hf_faces.size());
320 assert (hf_faces.size() == nb_faces.size());
321
322 std::vector<int> nbhf(hf_faces.size());
323
324 for (std::vector<int>::size_type i = 0; i < p_faces.size(); ++i) {
325 const int nbf = nb_faces[i];
326
327 assert (2*std::vector<int>::size_type(nbf) + 1 < f2hf_.size());
328 assert ((f2hf_[2*nbf + 0] < 0) ^ (f2hf_[2*nbf + 1] < 0));
329
330 const int p = (f2hf_[2*nbf + 0] < 0) ? 1 : 0; // "Self"
331 nbhf[ i ] = f2hf_[2*nbf + p];
332 }
333
334 for (std::vector<int>::size_type i = 0; i < p_faces.size(); ++i) {
335 const int f = p_faces [i];
336 const int hf = hf_faces[i];
337
338 assert (0 <= f);
339 assert (0 <= hf);
340 assert (2*std::vector<int>::size_type(f) + 1 < f2hf_.size());
341
342 assert ((f2hf_[2*f + 0] < 0 ) ^ (f2hf_[2*f + 1] < 0 ));
343 assert ((f2hf_[2*f + 0] == hf) ^ (f2hf_[2*f + 1] == hf));
344
345 const int p = (f2hf_[2*f + 0] == hf) ? 1 : 0; // "Other"
346
347 f2hf_[2*f + p] = nbhf[ i ];
348 }
349 }
350
351 // -----------------------------------------------------------------
352 // System assembly innards
353 // -----------------------------------------------------------------
354
355 enum { DofPerCell = 1 };
356
357 void
358 initResidual(const int c, double* F) const {
359 (void) c; // Suppress 'unused' warning
360 *F = 0.0;
361 }
362
363 template <class ReservoirState,
364 class Grid >
365 void
367 const Grid& g ,
368 const double dt ,
369 const int c ,
370 const int f ,
371 double* J1 ,
372 double* J2 ,
373 double* F ) const {
374
375 const int *n = g.face_cells + (2 * f);
376 double dflux = state.faceflux()[f];
377 double gflux = gravityFlux(f);
378 double pcflux,dpcflux[2];
379 capFlux(f,n, pcflux, dpcflux);
380 gflux += pcflux;
381
382 int pix[2];
383 double m[2], dm[2];
384 upwindMobility(dflux, gflux, n, pix, m, dm);
385
386 assert (! ((m[0] < 0) || (m[1] < 0)));
387
388 double mt = m[0] + m[1];
389 assert (mt > 0);
390
391 double sgn = 2.0*(n[0] == c) - 1.0;
392 dflux *= sgn;
393 gflux *= sgn;
394
395
396 double f1 = m[0] / mt;
397 const double v1 = dflux + m[1]*gflux;
398
399 // Assemble residual contributions
400 *F += dt * f1 * v1;
401
402 // Assemble Jacobian (J1 <-> c, J2 <-> other)
403 double *J[2];
404 if (n[0] == c) {
405 J[0] = J1; J[1] = J2;
406 // sign is positive
407 J1[0*2 + 0] += sgn*dt * f1 * dpcflux[0] * m[1];
408 J2[0*2 + 0] += sgn*dt * f1 * dpcflux[1] * m[1];
409 } else {
410 J[0] = J2; J[1] = J1;
411 // sign is negative
412 J1[0*2 + 0] += sgn*dt * f1 * dpcflux[1] * m[1];
413 J2[0*2 + 0] += sgn*dt * f1 * dpcflux[0] * m[1];
414 }
415
416 // dF/dm_1 \cdot dm_1/ds
417 *J[ pix[0] ] += dt * (1 - f1) / mt * v1 * dm[0];
418
419 /* dF/dm_2 \cdot dm_2/ds */
420 *J[ pix[1] ] -= dt * f1 / mt * v1 * dm[1];
421 *J[ pix[1] ] += dt * f1 * gflux * dm[1];
422 }
423
424 template <class Grid>
425 void
426 accumulation(const Grid& g,
427 const int c,
428 double* J,
429 double* F) const {
430 (void) g;
431
432 const double pv = store_.porevol(c);
433
434 *J += pv;
435 *F += pv * store_.ds(c);
436 }
437
438 template <class Grid ,
439 class SourceTerms>
440 void
441 sourceTerms(const Grid& g ,
442 const SourceTerms* src,
443 const int i ,
444 const double dt ,
445 double* J ,
446 double* F ) const {
447
448 (void) g;
449
450 double dflux = -src->flux[i]; // ->flux[] is rate of *inflow*
451
452 if (dflux < 0) {
453 // src -> cell, affects residual only.
454 *F += dt * dflux * src->saturation[2*i + 0];
455 } else {
456 // cell -> src
457 const int c = src->cell[i];
458 const double* m = store_.mob (c);
459 const double* dm = store_.dmob(c);
460
461 const double mt = m[0] + m[1];
462
463 assert (! ((m[0] < 0) || (m[1] < 0)));
464 assert (mt > 0);
465
466 const double f = m[0] / mt;
467 const double df = ((1 - f)*dm[0] - f*dm[1]) / mt;
468
469 *F += dt * dflux * f;
470 *J += dt * dflux * df;
471 }
472 }
473 template <class Grid>
474 void
475 initGravityTrans(const Grid& g ,
476 const std::vector<double> & htrans) {
477
478 assert (htrans.size() ==
479 static_cast<std::vector<double>::size_type>(g.cell_facepos[ g.number_of_cells ]));
480
481 for (int f = 0; f < g.number_of_faces; ++f) {
482 store_.trans(f) = 0.0;
483 }
484
485 auto i = grid_size_t(0);
486 for (int c = 0; c < g.number_of_cells; ++c) {
487 for (; i < g.cell_facepos[c + 1]; ++i) {
488 int f = g.cell_faces[i];
489
490 assert (htrans[i] > 0.0);
491
492 store_.trans(f) += 1.0 / htrans[i];
493 }
494 }
495
496 for (int f = 0; f < g.number_of_faces; ++f) {
497 store_.trans(f) = 1.0 / store_.trans(f);
498 }
499
500 if (gravity_) {
501 this->computeStaticGravity(g);
502 }
503 }
504
505 // -----------------------------------------------------------------
506 // Newton control
507 // -----------------------------------------------------------------
508
509 template <class ReservoirState,
510 class Grid ,
511 class JacobianSystem>
512 void
514 const Grid& g ,
515 JacobianSystem& sys ) {
516
517 (void) state; // Suppress 'unused' warning.
518
519 typename JacobianSystem::vector_type& x =
520 sys.vector().writableSolution();
521
522 assert (x.size() == (::std::size_t) (g.number_of_cells));
523
524 if (init_step_use_previous_sol_) {
525 std::fill(x.begin(), x.end(), 0.0);
526 } else {
527 const std::vector<double>& s = state.saturation();
528 for (int c = 0, nc = g.number_of_cells; c < nc; ++c) {
529 // Impose s=0.5 at next time level as an NR initial value.
530 x[c] = 0.5 - s[2*c + 0];
531 }
532 }
533 }
534
535 template <class ReservoirState,
536 class Grid ,
537 class JacobianSystem>
538 bool
540 const Grid& g ,
541 JacobianSystem& sys) {
542
543 double s[2], mob[2], dmob[2 * 2], pc, dpc;
544
545 const typename JacobianSystem::vector_type& x =
546 sys.vector().solution();
547 const ::std::vector<double>& sat = state.saturation();
548
549 bool in_range = true;
550 for (int c = 0; c < g.number_of_cells; ++c) {
551 store_.ds(c) = x[c]; // Store sat-change for accumulation().
552
553 s[0] = sat[c*2 + 0] + x[c];
554
555 double s_min = fluid_.s_min(c);
556 double s_max = fluid_.s_max(c);
557
558 if ( s[0] < (s_min - sat_tol_) || s[0] > (s_max + sat_tol_) ) {
559 // if (s[0] < s_min){
560 // std::cout << "Warning: s out of range, s-s_min = " << s_min-s[0] << std::endl;
561 // }
562 // if (s[0] > s_max){
563 // std::cout << "Warning: s out of range, s-s_max = " << s[0]-s_max << std::endl;
564 // }
565 in_range = false; //line search fails
566 }
567 s[0] = std::max(s_min, s[0]);
568 s[0] = std::min(s_max, s[0]);
569 s[1] = 1 - s[0];
570
571 fluid_.mobility(c, s, mob, dmob);
572 fluid_.pc(c, s, pc, dpc);
573
574 store_.mob (c)[0] = mob [0];
575 store_.mob (c)[1] = mob [1];
576 store_.dmob(c)[0] = dmob[0*2 + 0];
577 store_.dmob(c)[1] = -dmob[1*2 + 1];
578 store_.pc(c) = pc;
579 store_.dpc(c) = dpc;
580 }
581 if (!in_range) {
582#ifdef VERBOSE
583 std::cout << "Warning: initIteration() - s was clamped in some cells.\n";
584#endif
585 }
586 return in_range;
587 }
588
589 template <class ReservoirState,
590 class Grid ,
591 class NewtonIterate >
592 void
594 const Grid& g ,
595 NewtonIterate& it ) {
596 // Nothing to do at end of iteration in this model.
597 (void) state; (void) g; (void) it;
598 }
599
600 template <class Grid ,
601 class SolutionVector,
602 class ReservoirState>
603 void
604 finishStep(const Grid& g ,
605 const SolutionVector& x ,
606 ReservoirState& state) {
607
608 double *s = &state.saturation()[0*2 + 0];
609
610 for (int c = 0; c < g.number_of_cells; ++c, s += 2) {
611 s[0] += x[c];
612 double s_min = fluid_.s_min(c);
613 double s_max = fluid_.s_max(c);
614
615#if 0
616 assert(s[0] >= s_min - sat_tol_);
617 assert(s[0] <= s_max + sat_tol_);
618#endif
619
620 s[0] = std::max(s_min, s[0]);
621 s[0] = std::min(s_max, s[0]);
622 s[1] = 1.0 - s[0];
623 }
624 }
625
626 private:
627 void
628 upwindMobility(const double dflux,
629 const double gflux,
630 const int* n ,
631 int* pix ,
632 double* m ,
633 double* dm ) const {
634 bool equal_sign = ( (! (dflux < 0)) && (! (gflux < 0)) ) ||
635 ( (! (dflux > 0)) && (! (gflux > 0)) );
636
637 if (equal_sign) {
638
639 if (! (dflux < 0) && ! (gflux < 0)) { pix[0] = 0; }
640 else { pix[0] = 1; }
641
642 m[0] = store_.mob(n[ pix[0] ]) [ 0 ];
643
644 if (! (dflux - m[0]*gflux < 0)) { pix[1] = 0; }
645 else { pix[1] = 1; }
646
647 m[1] = store_.mob(n[ pix[1] ]) [ 1 ];
648
649 } else {
650
651 if (! (dflux < 0) && ! (gflux > 0)) { pix[1] = 0; }
652 else { pix[1] = 1; }
653
654 m[1] = store_.mob(n[ pix[1] ]) [ 1 ];
655
656 if (dflux + m[1]*gflux > 0) { pix[0] = 0; }
657 else { pix[0] = 1; }
658
659 m[0] = store_.mob(n[ pix[0] ]) [ 0 ];
660 }
661
662 dm[0] = store_.dmob(n[ pix[0] ]) [ 0 ];
663 dm[1] = store_.dmob(n[ pix[1] ]) [ 1 ];
664 }
665
666 template <class Grid>
667 void
668 computeStaticGravity(const Grid& g) {
669
670 const int d = g.dimensions;
671 auto i = grid_size_t(0);
672
673 for (int c = 0; c < g.number_of_cells; ++c) {
674 const double* cc = g.cell_centroids + (c * d);
675
676 for (; i < g.cell_facepos[c + 1]; ++i) {
677 const int f = g.cell_faces[i];
678 const double* fc = g.face_centroids + (f * d);
679
680 double dg = 0.0;
681 for (int j = 0; j < d; ++j) {
682 dg += gravity_[j] * (fc[j] - cc[j]);
683 }
684
685 store_.dg(i) = store_.trans(f) * dg;
686 }
687 }
688 }
689
690 double
691 gravityFlux(const int f) const {
692 double gflux;
693
694 if (gravity_) {
695 int i1 = f2hf_[2*f + 0];
696 int i2 = f2hf_[2*f + 1];
697
698 assert ((i1 >= 0) && (i2 >= 0));
699
700 gflux = store_.dg(i1) - store_.dg(i2);
701 gflux *= store_.drho();
702 } else {
703 gflux = 0.0;
704 }
705
706 return gflux;
707 }
708 void
709 capFlux(const int f,const int* n,double& pcflux, double* dpcflux) const {
710 //double capflux;
711 int i1 = n[0];
712 int i2 = n[1];
713 assert ((i1 >= 0) && (i2 >= 0));
714 //double sgn=-1.0;
715 pcflux = store_.trans(f)*(store_.pc(i2) - store_.pc(i1));
716 dpcflux[0] = -store_.trans(f)*store_.dpc(i1);
717 dpcflux[1] = store_.trans(f)*store_.dpc(i2);
718 }
719
720 TwophaseFluid fluid_ ;
721 const double* gravity_;
722 std::vector<int> f2hf_ ;
723 spu_2p::ModelParameterStorage store_ ;
724 bool init_step_use_previous_sol_;
725 double sat_tol_;
726 };
727}
728#endif /* OPM_SINGLEPOINTUPWINDTWOPHASE_HPP_HEADER */
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 initStep(const ReservoirState &state, const Grid &g, JacobianSystem &sys)
Definition: SinglePointUpwindTwoPhase.hpp:513
void accumulation(const Grid &g, const int c, double *J, double *F) const
Definition: SinglePointUpwindTwoPhase.hpp:426
void initGravityTrans(const Grid &g, const std::vector< double > &htrans)
Definition: SinglePointUpwindTwoPhase.hpp:475
void initResidual(const int c, double *F) const
Definition: SinglePointUpwindTwoPhase.hpp:358
void sourceTerms(const Grid &g, const SourceTerms *src, const int i, const double dt, double *J, double *F) const
Definition: SinglePointUpwindTwoPhase.hpp:441
SinglePointUpwindTwoPhase(const TwophaseFluid &fluid, const Grid &g, const std::vector< double > &porevol, const double *grav=0, const bool guess_previous=true)
Definition: SinglePointUpwindTwoPhase.hpp:281
void makefhfQPeriodic(const std::vector< int > &p_faces, const std::vector< int > &hf_faces, const std::vector< int > &nb_faces)
Definition: SinglePointUpwindTwoPhase.hpp:312
void fluxConnection(const ReservoirState &state, const Grid &g, const double dt, const int c, const int f, double *J1, double *J2, double *F) const
Definition: SinglePointUpwindTwoPhase.hpp:366
void finishStep(const Grid &g, const SolutionVector &x, ReservoirState &state)
Definition: SinglePointUpwindTwoPhase.hpp:604
void finishIteration(const ReservoirState &state, const Grid &g, NewtonIterate &it)
Definition: SinglePointUpwindTwoPhase.hpp:593
@ DofPerCell
Definition: SinglePointUpwindTwoPhase.hpp:355
bool initIteration(const ReservoirState &state, const Grid &g, JacobianSystem &sys)
Definition: SinglePointUpwindTwoPhase.hpp:539
Definition: SinglePointUpwindTwoPhase.hpp:82
double * porevol()
Definition: SinglePointUpwindTwoPhase.hpp:166
ModelParameterStorage(int nc, int totconn)
Definition: SinglePointUpwindTwoPhase.hpp:91
double & drho()
Definition: SinglePointUpwindTwoPhase.hpp:123
double drho() const
Definition: SinglePointUpwindTwoPhase.hpp:128
double trans(int f) const
Definition: SinglePointUpwindTwoPhase.hpp:256
double dg(int i) const
Definition: SinglePointUpwindTwoPhase.hpp:190
double * mob(int c)
Definition: SinglePointUpwindTwoPhase.hpp:136
double & pc(int c)
Definition: SinglePointUpwindTwoPhase.hpp:215
double & dpc(int c)
Definition: SinglePointUpwindTwoPhase.hpp:231
double & trans(int f)
Definition: SinglePointUpwindTwoPhase.hpp:248
double & ds(int c)
Definition: SinglePointUpwindTwoPhase.hpp:199
double pc(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:222
double dpc(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:239
double ds(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:207
const double * mob(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:143
double porevol(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:172
double & dg(int i)
Definition: SinglePointUpwindTwoPhase.hpp:182
const double * dmob(int c) const
Definition: SinglePointUpwindTwoPhase.hpp:160
double * dmob(int c)
Definition: SinglePointUpwindTwoPhase.hpp:152
min[0]
Definition: elasticity_upscale_impl.hpp:146
int j
Definition: elasticity_upscale_impl.hpp:658
Definition: ImplicitAssembly.hpp:43