ECLPvtCommon.hpp
Go to the documentation of this file.
1/*
2 Copyright 2017 Statoil ASA.
3
4 This file is part of the Open Porous Media Project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef OPM_ECLPVTCOMMON_HEADER_INCLUDED
21#define OPM_ECLPVTCOMMON_HEADER_INCLUDED
22
29
30#include <algorithm>
31#include <cassert>
32#include <cstddef>
33#include <array>
34#include <functional>
35#include <initializer_list>
36#include <iterator>
37#include <memory>
38#include <utility>
39#include <type_traits>
40
47
48namespace Opm {
49 class ECLInitFileData;
50} // Opm
51
52namespace Opm { namespace ECLPVT {
53
57 {
59 using Converter = std::function<double(const double)>;
60
63
65 std::vector<Converter> column;
66 };
67
73 struct ToSI {
83 density(const ::Opm::ECLUnits::UnitSystem& usys);
84
94 pressure(const ::Opm::ECLUnits::UnitSystem& usys);
95
105 compressibility(const ::Opm::ECLUnits::UnitSystem& usys);
106
116 disGas(const ::Opm::ECLUnits::UnitSystem& usys);
117
127 vapOil(const ::Opm::ECLUnits::UnitSystem& usys);
128
139 recipFvf(const ::Opm::ECLUnits::UnitSystem& usys);
140
151 recipFvfDerivPress(const ::Opm::ECLUnits::UnitSystem& usys);
152
164 recipFvfDerivVapOil(const ::Opm::ECLUnits::UnitSystem& usys);
165
176 recipFvfVisc(const ::Opm::ECLUnits::UnitSystem& usys);
177
189 recipFvfViscDerivPress(const ::Opm::ECLUnits::UnitSystem& usys);
190
202 recipFvfViscDerivVapOil(const ::Opm::ECLUnits::UnitSystem& usys);
203
216 recipFvfGas(const ::Opm::ECLUnits::UnitSystem& usys);
217
230 recipFvfGasDerivPress(const ::Opm::ECLUnits::UnitSystem& usys);
231
245 recipFvfGasDerivVapOil(const ::Opm::ECLUnits::UnitSystem& usys);
246
259 recipFvfGasVisc(const ::Opm::ECLUnits::UnitSystem& usys);
260
274 recipFvfGasViscDerivPress(const ::Opm::ECLUnits::UnitSystem& usys);
275
289 recipFvfGasViscDerivVapOil(const ::Opm::ECLUnits::UnitSystem& usys);
290 };
291 };
292
293 enum class RawCurve {
295 FVF,
296
298 Viscosity,
299
302 };
303
308 struct PVTGraph {
310 std::vector<double> press;
311
313 std::vector<double> mixRat;
314
317 std::vector<double> value;
318 };
319
320 template <std::size_t N>
322 public:
323 explicit DenseVector(const std::array<double, N>& other)
324 : x_(other)
325 {}
326
328 {
329 std::transform(std::begin(this->x_),
330 std::end (this->x_),
331 std::begin(rhs .x_),
332 std::begin(this->x_),
333 std::plus<double>());
334
335 return *this;
336 }
337
339 {
340 std::transform(std::begin(this->x_),
341 std::end (this->x_),
342 std::begin(rhs .x_),
343 std::begin(this->x_),
344 std::minus<double>());
345
346 return *this;
347 }
348
349 DenseVector& operator*=(const double rhs)
350 {
351 std::transform(std::begin(this->x_),
352 std::end (this->x_),
353 std::begin(this->x_),
354 [rhs](const double xi)
355 {
356 return rhs * xi;
357 });
358
359 return *this;
360 }
361
362 DenseVector& operator/=(const double rhs)
363 {
364 std::transform(std::begin(this->x_),
365 std::end (this->x_),
366 std::begin(this->x_),
367 [rhs](const double xi)
368 {
369 return xi / rhs;
370 });
371
372 return *this;
373 }
374
375 const std::array<double, N>& array() const
376 {
377 return this->x_;
378 }
379
380 private:
381 std::array<double, N> x_;
382 };
383
384 template <std::size_t N>
386 {
387 return v *= 1.0 / a;
388 }
389
390 template <std::size_t N>
392 {
393 return v *= a;
394 }
395
396 template <std::size_t N>
398 {
399 return v *= a;
400 }
401
402 template <std::size_t N>
404 {
405 return u += v;
406 }
407
408 template <std::size_t N>
410 {
411 return u -= v;
412 }
413
414 template <class Extrapolation, bool IsAscendingRange>
417 const RawCurve curve)
418 {
419 assert ((curve == RawCurve::FVF) ||
420 (curve == RawCurve::Viscosity));
421
422 const auto colID = (curve == RawCurve::FVF)
423 ? std::size_t{0} : std::size_t{1};
424
425 auto x = interpolant.independentVariable();
426 auto y = interpolant.resultVariable(colID);
427
428 assert ((x.size() == y.size()) && "Setup Error");
429
430 // Post-process ordinates according to which curve is requested.
431 if (curve == RawCurve::FVF) {
432 // y == 1/B. Convert to proper FVF.
433 for (auto& yi : y) {
434 yi = 1.0 / yi;
435 }
436 }
437 else {
438 // y == 1/(B*mu). Extract viscosity term through the usual
439 // conversion formula:
440 //
441 // (1 / B) / (1 / (B*mu)).
442 const auto b = interpolant.resultVariable(0); // 1/B
443
444 assert ((b.size() == y.size()) && "Setup Error");
445
446 for (auto n = y.size(), i = 0*n; i < n; ++i) {
447 y[i] = b[i] / y[i];
448 }
449 }
450
451 // Graph == pair<vector<double>, vector<double>>
452 return FlowDiagnostics::Graph { std::move(x), std::move(y) };
453 }
454
458 class PVDx
459 {
460 public:
463
479 PVDx(ElemIt xBegin,
480 ElemIt xEnd,
481 const ConvertUnits& convert,
482 std::vector<ElemIt>& colIt);
483
489 std::vector<double>
490 formationVolumeFactor(const std::vector<double>& p) const;
491
497 std::vector<double>
498 viscosity(const std::vector<double>& p) const;
499
513 PVTGraph getPvtCurve(const RawCurve curve) const;
514
515 private:
517 using Extrap = ::Opm::Interp1D::PiecewisePolynomial::
518 ExtrapolationPolicy::Linearly;
519
522
525 using EvalPt = std::decay<
526 decltype(std::declval<Backend>().classifyPoint(0.0))
527 >::type;
528
535 Backend interp_;
536
539 EvalPt getInterpPoint(const double p) const
540 {
541 return this->interp_.classifyPoint(p);
542 }
543
545 double fvf_recip(const EvalPt& pt) const
546 {
547 const auto col = std::size_t{0};
548
549 return this->interp_.evaluate(col, pt);
550 }
551
554 double fvf_mu_recip(const EvalPt& pt) const
555 {
556 const auto col = std::size_t{1};
557
558 return this->interp_.evaluate(col, pt);
559 }
560
563 template <class EvalDynamicQuant>
564 std::vector<double>
565 computeQuantity(const std::vector<double>& p,
566 EvalDynamicQuant&& eval) const
567 {
568 auto result = std::vector<double>{};
569 result.reserve(p.size());
570
571 for (const auto& pi : p) {
572 result.push_back(eval(this->getInterpPoint(pi)));
573 }
574
575 return result;
576 }
577 };
578
582 template <class SubtableInterpolant>
583 class PVTx
584 {
585 public:
586 PVTx(std::vector<double> key,
587 std::vector<SubtableInterpolant> propInterp)
588 : key_ (std::move(key))
589 , propInterp_(std::move(propInterp))
590 {
591 if (this->key_.size() != this->propInterp_.size()) {
592 throw std::invalid_argument {
593 "Size of Key Table Does Not Match "
594 "Number of Sub-Table Interpolants"
595 };
596 }
597
598 if (this->key_.size() < 2) {
599 throw std::invalid_argument {
600 "Mixing-Dependent Property Evaluator "
601 "Must Have At Least Two Inner Tables"
602 };
603 }
604 }
605
607 {
608 const std::vector<double>& data;
609 };
610
612 {
613 const std::vector<double>& data;
614 };
615
616 std::vector<double>
618 const InnerVariate& x) const
619 {
620 const auto col = std::size_t{0};
621
622 return this->computeQuantity(key, x,
623 [this, col](const std::size_t curve,
624 const InnerEvalPoint& pt) -> double
625 { // IFunc: Interpolate 1 / B.
626 return this->propInterp_[curve].evaluate(col, pt);
627 },
628 [](const double recipFvF) -> double
629 {
630 // OFunc: Convert reciprocal FvF to ordinary FvF.
631 return 1.0 / recipFvF;
632 });
633 }
634
635 std::vector<double>
637 const InnerVariate& x) const
638 {
639 return this->computeQuantity(key, x,
640 [this](const std::size_t curve,
641 const InnerEvalPoint& pt) -> DenseVector<2>
642 {
643 // IFunc: Interpolate 1/B and 1/(B*mu)
644 const auto& I = this->propInterp_[curve];
645
646 const auto fvf_recip = I.evaluate(0, pt);
647 const auto fvf_mu_recip = I.evaluate(1, pt);
648
649 // { (1 / B) , (1 / (B*mu)) }
650 return DenseVector<2>{
651 std::array<double,2>{
652 { fvf_recip, fvf_mu_recip }
653 }
654 };
655 },
656 [](const DenseVector<2>& recipFvFVisc) -> double
657 {
658 // OFunc: Compute viscosity as
659 // (1 / B) / (1 / B*mu)
660
661 const auto& v = recipFvFVisc.array();
662
663 return v[0] / v[1];
664 });
665 }
666
686 std::vector<PVTGraph>
687 getPvtCurve(const RawCurve curve) const
688 {
689 if (curve == RawCurve::SaturatedState) {
690 return this->saturatedStateCurve();
691 }
692
693 return this->mainPvtCurve(curve);
694 }
695
696 private:
697 using InnerEvalPoint = typename std::decay<
698 decltype(std::declval<SubtableInterpolant>().classifyPoint(0.0))
699 >::type;
700
701 using OuterInterpPoint =
702 ::Opm::Interp1D::PiecewisePolynomial::LocalInterpPoint;
703
704 struct InnerInterpPoint {
705 InnerEvalPoint left;
706 InnerEvalPoint right;
707 };
708
709 std::vector<double> key_;
710 std::vector<SubtableInterpolant> propInterp_;
711
712 InnerInterpPoint getInterpPoint(const std::size_t i,
713 const double x) const
714 {
715 assert ((i + 1) < this->propInterp_.size());
716
717 return {
718 this->propInterp_[i + 0].classifyPoint(x),
719 this->propInterp_[i + 1].classifyPoint(x)
720 };
721 }
722
723 template <class Function>
724 auto interpolate(Function&& func,
725 const OuterInterpPoint& outer,
726 const double x) const
727 -> decltype(func(outer.interval, std::declval<InnerEvalPoint>()))
728 {
729 assert (outer.cat == ::Opm::Interp1D::PointCategory::InRange);
730
731 const auto pt =
732 this->getInterpPoint(outer.interval, x);
733
734 const auto yLeft = func(outer.interval + 0, pt.left);
735 const auto yRight = func(outer.interval + 1, pt.right);
736
737 const auto t = outer.t / (this->key_[outer.interval + 1] -
738 this->key_[outer.interval + 0]);
739
740 // t == 0 => yLeft, t == 1 => yRight
741 return t*yRight + (1.0 - t)*yLeft;
742 }
743
744 template <class Function>
745 auto extrapLeft(Function&& func,
746 const OuterInterpPoint& outer,
747 const double x) const
748 -> decltype(func(outer.interval, std::declval<InnerEvalPoint>()))
749 {
750 assert (outer.cat == ::Opm::Interp1D::PointCategory::LeftOfRange);
751 assert (outer.interval == 0*this->key_.size());
752
753 const auto pt =
754 this->getInterpPoint(outer.interval, x);
755
756 const auto yLeft = func(0, pt.left);
757 const auto yRight = func(1, pt.right);
758
759 const auto dydk =
760 (yRight - yLeft) / (this->key_[1] - this->key_[0]);
761
762 return yLeft + outer.t*dydk;
763 }
764
765 template <class Function>
766 auto extrapRight(Function&& func,
767 const OuterInterpPoint& outer,
768 const double x) const
769 -> decltype(func(outer.interval, std::declval<InnerEvalPoint>()))
770 {
771 const auto nIntervals = this->key_.size() - 1;
772
773 assert (outer.cat == ::Opm::Interp1D::PointCategory::RightOfRange);
774 assert (outer.interval == nIntervals);
775
776 const auto pt = this->getInterpPoint(nIntervals - 1, x);
777
778 const auto yLeft = func(nIntervals - 1, pt.left);
779 const auto yRight = func(nIntervals - 0, pt.right);
780
781 const auto dydk =
782 (yRight - yLeft) / (this->key_[nIntervals - 0] -
783 this->key_[nIntervals - 1]);
784
785 return yRight + outer.t*dydk;
786 }
787
788 template <class Function>
789 auto evaluate(const double key,
790 const double x,
791 Function&& func) const
792 -> decltype(func(std::declval<OuterInterpPoint>().interval,
793 std::declval<InnerEvalPoint>()))
794 {
795 const auto outer = ::Opm::Interp1D::PiecewisePolynomial::
796 LocalInterpPoint::identify(this->key_, key);
797
798 switch (outer.cat) {
799 case ::Opm::Interp1D::PointCategory::InRange:
800 return this->interpolate(std::forward<Function>(func),
801 outer, x);
802
803 case ::Opm::Interp1D::PointCategory::LeftOfRange:
804 return this->extrapLeft(std::forward<Function>(func),
805 outer, x);
806
807 case ::Opm::Interp1D::PointCategory::RightOfRange:
808 return this->extrapRight(std::forward<Function>(func),
809 outer, x);
810 }
811
812 throw std::logic_error {
813 "Outer/Primary Key Cannot Be Classified"
814 };
815 }
816
817 template <class InnerFunction, class OuterFunction>
818 std::vector<double>
819 computeQuantity(const PrimaryKey& key,
820 const InnerVariate& x,
821 InnerFunction&& ifunc,
822 OuterFunction ofunc) const
823 {
824 auto result = std::vector<double>{};
825
826 const auto nVals = key.data.size();
827
828 if (x.data.size() != nVals) {
829 throw std::invalid_argument {
830 "Number of Inner Sampling Points Does Not Match "
831 "Number of Outer Sampling Points"
832 };
833 }
834
835 result.reserve(nVals);
836
837 for (auto i = 0*nVals; i < nVals; ++i) {
838 const auto q =
839 this->evaluate(key.data[i], x.data[i],
840 std::forward<InnerFunction>(ifunc));
841
842 result.push_back(ofunc(q));
843 }
844
845 return result;
846 }
847
848 std::vector<PVTGraph>
849 mainPvtCurve(const RawCurve curve) const
850 {
851 // Uses setup appropriate for PVTO. The PVTG case must be
852 // handled in the caller.
853
854 auto ret = std::vector<PVTGraph>{};
855 ret.reserve(this->propInterp_.size());
856
857 auto i = static_cast<std::vector<double>::size_type>(0);
858
859 for (const auto& interp : this->propInterp_) {
860 auto basic = extractRawPVTCurve(interp, curve);
861
862 ret.emplace_back();
863 auto& pvtgraph = ret.back();
864
865 pvtgraph.mixRat.assign(basic.first.size(), this->key_[i]);
866
867 pvtgraph.press = std::move(basic.first);
868 pvtgraph.value = std::move(basic.second);
869
870 i += 1;
871 }
872
873 return ret;
874 }
875
876 std::vector<PVTGraph> saturatedStateCurve() const
877 {
878 // Uses setup appropriate for PVTO. The PVTG case must be
879 // handled in the caller.
880
881 auto curve = PVTGraph{};
882
883 curve.press.reserve(this->propInterp_.size());
884 curve.mixRat = this->key_;
885 curve.value = this->key_;
886
887 for (const auto& interp : this->propInterp_) {
888 const auto& yi = interp.independentVariable();
889
890 curve.press.push_back(yi[0]);
891 }
892
893 return { curve };
894 }
895 };
896
902 std::vector<double>
904 const ECLPhaseIndex phase);
905}} // Opm::ECLPVT
906
907#endif // OPM_ECLPVTCOMMON_HEADER_INCLUDED
const cJSON *const b
Definition: cJSON.h:251
Definition: ECLResultData.hpp:177
Definition: ECLPvtCommon.hpp:321
DenseVector & operator/=(const double rhs)
Definition: ECLPvtCommon.hpp:362
DenseVector & operator-=(const DenseVector &rhs)
Definition: ECLPvtCommon.hpp:338
DenseVector(const std::array< double, N > &other)
Definition: ECLPvtCommon.hpp:323
const std::array< double, N > & array() const
Definition: ECLPvtCommon.hpp:375
DenseVector & operator+=(const DenseVector &rhs)
Definition: ECLPvtCommon.hpp:327
DenseVector & operator*=(const double rhs)
Definition: ECLPvtCommon.hpp:349
Definition: ECLPvtCommon.hpp:459
PVTGraph getPvtCurve(const RawCurve curve) const
std::vector< double > formationVolumeFactor(const std::vector< double > &p) const
ECLPropTableRawData::ElementIterator ElemIt
Convenience type alias.
Definition: ECLPvtCommon.hpp:462
PVDx(ElemIt xBegin, ElemIt xEnd, const ConvertUnits &convert, std::vector< ElemIt > &colIt)
std::vector< double > viscosity(const std::vector< double > &p) const
Definition: ECLPvtCommon.hpp:584
PVTx(std::vector< double > key, std::vector< SubtableInterpolant > propInterp)
Definition: ECLPvtCommon.hpp:586
std::vector< double > viscosity(const PrimaryKey &key, const InnerVariate &x) const
Definition: ECLPvtCommon.hpp:636
std::vector< double > formationVolumeFactor(const PrimaryKey &key, const InnerVariate &x) const
Definition: ECLPvtCommon.hpp:617
std::vector< PVTGraph > getPvtCurve(const RawCurve curve) const
Definition: ECLPvtCommon.hpp:687
Definition: ECLPiecewiseLinearInterpolant.hpp:52
std::vector< double > resultVariable(const std::size_t col) const
Definition: ECLPiecewiseLinearInterpolant.hpp:181
const std::vector< double > & independentVariable() const
Retrieve abscissas of interpolant's independent variate.
Definition: ECLPiecewiseLinearInterpolant.hpp:168
LocalInterpPoint classifyPoint(const double x) const
Definition: ECLPiecewiseLinearInterpolant.hpp:123
not_this_one begin(...)
DenseVector< N > operator-(DenseVector< N > u, const DenseVector< N > &v)
Definition: ECLPvtCommon.hpp:409
RawCurve
Definition: ECLPvtCommon.hpp:293
@ SaturatedState
Enveloping curve for saturated state (wet gas or live oil)
@ FVF
Formation volume factor (B_\alpha)
std::vector< double > surfaceMassDensity(const ECLInitFileData &init, const ECLPhaseIndex phase)
DenseVector< N > operator+(DenseVector< N > u, const DenseVector< N > &v)
Definition: ECLPvtCommon.hpp:403
DenseVector< N > operator/(DenseVector< N > v, const double a)
Definition: ECLPvtCommon.hpp:385
FlowDiagnostics::Graph extractRawPVTCurve(const Interp1D::PiecewisePolynomial::Linear< Extrapolation, IsAscendingRange > &interpolant, const RawCurve curve)
Definition: ECLPvtCommon.hpp:416
DenseVector< N > operator*(const double a, DenseVector< N > v)
Definition: ECLPvtCommon.hpp:391
std::pair< std::vector< double >, std::vector< double > > Graph
Definition: DerivedQuantities.hpp:37
std::function< double(double, double)> function
Definition: Operate.hpp:28
std::vector< double > init(const std::string &kewyord, const TableManager &tables, const Phases &phases, const std::vector< double > &cell_depth, const std::vector< int > &num, const std::vector< int > &endnum)
Definition: A.hpp:4
ECLPhaseIndex
Definition: ECLPhaseIndex.hpp:28
@ end
Definition: ActionValue.hpp:20
static const double pi
Definition: exprtk.hpp:759
x y t t *t x y t t t x y t t t x *y t *t t x *y t *t t x y t t t x y t t t t(t+t)") define_sfop3(16
x y t t *t x y t t t x y t t t x *y t *t t x *y t *t t x y t t t x y t t t x(y+z)
Definition: ECLPvtCommon.hpp:57
Converter indep
How to convert the independent variate (1st column)
Definition: ECLPvtCommon.hpp:62
std::vector< Converter > column
How to convert the dependent variates (2nd... columns).
Definition: ECLPvtCommon.hpp:65
std::function< double(const double)> Converter
Convenience type alias for a value transformation.
Definition: ECLPvtCommon.hpp:59
Definition: ECLPvtCommon.hpp:73
static ConvertUnits::Converter recipFvf(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter pressure(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfDerivVapOil(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfViscDerivVapOil(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter vapOil(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter disGas(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGas(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGasViscDerivPress(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGasDerivVapOil(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter density(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter compressibility(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGasDerivPress(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGasVisc(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfGasViscDerivVapOil(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfVisc(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfViscDerivPress(const ::Opm::ECLUnits::UnitSystem &usys)
static ConvertUnits::Converter recipFvfDerivPress(const ::Opm::ECLUnits::UnitSystem &usys)
Definition: ECLPvtCommon.hpp:70
Definition: ECLPvtCommon.hpp:308
std::vector< double > mixRat
Mixing ratio. Typically Rs or Rv.
Definition: ECLPvtCommon.hpp:313
std::vector< double > press
Pressure values.
Definition: ECLPvtCommon.hpp:310
std::vector< double > value
Definition: ECLPvtCommon.hpp:317
Definition: ECLPvtCommon.hpp:612
const std::vector< double > & data
Definition: ECLPvtCommon.hpp:613
Definition: ECLPvtCommon.hpp:607
const std::vector< double > & data
Definition: ECLPvtCommon.hpp:608
DataVector::const_iterator ElementIterator
Iterator to table elements. Must be random access.
Definition: ECLPropTable.hpp:46