BlackoilModelBase_impl.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2013, 2015 SINTEF ICT, Applied Mathematics.
3  Copyright 2014, 2015 Dr. Blatt - HPC-Simulation-Software & Services
4  Copyright 2014, 2015 Statoil ASA.
5  Copyright 2015 NTNU
6  Copyright 2015 IRIS AS
7 
8  This file is part of the Open Porous Media project (OPM).
9 
10  OPM is free software: you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation, either version 3 of the License, or
13  (at your option) any later version.
14 
15  OPM is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU General Public License for more details.
19 
20  You should have received a copy of the GNU General Public License
21  along with OPM. If not, see <http://www.gnu.org/licenses/>.
22 */
23 
24 #ifndef OPM_BLACKOILMODELBASE_IMPL_HEADER_INCLUDED
25 #define OPM_BLACKOILMODELBASE_IMPL_HEADER_INCLUDED
26 
28 
38 
39 #include <opm/core/grid.h>
40 #include <opm/core/linalg/LinearSolverInterface.hpp>
41 #include <opm/core/linalg/ParallelIstlInformation.hpp>
42 #include <opm/core/props/rock/RockCompressibility.hpp>
43 #include <opm/common/ErrorMacros.hpp>
44 #include <opm/common/Exceptions.hpp>
45 #include <opm/core/utility/Units.hpp>
46 #include <opm/core/well_controls.h>
47 #include <opm/core/utility/parameters/ParameterGroup.hpp>
48 #include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
49 
50 #include <cassert>
51 #include <cmath>
52 #include <iostream>
53 #include <iomanip>
54 #include <limits>
55 #include <vector>
56 //#include <fstream>
57 
58 // A debugging utility.
59 #define OPM_AD_DUMP(foo) \
60  do { \
61  std::cout << "==========================================\n" \
62  << #foo ":\n" \
63  << collapseJacs(foo) << std::endl; \
64  } while (0)
65 
66 #define OPM_AD_DUMPVAL(foo) \
67  do { \
68  std::cout << "==========================================\n" \
69  << #foo ":\n" \
70  << foo.value() << std::endl; \
71  } while (0)
72 
73 #define OPM_AD_DISKVAL(foo) \
74  do { \
75  std::ofstream os(#foo); \
76  os.precision(16); \
77  os << foo.value() << std::endl; \
78  } while (0)
79 
80 
81 namespace Opm {
82 
84 typedef ADB::V V;
85 typedef ADB::M M;
86 typedef Eigen::Array<double,
87  Eigen::Dynamic,
88  Eigen::Dynamic,
89  Eigen::RowMajor> DataBlock;
90 
91 
92 namespace detail {
93 
94 
95  inline
96  std::vector<int>
97  buildAllCells(const int nc)
98  {
99  std::vector<int> all_cells(nc);
100 
101  for (int c = 0; c < nc; ++c) { all_cells[c] = c; }
102 
103  return all_cells;
104  }
105 
106 
107 
108  template <class PU>
109  std::vector<bool>
110  activePhases(const PU& pu)
111  {
112  const int maxnp = Opm::BlackoilPhases::MaxNumPhases;
113  std::vector<bool> active(maxnp, false);
114 
115  for (int p = 0; p < pu.MaxNumPhases; ++p) {
116  active[ p ] = pu.phase_used[ p ] != 0;
117  }
118 
119  return active;
120  }
121 
122 
123 
124  template <class PU>
125  std::vector<int>
126  active2Canonical(const PU& pu)
127  {
128  const int maxnp = Opm::BlackoilPhases::MaxNumPhases;
129  std::vector<int> act2can(maxnp, -1);
130 
131  for (int phase = 0; phase < maxnp; ++phase) {
132  if (pu.phase_used[ phase ]) {
133  act2can[ pu.phase_pos[ phase ] ] = phase;
134  }
135  }
136 
137  return act2can;
138  }
139 
140 } // namespace detail
141 
142 
143  template <class Grid, class Implementation>
146  const Grid& grid ,
147  const BlackoilPropsAdInterface& fluid,
148  const DerivedGeology& geo ,
149  const RockCompressibility* rock_comp_props,
150  const Wells* wells_arg,
151  const NewtonIterationBlackoilInterface& linsolver,
152  Opm::EclipseStateConstPtr eclState,
153  const bool has_disgas,
154  const bool has_vapoil,
155  const bool terminal_output)
156  : grid_ (grid)
157  , fluid_ (fluid)
158  , geo_ (geo)
159  , rock_comp_props_(rock_comp_props)
160  , wells_ (wells_arg)
161  , vfp_properties_(eclState->getTableManager()->getVFPInjTables(), eclState->getTableManager()->getVFPProdTables())
162  , linsolver_ (linsolver)
163  , active_(detail::activePhases(fluid.phaseUsage()))
164  , canph_ (detail::active2Canonical(fluid.phaseUsage()))
165  , cells_ (detail::buildAllCells(Opm::AutoDiffGrid::numCells(grid)))
166  , ops_ (grid, eclState)
167  , wops_ (wells_)
168  , has_disgas_(has_disgas)
169  , has_vapoil_(has_vapoil)
170  , param_( param )
171  , use_threshold_pressure_(false)
172  , rq_ (fluid.numPhases())
173  , phaseCondition_(AutoDiffGrid::numCells(grid))
174  , isRs_(V::Zero(AutoDiffGrid::numCells(grid)))
175  , isRv_(V::Zero(AutoDiffGrid::numCells(grid)))
176  , isSg_(V::Zero(AutoDiffGrid::numCells(grid)))
177  , residual_ ( { std::vector<ADB>(fluid.numPhases(), ADB::null()),
178  ADB::null(),
179  ADB::null(),
180  { 1.1169, 1.0031, 0.0031 }} ) // the default magic numbers
181  , terminal_output_ (terminal_output)
182  , material_name_{ "Water", "Oil", "Gas" }
183  {
184  assert(numMaterials() == 3); // Due to the material_name_ init above.
185 #if HAVE_MPI
186  if ( linsolver_.parallelInformation().type() == typeid(ParallelISTLInformation) )
187  {
188  const ParallelISTLInformation& info =
189  boost::any_cast<const ParallelISTLInformation&>(linsolver_.parallelInformation());
190  if ( terminal_output_ ) {
191  // Only rank 0 does print to std::cout if terminal_output is enabled
192  terminal_output_ = (info.communicator().rank()==0);
193  }
194  int local_number_of_wells = wells_ ? wells_->number_of_wells : 0;
195  int global_number_of_wells = info.communicator().sum(local_number_of_wells);
196  wells_active_ = ( wells_ && global_number_of_wells > 0 );
197  }else
198  {
199  wells_active_ = ( wells_ && wells_->number_of_wells > 0 );
200  }
201 #else
202  wells_active_ = ( wells_ && wells_->number_of_wells > 0 );
203 #endif
204  }
205 
206 
207 
208 
209 
210  template <class Grid, class Implementation>
211  void
213  prepareStep(const double dt,
214  ReservoirState& reservoir_state,
215  WellState& /* well_state */)
216  {
217  pvdt_ = geo_.poreVolume() / dt;
218  if (active_[Gas]) {
219  updatePrimalVariableFromState(reservoir_state);
220  }
221  }
222 
223 
224 
225 
226 
227  template <class Grid, class Implementation>
228  void
230  afterStep(const double /* dt */,
231  ReservoirState& /* reservoir_state */,
232  WellState& /* well_state */)
233  {
234  // Does nothing in this model.
235  }
236 
237 
238 
239 
240 
241  template <class Grid, class Implementation>
242  int
245  {
246  return residual_.sizeNonLinear();
247  }
248 
249 
250 
251 
252 
253  template <class Grid, class Implementation>
254  int
257  {
258  return linsolver_.iterations();
259  }
260 
261 
262 
263 
264 
265  template <class Grid, class Implementation>
266  bool
269  {
270  return terminal_output_;
271  }
272 
273 
274 
275 
276 
277  template <class Grid, class Implementation>
278  int
280  numPhases() const
281  {
282  return fluid_.numPhases();
283  }
284 
285 
286 
287 
288 
289  template <class Grid, class Implementation>
290  int
293  {
294  return material_name_.size();
295  }
296 
297 
298 
299 
300 
301  template <class Grid, class Implementation>
302  const std::string&
304  materialName(int material_index) const
305  {
306  assert(material_index < numMaterials());
307  return material_name_[material_index];
308  }
309 
310 
311 
312 
313 
314  template <class Grid, class Implementation>
315  void
317  setThresholdPressures(const std::vector<double>& threshold_pressures_by_face)
318  {
319  const int num_faces = AutoDiffGrid::numFaces(grid_);
320  if (int(threshold_pressures_by_face.size()) != num_faces) {
321  OPM_THROW(std::runtime_error, "Illegal size of threshold_pressures_by_face input, must be equal to number of faces.");
322  }
323  use_threshold_pressure_ = true;
324  // Map to interior faces.
325  const int num_ifaces = ops_.internal_faces.size();
326  threshold_pressures_by_interior_face_.resize(num_ifaces);
327  for (int ii = 0; ii < num_ifaces; ++ii) {
328  threshold_pressures_by_interior_face_[ii] = threshold_pressures_by_face[ops_.internal_faces[ii]];
329  }
330  }
331 
332 
333 
334 
335 
336  template <class Grid, class Implementation>
338  : accum(2, ADB::null())
339  , mflux( ADB::null())
340  , b ( ADB::null())
341  , dh ( ADB::null())
342  , mob ( ADB::null())
343  {
344  }
345 
346 
347 
348 
349 
350  template <class Grid, class Implementation>
353  : w2p(),
354  p2w()
355  {
356  if( wells )
357  {
358  w2p = Eigen::SparseMatrix<double>(wells->well_connpos[ wells->number_of_wells ], wells->number_of_wells);
359  p2w = Eigen::SparseMatrix<double>(wells->number_of_wells, wells->well_connpos[ wells->number_of_wells ]);
360 
361  const int nw = wells->number_of_wells;
362  const int* const wpos = wells->well_connpos;
363 
364  typedef Eigen::Triplet<double> Tri;
365 
366  std::vector<Tri> scatter, gather;
367  scatter.reserve(wpos[nw]);
368  gather .reserve(wpos[nw]);
369 
370  for (int w = 0, i = 0; w < nw; ++w) {
371  for (; i < wpos[ w + 1 ]; ++i) {
372  scatter.push_back(Tri(i, w, 1.0));
373  gather .push_back(Tri(w, i, 1.0));
374  }
375  }
376 
377  w2p.setFromTriplets(scatter.begin(), scatter.end());
378  p2w.setFromTriplets(gather .begin(), gather .end());
379  }
380  }
381 
382 
383 
384 
385 
386  template <class Grid, class Implementation>
387  void
389  {
390  // HACK: throw away the derivatives. this may not be the most
391  // performant way to do things, but it will make the state
392  // automatically consistent with variableState() (and doing
393  // things automatically is all the rage in this module ;)
394  state.pressure = ADB::constant(state.pressure.value());
395  state.temperature = ADB::constant(state.temperature.value());
396  state.rs = ADB::constant(state.rs.value());
397  state.rv = ADB::constant(state.rv.value());
398  const int num_phases = state.saturation.size();
399  for (int phaseIdx = 0; phaseIdx < num_phases; ++ phaseIdx) {
400  state.saturation[phaseIdx] = ADB::constant(state.saturation[phaseIdx].value());
401  }
402  state.qs = ADB::constant(state.qs.value());
403  state.bhp = ADB::constant(state.bhp.value());
404  assert(state.canonical_phase_pressures.size() == static_cast<std::size_t>(Opm::BlackoilPhases::MaxNumPhases));
405  for (int canphase = 0; canphase < Opm::BlackoilPhases::MaxNumPhases; ++canphase) {
406  ADB& pp = state.canonical_phase_pressures[canphase];
407  pp = ADB::constant(pp.value());
408  }
409  }
410 
411 
412 
413 
414 
415  template <class Grid, class Implementation>
418  const WellState& xw) const
419  {
420  std::vector<V> vars0 = asImpl().variableStateInitials(x, xw);
421  std::vector<ADB> vars = ADB::variables(vars0);
422  return asImpl().variableStateExtractVars(x, asImpl().variableStateIndices(), vars);
423  }
424 
425 
426 
427 
428 
429  template <class Grid, class Implementation>
430  std::vector<V>
432  const WellState& xw) const
433  {
434  assert(active_[ Oil ]);
435 
436  const int np = x.numPhases();
437 
438  std::vector<V> vars0;
439  // p, Sw and Rs, Rv or Sg is used as primary depending on solution conditions
440  // and bhp and Q for the wells
441  vars0.reserve(np + 1);
443  variableWellStateInitials(xw, vars0);
444  return vars0;
445  }
446 
447 
448 
449 
450 
451  template <class Grid, class Implementation>
452  void
454  {
455  using namespace Opm::AutoDiffGrid;
456  const int nc = numCells(grid_);
457  const int np = x.numPhases();
458  // Initial pressure.
459  assert (not x.pressure().empty());
460  const V p = Eigen::Map<const V>(& x.pressure()[0], nc, 1);
461  vars0.push_back(p);
462 
463  // Initial saturation.
464  assert (not x.saturation().empty());
465  const DataBlock s = Eigen::Map<const DataBlock>(& x.saturation()[0], nc, np);
466  const Opm::PhaseUsage pu = fluid_.phaseUsage();
467  // We do not handle a Water/Gas situation correctly, guard against it.
468  assert (active_[ Oil]);
469  if (active_[ Water ]) {
470  const V sw = s.col(pu.phase_pos[ Water ]);
471  vars0.push_back(sw);
472  }
473 
474  if (active_[ Gas ]) {
475  // define new primary variable xvar depending on solution condition
476  V xvar(nc);
477  const V sg = s.col(pu.phase_pos[ Gas ]);
478  const V rs = Eigen::Map<const V>(& x.gasoilratio()[0], x.gasoilratio().size());
479  const V rv = Eigen::Map<const V>(& x.rv()[0], x.rv().size());
480  xvar = isRs_*rs + isRv_*rv + isSg_*sg;
481  vars0.push_back(xvar);
482  }
483  }
484 
485 
486 
487 
488 
489  template <class Grid, class Implementation>
490  void
492  {
493  // Initial well rates.
494  if ( localWellsActive() )
495  {
496  // Need to reshuffle well rates, from phase running fastest
497  // to wells running fastest.
498  const int nw = wells().number_of_wells;
499  const int np = wells().number_of_phases;
500 
501  // The transpose() below switches the ordering.
502  const DataBlock wrates = Eigen::Map<const DataBlock>(& xw.wellRates()[0], nw, np).transpose();
503  const V qs = Eigen::Map<const V>(wrates.data(), nw*np);
504  vars0.push_back(qs);
505 
506  // Initial well bottom-hole pressure.
507  assert (not xw.bhp().empty());
508  const V bhp = Eigen::Map<const V>(& xw.bhp()[0], xw.bhp().size());
509  vars0.push_back(bhp);
510  }
511  else
512  {
513  // push null states for qs and bhp
514  vars0.push_back(V());
515  vars0.push_back(V());
516  }
517  }
518 
519 
520 
521 
522 
523  template <class Grid, class Implementation>
524  std::vector<int>
526  {
527  assert(active_[Oil]);
528  std::vector<int> indices(5, -1);
529  int next = 0;
530  indices[Pressure] = next++;
531  if (active_[Water]) {
532  indices[Sw] = next++;
533  }
534  if (active_[Gas]) {
535  indices[Xvar] = next++;
536  }
537  indices[Qs] = next++;
538  indices[Bhp] = next++;
539  assert(next == fluid_.numPhases() + 2);
540  return indices;
541  }
542 
543 
544 
545 
546  template <class Grid, class Implementation>
547  std::vector<int>
549  {
550  // Black oil model standard is 5 equation.
551  // For the pure well solve, only the well equations are picked.
552  std::vector<int> indices(5, -1);
553  int next = 0;
554  indices[Qs] = next++;
555  indices[Bhp] = next++;
556  assert(next == 2);
557  return indices;
558  }
559 
560 
561 
562 
563 
564  template <class Grid, class Implementation>
567  const std::vector<int>& indices,
568  std::vector<ADB>& vars) const
569  {
570  //using namespace Opm::AutoDiffGrid;
571  const int nc = Opm::AutoDiffGrid::numCells(grid_);
572  const Opm::PhaseUsage pu = fluid_.phaseUsage();
573 
574  SolutionState state(fluid_.numPhases());
575 
576  // Pressure.
577  state.pressure = std::move(vars[indices[Pressure]]);
578 
579  // Temperature cannot be a variable at this time (only constant).
580  const V temp = Eigen::Map<const V>(& x.temperature()[0], x.temperature().size());
581  state.temperature = ADB::constant(temp);
582 
583  // Saturations
584  {
585  ADB so = ADB::constant(V::Ones(nc, 1));
586 
587  if (active_[ Water ]) {
588  state.saturation[pu.phase_pos[ Water ]] = std::move(vars[indices[Sw]]);
589  const ADB& sw = state.saturation[pu.phase_pos[ Water ]];
590  so -= sw;
591  }
592 
593  if (active_[ Gas ]) {
594  // Define Sg Rs and Rv in terms of xvar.
595  // Xvar is only defined if gas phase is active
596  const ADB& xvar = vars[indices[Xvar]];
597  ADB& sg = state.saturation[ pu.phase_pos[ Gas ] ];
598  sg = isSg_*xvar + isRv_*so;
599  so -= sg;
600 
601  if (active_[ Oil ]) {
602  // RS and RV is only defined if both oil and gas phase are active.
603  const ADB& sw = (active_[ Water ]
604  ? state.saturation[ pu.phase_pos[ Water ] ]
605  : ADB::constant(V::Zero(nc, 1)));
606  state.canonical_phase_pressures = computePressures(state.pressure, sw, so, sg);
607  const ADB rsSat = fluidRsSat(state.canonical_phase_pressures[ Oil ], so , cells_);
608  if (has_disgas_) {
609  state.rs = (1-isRs_)*rsSat + isRs_*xvar;
610  } else {
611  state.rs = rsSat;
612  }
613  const ADB rvSat = fluidRvSat(state.canonical_phase_pressures[ Gas ], so , cells_);
614  if (has_vapoil_) {
615  state.rv = (1-isRv_)*rvSat + isRv_*xvar;
616  } else {
617  state.rv = rvSat;
618  }
619  }
620  }
621 
622  if (active_[ Oil ]) {
623  // Note that so is never a primary variable.
624  state.saturation[pu.phase_pos[ Oil ]] = std::move(so);
625  }
626  }
627  // wells
628  variableStateExtractWellsVars(indices, vars, state);
629  return state;
630  }
631 
632 
633 
634 
635 
636  template <class Grid, class Implementation>
637  void
639  std::vector<ADB>& vars,
640  SolutionState& state) const
641  {
642  // Qs.
643  state.qs = std::move(vars[indices[Qs]]);
644 
645  // Bhp.
646  state.bhp = std::move(vars[indices[Bhp]]);
647  }
648 
649 
650 
651 
652 
653  template <class Grid, class Implementation>
654  void
656  const int aix )
657  {
658  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
659 
660  const ADB& press = state.pressure;
661  const ADB& temp = state.temperature;
662  const std::vector<ADB>& sat = state.saturation;
663  const ADB& rs = state.rs;
664  const ADB& rv = state.rv;
665 
666  const std::vector<PhasePresence> cond = phaseCondition();
667 
668  const ADB pv_mult = poroMult(press);
669 
670  const int maxnp = Opm::BlackoilPhases::MaxNumPhases;
671  for (int phase = 0; phase < maxnp; ++phase) {
672  if (active_[ phase ]) {
673  const int pos = pu.phase_pos[ phase ];
674  rq_[pos].b = fluidReciprocFVF(phase, state.canonical_phase_pressures[phase], temp, rs, rv, cond);
675  rq_[pos].accum[aix] = pv_mult * rq_[pos].b * sat[pos];
676  // OPM_AD_DUMP(rq_[pos].b);
677  // OPM_AD_DUMP(rq_[pos].accum[aix]);
678  }
679  }
680 
681  if (active_[ Oil ] && active_[ Gas ]) {
682  // Account for gas dissolved in oil and vaporized oil
683  const int po = pu.phase_pos[ Oil ];
684  const int pg = pu.phase_pos[ Gas ];
685 
686  // Temporary copy to avoid contribution of dissolved gas in the vaporized oil
687  // when both dissolved gas and vaporized oil are present.
688  const ADB accum_gas_copy =rq_[pg].accum[aix];
689 
690  rq_[pg].accum[aix] += state.rs * rq_[po].accum[aix];
691  rq_[po].accum[aix] += state.rv * accum_gas_copy;
692  // OPM_AD_DUMP(rq_[pg].accum[aix]);
693  }
694  }
695 
696  namespace detail {
697  inline
698  double getGravity(const double* g, const int dim) {
699  double grav = 0.0;
700  if (g) {
701  // Guard against gravity in anything but last dimension.
702  for (int dd = 0; dd < dim - 1; ++dd) {
703  assert(g[dd] == 0.0);
704  }
705  grav = g[dim - 1];
706  }
707  return grav;
708  }
709  }
710 
711 
712 
713  template <class Grid, class Implementation>
715  const WellState& xw)
716  {
717  if( ! localWellsActive() ) return ;
718 
719  using namespace Opm::AutoDiffGrid;
720  // 1. Compute properties required by computeConnectionPressureDelta().
721  // Note that some of the complexity of this part is due to the function
722  // taking std::vector<double> arguments, and not Eigen objects.
723  const int nperf = wells().well_connpos[wells().number_of_wells];
724  const int nw = wells().number_of_wells;
725  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
726 
727  // Compute the average pressure in each well block
728  const V perf_press = Eigen::Map<const V>(xw.perfPress().data(), nperf);
729  V avg_press = perf_press*0;
730  for (int w = 0; w < nw; ++w) {
731  for (int perf = wells().well_connpos[w]; perf < wells().well_connpos[w+1]; ++perf) {
732  const double p_above = perf == wells().well_connpos[w] ? state.bhp.value()[w] : perf_press[perf - 1];
733  const double p_avg = (perf_press[perf] + p_above)/2;
734  avg_press[perf] = p_avg;
735  }
736  }
737 
738  // Use cell values for the temperature as the wells don't knows its temperature yet.
739  const ADB perf_temp = subset(state.temperature, well_cells);
740 
741  // Compute b, rsmax, rvmax values for perforations.
742  // Evaluate the properties using average well block pressures
743  // and cell values for rs, rv, phase condition and temperature.
744  const ADB avg_press_ad = ADB::constant(avg_press);
745  std::vector<PhasePresence> perf_cond(nperf);
746  const std::vector<PhasePresence>& pc = phaseCondition();
747  for (int perf = 0; perf < nperf; ++perf) {
748  perf_cond[perf] = pc[well_cells[perf]];
749  }
750  const PhaseUsage& pu = fluid_.phaseUsage();
751  DataBlock b(nperf, pu.num_phases);
752  std::vector<double> rsmax_perf(nperf, 0.0);
753  std::vector<double> rvmax_perf(nperf, 0.0);
754  if (pu.phase_used[BlackoilPhases::Aqua]) {
755  const V bw = fluid_.bWat(avg_press_ad, perf_temp, well_cells).value();
756  b.col(pu.phase_pos[BlackoilPhases::Aqua]) = bw;
757  }
758  assert(active_[Oil]);
759  const V perf_so = subset(state.saturation[pu.phase_pos[Oil]].value(), well_cells);
760  if (pu.phase_used[BlackoilPhases::Liquid]) {
761  const ADB perf_rs = subset(state.rs, well_cells);
762  const V bo = fluid_.bOil(avg_press_ad, perf_temp, perf_rs, perf_cond, well_cells).value();
763  b.col(pu.phase_pos[BlackoilPhases::Liquid]) = bo;
764  const V rssat = fluidRsSat(avg_press, perf_so, well_cells);
765  rsmax_perf.assign(rssat.data(), rssat.data() + nperf);
766  }
767  if (pu.phase_used[BlackoilPhases::Vapour]) {
768  const ADB perf_rv = subset(state.rv, well_cells);
769  const V bg = fluid_.bGas(avg_press_ad, perf_temp, perf_rv, perf_cond, well_cells).value();
770  b.col(pu.phase_pos[BlackoilPhases::Vapour]) = bg;
771  const V rvsat = fluidRvSat(avg_press, perf_so, well_cells);
772  rvmax_perf.assign(rvsat.data(), rvsat.data() + nperf);
773  }
774  // b is row major, so can just copy data.
775  std::vector<double> b_perf(b.data(), b.data() + nperf * pu.num_phases);
776  // Extract well connection depths.
777  const V depth = cellCentroidsZToEigen(grid_);
778  const V pdepth = subset(depth, well_cells);
779  std::vector<double> perf_depth(pdepth.data(), pdepth.data() + nperf);
780 
781  // Surface density.
782  DataBlock surf_dens(nperf, pu.num_phases);
783  for (int phase = 0; phase < pu.num_phases; ++ phase) {
784  surf_dens.col(phase) = V::Constant(nperf, fluid_.surfaceDensity()[pu.phase_pos[phase]]);
785  }
786 
787  std::vector<double> surf_dens_perf(surf_dens.data(), surf_dens.data() + nperf * pu.num_phases);
788 
789  // Gravity
790  double grav = detail::getGravity(geo_.gravity(), dimensions(grid_));
791 
792  // 2. Compute densities
793  std::vector<double> cd =
795  wells(), xw, fluid_.phaseUsage(),
796  b_perf, rsmax_perf, rvmax_perf, surf_dens_perf);
797 
798  // 3. Compute pressure deltas
799  std::vector<double> cdp =
801  wells(), perf_depth, cd, grav);
802 
803  // 4. Store the results
804  well_perforation_densities_ = Eigen::Map<const V>(cd.data(), nperf);
805  well_perforation_pressure_diffs_ = Eigen::Map<const V>(cdp.data(), nperf);
806  }
807 
808 
809 
810 
811 
812  template <class Grid, class Implementation>
813  void
815  assemble(const ReservoirState& reservoir_state,
816  WellState& well_state,
817  const bool initial_assembly)
818  {
819  using namespace Opm::AutoDiffGrid;
820 
821  // If we have VFP tables, we need the well connection
822  // pressures for the "simple" hydrostatic correction
823  // between well depth and vfp table depth.
824  if (isVFPActive()) {
825  SolutionState state = asImpl().variableState(reservoir_state, well_state);
826  SolutionState state0 = state;
827  asImpl().makeConstantState(state0);
828  computeWellConnectionPressures(state0, well_state);
829  }
830 
831  // Possibly switch well controls and updating well state to
832  // get reasonable initial conditions for the wells
833  updateWellControls(well_state);
834 
835  // Create the primary variables.
836  SolutionState state = asImpl().variableState(reservoir_state, well_state);
837 
838  if (initial_assembly) {
839  // Create the (constant, derivativeless) initial state.
840  SolutionState state0 = state;
841  asImpl().makeConstantState(state0);
842  // Compute initial accumulation contributions
843  // and well connection pressures.
844  asImpl().computeAccum(state0, 0);
845  computeWellConnectionPressures(state0, well_state);
846  }
847 
848  // OPM_AD_DISKVAL(state.pressure);
849  // OPM_AD_DISKVAL(state.saturation[0]);
850  // OPM_AD_DISKVAL(state.saturation[1]);
851  // OPM_AD_DISKVAL(state.saturation[2]);
852  // OPM_AD_DISKVAL(state.rs);
853  // OPM_AD_DISKVAL(state.rv);
854  // OPM_AD_DISKVAL(state.qs);
855  // OPM_AD_DISKVAL(state.bhp);
856 
857  // -------- Mass balance equations --------
858  asImpl().assembleMassBalanceEq(state);
859 
860  // -------- Well equations ----------
861 
862  if ( ! wellsActive() ) {
863  return;
864  }
865 
866  V aliveWells;
867  const int np = wells().number_of_phases;
868  std::vector<ADB> cq_s(np, ADB::null());
869 
870  const int nw = wells().number_of_wells;
871  const int nperf = wells().well_connpos[nw];
872  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
873 
874  std::vector<ADB> mob_perfcells(np, ADB::null());
875  std::vector<ADB> b_perfcells(np, ADB::null());
876  for (int phase = 0; phase < np; ++phase) {
877  mob_perfcells[phase] = subset(rq_[phase].mob, well_cells);
878  b_perfcells[phase] = subset(rq_[phase].b, well_cells);
879  }
880  if (param_.solve_welleq_initially_ && initial_assembly) {
881  // solve the well equations as a pre-processing step
882  solveWellEq(mob_perfcells, b_perfcells, state, well_state);
883  }
884 
885  asImpl().computeWellFlux(state, mob_perfcells, b_perfcells, aliveWells, cq_s);
886  asImpl().updatePerfPhaseRatesAndPressures(cq_s, state, well_state);
887  asImpl().addWellFluxEq(cq_s, state);
888  asImpl().addWellContributionToMassBalanceEq(cq_s, state, well_state);
889  addWellControlEq(state, well_state, aliveWells);
890  }
891 
892 
893 
894 
895 
896  template <class Grid, class Implementation>
897  void
900  {
901  // Compute b_p and the accumulation term b_p*s_p for each phase,
902  // except gas. For gas, we compute b_g*s_g + Rs*b_o*s_o.
903  // These quantities are stored in rq_[phase].accum[1].
904  // The corresponding accumulation terms from the start of
905  // the timestep (b^0_p*s^0_p etc.) were already computed
906  // on the initial call to assemble() and stored in rq_[phase].accum[0].
907  asImpl().computeAccum(state, 1);
908 
909  // Set up the common parts of the mass balance equations
910  // for each active phase.
911  const V transi = subset(geo_.transmissibility(), ops_.internal_faces);
912  const V trans_nnc = ops_.nnc_trans;
913  V trans_all(transi.size() + trans_nnc.size());
914  trans_all << transi, trans_nnc;
915 
916  const std::vector<ADB> kr = asImpl().computeRelPerm(state);
917 #pragma omp parallel for schedule(static)
918  for (int phaseIdx = 0; phaseIdx < fluid_.numPhases(); ++phaseIdx) {
919  asImpl().computeMassFlux(phaseIdx, trans_all, kr[canph_[phaseIdx]], state.canonical_phase_pressures[canph_[phaseIdx]], state);
920 
921  residual_.material_balance_eq[ phaseIdx ] =
922  pvdt_ * (rq_[phaseIdx].accum[1] - rq_[phaseIdx].accum[0])
923  + ops_.div*rq_[phaseIdx].mflux;
924  }
925 
926  // -------- Extra (optional) rs and rv contributions to the mass balance equations --------
927 
928  // Add the extra (flux) terms to the mass balance equations
929  // From gas dissolved in the oil phase (rs) and oil vaporized in the gas phase (rv)
930  // The extra terms in the accumulation part of the equation are already handled.
931  if (active_[ Oil ] && active_[ Gas ]) {
932  const int po = fluid_.phaseUsage().phase_pos[ Oil ];
933  const int pg = fluid_.phaseUsage().phase_pos[ Gas ];
934 
935  const UpwindSelector<double> upwindOil(grid_, ops_,
936  rq_[po].dh.value());
937  const ADB rs_face = upwindOil.select(state.rs);
938 
939  const UpwindSelector<double> upwindGas(grid_, ops_,
940  rq_[pg].dh.value());
941  const ADB rv_face = upwindGas.select(state.rv);
942 
943  residual_.material_balance_eq[ pg ] += ops_.div * (rs_face * rq_[po].mflux);
944  residual_.material_balance_eq[ po ] += ops_.div * (rv_face * rq_[pg].mflux);
945 
946  // OPM_AD_DUMP(residual_.material_balance_eq[ Gas ]);
947 
948  }
949 
950 
951  if (param_.update_equations_scaling_) {
952  asImpl().updateEquationsScaling();
953  }
954 
955  }
956 
957 
958 
959 
960 
961  template <class Grid, class Implementation>
962  void
964  ADB::V B;
965  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
966  for ( int idx=0; idx<MaxNumPhases; ++idx )
967  {
968  if (active_[idx]) {
969  const int pos = pu.phase_pos[idx];
970  const ADB& temp_b = rq_[pos].b;
971  B = 1. / temp_b.value();
972  residual_.matbalscale[idx] = B.mean();
973  }
974  }
975  }
976 
977 
978 
979 
980 
981  template <class Grid, class Implementation>
982  void
984  const SolutionState&,
985  const WellState&)
986  {
987  // Add well contributions to mass balance equations
988  const int nc = Opm::AutoDiffGrid::numCells(grid_);
989  const int nw = wells().number_of_wells;
990  const int nperf = wells().well_connpos[nw];
991  const int np = wells().number_of_phases;
992  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
993  for (int phase = 0; phase < np; ++phase) {
994  residual_.material_balance_eq[phase] -= superset(cq_s[phase], well_cells, nc);
995  }
996  }
997 
998 
999 
1000 
1001  template <class Grid, class Implementation>
1002  void
1004  const std::vector<ADB>& mob_perfcells,
1005  const std::vector<ADB>& b_perfcells,
1006  V& aliveWells,
1007  std::vector<ADB>& cq_s)
1008  {
1009  if( ! localWellsActive() ) return ;
1010 
1011  const int np = wells().number_of_phases;
1012  const int nw = wells().number_of_wells;
1013  const int nperf = wells().well_connpos[nw];
1014  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
1015  V Tw = Eigen::Map<const V>(wells().WI, nperf);
1016  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
1017 
1018  // pressure diffs computed already (once per step, not changing per iteration)
1019  const V& cdp = well_perforation_pressure_diffs_;
1020  // Extract needed quantities for the perforation cells
1021  const ADB& p_perfcells = subset(state.pressure, well_cells);
1022  const ADB& rv_perfcells = subset(state.rv, well_cells);
1023  const ADB& rs_perfcells = subset(state.rs, well_cells);
1024 
1025  // Perforation pressure
1026  const ADB perfpressure = (wops_.w2p * state.bhp) + cdp;
1027 
1028  // Pressure drawdown (also used to determine direction of flow)
1029  const ADB drawdown = p_perfcells - perfpressure;
1030 
1031  // Compute vectors with zero and ones that
1032  // selects the wanted quantities.
1033 
1034  // selects injection perforations
1035  V selectInjectingPerforations = V::Zero(nperf);
1036  // selects producing perforations
1037  V selectProducingPerforations = V::Zero(nperf);
1038  for (int c = 0; c < nperf; ++c){
1039  if (drawdown.value()[c] < 0)
1040  selectInjectingPerforations[c] = 1;
1041  else
1042  selectProducingPerforations[c] = 1;
1043  }
1044 
1045  // Handle cross flow
1046  const V numInjectingPerforations = (wops_.p2w * ADB::constant(selectInjectingPerforations)).value();
1047  const V numProducingPerforations = (wops_.p2w * ADB::constant(selectProducingPerforations)).value();
1048  for (int w = 0; w < nw; ++w) {
1049  if (!wells().allow_cf[w]) {
1050  for (int perf = wells().well_connpos[w] ; perf < wells().well_connpos[w+1]; ++perf) {
1051  // Crossflow is not allowed; reverse flow is prevented.
1052  // At least one of the perforation must be open in order to have a meeningful
1053  // equation to solve. For the special case where all perforations have reverse flow,
1054  // and the target rate is non-zero all of the perforations are keept open.
1055  if (wells().type[w] == INJECTOR && numInjectingPerforations[w] > 0) {
1056  selectProducingPerforations[perf] = 0.0;
1057  } else if (wells().type[w] == PRODUCER && numProducingPerforations[w] > 0 ){
1058  selectInjectingPerforations[perf] = 0.0;
1059  }
1060  }
1061  }
1062  }
1063 
1064  // HANDLE FLOW INTO WELLBORE
1065  // compute phase volumetric rates at standard conditions
1066  std::vector<ADB> cq_ps(np, ADB::null());
1067  for (int phase = 0; phase < np; ++phase) {
1068  const ADB cq_p = -(selectProducingPerforations * Tw) * (mob_perfcells[phase] * drawdown);
1069  cq_ps[phase] = b_perfcells[phase] * cq_p;
1070  }
1071  if (active_[Oil] && active_[Gas]) {
1072  const int oilpos = pu.phase_pos[Oil];
1073  const int gaspos = pu.phase_pos[Gas];
1074  const ADB cq_psOil = cq_ps[oilpos];
1075  const ADB cq_psGas = cq_ps[gaspos];
1076  cq_ps[gaspos] += rs_perfcells * cq_psOil;
1077  cq_ps[oilpos] += rv_perfcells * cq_psGas;
1078  }
1079 
1080  // HANDLE FLOW OUT FROM WELLBORE
1081  // Using total mobilities
1082  ADB total_mob = mob_perfcells[0];
1083  for (int phase = 1; phase < np; ++phase) {
1084  total_mob += mob_perfcells[phase];
1085  }
1086  // injection perforations total volume rates
1087  const ADB cqt_i = -(selectInjectingPerforations * Tw) * (total_mob * drawdown);
1088 
1089  // compute wellbore mixture for injecting perforations
1090  // The wellbore mixture depends on the inflow from the reservoar
1091  // and the well injection rates.
1092 
1093  // compute avg. and total wellbore phase volumetric rates at standard conds
1094  const DataBlock compi = Eigen::Map<const DataBlock>(wells().comp_frac, nw, np);
1095  std::vector<ADB> wbq(np, ADB::null());
1096  ADB wbqt = ADB::constant(V::Zero(nw));
1097  for (int phase = 0; phase < np; ++phase) {
1098  const ADB& q_ps = wops_.p2w * cq_ps[phase];
1099  const ADB& q_s = subset(state.qs, Span(nw, 1, phase*nw));
1100  Selector<double> injectingPhase_selector(q_s.value(), Selector<double>::GreaterZero);
1101  const int pos = pu.phase_pos[phase];
1102  wbq[phase] = (compi.col(pos) * injectingPhase_selector.select(q_s,ADB::constant(V::Zero(nw)))) - q_ps;
1103  wbqt += wbq[phase];
1104  }
1105  // compute wellbore mixture at standard conditions.
1106  Selector<double> notDeadWells_selector(wbqt.value(), Selector<double>::Zero);
1107  std::vector<ADB> cmix_s(np, ADB::null());
1108  for (int phase = 0; phase < np; ++phase) {
1109  const int pos = pu.phase_pos[phase];
1110  cmix_s[phase] = wops_.w2p * notDeadWells_selector.select(ADB::constant(compi.col(pos)), wbq[phase]/wbqt);
1111  }
1112 
1113  // compute volume ratio between connection at standard conditions
1114  ADB volumeRatio = ADB::constant(V::Zero(nperf));
1115  const ADB d = V::Constant(nperf,1.0) - rv_perfcells * rs_perfcells;
1116  for (int phase = 0; phase < np; ++phase) {
1117  ADB tmp = cmix_s[phase];
1118 
1119  if (phase == Oil && active_[Gas]) {
1120  const int gaspos = pu.phase_pos[Gas];
1121  tmp = tmp - rv_perfcells * cmix_s[gaspos] / d;
1122  }
1123  if (phase == Gas && active_[Oil]) {
1124  const int oilpos = pu.phase_pos[Oil];
1125  tmp = tmp - rs_perfcells * cmix_s[oilpos] / d;
1126  }
1127  volumeRatio += tmp / b_perfcells[phase];
1128  }
1129 
1130  // injecting connections total volumerates at standard conditions
1131  ADB cqt_is = cqt_i/volumeRatio;
1132 
1133  // connection phase volumerates at standard conditions
1134  for (int phase = 0; phase < np; ++phase) {
1135  cq_s[phase] = cq_ps[phase] + cmix_s[phase]*cqt_is;
1136  }
1137 
1138  // check for dead wells (used in the well controll equations)
1139  aliveWells = V::Constant(nw, 1.0);
1140  for (int w = 0; w < nw; ++w) {
1141  if (wbqt.value()[w] == 0) {
1142  aliveWells[w] = 0.0;
1143  }
1144  }
1145  }
1146 
1147 
1148 
1149 
1150 
1151  template <class Grid, class Implementation>
1153  const SolutionState& state,
1154  WellState& xw)
1155  {
1156  // Update the perforation phase rates (used to calculate the pressure drop in the wellbore).
1157  const int np = wells().number_of_phases;
1158  const int nw = wells().number_of_wells;
1159  const int nperf = wells().well_connpos[nw];
1160  V cq = superset(cq_s[0].value(), Span(nperf, np, 0), nperf*np);
1161  for (int phase = 1; phase < np; ++phase) {
1162  cq += superset(cq_s[phase].value(), Span(nperf, np, phase), nperf*np);
1163  }
1164  xw.perfPhaseRates().assign(cq.data(), cq.data() + nperf*np);
1165 
1166  // Update the perforation pressures.
1167  const V& cdp = well_perforation_pressure_diffs_;
1168  const V perfpressure = (wops_.w2p * state.bhp.value().matrix()).array() + cdp;
1169  xw.perfPress().assign(perfpressure.data(), perfpressure.data() + nperf);
1170  }
1171 
1172 
1173 
1174 
1175 
1176  template <class Grid, class Implementation>
1178  const SolutionState& state)
1179  {
1180  const int np = wells().number_of_phases;
1181  const int nw = wells().number_of_wells;
1182  ADB qs = state.qs;
1183  for (int phase = 0; phase < np; ++phase) {
1184  qs -= superset(wops_.p2w * cq_s[phase], Span(nw, 1, phase*nw), nw*np);
1185 
1186  }
1187 
1188  residual_.well_flux_eq = qs;
1189  }
1190 
1191 
1192 
1193 
1194 
1195  namespace detail
1196  {
1197  inline
1198  double rateToCompare(const std::vector<double>& well_phase_flow_rate,
1199  const int well,
1200  const int num_phases,
1201  const double* distr)
1202  {
1203  double rate = 0.0;
1204  for (int phase = 0; phase < num_phases; ++phase) {
1205  // Important: well_phase_flow_rate is ordered with all phase rates for first
1206  // well first, then all phase rates for second well etc.
1207  rate += well_phase_flow_rate[well*num_phases + phase] * distr[phase];
1208  }
1209  return rate;
1210  }
1211 
1212  inline
1213  bool constraintBroken(const std::vector<double>& bhp,
1214  const std::vector<double>& thp,
1215  const std::vector<double>& well_phase_flow_rate,
1216  const int well,
1217  const int num_phases,
1218  const WellType& well_type,
1219  const WellControls* wc,
1220  const int ctrl_index)
1221  {
1222  const WellControlType ctrl_type = well_controls_iget_type(wc, ctrl_index);
1223  const double target = well_controls_iget_target(wc, ctrl_index);
1224  const double* distr = well_controls_iget_distr(wc, ctrl_index);
1225 
1226  bool broken = false;
1227 
1228  switch (well_type) {
1229  case INJECTOR:
1230  {
1231  switch (ctrl_type) {
1232  case BHP:
1233  broken = bhp[well] > target;
1234  break;
1235 
1236  case THP:
1237  broken = thp[well] > target;
1238  break;
1239 
1240  case RESERVOIR_RATE: // Intentional fall-through
1241  case SURFACE_RATE:
1242  broken = rateToCompare(well_phase_flow_rate,
1243  well, num_phases, distr) > target;
1244  break;
1245  }
1246  }
1247  break;
1248 
1249  case PRODUCER:
1250  {
1251  switch (ctrl_type) {
1252  case BHP:
1253  broken = bhp[well] < target;
1254  break;
1255 
1256  case THP:
1257  broken = thp[well] < target;
1258  break;
1259 
1260  case RESERVOIR_RATE: // Intentional fall-through
1261  case SURFACE_RATE:
1262  // Note that the rates compared below are negative,
1263  // so breaking the constraints means: too high flow rate
1264  // (as for injection).
1265  broken = rateToCompare(well_phase_flow_rate,
1266  well, num_phases, distr) < target;
1267  break;
1268  }
1269  }
1270  break;
1271 
1272  default:
1273  OPM_THROW(std::logic_error, "Can only handle INJECTOR and PRODUCER wells.");
1274  }
1275 
1276  return broken;
1277  }
1278  } // namespace detail
1279 
1280 
1281  namespace detail {
1290  inline
1291  double computeHydrostaticCorrection(const Wells& wells, const int w, double vfp_ref_depth,
1292  const ADB::V& well_perforation_densities, const double gravity) {
1293  if ( wells.well_connpos[w] == wells.well_connpos[w+1] )
1294  {
1295  // This is a well with no perforations.
1296  // If this is the last well we would subscript over the
1297  // bounds below.
1298  // we assume well_perforation_densities to be 0
1299  return 0;
1300  }
1301  const double well_ref_depth = wells.depth_ref[w];
1302  const double dh = vfp_ref_depth - well_ref_depth;
1303  const int perf = wells.well_connpos[w];
1304  const double rho = well_perforation_densities[perf];
1305  const double dp = rho*gravity*dh;
1306 
1307  return dp;
1308  }
1309 
1310  inline
1311  ADB::V computeHydrostaticCorrection(const Wells& wells, const ADB::V vfp_ref_depth,
1312  const ADB::V& well_perforation_densities, const double gravity) {
1313  const int nw = wells.number_of_wells;
1314  ADB::V retval = ADB::V::Zero(nw);
1315 
1316 #pragma omp parallel for schedule(static)
1317  for (int i=0; i<nw; ++i) {
1318  retval[i] = computeHydrostaticCorrection(wells, i, vfp_ref_depth[i], well_perforation_densities, gravity);
1319  }
1320 
1321  return retval;
1322  }
1323 
1324  } //Namespace
1325 
1326 
1327  template <class Grid, class Implementation>
1329  {
1330  if( ! localWellsActive() ) {
1331  return false;
1332  }
1333 
1335  return false;
1336  }
1337 
1338  const int nw = wells().number_of_wells;
1339  //Loop over all wells
1340  for (int w = 0; w < nw; ++w) {
1341  const WellControls* wc = wells().ctrls[w];
1342 
1343  const int nwc = well_controls_get_num(wc);
1344 
1345  //Loop over all controls
1346  for (int c=0; c < nwc; ++c) {
1347  const WellControlType ctrl_type = well_controls_iget_type(wc, c);
1348 
1349  if (ctrl_type == THP) {
1350  return true;
1351  }
1352  }
1353  }
1354 
1355  return false;
1356  }
1357 
1358 
1359  template <class Grid, class Implementation>
1361  {
1362  if( ! localWellsActive() ) return ;
1363 
1364  std::string modestring[4] = { "BHP", "THP", "RESERVOIR_RATE", "SURFACE_RATE" };
1365  // Find, for each well, if any constraints are broken. If so,
1366  // switch control to first broken constraint.
1367  const int np = wells().number_of_phases;
1368  const int nw = wells().number_of_wells;
1369  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
1370 #pragma omp parallel for schedule(dynamic)
1371  for (int w = 0; w < nw; ++w) {
1372  const WellControls* wc = wells().ctrls[w];
1373  // The current control in the well state overrides
1374  // the current control set in the Wells struct, which
1375  // is instead treated as a default.
1376  int current = xw.currentControls()[w];
1377  // Loop over all controls except the current one, and also
1378  // skip any RESERVOIR_RATE controls, since we cannot
1379  // handle those.
1380  const int nwc = well_controls_get_num(wc);
1381  int ctrl_index = 0;
1382  for (; ctrl_index < nwc; ++ctrl_index) {
1383  if (ctrl_index == current) {
1384  // This is the currently used control, so it is
1385  // used as an equation. So this is not used as an
1386  // inequality constraint, and therefore skipped.
1387  continue;
1388  }
1390  xw.bhp(), xw.thp(), xw.wellRates(),
1391  w, np, wells().type[w], wc, ctrl_index)) {
1392  // ctrl_index will be the index of the broken constraint after the loop.
1393  break;
1394  }
1395  }
1396  if (ctrl_index != nwc) {
1397  // Constraint number ctrl_index was broken, switch to it.
1398  if (terminal_output_)
1399  {
1400  std::cout << "Switching control mode for well " << wells().name[w]
1401  << " from " << modestring[well_controls_iget_type(wc, current)]
1402  << " to " << modestring[well_controls_iget_type(wc, ctrl_index)] << std::endl;
1403  }
1404  xw.currentControls()[w] = ctrl_index;
1405  current = xw.currentControls()[w];
1406  }
1407 
1408  //Get gravity for THP hydrostatic corrrection
1409  const double gravity = detail::getGravity(geo_.gravity(), UgGridHelpers::dimensions(grid_));
1410 
1411  // Updating well state and primary variables.
1412  // Target values are used as initial conditions for BHP, THP, and SURFACE_RATE
1413  const double target = well_controls_iget_target(wc, current);
1414  const double* distr = well_controls_iget_distr(wc, current);
1415  switch (well_controls_iget_type(wc, current)) {
1416  case BHP:
1417  xw.bhp()[w] = target;
1418  break;
1419 
1420  case THP: {
1421  double aqua = 0.0;
1422  double liquid = 0.0;
1423  double vapour = 0.0;
1424 
1425  if (active_[ Water ]) {
1426  aqua = xw.wellRates()[w*np + pu.phase_pos[ Water ] ];
1427  }
1428  if (active_[ Oil ]) {
1429  liquid = xw.wellRates()[w*np + pu.phase_pos[ Oil ] ];
1430  }
1431  if (active_[ Gas ]) {
1432  vapour = xw.wellRates()[w*np + pu.phase_pos[ Gas ] ];
1433  }
1434 
1435  const int vfp = well_controls_iget_vfp(wc, current);
1436  const double& thp = well_controls_iget_target(wc, current);
1437  const double& alq = well_controls_iget_alq(wc, current);
1438 
1439  //Set *BHP* target by calculating bhp from THP
1440  const WellType& well_type = wells().type[w];
1441 
1442  if (well_type == INJECTOR) {
1444  wells(), w, vfp_properties_.getInj()->getTable(vfp)->getDatumDepth(),
1445  well_perforation_densities_, gravity);
1446 
1447  xw.bhp()[w] = vfp_properties_.getInj()->bhp(vfp, aqua, liquid, vapour, thp) - dp;
1448  }
1449  else if (well_type == PRODUCER) {
1451  wells(), w, vfp_properties_.getProd()->getTable(vfp)->getDatumDepth(),
1452  well_perforation_densities_, gravity);
1453 
1454  xw.bhp()[w] = vfp_properties_.getProd()->bhp(vfp, aqua, liquid, vapour, thp, alq) - dp;
1455  }
1456  else {
1457  OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
1458  }
1459  break;
1460  }
1461 
1462  case RESERVOIR_RATE:
1463  // No direct change to any observable quantity at
1464  // surface condition. In this case, use existing
1465  // flow rates as initial conditions as reservoir
1466  // rate acts only in aggregate.
1467  break;
1468 
1469  case SURFACE_RATE:
1470  for (int phase = 0; phase < np; ++phase) {
1471  if (distr[phase] > 0.0) {
1472  xw.wellRates()[np*w + phase] = target * distr[phase];
1473  }
1474  }
1475  break;
1476  }
1477 
1478  }
1479  }
1480 
1481 
1482 
1483 
1484 
1485  template <class Grid, class Implementation>
1486  void BlackoilModelBase<Grid, Implementation>::solveWellEq(const std::vector<ADB>& mob_perfcells,
1487  const std::vector<ADB>& b_perfcells,
1488  SolutionState& state,
1489  WellState& well_state)
1490  {
1491  V aliveWells;
1492  const int np = wells().number_of_phases;
1493  std::vector<ADB> cq_s(np, ADB::null());
1494  std::vector<int> indices = variableWellStateIndices();
1495  SolutionState state0 = state;
1496  asImpl().makeConstantState(state0);
1497 
1498  std::vector<ADB> mob_perfcells_const(np, ADB::null());
1499  std::vector<ADB> b_perfcells_const(np, ADB::null());
1500  for (int phase = 0; phase < np; ++phase) {
1501  mob_perfcells_const[phase] = ADB::constant(mob_perfcells[phase].value());
1502  b_perfcells_const[phase] = ADB::constant(b_perfcells[phase].value());
1503  }
1504 
1505  int it = 0;
1506  bool converged;
1507  do {
1508  // bhp and Q for the wells
1509  std::vector<V> vars0;
1510  vars0.reserve(2);
1511  variableWellStateInitials(well_state, vars0);
1512  std::vector<ADB> vars = ADB::variables(vars0);
1513 
1514  SolutionState wellSolutionState = state0;
1515  variableStateExtractWellsVars(indices, vars, wellSolutionState);
1516  asImpl().computeWellFlux(wellSolutionState, mob_perfcells_const, b_perfcells_const, aliveWells, cq_s);
1517  asImpl().updatePerfPhaseRatesAndPressures(cq_s, wellSolutionState, well_state);
1518  asImpl().addWellFluxEq(cq_s, wellSolutionState);
1519  addWellControlEq(wellSolutionState, well_state, aliveWells);
1520  converged = getWellConvergence(it);
1521 
1522  if (converged) {
1523  break;
1524  }
1525 
1526  ++it;
1527  if( localWellsActive() )
1528  {
1529  std::vector<ADB> eqs;
1530  eqs.reserve(2);
1531  eqs.push_back(residual_.well_flux_eq);
1532  eqs.push_back(residual_.well_eq);
1533  ADB total_residual = vertcatCollapseJacs(eqs);
1534  const std::vector<M>& Jn = total_residual.derivative();
1535  typedef Eigen::SparseMatrix<double> Sp;
1536  Sp Jn0;
1537  Jn[0].toSparse(Jn0);
1538  const Eigen::SparseLU< Sp > solver(Jn0);
1539  ADB::V total_residual_v = total_residual.value();
1540  const Eigen::VectorXd& dx = solver.solve(total_residual_v.matrix());
1541  assert(dx.size() == (well_state.numWells() * (well_state.numPhases()+1)));
1542  updateWellState(dx.array(), well_state);
1543  updateWellControls(well_state);
1544  }
1545  } while (it < 15);
1546 
1547  if (converged) {
1548  if ( terminal_output_ ) {
1549  std::cout << "well converged iter: " << it << std::endl;
1550  }
1551  const int nw = wells().number_of_wells;
1552  {
1553  // We will set the bhp primary variable to the new ones,
1554  // but we do not change the derivatives here.
1555  ADB::V new_bhp = Eigen::Map<ADB::V>(well_state.bhp().data(), nw);
1556  // Avoiding the copy below would require a value setter method
1557  // in AutoDiffBlock.
1558  std::vector<ADB::M> old_derivs = state.bhp.derivative();
1559  state.bhp = ADB::function(std::move(new_bhp), std::move(old_derivs));
1560  }
1561  {
1562  // Need to reshuffle well rates, from phase running fastest
1563  // to wells running fastest.
1564  // The transpose() below switches the ordering.
1565  const DataBlock wrates = Eigen::Map<const DataBlock>(well_state.wellRates().data(), nw, np).transpose();
1566  ADB::V new_qs = Eigen::Map<const V>(wrates.data(), nw*np);
1567  std::vector<ADB::M> old_derivs = state.qs.derivative();
1568  state.qs = ADB::function(std::move(new_qs), std::move(old_derivs));
1569  }
1570  asImpl().computeWellConnectionPressures(state, well_state);
1571  }
1572 
1573  }
1574 
1575 
1576 
1577 
1578 
1579  template <class Grid, class Implementation>
1581  const WellState& xw,
1582  const V& aliveWells)
1583  {
1584  if( ! localWellsActive() ) return;
1585 
1586  const int np = wells().number_of_phases;
1587  const int nw = wells().number_of_wells;
1588 
1589  ADB aqua = ADB::constant(ADB::V::Zero(nw));
1590  ADB liquid = ADB::constant(ADB::V::Zero(nw));
1591  ADB vapour = ADB::constant(ADB::V::Zero(nw));
1592 
1593  if (active_[Water]) {
1594  aqua += subset(state.qs, Span(nw, 1, BlackoilPhases::Aqua*nw));
1595  }
1596  if (active_[Oil]) {
1597  liquid += subset(state.qs, Span(nw, 1, BlackoilPhases::Liquid*nw));
1598  }
1599  if (active_[Gas]) {
1600  vapour += subset(state.qs, Span(nw, 1, BlackoilPhases::Vapour*nw));
1601  }
1602 
1603  //THP calculation variables
1604  std::vector<int> inj_table_id(nw, -1);
1605  std::vector<int> prod_table_id(nw, -1);
1606  ADB::V thp_inj_target_v = ADB::V::Zero(nw);
1607  ADB::V thp_prod_target_v = ADB::V::Zero(nw);
1608  ADB::V alq_v = ADB::V::Zero(nw);
1609 
1610  //Hydrostatic correction variables
1611  ADB::V rho_v = ADB::V::Zero(nw);
1612  ADB::V vfp_ref_depth_v = ADB::V::Zero(nw);
1613 
1614  //Target vars
1615  ADB::V bhp_targets = ADB::V::Zero(nw);
1616  ADB::V rate_targets = ADB::V::Zero(nw);
1617  Eigen::SparseMatrix<double> rate_distr(nw, np*nw);
1618 
1619  //Selection variables
1620  std::vector<int> bhp_elems;
1621  std::vector<int> thp_inj_elems;
1622  std::vector<int> thp_prod_elems;
1623  std::vector<int> rate_elems;
1624 
1625  //Run through all wells to calculate BHP/RATE targets
1626  //and gather info about current control
1627  for (int w = 0; w < nw; ++w) {
1628  auto wc = wells().ctrls[w];
1629 
1630  // The current control in the well state overrides
1631  // the current control set in the Wells struct, which
1632  // is instead treated as a default.
1633  const int current = xw.currentControls()[w];
1634 
1635  switch (well_controls_iget_type(wc, current)) {
1636  case BHP:
1637  {
1638  bhp_elems.push_back(w);
1639  bhp_targets(w) = well_controls_iget_target(wc, current);
1640  rate_targets(w) = -1e100;
1641  }
1642  break;
1643 
1644  case THP:
1645  {
1646  const int perf = wells().well_connpos[w];
1647  rho_v[w] = well_perforation_densities_[perf];
1648 
1649  const int table_id = well_controls_iget_vfp(wc, current);
1650  const double target = well_controls_iget_target(wc, current);
1651 
1652  const WellType& well_type = wells().type[w];
1653  if (well_type == INJECTOR) {
1654  inj_table_id[w] = table_id;
1655  thp_inj_target_v[w] = target;
1656  alq_v[w] = -1e100;
1657 
1658  vfp_ref_depth_v[w] = vfp_properties_.getInj()->getTable(table_id)->getDatumDepth();
1659 
1660  thp_inj_elems.push_back(w);
1661  }
1662  else if (well_type == PRODUCER) {
1663  prod_table_id[w] = table_id;
1664  thp_prod_target_v[w] = target;
1665  alq_v[w] = well_controls_iget_alq(wc, current);
1666 
1667  vfp_ref_depth_v[w] = vfp_properties_.getProd()->getTable(table_id)->getDatumDepth();
1668 
1669  thp_prod_elems.push_back(w);
1670  }
1671  else {
1672  OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER type well");
1673  }
1674  bhp_targets(w) = -1e100;
1675  rate_targets(w) = -1e100;
1676  }
1677  break;
1678 
1679  case RESERVOIR_RATE: // Intentional fall-through
1680  case SURFACE_RATE:
1681  {
1682  rate_elems.push_back(w);
1683  // RESERVOIR and SURFACE rates look the same, from a
1684  // high-level point of view, in the system of
1685  // simultaneous linear equations.
1686 
1687  const double* const distr =
1688  well_controls_iget_distr(wc, current);
1689 
1690  for (int p = 0; p < np; ++p) {
1691  rate_distr.insert(w, p*nw + w) = distr[p];
1692  }
1693 
1694  bhp_targets(w) = -1.0e100;
1695  rate_targets(w) = well_controls_iget_target(wc, current);
1696  }
1697  break;
1698  }
1699  }
1700 
1701  //Calculate BHP target from THP
1702  const ADB thp_inj_target = ADB::constant(thp_inj_target_v);
1703  const ADB thp_prod_target = ADB::constant(thp_prod_target_v);
1704  const ADB alq = ADB::constant(alq_v);
1705  const ADB bhp_from_thp_inj = vfp_properties_.getInj()->bhp(inj_table_id, aqua, liquid, vapour, thp_inj_target);
1706  const ADB bhp_from_thp_prod = vfp_properties_.getProd()->bhp(prod_table_id, aqua, liquid, vapour, thp_prod_target, alq);
1707 
1708  //Perform hydrostatic correction to computed targets
1709  double gravity = detail::getGravity(geo_.gravity(), UgGridHelpers::dimensions(grid_));
1710  const ADB::V dp_v = detail::computeHydrostaticCorrection(wells(), vfp_ref_depth_v, well_perforation_densities_, gravity);
1711  const ADB dp = ADB::constant(dp_v);
1712  const ADB dp_inj = superset(subset(dp, thp_inj_elems), thp_inj_elems, nw);
1713  const ADB dp_prod = superset(subset(dp, thp_prod_elems), thp_prod_elems, nw);
1714 
1715  //Calculate residuals
1716  const ADB thp_inj_residual = state.bhp - bhp_from_thp_inj + dp_inj;
1717  const ADB thp_prod_residual = state.bhp - bhp_from_thp_prod + dp_prod;
1718  const ADB bhp_residual = state.bhp - bhp_targets;
1719  const ADB rate_residual = rate_distr * state.qs - rate_targets;
1720 
1721  //Select the right residual for each well
1722  residual_.well_eq = superset(subset(bhp_residual, bhp_elems), bhp_elems, nw) +
1723  superset(subset(thp_inj_residual, thp_inj_elems), thp_inj_elems, nw) +
1724  superset(subset(thp_prod_residual, thp_prod_elems), thp_prod_elems, nw) +
1725  superset(subset(rate_residual, rate_elems), rate_elems, nw);
1726 
1727  // For wells that are dead (not flowing), and therefore not communicating
1728  // with the reservoir, we set the equation to be equal to the well's total
1729  // flow. This will be a solution only if the target rate is also zero.
1730  Eigen::SparseMatrix<double> rate_summer(nw, np*nw);
1731  for (int w = 0; w < nw; ++w) {
1732  for (int phase = 0; phase < np; ++phase) {
1733  rate_summer.insert(w, phase*nw + w) = 1.0;
1734  }
1735  }
1736  Selector<double> alive_selector(aliveWells, Selector<double>::NotEqualZero);
1737  residual_.well_eq = alive_selector.select(residual_.well_eq, rate_summer * state.qs);
1738  // OPM_AD_DUMP(residual_.well_eq);
1739  }
1740 
1741 
1742 
1743 
1744 
1745  template <class Grid, class Implementation>
1747  {
1749  }
1750 
1751 
1752 
1753 
1754 
1755  namespace detail
1756  {
1762  inline
1763  double infinityNorm( const ADB& a, const boost::any& pinfo = boost::any() )
1764  {
1765  static_cast<void>(pinfo); // Suppress warning in non-MPI case.
1766 #if HAVE_MPI
1767  if ( pinfo.type() == typeid(ParallelISTLInformation) )
1768  {
1769  const ParallelISTLInformation& real_info =
1770  boost::any_cast<const ParallelISTLInformation&>(pinfo);
1771  double result=0;
1772  real_info.computeReduction(a.value(), Reduction::makeGlobalMaxFunctor<double>(), result);
1773  return result;
1774  }
1775  else
1776 #endif
1777  {
1778  if( a.value().size() > 0 ) {
1779  return a.value().matrix().lpNorm<Eigen::Infinity> ();
1780  }
1781  else { // this situation can occur when no wells are present
1782  return 0.0;
1783  }
1784  }
1785  }
1786 
1790  inline
1791  double infinityNormWell( const ADB& a, const boost::any& pinfo )
1792  {
1793  static_cast<void>(pinfo); // Suppress warning in non-MPI case.
1794  double result=0;
1795  if( a.value().size() > 0 ) {
1796  result = a.value().matrix().lpNorm<Eigen::Infinity> ();
1797  }
1798 #if HAVE_MPI
1799  if ( pinfo.type() == typeid(ParallelISTLInformation) )
1800  {
1801  const ParallelISTLInformation& real_info =
1802  boost::any_cast<const ParallelISTLInformation&>(pinfo);
1803  result = real_info.communicator().max(result);
1804  }
1805 #endif
1806  return result;
1807  }
1808 
1809  } // namespace detail
1810 
1811 
1812 
1813 
1814 
1815  template <class Grid, class Implementation>
1817  ReservoirState& reservoir_state,
1818  WellState& well_state)
1819  {
1820  using namespace Opm::AutoDiffGrid;
1821  const int np = fluid_.numPhases();
1822  const int nc = numCells(grid_);
1823  const int nw = localWellsActive() ? wells().number_of_wells : 0;
1824  const V null;
1825  assert(null.size() == 0);
1826  const V zero = V::Zero(nc);
1827 
1828  // Extract parts of dx corresponding to each part.
1829  const V dp = subset(dx, Span(nc));
1830  int varstart = nc;
1831  const V dsw = active_[Water] ? subset(dx, Span(nc, 1, varstart)) : null;
1832  varstart += dsw.size();
1833 
1834  const V dxvar = active_[Gas] ? subset(dx, Span(nc, 1, varstart)): null;
1835  varstart += dxvar.size();
1836 
1837  // Extract well parts np phase rates + bhp
1838  const V dwells = subset(dx, Span((np+1)*nw, 1, varstart));
1839  varstart += dwells.size();
1840 
1841  assert(varstart == dx.size());
1842 
1843  // Pressure update.
1844  const double dpmaxrel = dpMaxRel();
1845  const V p_old = Eigen::Map<const V>(&reservoir_state.pressure()[0], nc, 1);
1846  const V absdpmax = dpmaxrel*p_old.abs();
1847  const V dp_limited = sign(dp) * dp.abs().min(absdpmax);
1848  const V p = (p_old - dp_limited).max(zero);
1849  std::copy(&p[0], &p[0] + nc, reservoir_state.pressure().begin());
1850 
1851 
1852  // Saturation updates.
1853  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
1854  const DataBlock s_old = Eigen::Map<const DataBlock>(& reservoir_state.saturation()[0], nc, np);
1855  const double dsmax = dsMax();
1856 
1857  V so;
1858  V sw;
1859  V sg;
1860 
1861  {
1862  V maxVal = zero;
1863  V dso = zero;
1864  if (active_[Water]){
1865  maxVal = dsw.abs().max(maxVal);
1866  dso = dso - dsw;
1867  }
1868 
1869  V dsg;
1870  if (active_[Gas]){
1871  dsg = isSg_ * dxvar - isRv_ * dsw;
1872  maxVal = dsg.abs().max(maxVal);
1873  dso = dso - dsg;
1874  }
1875 
1876  maxVal = dso.abs().max(maxVal);
1877 
1878  V step = dsmax/maxVal;
1879  step = step.min(1.);
1880 
1881  if (active_[Water]) {
1882  const int pos = pu.phase_pos[ Water ];
1883  const V sw_old = s_old.col(pos);
1884  sw = sw_old - step * dsw;
1885  }
1886 
1887  if (active_[Gas]) {
1888  const int pos = pu.phase_pos[ Gas ];
1889  const V sg_old = s_old.col(pos);
1890  sg = sg_old - step * dsg;
1891  }
1892 
1893  const int pos = pu.phase_pos[ Oil ];
1894  const V so_old = s_old.col(pos);
1895  so = so_old - step * dso;
1896  }
1897 
1898  // Appleyard chop process.
1899  auto ixg = sg < 0;
1900  for (int c = 0; c < nc; ++c) {
1901  if (ixg[c]) {
1902  sw[c] = sw[c] / (1-sg[c]);
1903  so[c] = so[c] / (1-sg[c]);
1904  sg[c] = 0;
1905  }
1906  }
1907 
1908 
1909  auto ixo = so < 0;
1910  for (int c = 0; c < nc; ++c) {
1911  if (ixo[c]) {
1912  sw[c] = sw[c] / (1-so[c]);
1913  sg[c] = sg[c] / (1-so[c]);
1914  so[c] = 0;
1915  }
1916  }
1917 
1918  auto ixw = sw < 0;
1919  for (int c = 0; c < nc; ++c) {
1920  if (ixw[c]) {
1921  so[c] = so[c] / (1-sw[c]);
1922  sg[c] = sg[c] / (1-sw[c]);
1923  sw[c] = 0;
1924  }
1925  }
1926 
1927  //const V sumSat = sw + so + sg;
1928  //sw = sw / sumSat;
1929  //so = so / sumSat;
1930  //sg = sg / sumSat;
1931 
1932  // Update the reservoir_state
1933  for (int c = 0; c < nc; ++c) {
1934  reservoir_state.saturation()[c*np + pu.phase_pos[ Water ]] = sw[c];
1935  }
1936 
1937  for (int c = 0; c < nc; ++c) {
1938  reservoir_state.saturation()[c*np + pu.phase_pos[ Gas ]] = sg[c];
1939  }
1940 
1941  if (active_[ Oil ]) {
1942  const int pos = pu.phase_pos[ Oil ];
1943  for (int c = 0; c < nc; ++c) {
1944  reservoir_state.saturation()[c*np + pos] = so[c];
1945  }
1946  }
1947 
1948  // Update rs and rv
1949  const double drmaxrel = drMaxRel();
1950  V rs;
1951  if (has_disgas_) {
1952  const V rs_old = Eigen::Map<const V>(&reservoir_state.gasoilratio()[0], nc);
1953  const V drs = isRs_ * dxvar;
1954  const V drs_limited = sign(drs) * drs.abs().min(rs_old.abs()*drmaxrel);
1955  rs = rs_old - drs_limited;
1956  }
1957  V rv;
1958  if (has_vapoil_) {
1959  const V rv_old = Eigen::Map<const V>(&reservoir_state.rv()[0], nc);
1960  const V drv = isRv_ * dxvar;
1961  const V drv_limited = sign(drv) * drv.abs().min(rv_old.abs()*drmaxrel);
1962  rv = rv_old - drv_limited;
1963  }
1964 
1965  // Sg is used as primal variable for water only cells.
1966  const double epsilon = std::sqrt(std::numeric_limits<double>::epsilon());
1967  auto watOnly = sw > (1 - epsilon);
1968 
1969  // phase translation sg <-> rs
1970  std::fill(primalVariable_.begin(), primalVariable_.end(), PrimalVariables::Sg);
1971 
1972  if (has_disgas_) {
1973  const V rsSat0 = fluidRsSat(p_old, s_old.col(pu.phase_pos[Oil]), cells_);
1974  const V rsSat = fluidRsSat(p, so, cells_);
1975  // The obvious case
1976  auto hasGas = (sg > 0 && isRs_ == 0);
1977 
1978  // Set oil saturated if previous rs is sufficiently large
1979  const V rs_old = Eigen::Map<const V>(&reservoir_state.gasoilratio()[0], nc);
1980  auto gasVaporized = ( (rs > rsSat * (1+epsilon) && isRs_ == 1 ) && (rs_old > rsSat0 * (1-epsilon)) );
1981  auto useSg = watOnly || hasGas || gasVaporized;
1982  for (int c = 0; c < nc; ++c) {
1983  if (useSg[c]) {
1984  rs[c] = rsSat[c];
1985  } else {
1987  }
1988  }
1989 
1990  }
1991 
1992  // phase transitions so <-> rv
1993  if (has_vapoil_) {
1994 
1995  // The gas pressure is needed for the rvSat calculations
1996  const V gaspress_old = computeGasPressure(p_old, s_old.col(Water), s_old.col(Oil), s_old.col(Gas));
1997  const V gaspress = computeGasPressure(p, sw, so, sg);
1998  const V rvSat0 = fluidRvSat(gaspress_old, s_old.col(pu.phase_pos[Oil]), cells_);
1999  const V rvSat = fluidRvSat(gaspress, so, cells_);
2000 
2001  // The obvious case
2002  auto hasOil = (so > 0 && isRv_ == 0);
2003 
2004  // Set oil saturated if previous rv is sufficiently large
2005  const V rv_old = Eigen::Map<const V>(&reservoir_state.rv()[0], nc);
2006  auto oilCondensed = ( (rv > rvSat * (1+epsilon) && isRv_ == 1) && (rv_old > rvSat0 * (1-epsilon)) );
2007  auto useSg = watOnly || hasOil || oilCondensed;
2008  for (int c = 0; c < nc; ++c) {
2009  if (useSg[c]) {
2010  rv[c] = rvSat[c];
2011  } else {
2013  }
2014  }
2015 
2016  }
2017 
2018  // Update the reservoir_state
2019  if (has_disgas_) {
2020  std::copy(&rs[0], &rs[0] + nc, reservoir_state.gasoilratio().begin());
2021  }
2022 
2023  if (has_vapoil_) {
2024  std::copy(&rv[0], &rv[0] + nc, reservoir_state.rv().begin());
2025  }
2026 
2027 
2028  updateWellState(dwells,well_state);
2029 
2030  // Update phase conditions used for property calculations.
2032  }
2033 
2034 
2035 
2036 
2037 
2038  template <class Grid, class Implementation>
2039  void
2041  WellState& well_state)
2042  {
2043 
2044  if( localWellsActive() )
2045  {
2046  const int np = wells().number_of_phases;
2047  const int nw = wells().number_of_wells;
2048 
2049  // Extract parts of dwells corresponding to each part.
2050  int varstart = 0;
2051  const V dqs = subset(dwells, Span(np*nw, 1, varstart));
2052  varstart += dqs.size();
2053  const V dbhp = subset(dwells, Span(nw, 1, varstart));
2054  varstart += dbhp.size();
2055  assert(varstart == dwells.size());
2056  const double dpmaxrel = dpMaxRel();
2057 
2058 
2059  // Qs update.
2060  // Since we need to update the wellrates, that are ordered by wells,
2061  // from dqs which are ordered by phase, the simplest is to compute
2062  // dwr, which is the data from dqs but ordered by wells.
2063  const DataBlock wwr = Eigen::Map<const DataBlock>(dqs.data(), np, nw).transpose();
2064  const V dwr = Eigen::Map<const V>(wwr.data(), nw*np);
2065  const V wr_old = Eigen::Map<const V>(&well_state.wellRates()[0], nw*np);
2066  const V wr = wr_old - dwr;
2067  std::copy(&wr[0], &wr[0] + wr.size(), well_state.wellRates().begin());
2068 
2069  // Bhp update.
2070  const V bhp_old = Eigen::Map<const V>(&well_state.bhp()[0], nw, 1);
2071  const V dbhp_limited = sign(dbhp) * dbhp.abs().min(bhp_old.abs()*dpmaxrel);
2072  const V bhp = bhp_old - dbhp_limited;
2073  std::copy(&bhp[0], &bhp[0] + bhp.size(), well_state.bhp().begin());
2074 
2075  //Get gravity for THP hydrostatic correction
2076  const double gravity = detail::getGravity(geo_.gravity(), UgGridHelpers::dimensions(grid_));
2077 
2078  // Thp update
2079  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
2080  //Loop over all wells
2081 #pragma omp parallel for schedule(static)
2082  for (int w=0; w<nw; ++w) {
2083  const WellControls* wc = wells().ctrls[w];
2084  const int nwc = well_controls_get_num(wc);
2085  //Loop over all controls until we find a THP control
2086  //that specifies what we need...
2087  //Will only update THP for wells with THP control
2088  for (int ctrl_index=0; ctrl_index < nwc; ++ctrl_index) {
2089  if (well_controls_iget_type(wc, ctrl_index) == THP) {
2090  double aqua = 0.0;
2091  double liquid = 0.0;
2092  double vapour = 0.0;
2093 
2094  if (active_[ Water ]) {
2095  aqua = wr[w*np + pu.phase_pos[ Water ] ];
2096  }
2097  if (active_[ Oil ]) {
2098  liquid = wr[w*np + pu.phase_pos[ Oil ] ];
2099  }
2100  if (active_[ Gas ]) {
2101  vapour = wr[w*np + pu.phase_pos[ Gas ] ];
2102  }
2103 
2104  double alq = well_controls_iget_alq(wc, ctrl_index);
2105  int table_id = well_controls_iget_vfp(wc, ctrl_index);
2106 
2107  const WellType& well_type = wells().type[w];
2108  if (well_type == INJECTOR) {
2110  wells(), w, vfp_properties_.getInj()->getTable(table_id)->getDatumDepth(),
2111  well_perforation_densities_, gravity);
2112 
2113  well_state.thp()[w] = vfp_properties_.getInj()->thp(table_id, aqua, liquid, vapour, bhp[w] + dp);
2114  }
2115  else if (well_type == PRODUCER) {
2117  wells(), w, vfp_properties_.getProd()->getTable(table_id)->getDatumDepth(),
2118  well_perforation_densities_, gravity);
2119 
2120  well_state.thp()[w] = vfp_properties_.getProd()->thp(table_id, aqua, liquid, vapour, bhp[w] + dp, alq);
2121  }
2122  else {
2123  OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well");
2124  }
2125 
2126  //Assume only one THP control specified for each well
2127  break;
2128  }
2129  }
2130  }
2131  }
2132  }
2133 
2134 
2135 
2136 
2137 
2138  template <class Grid, class Implementation>
2139  std::vector<ADB>
2141  {
2142  using namespace Opm::AutoDiffGrid;
2143  const int nc = numCells(grid_);
2144 
2145  const ADB zero = ADB::constant(V::Zero(nc));
2146 
2147  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
2148  const ADB& sw = (active_[ Water ]
2149  ? state.saturation[ pu.phase_pos[ Water ] ]
2150  : zero);
2151 
2152  const ADB& so = (active_[ Oil ]
2153  ? state.saturation[ pu.phase_pos[ Oil ] ]
2154  : zero);
2155 
2156  const ADB& sg = (active_[ Gas ]
2157  ? state.saturation[ pu.phase_pos[ Gas ] ]
2158  : zero);
2159 
2160  return fluid_.relperm(sw, so, sg, cells_);
2161  }
2162 
2163 
2164 
2165 
2166 
2167  template <class Grid, class Implementation>
2168  std::vector<ADB>
2170  computePressures(const ADB& po,
2171  const ADB& sw,
2172  const ADB& so,
2173  const ADB& sg) const
2174  {
2175  // convert the pressure offsets to the capillary pressures
2176  std::vector<ADB> pressure = fluid_.capPress(sw, so, sg, cells_);
2177  for (int phaseIdx = 0; phaseIdx < BlackoilPhases::MaxNumPhases; ++phaseIdx) {
2178  // The reference pressure is always the liquid phase (oil) pressure.
2179  if (phaseIdx == BlackoilPhases::Liquid)
2180  continue;
2181  pressure[phaseIdx] = pressure[phaseIdx] - pressure[BlackoilPhases::Liquid];
2182  }
2183 
2184  // Since pcow = po - pw, but pcog = pg - po,
2185  // we have
2186  // pw = po - pcow
2187  // pg = po + pcgo
2188  // This is an unfortunate inconsistency, but a convention we must handle.
2189  for (int phaseIdx = 0; phaseIdx < BlackoilPhases::MaxNumPhases; ++phaseIdx) {
2190  if (phaseIdx == BlackoilPhases::Aqua) {
2191  pressure[phaseIdx] = po - pressure[phaseIdx];
2192  } else {
2193  pressure[phaseIdx] += po;
2194  }
2195  }
2196 
2197  return pressure;
2198  }
2199 
2200 
2201 
2202 
2203 
2204  template <class Grid, class Implementation>
2205  V
2207  const V& sw,
2208  const V& so,
2209  const V& sg) const
2210  {
2211  assert (active_[Gas]);
2212  std::vector<ADB> cp = fluid_.capPress(ADB::constant(sw),
2213  ADB::constant(so),
2214  ADB::constant(sg),
2215  cells_);
2216  return cp[Gas].value() + po;
2217  }
2218 
2219 
2220 
2221 
2222 
2223  template <class Grid, class Implementation>
2224  void
2226  const V& transi,
2227  const ADB& kr ,
2228  const ADB& phasePressure,
2229  const SolutionState& state)
2230  {
2231  // Compute and store mobilities.
2232  const int canonicalPhaseIdx = canph_[ actph ];
2233  const std::vector<PhasePresence>& cond = phaseCondition();
2234  const ADB tr_mult = transMult(state.pressure);
2235  const ADB mu = fluidViscosity(canonicalPhaseIdx, phasePressure, state.temperature, state.rs, state.rv, cond);
2236  rq_[ actph ].mob = tr_mult * kr / mu;
2237 
2238  // Compute head differentials. Gravity potential is done using the face average as in eclipse and MRST.
2239  const ADB rho = fluidDensity(canonicalPhaseIdx, rq_[actph].b, state.rs, state.rv);
2240  const ADB rhoavg = ops_.caver * rho;
2241  rq_[ actph ].dh = ops_.ngrad * phasePressure - geo_.gravity()[2] * (rhoavg * (ops_.ngrad * geo_.z().matrix()));
2243  applyThresholdPressures(rq_[ actph ].dh);
2244  }
2245 
2246  // Compute phase fluxes with upwinding of formation value factor and mobility.
2247  const ADB& b = rq_[ actph ].b;
2248  const ADB& mob = rq_[ actph ].mob;
2249  const ADB& dh = rq_[ actph ].dh;
2250  UpwindSelector<double> upwind(grid_, ops_, dh.value());
2251  rq_[ actph ].mflux = upwind.select(b * mob) * (transi * dh);
2252  }
2253 
2254 
2255 
2256 
2257 
2258  template <class Grid, class Implementation>
2259  void
2261  {
2262  // We support reversible threshold pressures only.
2263  // Method: if the potential difference is lower (in absolute
2264  // value) than the threshold for any face, then the potential
2265  // (and derivatives) is set to zero. If it is above the
2266  // threshold, the threshold pressure is subtracted from the
2267  // absolute potential (the potential is moved towards zero).
2268 
2269  // Identify the set of faces where the potential is under the
2270  // threshold, that shall have zero flow. Storing the bool
2271  // Array as a V (a double Array) with 1 and 0 elements, a
2272  // 1 where flow is allowed, a 0 where it is not.
2273  const V high_potential = (dp.value().abs() >= threshold_pressures_by_interior_face_).template cast<double>();
2274 
2275  // Create a sparse vector that nullifies the low potential elements.
2276  const M keep_high_potential(high_potential.matrix().asDiagonal());
2277 
2278  // Find the current sign for the threshold modification
2279  const V sign_dp = sign(dp.value());
2280  const V threshold_modification = sign_dp * threshold_pressures_by_interior_face_;
2281 
2282  // Modify potential and nullify where appropriate.
2283  dp = keep_high_potential * (dp - threshold_modification);
2284  }
2285 
2286 
2287 
2288 
2289 
2290  template <class Grid, class Implementation>
2291  std::vector<double>
2293  {
2294  std::vector<double> residualNorms;
2295 
2296  std::vector<ADB>::const_iterator massBalanceIt = residual_.material_balance_eq.begin();
2297  const std::vector<ADB>::const_iterator endMassBalanceIt = residual_.material_balance_eq.end();
2298 
2299  for (; massBalanceIt != endMassBalanceIt; ++massBalanceIt) {
2300  const double massBalanceResid = detail::infinityNorm( (*massBalanceIt),
2302  if (!std::isfinite(massBalanceResid)) {
2303  OPM_THROW(Opm::NumericalProblem,
2304  "Encountered a non-finite residual");
2305  }
2306  residualNorms.push_back(massBalanceResid);
2307  }
2308 
2309  // the following residuals are not used in the oscillation detection now
2310  const double wellFluxResid = detail::infinityNormWell( residual_.well_flux_eq,
2312  if (!std::isfinite(wellFluxResid)) {
2313  OPM_THROW(Opm::NumericalProblem,
2314  "Encountered a non-finite residual");
2315  }
2316  residualNorms.push_back(wellFluxResid);
2317 
2318  const double wellResid = detail::infinityNormWell( residual_.well_eq,
2320  if (!std::isfinite(wellResid)) {
2321  OPM_THROW(Opm::NumericalProblem,
2322  "Encountered a non-finite residual");
2323  }
2324  residualNorms.push_back(wellResid);
2325 
2326  return residualNorms;
2327  }
2328 
2329 
2330 
2331 
2332 
2333  template <class Grid, class Implementation>
2334  double
2335  BlackoilModelBase<Grid, Implementation>::convergenceReduction(const Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>& B,
2336  const Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>& tempV,
2337  const Eigen::Array<double, Eigen::Dynamic, Eigen::Dynamic>& R,
2338  std::vector<double>& R_sum,
2339  std::vector<double>& maxCoeff,
2340  std::vector<double>& B_avg,
2341  std::vector<double>& maxNormWell,
2342  int nc,
2343  int nw) const
2344  {
2345  const int np = asImpl().numPhases();
2346  const int nm = asImpl().numMaterials();
2347 
2348  // Do the global reductions
2349 #if HAVE_MPI
2350  if ( linsolver_.parallelInformation().type() == typeid(ParallelISTLInformation) )
2351  {
2352  const ParallelISTLInformation& info =
2353  boost::any_cast<const ParallelISTLInformation&>(linsolver_.parallelInformation());
2354 
2355  // Compute the global number of cells and porevolume
2356  std::vector<int> v(nc, 1);
2357  auto nc_and_pv = std::tuple<int, double>(0, 0.0);
2358  auto nc_and_pv_operators = std::make_tuple(Opm::Reduction::makeGlobalSumFunctor<int>(),
2359  Opm::Reduction::makeGlobalSumFunctor<double>());
2360  auto nc_and_pv_containers = std::make_tuple(v, geo_.poreVolume());
2361  info.computeReduction(nc_and_pv_containers, nc_and_pv_operators, nc_and_pv);
2362 
2363  for ( int idx = 0; idx < nm; ++idx )
2364  {
2365  auto values = std::tuple<double,double,double>(0.0 ,0.0 ,0.0);
2366  auto containers = std::make_tuple(B.col(idx),
2367  tempV.col(idx),
2368  R.col(idx));
2369  auto operators = std::make_tuple(Opm::Reduction::makeGlobalSumFunctor<double>(),
2370  Opm::Reduction::makeGlobalMaxFunctor<double>(),
2371  Opm::Reduction::makeGlobalSumFunctor<double>());
2372  info.computeReduction(containers, operators, values);
2373  B_avg[idx] = std::get<0>(values)/std::get<0>(nc_and_pv);
2374  maxCoeff[idx] = std::get<1>(values);
2375  R_sum[idx] = std::get<2>(values);
2376  assert(nm >= np);
2377  if (idx < np) {
2378  maxNormWell[idx] = 0.0;
2379  for ( int w = 0; w < nw; ++w ) {
2380  maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_.well_flux_eq.value()[nw*idx + w]));
2381  }
2382  }
2383  }
2384  info.communicator().max(maxNormWell.data(), np);
2385  // Compute pore volume
2386  return std::get<1>(nc_and_pv);
2387  }
2388  else
2389 #endif
2390  {
2391  B_avg.resize(nm);
2392  maxCoeff.resize(nm);
2393  R_sum.resize(nm);
2394  maxNormWell.resize(np);
2395  for ( int idx = 0; idx < nm; ++idx )
2396  {
2397  B_avg[idx] = B.col(idx).sum()/nc;
2398  maxCoeff[idx] = tempV.col(idx).maxCoeff();
2399  R_sum[idx] = R.col(idx).sum();
2400 
2401  assert(nm >= np);
2402  if (idx < np) {
2403  maxNormWell[idx] = 0.0;
2404  for ( int w = 0; w < nw; ++w ) {
2405  maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_.well_flux_eq.value()[nw*idx + w]));
2406  }
2407  }
2408  }
2409  // Compute total pore volume
2410  return geo_.poreVolume().sum();
2411  }
2412  }
2413 
2414 
2415 
2416 
2417 
2418  template <class Grid, class Implementation>
2419  bool
2420  BlackoilModelBase<Grid, Implementation>::getConvergence(const double dt, const int iteration)
2421  {
2422  const double tol_mb = param_.tolerance_mb_;
2423  const double tol_cnv = param_.tolerance_cnv_;
2424  const double tol_wells = param_.tolerance_wells_;
2425 
2426  const int nc = Opm::AutoDiffGrid::numCells(grid_);
2427  const int nw = localWellsActive() ? wells().number_of_wells : 0;
2428  const int np = asImpl().numPhases();
2429  const int nm = asImpl().numMaterials();
2430  assert(int(rq_.size()) == nm);
2431 
2432  const V pv = geo_.poreVolume();
2433 
2434  std::vector<double> R_sum(nm);
2435  std::vector<double> B_avg(nm);
2436  std::vector<double> maxCoeff(nm);
2437  std::vector<double> maxNormWell(np);
2438  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> B(nc, nm);
2439  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> R(nc, nm);
2440  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> tempV(nc, nm);
2441 
2442  for ( int idx = 0; idx < nm; ++idx )
2443  {
2444  const ADB& tempB = rq_[idx].b;
2445  B.col(idx) = 1./tempB.value();
2446  R.col(idx) = residual_.material_balance_eq[idx].value();
2447  tempV.col(idx) = R.col(idx).abs()/pv;
2448  }
2449 
2450  const double pvSum = convergenceReduction(B, tempV, R,
2451  R_sum, maxCoeff, B_avg, maxNormWell,
2452  nc, nw);
2453 
2454  std::vector<double> CNV(nm);
2455  std::vector<double> mass_balance_residual(nm);
2456  std::vector<double> well_flux_residual(np);
2457 
2458  bool converged_MB = true;
2459  bool converged_CNV = true;
2460  bool converged_Well = true;
2461  // Finish computation
2462  for ( int idx = 0; idx < nm; ++idx )
2463  {
2464  CNV[idx] = B_avg[idx] * dt * maxCoeff[idx];
2465  mass_balance_residual[idx] = std::abs(B_avg[idx]*R_sum[idx]) * dt / pvSum;
2466  converged_MB = converged_MB && (mass_balance_residual[idx] < tol_mb);
2467  converged_CNV = converged_CNV && (CNV[idx] < tol_cnv);
2468  // Well flux convergence is only for fluid phases, not other materials
2469  // in our current implementation.
2470  assert(nm >= np);
2471  if (idx < np) {
2472  well_flux_residual[idx] = B_avg[idx] * maxNormWell[idx];
2473  converged_Well = converged_Well && (well_flux_residual[idx] < tol_wells);
2474  }
2475  }
2476 
2477  const double residualWell = detail::infinityNormWell(residual_.well_eq,
2479  converged_Well = converged_Well && (residualWell < Opm::unit::barsa);
2480  const bool converged = converged_MB && converged_CNV && converged_Well;
2481 
2482  // Residual in Pascal can have high values and still be ok.
2483  const double maxWellResidualAllowed = 1000.0 * maxResidualAllowed();
2484 
2485  for (int idx = 0; idx < nm; ++idx) {
2486  if (std::isnan(mass_balance_residual[idx])
2487  || std::isnan(CNV[idx])
2488  || (idx < np && std::isnan(well_flux_residual[idx]))) {
2489  OPM_THROW(Opm::NumericalProblem, "NaN residual for phase " << materialName(idx));
2490  }
2491  if (mass_balance_residual[idx] > maxResidualAllowed()
2492  || CNV[idx] > maxResidualAllowed()
2493  || (idx < np && well_flux_residual[idx] > maxResidualAllowed())) {
2494  OPM_THROW(Opm::NumericalProblem, "Too large residual for phase " << materialName(idx));
2495  }
2496  }
2497  if (std::isnan(residualWell) || residualWell > maxWellResidualAllowed) {
2498  OPM_THROW(Opm::NumericalProblem, "NaN or too large residual for well control equation");
2499  }
2500 
2501  if ( terminal_output_ )
2502  {
2503  // Only rank 0 does print to std::cout
2504  if (iteration == 0) {
2505  std::cout << "\nIter";
2506  for (int idx = 0; idx < nm; ++idx) {
2507  std::cout << " MB(" << materialName(idx).substr(0, 3) << ") ";
2508  }
2509  for (int idx = 0; idx < nm; ++idx) {
2510  std::cout << " CNV(" << materialName(idx).substr(0, 1) << ") ";
2511  }
2512  for (int idx = 0; idx < np; ++idx) {
2513  std::cout << " W-FLUX(" << materialName(idx).substr(0, 1) << ")";
2514  }
2515  std::cout << '\n';
2516  }
2517  const std::streamsize oprec = std::cout.precision(3);
2518  const std::ios::fmtflags oflags = std::cout.setf(std::ios::scientific);
2519  std::cout << std::setw(4) << iteration;
2520  for (int idx = 0; idx < nm; ++idx) {
2521  std::cout << std::setw(11) << mass_balance_residual[idx];
2522  }
2523  for (int idx = 0; idx < nm; ++idx) {
2524  std::cout << std::setw(11) << CNV[idx];
2525  }
2526  for (int idx = 0; idx < np; ++idx) {
2527  std::cout << std::setw(11) << well_flux_residual[idx];
2528  }
2529  std::cout << std::endl;
2530  std::cout.precision(oprec);
2531  std::cout.flags(oflags);
2532  }
2533  return converged;
2534  }
2535 
2536 
2537 
2538 
2539 
2540  template <class Grid, class Implementation>
2541  bool
2543  {
2544  const double tol_wells = param_.tolerance_wells_;
2545 
2546  const int nc = Opm::AutoDiffGrid::numCells(grid_);
2547  const int nw = localWellsActive() ? wells().number_of_wells : 0;
2548  const int np = asImpl().numPhases();
2549  const int nm = asImpl().numMaterials();
2550 
2551  const V pv = geo_.poreVolume();
2552  std::vector<double> R_sum(nm);
2553  std::vector<double> B_avg(nm);
2554  std::vector<double> maxCoeff(nm);
2555  std::vector<double> maxNormWell(np);
2556  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> B(nc, nm);
2557  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> R(nc, nm);
2558  Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> tempV(nc, nm);
2559  for ( int idx = 0; idx < nm; ++idx )
2560  {
2561  const ADB& tempB = rq_[idx].b;
2562  B.col(idx) = 1./tempB.value();
2563  R.col(idx) = residual_.material_balance_eq[idx].value();
2564  tempV.col(idx) = R.col(idx).abs()/pv;
2565  }
2566 
2567  convergenceReduction(B, tempV, R, R_sum, maxCoeff, B_avg, maxNormWell, nc, nw);
2568 
2569  std::vector<double> well_flux_residual(np);
2570  bool converged_Well = true;
2571  // Finish computation
2572  for ( int idx = 0; idx < np; ++idx )
2573  {
2574  well_flux_residual[idx] = B_avg[idx] * maxNormWell[idx];
2575  converged_Well = converged_Well && (well_flux_residual[idx] < tol_wells);
2576  }
2577 
2578  const double residualWell = detail::infinityNormWell(residual_.well_eq,
2580  converged_Well = converged_Well && (residualWell < Opm::unit::barsa);
2581  const bool converged = converged_Well;
2582 
2583  // if one of the residuals is NaN, throw exception, so that the solver can be restarted
2584  for (int idx = 0; idx < np; ++idx) {
2585  if (std::isnan(well_flux_residual[idx])) {
2586  OPM_THROW(Opm::NumericalProblem, "NaN residual for phase " << materialName(idx));
2587  }
2588  if (well_flux_residual[idx] > maxResidualAllowed()) {
2589  OPM_THROW(Opm::NumericalProblem, "Too large residual for phase " << materialName(idx));
2590  }
2591  }
2592 
2593  if ( terminal_output_ )
2594  {
2595  // Only rank 0 does print to std::cout
2596  if (iteration == 0) {
2597  std::cout << "\nIter";
2598  for (int idx = 0; idx < np; ++idx) {
2599  std::cout << " W-FLUX(" << materialName(idx).substr(0, 1) << ")";
2600  }
2601  std::cout << '\n';
2602  }
2603  const std::streamsize oprec = std::cout.precision(3);
2604  const std::ios::fmtflags oflags = std::cout.setf(std::ios::scientific);
2605  std::cout << std::setw(4) << iteration;
2606  for (int idx = 0; idx < np; ++idx) {
2607  std::cout << std::setw(11) << well_flux_residual[idx];
2608  }
2609  std::cout << std::endl;
2610  std::cout.precision(oprec);
2611  std::cout.flags(oflags);
2612  }
2613  return converged;
2614  }
2615 
2616 
2617 
2618 
2619 
2620  template <class Grid, class Implementation>
2621  ADB
2623  const ADB& p ,
2624  const ADB& temp ,
2625  const ADB& rs ,
2626  const ADB& rv ,
2627  const std::vector<PhasePresence>& cond) const
2628  {
2629  switch (phase) {
2630  case Water:
2631  return fluid_.muWat(p, temp, cells_);
2632  case Oil:
2633  return fluid_.muOil(p, temp, rs, cond, cells_);
2634  case Gas:
2635  return fluid_.muGas(p, temp, rv, cond, cells_);
2636  default:
2637  OPM_THROW(std::runtime_error, "Unknown phase index " << phase);
2638  }
2639  }
2640 
2641 
2642 
2643 
2644 
2645  template <class Grid, class Implementation>
2646  ADB
2648  const ADB& p ,
2649  const ADB& temp ,
2650  const ADB& rs ,
2651  const ADB& rv ,
2652  const std::vector<PhasePresence>& cond) const
2653  {
2654  switch (phase) {
2655  case Water:
2656  return fluid_.bWat(p, temp, cells_);
2657  case Oil:
2658  return fluid_.bOil(p, temp, rs, cond, cells_);
2659  case Gas:
2660  return fluid_.bGas(p, temp, rv, cond, cells_);
2661  default:
2662  OPM_THROW(std::runtime_error, "Unknown phase index " << phase);
2663  }
2664  }
2665 
2666 
2667 
2668 
2669 
2670  template <class Grid, class Implementation>
2671  ADB
2673  const ADB& b,
2674  const ADB& rs,
2675  const ADB& rv) const
2676  {
2677  const double* rhos = fluid_.surfaceDensity();
2678  ADB rho = rhos[phase] * b;
2679  if (phase == Oil && active_[Gas]) {
2680  // It is correct to index into rhos with canonical phase indices.
2681  rho += rhos[Gas] * rs * b;
2682  }
2683  if (phase == Gas && active_[Oil]) {
2684  // It is correct to index into rhos with canonical phase indices.
2685  rho += rhos[Oil] * rv * b;
2686  }
2687  return rho;
2688  }
2689 
2690 
2691 
2692 
2693 
2694  template <class Grid, class Implementation>
2695  V
2697  const V& satOil,
2698  const std::vector<int>& cells) const
2699  {
2700  return fluid_.rsSat(ADB::constant(p), ADB::constant(satOil), cells).value();
2701  }
2702 
2703 
2704 
2705 
2706 
2707  template <class Grid, class Implementation>
2708  ADB
2710  const ADB& satOil,
2711  const std::vector<int>& cells) const
2712  {
2713  return fluid_.rsSat(p, satOil, cells);
2714  }
2715 
2716 
2717 
2718 
2719 
2720  template <class Grid, class Implementation>
2721  V
2723  const V& satOil,
2724  const std::vector<int>& cells) const
2725  {
2726  return fluid_.rvSat(ADB::constant(p), ADB::constant(satOil), cells).value();
2727  }
2728 
2729 
2730 
2731 
2732 
2733  template <class Grid, class Implementation>
2734  ADB
2736  const ADB& satOil,
2737  const std::vector<int>& cells) const
2738  {
2739  return fluid_.rvSat(p, satOil, cells);
2740  }
2741 
2742 
2743 
2744 
2745 
2746  template <class Grid, class Implementation>
2747  ADB
2749  {
2750  const int n = p.size();
2751  if (rock_comp_props_ && rock_comp_props_->isActive()) {
2752  V pm(n);
2753  V dpm(n);
2754 #pragma omp parallel for schedule(static)
2755  for (int i = 0; i < n; ++i) {
2756  pm[i] = rock_comp_props_->poroMult(p.value()[i]);
2757  dpm[i] = rock_comp_props_->poroMultDeriv(p.value()[i]);
2758  }
2759  ADB::M dpm_diag(dpm.matrix().asDiagonal());
2760  const int num_blocks = p.numBlocks();
2761  std::vector<ADB::M> jacs(num_blocks);
2762 #pragma omp parallel for schedule(dynamic)
2763  for (int block = 0; block < num_blocks; ++block) {
2764  fastSparseProduct(dpm_diag, p.derivative()[block], jacs[block]);
2765  }
2766  return ADB::function(std::move(pm), std::move(jacs));
2767  } else {
2768  return ADB::constant(V::Constant(n, 1.0));
2769  }
2770  }
2771 
2772 
2773 
2774 
2775 
2776  template <class Grid, class Implementation>
2777  ADB
2779  {
2780  const int n = p.size();
2781  if (rock_comp_props_ && rock_comp_props_->isActive()) {
2782  V tm(n);
2783  V dtm(n);
2784 #pragma omp parallel for schedule(static)
2785  for (int i = 0; i < n; ++i) {
2786  tm[i] = rock_comp_props_->transMult(p.value()[i]);
2787  dtm[i] = rock_comp_props_->transMultDeriv(p.value()[i]);
2788  }
2789  ADB::M dtm_diag(dtm.matrix().asDiagonal());
2790  const int num_blocks = p.numBlocks();
2791  std::vector<ADB::M> jacs(num_blocks);
2792 #pragma omp parallel for schedule(dynamic)
2793  for (int block = 0; block < num_blocks; ++block) {
2794  fastSparseProduct(dtm_diag, p.derivative()[block], jacs[block]);
2795  }
2796  return ADB::function(std::move(tm), std::move(jacs));
2797  } else {
2798  return ADB::constant(V::Constant(n, 1.0));
2799  }
2800  }
2801 
2802 
2803 
2804 
2805 
2806  template <class Grid, class Implementation>
2807  void
2809  {
2810  using namespace Opm::AutoDiffGrid;
2811  const int nc = numCells(grid_);
2812  const int np = state.numPhases();
2813 
2814  const PhaseUsage& pu = fluid_.phaseUsage();
2815  const DataBlock s = Eigen::Map<const DataBlock>(& state.saturation()[0], nc, np);
2816  if (active_[ Gas ]) {
2817  // Oil/Gas or Water/Oil/Gas system
2818  const V so = s.col(pu.phase_pos[ Oil ]);
2819  const V sg = s.col(pu.phase_pos[ Gas ]);
2820 
2821  for (V::Index c = 0, e = sg.size(); c != e; ++c) {
2822  if (so[c] > 0) { phaseCondition_[c].setFreeOil (); }
2823  if (sg[c] > 0) { phaseCondition_[c].setFreeGas (); }
2824  if (active_[ Water ]) { phaseCondition_[c].setFreeWater(); }
2825  }
2826  }
2827  else {
2828  // Water/Oil system
2829  assert (active_[ Water ]);
2830 
2831  const V so = s.col(pu.phase_pos[ Oil ]);
2832 
2833 
2834  for (V::Index c = 0, e = so.size(); c != e; ++c) {
2835  phaseCondition_[c].setFreeWater();
2836 
2837  if (so[c] > 0) { phaseCondition_[c].setFreeOil(); }
2838  }
2839  }
2840  }
2841 
2842 
2843 
2844 
2845 
2846  template <class Grid, class Implementation>
2847  void
2849  {
2850  using namespace Opm::AutoDiffGrid;
2851  const int nc = numCells(grid_);
2852  const int np = state.numPhases();
2853 
2854  const PhaseUsage& pu = fluid_.phaseUsage();
2855  const DataBlock s = Eigen::Map<const DataBlock>(& state.saturation()[0], nc, np);
2856 
2857  // Water/Oil/Gas system
2858  assert (active_[ Gas ]);
2859 
2860  // reset the primary variables if RV and RS is not set Sg is used as primary variable.
2861  primalVariable_.resize(nc);
2862  std::fill(primalVariable_.begin(), primalVariable_.end(), PrimalVariables::Sg);
2863 
2864  const V sg = s.col(pu.phase_pos[ Gas ]);
2865  const V so = s.col(pu.phase_pos[ Oil ]);
2866  const V sw = s.col(pu.phase_pos[ Water ]);
2867 
2868  const double epsilon = std::sqrt(std::numeric_limits<double>::epsilon());
2869  auto watOnly = sw > (1 - epsilon);
2870  auto hasOil = so > 0;
2871  auto hasGas = sg > 0;
2872 
2873  // For oil only cells Rs is used as primal variable. For cells almost full of water
2874  // the default primal variable (Sg) is used.
2875  if (has_disgas_) {
2876  for (V::Index c = 0, e = sg.size(); c != e; ++c) {
2877  if ( !watOnly[c] && hasOil[c] && !hasGas[c] ) {primalVariable_[c] = PrimalVariables::RS; }
2878  }
2879  }
2880 
2881  // For gas only cells Rv is used as primal variable. For cells almost full of water
2882  // the default primal variable (Sg) is used.
2883  if (has_vapoil_) {
2884  for (V::Index c = 0, e = so.size(); c != e; ++c) {
2885  if ( !watOnly[c] && hasGas[c] && !hasOil[c] ) {primalVariable_[c] = PrimalVariables::RV; }
2886  }
2887  }
2889  }
2890 
2891 
2892 
2893 
2894 
2896  template <class Grid, class Implementation>
2897  void
2899  {
2900  if (! active_[Gas]) {
2901  OPM_THROW(std::logic_error, "updatePhaseCondFromPrimarVariable() logic requires active gas phase.");
2902  }
2903  const int nc = primalVariable_.size();
2904  isRs_ = V::Zero(nc);
2905  isRv_ = V::Zero(nc);
2906  isSg_ = V::Zero(nc);
2907  for (int c = 0; c < nc; ++c) {
2908  phaseCondition_[c] = PhasePresence(); // No free phases.
2909  phaseCondition_[c].setFreeWater(); // Not necessary for property calculation usage.
2910  switch (primalVariable_[c]) {
2911  case PrimalVariables::Sg:
2912  phaseCondition_[c].setFreeOil();
2913  phaseCondition_[c].setFreeGas();
2914  isSg_[c] = 1;
2915  break;
2916  case PrimalVariables::RS:
2917  phaseCondition_[c].setFreeOil();
2918  isRs_[c] = 1;
2919  break;
2920  case PrimalVariables::RV:
2921  phaseCondition_[c].setFreeGas();
2922  isRv_[c] = 1;
2923  break;
2924  default:
2925  OPM_THROW(std::logic_error, "Unknown primary variable enum value in cell " << c << ": " << primalVariable_[c]);
2926  }
2927  }
2928  }
2929 
2930 
2931 
2932 
2933 } // namespace Opm
2934 
2935 #endif // OPM_BLACKOILMODELBASE_IMPL_HEADER_INCLUDED
VFPEvaluation bhp(const VFPProdTable *table, const double &aqua, const double &liquid, const double &vapour, const double &thp, const double &alq)
Definition: VFPHelpers.hpp:517
Definition: GeoProps.hpp:53
std::vector< double > computeResidualNorms() const
Compute the residual norms of the mass balance for each phase, the well flux, and the well equation...
Definition: BlackoilModelBase_impl.hpp:2292
void makeConstantState(SolutionState &state) const
Definition: BlackoilModelBase_impl.hpp:388
Definition: BlackoilModelEnums.hpp:38
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
Definition: BlackoilModelEnums.hpp:43
double drMaxRel() const
Definition: BlackoilModelBase.hpp:518
std::vector< ADB > material_balance_eq
Definition: LinearisedBlackoilResidual.hpp:54
SolutionState variableStateExtractVars(const ReservoirState &x, const std::vector< int > &indices, std::vector< ADB > &vars) const
Definition: BlackoilModelBase_impl.hpp:566
virtual ADB muGas(const ADB &pg, const ADB &T, const ADB &rv, const std::vector< PhasePresence > &cond, const Cells &cells) const =0
LinearisedBlackoilResidual residual_
Definition: BlackoilModelBase.hpp:279
virtual ADB muWat(const ADB &pw, const ADB &T, const Cells &cells) const =0
Definition: BlackoilPropsAdInterface.hpp:38
double rateToCompare(const std::vector< double > &well_phase_flow_rate, const int well, const int num_phases, const double *distr)
Definition: BlackoilModelBase_impl.hpp:1198
std::vector< double > matbalscale
Definition: LinearisedBlackoilResidual.hpp:66
std::vector< int > primalVariable_
Definition: BlackoilModelBase.hpp:284
const DerivedGeology & geo_
Definition: BlackoilModelBase.hpp:251
M caver
Extract for each face the average of its adjacent cells' values.
Definition: AutoDiffHelpers.hpp:54
AutoDiffBlock< double > ADB
Definition: BlackoilModelBase_impl.hpp:83
Eigen::Array< Scalar, Eigen::Dynamic, 1 > V
Underlying type for values.
Definition: AutoDiffBlock.hpp:98
V fluidRvSat(const V &p, const V &so, const std::vector< int > &cells) const
Definition: BlackoilModelBase_impl.hpp:2722
const VFPInjProperties * getInj() const
Definition: VFPProperties.hpp:61
static std::vector< AutoDiffBlock > variables(const std::vector< V > &initial_values)
Definition: AutoDiffBlock.hpp:202
Definition: BlackoilModelEnums.hpp:47
const Vector & transmissibility() const
Definition: GeoProps.hpp:177
Definition: AdditionalObjectDeleter.hpp:22
V isRs_
Definition: BlackoilModelBase.hpp:273
bool getConvergence(const double dt, const int iteration)
Definition: BlackoilModelBase_impl.hpp:2420
void afterStep(const double dt, ReservoirState &reservoir_state, WellState &well_state)
Definition: BlackoilModelBase_impl.hpp:230
void updateState(const V &dx, ReservoirState &reservoir_state, WellState &well_state)
Definition: BlackoilModelBase_impl.hpp:1816
double infinityNorm(const ADB &a, const boost::any &pinfo=boost::any())
Compute the L-infinity norm of a vector This function is not suitable to compute on the well equatio...
Definition: BlackoilModelBase_impl.hpp:1763
ModelTraits< Implementation >::ModelParameters ModelParameters
Definition: BlackoilModelBase.hpp:108
double thp(int table_id, const double &aqua, const double &liquid, const double &vapour, const double &bhp, const double &alq) const
const VFPInjTable * getTable(const int table_id) const
const Wells & wells() const
Definition: BlackoilModelBase.hpp:309
const std::vector< bool > active_
Definition: BlackoilModelBase.hpp:257
double convergenceReduction(const Eigen::Array< double, Eigen::Dynamic, Eigen::Dynamic > &B, const Eigen::Array< double, Eigen::Dynamic, Eigen::Dynamic > &tempV, const Eigen::Array< double, Eigen::Dynamic, Eigen::Dynamic > &R, std::vector< double > &R_sum, std::vector< double > &maxCoeff, std::vector< double > &B_avg, std::vector< double > &maxNormWell, int nc, int nw) const
Compute the reduction within the convergence check.
Definition: BlackoilModelBase_impl.hpp:2335
static AutoDiffBlock null()
Construct an empty AutoDiffBlock.
Definition: AutoDiffBlock.hpp:103
void variableStateExtractWellsVars(const std::vector< int > &indices, std::vector< ADB > &vars, SolutionState &state) const
Definition: BlackoilModelBase_impl.hpp:638
const RockCompressibility * rock_comp_props_
Definition: BlackoilModelBase.hpp:252
int numBlocks() const
Number of Jacobian blocks.
Definition: AutoDiffBlock.hpp:419
Definition: BlackoilModelEnums.hpp:32
void computeWellConnectionPressures(const SolutionState &state, const WellState &xw)
Definition: BlackoilModelBase_impl.hpp:714
double computeHydrostaticCorrection(const Wells &wells, const int w, double vfp_ref_depth, const ADB::V &well_perforation_densities, const double gravity)
Definition: BlackoilModelBase_impl.hpp:1291
ModelTraits< Implementation >::ReservoirState ReservoirState
Definition: BlackoilModelBase.hpp:106
void updateWellState(const V &dwells, WellState &well_state)
Definition: BlackoilModelBase_impl.hpp:2040
const std::vector< int > canph_
Definition: BlackoilModelBase.hpp:259
bool wellsActive() const
Definition: BlackoilModelBase.hpp:305
Definition: AutoDiffHelpers.hpp:617
virtual SolutionVector computeNewtonIncrement(const LinearisedBlackoilResidual &residual) const =0
Implementation & asImpl()
Definition: BlackoilModelBase.hpp:292
virtual ADB rsSat(const ADB &po, const Cells &cells) const =0
virtual std::vector< ADB > capPress(const ADB &sw, const ADB &so, const ADB &sg, const Cells &cells) const =0
ADB transMult(const ADB &p) const
Definition: BlackoilModelBase_impl.hpp:2778
double maxResidualAllowed() const
Definition: BlackoilModelBase.hpp:519
Eigen::Array< double, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor > DataBlock
Definition: BlackoilModelBase_impl.hpp:89
virtual int numPhases() const =0
int numMaterials() const
Definition: BlackoilModelBase_impl.hpp:292
Definition: BlackoilModelEnums.hpp:46
Definition: GridHelpers.hpp:47
Selection. Choose first of two elements if selection basis element is nonnegative.
Definition: AutoDiffHelpers.hpp:359
Definition: BlackoilModelEnums.hpp:37
bool getWellConvergence(const int iteration)
Definition: BlackoilModelBase_impl.hpp:2542
void computeMassFlux(const int actph, const V &transi, const ADB &kr, const ADB &p, const SolutionState &state)
Definition: BlackoilModelBase_impl.hpp:2225
const Vector & poreVolume() const
Definition: GeoProps.hpp:176
Definition: BlackoilModelEnums.hpp:36
V pvdt_
Definition: BlackoilModelBase.hpp:285
bool localWellsActive() const
Definition: BlackoilModelBase.hpp:307
V well_perforation_pressure_diffs_
Definition: BlackoilModelBase.hpp:277
static std::vector< double > computeConnectionPressureDelta(const Wells &wells, const std::vector< double > &z_perf, const std::vector< double > &dens_perf, const double gravity)
void classifyCondition(const ReservoirState &state)
Definition: BlackoilModelBase_impl.hpp:2808
const WellOps wops_
Definition: BlackoilModelBase.hpp:262
void fastSparseProduct(const AutoDiffMatrix &lhs, const AutoDiffMatrix &rhs, AutoDiffMatrix &res)
Definition: AutoDiffMatrix.hpp:696
ADB select(const ADB &x1, const ADB &x2) const
Apply selector to ADB quantities.
Definition: AutoDiffHelpers.hpp:409
const BlackoilPropsAdInterface & fluid_
Definition: BlackoilModelBase.hpp:250
ModelTraits< Implementation >::SolutionState SolutionState
Definition: BlackoilModelBase.hpp:109
const VFPProdTable * getTable(const int table_id) const
V threshold_pressures_by_interior_face_
Definition: BlackoilModelBase.hpp:269
int size() const
Number of elements.
Definition: AutoDiffBlock.hpp:413
ModelParameters param_
Definition: BlackoilModelBase.hpp:266
void setThresholdPressures(const std::vector< double > &threshold_pressures_by_face)
Set threshold pressures that prevent or reduce flow. This prevents flow across faces if the potential...
Definition: BlackoilModelBase_impl.hpp:317
Eigen::SparseMatrix< double > p2w
Definition: BlackoilModelBase.hpp:244
ADB well_flux_eq
Definition: LinearisedBlackoilResidual.hpp:59
void updatePhaseCondFromPrimalVariable()
Update the phaseCondition_ member based on the primalVariable_ member.
Definition: BlackoilModelBase_impl.hpp:2898
std::vector< int > variableStateIndices() const
Definition: BlackoilModelBase_impl.hpp:525
BlackoilModelBase(const ModelParameters &param, const Grid &grid, const BlackoilPropsAdInterface &fluid, const DerivedGeology &geo, const RockCompressibility *rock_comp_props, const Wells *wells, const NewtonIterationBlackoilInterface &linsolver, Opm::EclipseStateConstPtr eclState, const bool has_disgas, const bool has_vapoil, const bool terminal_output)
Definition: BlackoilModelBase_impl.hpp:145
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 AutoDiffBlock constant(V &&val)
Definition: AutoDiffBlock.hpp:110
Eigen::ArrayXd sign(const Eigen::ArrayXd &x)
Return a vector of (-1.0, 0.0 or 1.0), depending on sign per element.
Definition: AutoDiffHelpers.hpp:713
virtual ADB bGas(const ADB &pg, const ADB &T, const ADB &rv, const std::vector< PhasePresence > &cond, const Cells &cells) const =0
Definition: BlackoilModelEnums.hpp:30
const std::vector< int > cells_
Definition: BlackoilModelBase.hpp:260
virtual const boost::any & parallelInformation() const =0
Get the information about the parallelization of the grid.
void solveWellEq(const std::vector< ADB > &mob_perfcells, const std::vector< ADB > &b_perfcells, SolutionState &state, WellState &well_state)
Definition: BlackoilModelBase_impl.hpp:1486
std::vector< bool > activePhases(const PU &pu)
Definition: BlackoilModelBase_impl.hpp:110
SolutionState variableState(const ReservoirState &x, const WellState &xw) const
Definition: BlackoilModelBase_impl.hpp:417
const std::vector< PhasePresence > phaseCondition() const
Definition: BlackoilModelBase.hpp:468
VFPProperties vfp_properties_
Definition: BlackoilModelBase.hpp:254
Definition: AutoDiffMatrix.hpp:43
M ngrad
Extract for each internal face the difference of its adjacent cells' values (first - second)...
Definition: AutoDiffHelpers.hpp:50
void variableReservoirStateInitials(const ReservoirState &x, std::vector< V > &vars0) const
Definition: BlackoilModelBase_impl.hpp:453
ADB::V computeHydrostaticCorrection(const Wells &wells, const ADB::V vfp_ref_depth, const ADB::V &well_perforation_densities, const double gravity)
Definition: BlackoilModelBase_impl.hpp:1311
Definition: BlackoilModelEnums.hpp:29
Eigen::Array< double, Eigen::Dynamic, 1 > cellCentroidsZToEigen(const UnstructuredGrid &grid)
Get the z coordinates of the cell centroids of a grid.
bool use_threshold_pressure_
Definition: BlackoilModelBase.hpp:267
V nnc_trans
The NNC transmissibilities.
Definition: AutoDiffHelpers.hpp:68
int linearIterationsLastSolve() const
Number of linear iterations used in last call to solveJacobianSystem().
Definition: BlackoilModelBase_impl.hpp:256
ADB::V V
Definition: BlackoilModelBase_impl.hpp:84
const Grid & grid_
Definition: BlackoilModelBase.hpp:249
bool empty() const
Definition: VFPProdProperties.hpp:149
int numPhases() const
The number of active fluid phases in the model.
Definition: BlackoilModelBase_impl.hpp:280
ADB::M M
Definition: BlackoilModelBase_impl.hpp:85
Definition: BlackoilModelEnums.hpp:44
M div
Extract for each cell the sum of its adjacent interior faces' (signed) values.
Definition: AutoDiffHelpers.hpp:56
Interface class for (linear) solvers for the fully implicit black-oil system.
Definition: NewtonIterationBlackoilInterface.hpp:31
std::vector< ADB > select(const std::vector< ADB > &xc) const
Apply selector to multiple per-cell quantities.
Definition: AutoDiffHelpers.hpp:225
V well_perforation_densities_
Definition: BlackoilModelBase.hpp:276
V isRv_
Definition: BlackoilModelBase.hpp:274
const bool has_vapoil_
Definition: BlackoilModelBase.hpp:264
ADB fluidDensity(const int phase, const ADB &b, const ADB &rs, const ADB &rv) const
Definition: BlackoilModelBase_impl.hpp:2672
std::vector< PhasePresence > phaseCondition_
Definition: BlackoilModelBase.hpp:272
HelperOps ops_
Definition: BlackoilModelBase.hpp:261
std::vector< V > variableStateInitials(const ReservoirState &x, const WellState &xw) const
Definition: BlackoilModelBase_impl.hpp:431
double dsMax() const
Definition: BlackoilModelBase.hpp:517
Eigen::SparseMatrix< double > w2p
Definition: BlackoilModelBase.hpp:243
const bool has_disgas_
Definition: BlackoilModelBase.hpp:263
ADB poroMult(const ADB &p) const
Definition: BlackoilModelBase_impl.hpp:2748
static AutoDiffBlock function(V &&val, std::vector< M > &&jac)
Definition: AutoDiffBlock.hpp:183
void assemble(const ReservoirState &reservoir_state, WellState &well_state, const bool initial_assembly)
Definition: BlackoilModelBase_impl.hpp:815
IFaces internal_faces
Definition: AutoDiffHelpers.hpp:47
virtual std::vector< ADB > relperm(const ADB &sw, const ADB &so, const ADB &sg, const Cells &cells) const =0
void computeAccum(const SolutionState &state, const int aix)
Definition: BlackoilModelBase_impl.hpp:655
V solveJacobianSystem() const
Definition: BlackoilModelBase_impl.hpp:1746
Definition: BlackoilModelEnums.hpp:45
V isSg_
Definition: BlackoilModelBase.hpp:275
const double * gravity() const
Definition: GeoProps.hpp:180
void updateEquationsScaling()
Update the scaling factors for mass balance equations.
Definition: BlackoilModelBase_impl.hpp:963
AutoDiffBlock< double > vertcatCollapseJacs(const std::vector< AutoDiffBlock< double > > &x)
Definition: AutoDiffHelpers.hpp:524
Definition: AutoDiffHelpers.hpp:176
WellOps(const Wells *wells)
Definition: BlackoilModelBase_impl.hpp:352
std::vector< ReservoirResidualQuant > rq_
Definition: BlackoilModelBase.hpp:271
double getGravity(const double *g, const int dim)
Definition: BlackoilModelBase_impl.hpp:698
bool terminal_output_
Whether we print something to std::cout.
Definition: BlackoilModelBase.hpp:282
std::vector< int > active2Canonical(const PU &pu)
Definition: BlackoilModelBase_impl.hpp:126
ADB bhp(const std::vector< int > &table_id, const Wells &wells, const ADB &qs, const ADB &thp, const ADB &alq) const
int sizeNonLinear() const
The size (number of unknowns) of the nonlinear system of equations.
Definition: BlackoilModelBase_impl.hpp:244
virtual ADB muOil(const ADB &po, const ADB &T, const ADB &rs, const std::vector< PhasePresence > &cond, const Cells &cells) const =0
V fluidRsSat(const V &p, const V &so, const std::vector< int > &cells) const
Definition: BlackoilModelBase_impl.hpp:2696
void prepareStep(const double dt, ReservoirState &reservoir_state, WellState &well_state)
Definition: BlackoilModelBase_impl.hpp:213
void updatePrimalVariableFromState(const ReservoirState &state)
Definition: BlackoilModelBase_impl.hpp:2848
double dpMaxRel() const
Definition: BlackoilModelBase.hpp:516
ADB fluidReciprocFVF(const int phase, const ADB &p, const ADB &temp, const ADB &rs, const ADB &rv, const std::vector< PhasePresence > &cond) const
Definition: BlackoilModelBase_impl.hpp:2647
void addWellFluxEq(const std::vector< ADB > &cq_s, const SolutionState &state)
Definition: BlackoilModelBase_impl.hpp:1177
const VFPProdProperties * getProd() const
Definition: VFPProperties.hpp:68
std::vector< int > buildAllCells(const int nc)
Definition: BlackoilModelBase_impl.hpp:97
void updateWellControls(WellState &xw) const
Definition: BlackoilModelBase_impl.hpp:1360
std::vector< ADB > computeRelPerm(const SolutionState &state) const
Definition: BlackoilModelBase_impl.hpp:2140
void computeWellFlux(const SolutionState &state, const std::vector< ADB > &mob_perfcells, const std::vector< ADB > &b_perfcells, V &aliveWells, std::vector< ADB > &cq_s)
Definition: BlackoilModelBase_impl.hpp:1003
void assembleMassBalanceEq(const SolutionState &state)
Definition: BlackoilModelBase_impl.hpp:899
ADB well_eq
Definition: LinearisedBlackoilResidual.hpp:64
std::vector< int > variableWellStateIndices() const
Definition: BlackoilModelBase_impl.hpp:548
virtual const double * surfaceDensity(int regionIdx=0) const =0
V computeGasPressure(const V &po, const V &sw, const V &so, const V &sg) const
Definition: BlackoilModelBase_impl.hpp:2206
bool terminalOutputEnabled() const
Return true if output to cout is wanted.
Definition: BlackoilModelBase_impl.hpp:268
void addWellContributionToMassBalanceEq(const std::vector< ADB > &cq_s, const SolutionState &state, const WellState &xw)
Definition: BlackoilModelBase_impl.hpp:983
bool empty() const
Definition: VFPInjProperties.hpp:138
ADB fluidViscosity(const int phase, const ADB &p, const ADB &temp, const ADB &rs, const ADB &rv, const std::vector< PhasePresence > &cond) const
Definition: BlackoilModelBase_impl.hpp:2622
ReservoirResidualQuant()
Definition: BlackoilModelBase_impl.hpp:337
const std::string & materialName(int material_index) const
Definition: BlackoilModelBase_impl.hpp:304
ADB::V V
Definition: BlackoilModelBase.hpp:103
void updatePerfPhaseRatesAndPressures(const std::vector< ADB > &cq_s, const SolutionState &state, WellState &xw)
Definition: BlackoilModelBase_impl.hpp:1152
virtual ADB bWat(const ADB &pw, const ADB &T, const Cells &cells) const =0
AutoDiff< Scalar > sqrt(const AutoDiff< Scalar > &x)
Definition: AutoDiff.hpp:287
bool constraintBroken(const std::vector< double > &bhp, const std::vector< double > &thp, const std::vector< double > &well_phase_flow_rate, const int well, const int num_phases, const WellType &well_type, const WellControls *wc, const int ctrl_index)
Definition: BlackoilModelBase_impl.hpp:1213
bool isVFPActive() const
Definition: BlackoilModelBase_impl.hpp:1328
double infinityNormWell(const ADB &a, const boost::any &pinfo)
Compute the L-infinity norm of a vector representing a well equation.
Definition: BlackoilModelBase_impl.hpp:1791
const V & value() const
Function value.
Definition: AutoDiffBlock.hpp:436
void applyThresholdPressures(ADB &dp)
Definition: BlackoilModelBase_impl.hpp:2260
const Vector & z() const
Definition: GeoProps.hpp:179
static std::vector< double > computeConnectionDensities(const Wells &wells, const WellStateFullyImplicitBlackoil &wstate, const PhaseUsage &phase_usage, const std::vector< double > &b_perf, const std::vector< double > &rsmax_perf, const std::vector< double > &rvmax_perf, const std::vector< double > &surf_dens_perf)
virtual ADB rvSat(const ADB &po, const Cells &cells) const =0
ADB bhp(const std::vector< int > &table_id, const Wells &wells, const ADB &qs, const ADB &thp) const
const std::vector< M > & derivative() const
Function derivatives.
Definition: AutoDiffBlock.hpp:442
void addWellControlEq(const SolutionState &state, const WellState &xw, const V &aliveWells)
Definition: BlackoilModelBase_impl.hpp:1580
ModelTraits< Implementation >::WellState WellState
Definition: BlackoilModelBase.hpp:107
virtual ADB bOil(const ADB &po, const ADB &T, const ADB &rs, const std::vector< PhasePresence > &cond, const Cells &cells) const =0
double thp(int table_id, const double &aqua, const double &liquid, const double &vapour, const double &bhp) const
void variableWellStateInitials(const WellState &xw, std::vector< V > &vars0) const
Definition: BlackoilModelBase_impl.hpp:491
Definition: BlackoilModelEnums.hpp:31
const NewtonIterationBlackoilInterface & linsolver_
Definition: BlackoilModelBase.hpp:255
std::vector< ADB > computePressures(const ADB &po, const ADB &sw, const ADB &so, const ADB &sg) const
Definition: BlackoilModelBase_impl.hpp:2170
virtual PhaseUsage phaseUsage() const =0