VFPHelpers.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2015 SINTEF ICT, Applied Mathematics.
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 
21 #ifndef OPM_AUTODIFF_VFPHELPERS_HPP_
22 #define OPM_AUTODIFF_VFPHELPERS_HPP_
23 
24 
25 #include <opm/parser/eclipse/EclipseState/Tables/VFPProdTable.hpp>
26 #include <opm/parser/eclipse/EclipseState/Tables/VFPInjTable.hpp>
28 
29 
33 namespace Opm {
34 namespace detail {
35 
36 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
51 inline double zeroIfNan(const double& value) {
52  return (std::isnan(value)) ? 0.0 : value;
53 }
54 
55 
56 
57 
58 
62 inline ADB zeroIfNan(const ADB& values) {
64 
65  const ADB::V z = ADB::V::Zero(values.size());
66  const ADB zero = ADB::constant(z, values.blockPattern());
67 
68  ADB retval = not_nan_selector.select(values, zero);
69  return retval;
70 }
71 
72 
73 
74 
75 
81 template <typename T>
82 static T getFlo(const T& aqua, const T& liquid, const T& vapour,
83  const VFPProdTable::FLO_TYPE& type) {
84  switch (type) {
85  case VFPProdTable::FLO_OIL:
86  //Oil = liquid phase
87  return liquid;
88  case VFPProdTable::FLO_LIQ:
89  //Liquid = aqua + liquid phases
90  return aqua + liquid;
91  case VFPProdTable::FLO_GAS:
92  //Gas = vapor phase
93  return vapour;
94  case VFPProdTable::FLO_INVALID: //Intentional fall-through
95  default:
96  OPM_THROW(std::logic_error, "Invalid FLO_TYPE: '" << type << "'");
97  }
98 }
99 
100 
101 
107 template <typename T>
108 static T getFlo(const T& aqua, const T& liquid, const T& vapour,
109  const VFPInjTable::FLO_TYPE& type) {
110  switch (type) {
111  case VFPInjTable::FLO_OIL:
112  //Oil = liquid phase
113  return liquid;
114  case VFPInjTable::FLO_WAT:
115  //Liquid = aqua phase
116  return aqua;
117  case VFPInjTable::FLO_GAS:
118  //Gas = vapor phase
119  return vapour;
120  case VFPInjTable::FLO_INVALID: //Intentional fall-through
121  default:
122  OPM_THROW(std::logic_error, "Invalid FLO_TYPE: '" << type << "'");
123  }
124 }
125 
126 
127 
128 
129 
130 
131 
136 template <typename T>
137 static T getWFR(const T& aqua, const T& liquid, const T& vapour,
138  const VFPProdTable::WFR_TYPE& type) {
139  switch(type) {
140  case VFPProdTable::WFR_WOR: {
141  //Water-oil ratio = water / oil
142  T wor = aqua / liquid;
143  return zeroIfNan(wor);
144  }
145  case VFPProdTable::WFR_WCT:
146  //Water cut = water / (water + oil)
147  return zeroIfNan(aqua / (aqua + liquid));
148  case VFPProdTable::WFR_WGR:
149  //Water-gas ratio = water / gas
150  return zeroIfNan(aqua / vapour);
151  case VFPProdTable::WFR_INVALID: //Intentional fall-through
152  default:
153  OPM_THROW(std::logic_error, "Invalid WFR_TYPE: '" << type << "'");
154  }
155 }
156 
157 
158 
159 
160 
161 
166 template <typename T>
167 static T getGFR(const T& aqua, const T& liquid, const T& vapour,
168  const VFPProdTable::GFR_TYPE& type) {
169  switch(type) {
170  case VFPProdTable::GFR_GOR:
171  // Gas-oil ratio = gas / oil
172  return zeroIfNan(vapour / liquid);
173  case VFPProdTable::GFR_GLR:
174  // Gas-liquid ratio = gas / (oil + water)
175  return zeroIfNan(vapour / (liquid + aqua));
176  case VFPProdTable::GFR_OGR:
177  // Oil-gas ratio = oil / gas
178  return zeroIfNan(liquid / vapour);
179  case VFPProdTable::GFR_INVALID: //Intentional fall-through
180  default:
181  OPM_THROW(std::logic_error, "Invalid GFR_TYPE: '" << type << "'");
182  }
183 }
184 
185 
186 
187 
188 
189 
193 struct InterpData {
194  InterpData() : ind_{0, 0}, inv_dist_(0.0), factor_(0.0) {}
195  int ind_[2]; //[First element greater than or equal to value, Last element smaller than or equal to value]
196  double inv_dist_; // 1 / distance between the two end points of the segment. Used to calculate derivatives and uses 1.0 / 0.0 = 0.0 as a convention
197  double factor_; // Interpolation factor
198 };
199 
200 
201 
202 
203 
204 
211 inline InterpData findInterpData(const double& value, const std::vector<double>& values) {
212  InterpData retval;
213 
214  const int nvalues = values.size();
215 
216  //If we only have one value in our vector, return that
217  if (values.size() == 1) {
218  retval.ind_[0] = 0;
219  retval.ind_[1] = 0;
220  retval.inv_dist_ = 0.0;
221  retval.factor_ = 0.0;
222  }
223  // Else search in the vector
224  else {
225  //If value is less than all values, use first interval
226  if (value < values.front()) {
227  retval.ind_[0] = 0;
228  retval.ind_[1] = 1;
229  }
230  //If value is greater than all values, use last interval
231  else if (value >= values.back()) {
232  retval.ind_[0] = nvalues-2;
233  retval.ind_[1] = nvalues-1;
234  }
235  else {
236  //Search internal intervals
237  for (int i=1; i<nvalues; ++i) {
238  if (values[i] >= value) {
239  retval.ind_[0] = i-1;
240  retval.ind_[1] = i;
241  break;
242  }
243  }
244  }
245 
246  const double start = values[retval.ind_[0]];
247  const double end = values[retval.ind_[1]];
248 
249  //Find interpolation ratio
250  if (end > start) {
251  //FIXME: Possible source for floating point error here if value and floor are large,
252  //but very close to each other
253  retval.inv_dist_ = 1.0 / (end-start);
254  retval.factor_ = (value-start) * retval.inv_dist_;
255  }
256  else {
257  retval.inv_dist_ = 0.0;
258  retval.factor_ = 0.0;
259  }
260  }
261 
262  return retval;
263 }
264 
265 
266 
267 
268 
269 
274  VFPEvaluation() : value(0.0), dthp(0.0), dwfr(0.0), dgfr(0.0), dalq(0.0), dflo(0.0) {};
275  double value;
276  double dthp;
277  double dwfr;
278  double dgfr;
279  double dalq;
280  double dflo;
281 };
282 
284  VFPEvaluation lhs,
285  const VFPEvaluation& rhs) {
286  lhs.value += rhs.value;
287  lhs.dthp += rhs.dthp;
288  lhs.dwfr += rhs.dwfr;
289  lhs.dgfr += rhs.dgfr;
290  lhs.dalq += rhs.dalq;
291  lhs.dflo += rhs.dflo;
292  return lhs;
293 }
294 
296  VFPEvaluation lhs,
297  const VFPEvaluation& rhs) {
298  lhs.value -= rhs.value;
299  lhs.dthp -= rhs.dthp;
300  lhs.dwfr -= rhs.dwfr;
301  lhs.dgfr -= rhs.dgfr;
302  lhs.dalq -= rhs.dalq;
303  lhs.dflo -= rhs.dflo;
304  return lhs;
305 }
306 
308  double lhs,
309  const VFPEvaluation& rhs) {
310  VFPEvaluation retval;
311  retval.value = rhs.value * lhs;
312  retval.dthp = rhs.dthp * lhs;
313  retval.dwfr = rhs.dwfr * lhs;
314  retval.dgfr = rhs.dgfr * lhs;
315  retval.dalq = rhs.dalq * lhs;
316  retval.dflo = rhs.dflo * lhs;
317  return retval;
318 }
319 
320 
321 
322 
323 
324 
328 #ifdef __GNUC__
329 #pragma GCC push_options
330 #pragma GCC optimize ("unroll-loops")
331 #endif
332 
333 
335  const VFPProdTable::array_type& array,
336  const InterpData& flo_i,
337  const InterpData& thp_i,
338  const InterpData& wfr_i,
339  const InterpData& gfr_i,
340  const InterpData& alq_i) {
341 
342  //Values and derivatives in a 5D hypercube
343  VFPEvaluation nn[2][2][2][2][2];
344 
345 
346  //Pick out nearest neighbors (nn) to our evaluation point
347  //This is not really required, but performance-wise it may pay off, since the 32-elements
348  //we copy to (nn) will fit better in cache than the full original table for the
349  //interpolation below.
350  //The following ladder of for loops will presumably be unrolled by a reasonable compiler.
351  for (int t=0; t<=1; ++t) {
352  for (int w=0; w<=1; ++w) {
353  for (int g=0; g<=1; ++g) {
354  for (int a=0; a<=1; ++a) {
355  for (int f=0; f<=1; ++f) {
356  //Shorthands for indexing
357  const int ti = thp_i.ind_[t];
358  const int wi = wfr_i.ind_[w];
359  const int gi = gfr_i.ind_[g];
360  const int ai = alq_i.ind_[a];
361  const int fi = flo_i.ind_[f];
362 
363  //Copy element
364  nn[t][w][g][a][f].value = array[ti][wi][gi][ai][fi];
365  }
366  }
367  }
368  }
369  }
370 
371  //Calculate derivatives
372  //Note that the derivative of the two end points of a line aligned with the
373  //"axis of the derivative" are equal
374  for (int i=0; i<=1; ++i) {
375  for (int j=0; j<=1; ++j) {
376  for (int k=0; k<=1; ++k) {
377  for (int l=0; l<=1; ++l) {
378  nn[0][i][j][k][l].dthp = (nn[1][i][j][k][l].value - nn[0][i][j][k][l].value) * thp_i.inv_dist_;
379  nn[i][0][j][k][l].dwfr = (nn[i][1][j][k][l].value - nn[i][0][j][k][l].value) * wfr_i.inv_dist_;
380  nn[i][j][0][k][l].dgfr = (nn[i][j][1][k][l].value - nn[i][j][0][k][l].value) * gfr_i.inv_dist_;
381  nn[i][j][k][0][l].dalq = (nn[i][j][k][1][l].value - nn[i][j][k][0][l].value) * alq_i.inv_dist_;
382  nn[i][j][k][l][0].dflo = (nn[i][j][k][l][1].value - nn[i][j][k][l][0].value) * flo_i.inv_dist_;
383 
384  nn[1][i][j][k][l].dthp = nn[0][i][j][k][l].dthp;
385  nn[i][1][j][k][l].dwfr = nn[i][0][j][k][l].dwfr;
386  nn[i][j][1][k][l].dgfr = nn[i][j][0][k][l].dgfr;
387  nn[i][j][k][1][l].dalq = nn[i][j][k][0][l].dalq;
388  nn[i][j][k][l][1].dflo = nn[i][j][k][l][0].dflo;
389  }
390  }
391  }
392  }
393 
394  double t1, t2; //interpolation variables, so that t1 = (1-t) and t2 = t.
395 
396  // Remove dimensions one by one
397  // Example: going from 3D to 2D to 1D, we start by interpolating along
398  // the z axis first, leaving a 2D problem. Then interpolating along the y
399  // axis, leaving a 1D, problem, etc.
400  t2 = flo_i.factor_;
401  t1 = (1.0-t2);
402  for (int t=0; t<=1; ++t) {
403  for (int w=0; w<=1; ++w) {
404  for (int g=0; g<=1; ++g) {
405  for (int a=0; a<=1; ++a) {
406  nn[t][w][g][a][0] = t1*nn[t][w][g][a][0] + t2*nn[t][w][g][a][1];
407  }
408  }
409  }
410  }
411 
412  t2 = alq_i.factor_;
413  t1 = (1.0-t2);
414  for (int t=0; t<=1; ++t) {
415  for (int w=0; w<=1; ++w) {
416  for (int g=0; g<=1; ++g) {
417  nn[t][w][g][0][0] = t1*nn[t][w][g][0][0] + t2*nn[t][w][g][1][0];
418  }
419  }
420  }
421 
422  t2 = gfr_i.factor_;
423  t1 = (1.0-t2);
424  for (int t=0; t<=1; ++t) {
425  for (int w=0; w<=1; ++w) {
426  nn[t][w][0][0][0] = t1*nn[t][w][0][0][0] + t2*nn[t][w][1][0][0];
427  }
428  }
429 
430  t2 = wfr_i.factor_;
431  t1 = (1.0-t2);
432  for (int t=0; t<=1; ++t) {
433  nn[t][0][0][0][0] = t1*nn[t][0][0][0][0] + t2*nn[t][1][0][0][0];
434  }
435 
436  t2 = thp_i.factor_;
437  t1 = (1.0-t2);
438  nn[0][0][0][0][0] = t1*nn[0][0][0][0][0] + t2*nn[1][0][0][0][0];
439 
440  return nn[0][0][0][0][0];
441 }
442 
443 
444 
445 
446 
452  const VFPInjTable::array_type& array,
453  const InterpData& flo_i,
454  const InterpData& thp_i) {
455 
456  //Values and derivatives in a 2D plane
457  VFPEvaluation nn[2][2];
458 
459 
460  //Pick out nearest neighbors (nn) to our evaluation point
461  //The following ladder of for loops will presumably be unrolled by a reasonable compiler.
462  for (int t=0; t<=1; ++t) {
463  for (int f=0; f<=1; ++f) {
464  //Shorthands for indexing
465  const int ti = thp_i.ind_[t];
466  const int fi = flo_i.ind_[f];
467 
468  //Copy element
469  nn[t][f].value = array[ti][fi];
470  }
471  }
472 
473  //Calculate derivatives
474  //Note that the derivative of the two end points of a line aligned with the
475  //"axis of the derivative" are equal
476  for (int i=0; i<=1; ++i) {
477  nn[0][i].dthp = (nn[1][i].value - nn[0][i].value) * thp_i.inv_dist_;
478  nn[i][0].dwfr = -1e100;
479  nn[i][0].dgfr = -1e100;
480  nn[i][0].dalq = -1e100;
481  nn[i][0].dflo = (nn[i][1].value - nn[i][0].value) * flo_i.inv_dist_;
482 
483  nn[1][i].dthp = nn[0][i].dthp;
484  nn[i][1].dwfr = nn[i][0].dwfr;
485  nn[i][1].dgfr = nn[i][0].dgfr;
486  nn[i][1].dalq = nn[i][0].dalq;
487  nn[i][1].dflo = nn[i][0].dflo;
488  }
489 
490  double t1, t2; //interpolation variables, so that t1 = (1-t) and t2 = t.
491 
492  // Go from 2D to 1D
493  t2 = flo_i.factor_;
494  t1 = (1.0-t2);
495  nn[0][0] = t1*nn[0][0] + t2*nn[0][1];
496  nn[1][0] = t1*nn[1][0] + t2*nn[1][1];
497 
498  // Go from line to point on line
499  t2 = thp_i.factor_;
500  t1 = (1.0-t2);
501  nn[0][0] = t1*nn[0][0] + t2*nn[1][0];
502 
503  return nn[0][0];
504 }
505 
506 
507 
508 
509 #ifdef __GNUC__
510 #pragma GCC pop_options //unroll loops
511 #endif
512 
513 
514 
515 
516 
517 inline VFPEvaluation bhp(const VFPProdTable* table,
518  const double& aqua,
519  const double& liquid,
520  const double& vapour,
521  const double& thp,
522  const double& alq) {
523  //Find interpolation variables
524  double flo = detail::getFlo(aqua, liquid, vapour, table->getFloType());
525  double wfr = detail::getWFR(aqua, liquid, vapour, table->getWFRType());
526  double gfr = detail::getGFR(aqua, liquid, vapour, table->getGFRType());
527 
528  //First, find the values to interpolate between
529  //Recall that flo is negative in Opm, so switch sign.
530  auto flo_i = detail::findInterpData(-flo, table->getFloAxis());
531  auto thp_i = detail::findInterpData( thp, table->getTHPAxis());
532  auto wfr_i = detail::findInterpData( wfr, table->getWFRAxis());
533  auto gfr_i = detail::findInterpData( gfr, table->getGFRAxis());
534  auto alq_i = detail::findInterpData( alq, table->getALQAxis());
535 
536  detail::VFPEvaluation retval = detail::interpolate(table->getTable(), flo_i, thp_i, wfr_i, gfr_i, alq_i);
537 
538  return retval;
539 }
540 
541 
542 
543 
544 
545 inline VFPEvaluation bhp(const VFPInjTable* table,
546  const double& aqua,
547  const double& liquid,
548  const double& vapour,
549  const double& thp) {
550  //Find interpolation variables
551  double flo = detail::getFlo(aqua, liquid, vapour, table->getFloType());
552 
553  //First, find the values to interpolate between
554  auto flo_i = detail::findInterpData(flo, table->getFloAxis());
555  auto thp_i = detail::findInterpData(thp, table->getTHPAxis());
556 
557  //Then perform the interpolation itself
558  detail::VFPEvaluation retval = detail::interpolate(table->getTable(), flo_i, thp_i);
559 
560  return retval;
561 }
562 
563 
564 
565 
566 
567 
568 
569 
573 template <typename T>
574 const T* getTable(const std::map<int, T*> tables, int table_id) {
575  auto entry = tables.find(table_id);
576  if (entry == tables.end()) {
577  OPM_THROW(std::invalid_argument, "Nonexistent table " << table_id << " referenced.");
578  }
579  else {
580  return entry->second;
581  }
582 }
583 
584 
585 
586 
587 
588 
589 
590 
591 
592 
596 inline void extendBlockPattern(const ADB& x, std::vector<int>& block_pattern) {
597  std::vector<int> x_block_pattern = x.blockPattern();
598 
599  if (x_block_pattern.empty()) {
600  return;
601  }
602  else {
603  if (block_pattern.empty()) {
604  block_pattern = x_block_pattern;
605  return;
606  }
607  else {
608  if (x_block_pattern != block_pattern) {
609  OPM_THROW(std::logic_error, "Block patterns do not match");
610  }
611  }
612  }
613 }
614 
618 inline std::vector<int> commonBlockPattern(
619  const ADB& x1,
620  const ADB& x2,
621  const ADB& x3,
622  const ADB& x4) {
623  std::vector<int> block_pattern;
624 
625  extendBlockPattern(x1, block_pattern);
626  extendBlockPattern(x2, block_pattern);
627  extendBlockPattern(x3, block_pattern);
628  extendBlockPattern(x4, block_pattern);
629 
630  return block_pattern;
631 }
632 
633 inline std::vector<int> commonBlockPattern(
634  const ADB& x1,
635  const ADB& x2,
636  const ADB& x3,
637  const ADB& x4,
638  const ADB& x5) {
639  std::vector<int> block_pattern = commonBlockPattern(x1, x2, x3, x4);
640  extendBlockPattern(x5, block_pattern);
641 
642  return block_pattern;
643 }
644 
645 
646 
647 
648 
649 
650 
651 
652 
653 
654 
655 
659 template <typename TYPE, typename TABLE>
660 TYPE getType(const TABLE* table);
661 
662 template <>
663 inline
664 VFPProdTable::FLO_TYPE getType(const VFPProdTable* table) {
665  return table->getFloType();
666 }
667 
668 template <>
669 inline
670 VFPProdTable::WFR_TYPE getType(const VFPProdTable* table) {
671  return table->getWFRType();
672 }
673 
674 template <>
675 inline
676 VFPProdTable::GFR_TYPE getType(const VFPProdTable* table) {
677  return table->getGFRType();
678 }
679 
680 
684 template <>
685 inline
686 VFPInjTable::FLO_TYPE getType(const VFPInjTable* table) {
687  return table->getFloType();
688 }
689 
690 
691 
692 
696 template <typename TYPE>
697 ADB getValue(
698  const ADB& aqua,
699  const ADB& liquid,
700  const ADB& vapour, TYPE type);
701 
702 template <>
703 inline
705  const ADB& aqua,
706  const ADB& liquid,
707  const ADB& vapour,
708  VFPProdTable::FLO_TYPE type) {
709  return detail::getFlo(aqua, liquid, vapour, type);
710 }
711 
712 template <>
713 inline
715  const ADB& aqua,
716  const ADB& liquid,
717  const ADB& vapour,
718  VFPProdTable::WFR_TYPE type) {
719  return detail::getWFR(aqua, liquid, vapour, type);
720 }
721 
722 template <>
723 inline
725  const ADB& aqua,
726  const ADB& liquid,
727  const ADB& vapour,
728  VFPProdTable::GFR_TYPE type) {
729  return detail::getGFR(aqua, liquid, vapour, type);
730 }
731 
732 template <>
733 inline
735  const ADB& aqua,
736  const ADB& liquid,
737  const ADB& vapour,
738  VFPInjTable::FLO_TYPE type) {
739  return detail::getFlo(aqua, liquid, vapour, type);
740 }
741 
749 template <typename TYPE, typename TABLE>
750 ADB combineADBVars(const std::vector<const TABLE*>& well_tables,
751  const ADB& aqua,
752  const ADB& liquid,
753  const ADB& vapour) {
754 
755  const int num_wells = static_cast<int>(well_tables.size());
756  assert(aqua.size() == num_wells);
757  assert(liquid.size() == num_wells);
758  assert(vapour.size() == num_wells);
759 
760  //Caching variable for flo/wfr/gfr
761  std::map<TYPE, ADB> map;
762 
763  //Indexing variable used when combining the different ADB types
764  std::map<TYPE, std::vector<int> > elems;
765 
766  //Compute all of the different ADB types,
767  //and record which wells use which types
768  for (int i=0; i<num_wells; ++i) {
769  const TABLE* table = well_tables[i];
770 
771  //Only do something if this well is under THP control
772  if (table != NULL) {
773  TYPE type = getType<TYPE>(table);
774 
775  //"Caching" of flo_type etc: Only calculate used types
776  //Create type if it does not exist
777  if (map.find(type) == map.end()) {
778  map.insert(std::pair<TYPE, ADB>(
779  type,
780  detail::getValue<TYPE>(aqua, liquid, vapour, type)
781  ));
782  }
783 
784  //Add the index for assembly later in gather_vars
785  elems[type].push_back(i);
786  }
787  }
788 
789  //Loop over all types of ADB variables, and combine them
790  //so that each well gets the proper variable
791  ADB retval = ADB::constant(ADB::V::Zero(num_wells));
792  for (const auto& entry : elems) {
793  const auto& key = entry.first;
794  const auto& value = entry.second;
795 
796  //Get the ADB for this type of variable
797  assert(map.find(key) != map.end());
798  const ADB& values = map.find(key)->second;
799 
800  //Get indices to all elements that should use this ADB
801  const std::vector<int>& current = value;
802 
803  //Add these elements to retval
804  retval = retval + superset(subset(values, current), current, values.size());
805  }
806 
807  return retval;
808 }
809 
814 inline double findX(const double& x0,
815  const double& x1,
816  const double& y0,
817  const double& y1,
818  const double& y) {
819  const double dx = x1 - x0;
820  const double dy = y1 - y0;
821 
829  double x = 0.0;
830 
831  if (dy != 0.0) {
832  x = x0 + (y-y0) * (dx/dy);
833  }
834  else {
835  x = x1;
836  }
837 
838  return x;
839 }
840 
841 
842 
843 
844 
845 
846 
847 
848 
849 
856 inline double findTHP(
857  const std::vector<double>& bhp_array,
858  const std::vector<double>& thp_array,
859  double bhp) {
860  int nthp = thp_array.size();
861 
862  double thp = -1e100;
863 
864  //Check that our thp axis is sorted
865  assert(std::is_sorted(thp_array.begin(), thp_array.end()));
866 
873  if (std::is_sorted(bhp_array.begin(), bhp_array.end())) {
874  //Target bhp less than all values in array, extrapolate
875  if (bhp <= bhp_array[0]) {
876  //TODO: LOG extrapolation
877  const double& x0 = thp_array[0];
878  const double& x1 = thp_array[1];
879  const double& y0 = bhp_array[0];
880  const double& y1 = bhp_array[1];
881  thp = detail::findX(x0, x1, y0, y1, bhp);
882  }
883  //Target bhp greater than all values in array, extrapolate
884  else if (bhp > bhp_array[nthp-1]) {
885  //TODO: LOG extrapolation
886  const double& x0 = thp_array[nthp-2];
887  const double& x1 = thp_array[nthp-1];
888  const double& y0 = bhp_array[nthp-2];
889  const double& y1 = bhp_array[nthp-1];
890  thp = detail::findX(x0, x1, y0, y1, bhp);
891  }
892  //Target bhp within table ranges, interpolate
893  else {
894  //Loop over the values and find min(bhp_array(thp)) == bhp
895  //so that we maximize the rate.
896 
897  //Find i so that bhp_array[i-1] <= bhp <= bhp_array[i];
898  //Assuming a small number of values in bhp_array, this should be quite
899  //efficient. Other strategies might be bisection, etc.
900  int i=0;
901  bool found = false;
902  for (; i<nthp-1; ++i) {
903  const double& y0 = bhp_array[i ];
904  const double& y1 = bhp_array[i+1];
905 
906  if (y0 < bhp && bhp <= y1) {
907  found = true;
908  break;
909  }
910  }
911  //Canary in a coal mine: shouldn't really be required
912  assert(found == true);
913  static_cast<void>(found); //Silence compiler warning
914 
915  const double& x0 = thp_array[i ];
916  const double& x1 = thp_array[i+1];
917  const double& y0 = bhp_array[i ];
918  const double& y1 = bhp_array[i+1];
919  thp = detail::findX(x0, x1, y0, y1, bhp);
920  }
921  }
922  //bhp_array not sorted, raw search.
923  else {
924  //Find i so that bhp_array[i-1] <= bhp <= bhp_array[i];
925  //Since the BHP values might not be sorted, first search within
926  //our interpolation values, and then try to extrapolate.
927  int i=0;
928  bool found = false;
929  for (; i<nthp-1; ++i) {
930  const double& y0 = bhp_array[i ];
931  const double& y1 = bhp_array[i+1];
932 
933  if (y0 < bhp && bhp <= y1) {
934  found = true;
935  break;
936  }
937  }
938  if (found) {
939  const double& x0 = thp_array[i ];
940  const double& x1 = thp_array[i+1];
941  const double& y0 = bhp_array[i ];
942  const double& y1 = bhp_array[i+1];
943  thp = detail::findX(x0, x1, y0, y1, bhp);
944  }
945  else if (bhp <= bhp_array[0]) {
946  //TODO: LOG extrapolation
947  const double& x0 = thp_array[0];
948  const double& x1 = thp_array[1];
949  const double& y0 = bhp_array[0];
950  const double& y1 = bhp_array[1];
951  thp = detail::findX(x0, x1, y0, y1, bhp);
952  }
953  //Target bhp greater than all values in array, extrapolate
954  else if (bhp > bhp_array[nthp-1]) {
955  //TODO: LOG extrapolation
956  const double& x0 = thp_array[nthp-2];
957  const double& x1 = thp_array[nthp-1];
958  const double& y0 = bhp_array[nthp-2];
959  const double& y1 = bhp_array[nthp-1];
960  thp = detail::findX(x0, x1, y0, y1, bhp);
961  }
962  else {
963  OPM_THROW(std::logic_error, "Programmer error: Unable to find THP in THP array");
964  }
965  }
966 
967  return thp;
968 }
969 
970 
971 
972 
973 
974 
975 
976 } // namespace detail
977 
978 
979 } // namespace
980 
981 
982 
983 
984 #endif /* OPM_AUTODIFF_VFPHELPERS_HPP_ */
VFPEvaluation bhp(const VFPProdTable *table, const double &aqua, const double &liquid, const double &vapour, const double &thp, const double &alq)
Definition: VFPHelpers.hpp:517
static T getWFR(const T &aqua, const T &liquid, const T &vapour, const VFPProdTable::WFR_TYPE &type)
Definition: VFPHelpers.hpp:137
Eigen::Array< Scalar, Eigen::Dynamic, 1 > subset(const Eigen::Array< Scalar, Eigen::Dynamic, 1 > &x, const IntVec &indices)
Returns x(indices).
Definition: AutoDiffHelpers.hpp:287
double inv_dist_
Definition: VFPHelpers.hpp:196
Eigen::Array< Scalar, Eigen::Dynamic, 1 > V
Underlying type for values.
Definition: AutoDiffBlock.hpp:98
Definition: AdditionalObjectDeleter.hpp:22
std::vector< int > blockPattern() const
Sizes (number of columns) of Jacobian blocks.
Definition: AutoDiffBlock.hpp:425
VFPEvaluation interpolate(const VFPProdTable::array_type &array, const InterpData &flo_i, const InterpData &thp_i, const InterpData &wfr_i, const InterpData &gfr_i, const InterpData &alq_i)
Definition: VFPHelpers.hpp:334
int ind_[2]
Definition: VFPHelpers.hpp:195
std::vector< int > commonBlockPattern(const ADB &x1, const ADB &x2, const ADB &x3, const ADB &x4)
Definition: VFPHelpers.hpp:618
double zeroIfNan(const double &value)
Definition: VFPHelpers.hpp:51
static T getGFR(const T &aqua, const T &liquid, const T &vapour, const VFPProdTable::GFR_TYPE &type)
Definition: VFPHelpers.hpp:167
Selection. Choose first of two elements if selection basis element is nonnegative.
Definition: AutoDiffHelpers.hpp:359
InterpData findInterpData(const double &value, const std::vector< double > &values)
Definition: VFPHelpers.hpp:211
double dthp
Definition: VFPHelpers.hpp:276
int size() const
Number of elements.
Definition: AutoDiffBlock.hpp:413
TYPE getType(const TABLE *table)
AutoDiffBlock< Scalar > superset(const AutoDiffBlock< Scalar > &x, const IntVec &indices, const int n)
Returns v where v(indices) == x, v(!indices) == 0 and v.size() == n.
Definition: AutoDiffHelpers.hpp:314
static T getFlo(const T &aqua, const T &liquid, const T &vapour, const VFPProdTable::FLO_TYPE &type)
Definition: VFPHelpers.hpp:82
double findTHP(const std::vector< double > &bhp_array, const std::vector< double > &thp_array, double bhp)
Definition: VFPHelpers.hpp:856
static AutoDiffBlock constant(V &&val)
Definition: AutoDiffBlock.hpp:110
InterpData()
Definition: VFPHelpers.hpp:194
double dalq
Definition: VFPHelpers.hpp:279
ADB combineADBVars(const std::vector< const TABLE * > &well_tables, const ADB &aqua, const ADB &liquid, const ADB &vapour)
Definition: VFPHelpers.hpp:750
Definition: VFPHelpers.hpp:273
void extendBlockPattern(const ADB &x, std::vector< int > &block_pattern)
Definition: VFPHelpers.hpp:596
double dgfr
Definition: VFPHelpers.hpp:278
double findX(const double &x0, const double &x1, const double &y0, const double &y1, const double &y)
Definition: VFPHelpers.hpp:814
double value
Definition: VFPHelpers.hpp:274
VFPEvaluation operator*(double lhs, const VFPEvaluation &rhs)
Definition: VFPHelpers.hpp:307
ADB getValue(const ADB &aqua, const ADB &liquid, const ADB &vapour, TYPE type)
Definition: VFPHelpers.hpp:193
VFPEvaluation operator-(VFPEvaluation lhs, const VFPEvaluation &rhs)
Definition: VFPHelpers.hpp:295
const V & value() const
Function value.
Definition: AutoDiffBlock.hpp:436
const T * getTable(const std::map< int, T * > tables, int table_id)
Definition: VFPHelpers.hpp:574
AutoDiffBlock< double > ADB
Definition: VFPHelpers.hpp:37
double factor_
Definition: VFPHelpers.hpp:197
VFPEvaluation operator+(VFPEvaluation lhs, const VFPEvaluation &rhs)
Definition: VFPHelpers.hpp:283
VFPEvaluation()
Definition: VFPHelpers.hpp:274
double dwfr
Definition: VFPHelpers.hpp:277
double dflo
Definition: VFPHelpers.hpp:280