BlackoilSolventModel_impl.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2015 IRIS AS
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef OPM_BLACKOILSOLVENTMODEL_IMPL_HEADER_INCLUDED
21 #define OPM_BLACKOILSOLVENTMODEL_IMPL_HEADER_INCLUDED
22 
24 
31 
32 #include <opm/core/grid.h>
33 #include <opm/core/linalg/LinearSolverInterface.hpp>
34 #include <opm/core/linalg/ParallelIstlInformation.hpp>
35 #include <opm/core/props/rock/RockCompressibility.hpp>
36 #include <opm/common/ErrorMacros.hpp>
37 #include <opm/common/Exceptions.hpp>
38 #include <opm/core/utility/Units.hpp>
39 #include <opm/core/well_controls.h>
40 #include <opm/core/utility/parameters/ParameterGroup.hpp>
41 
42 #include <cassert>
43 #include <cmath>
44 #include <iostream>
45 #include <iomanip>
46 #include <limits>
47 
48 namespace Opm {
49 
50 
51 
52  namespace detail {
53 
54  template <class PU>
55  int solventPos(const PU& pu)
56  {
57  const int maxnp = Opm::BlackoilPhases::MaxNumPhases;
58  int pos = 0;
59  for (int phase = 0; phase < maxnp; ++phase) {
60  if (pu.phase_used[phase]) {
61  pos++;
62  }
63  }
64 
65  return pos;
66  }
67 
68  } // namespace detail
69 
70 
71 
72  template <class Grid>
74  const Grid& grid,
75  const BlackoilPropsAdInterface& fluid,
76  const DerivedGeology& geo,
77  const RockCompressibility* rock_comp_props,
78  const SolventPropsAdFromDeck& solvent_props,
79  const Wells* wells_arg,
80  const NewtonIterationBlackoilInterface& linsolver,
81  const EclipseStateConstPtr eclState,
82  const bool has_disgas,
83  const bool has_vapoil,
84  const bool terminal_output,
85  const bool has_solvent)
86  : Base(param, grid, fluid, geo, rock_comp_props, wells_arg, linsolver,
87  eclState, has_disgas, has_vapoil, terminal_output),
88  has_solvent_(has_solvent),
89  solvent_pos_(detail::solventPos(fluid.phaseUsage())),
90  solvent_props_(solvent_props)
91  {
92  if (has_solvent_) {
93 
94  // If deck has solvent, residual_ should contain solvent equation.
95  rq_.resize(fluid_.numPhases() + 1);
97  Base::material_name_.push_back("Solvent");
98  assert(solvent_pos_ == fluid_.numPhases());
99  if (has_vapoil_) {
100  OPM_THROW(std::runtime_error, "Solvent option only works with dead gas\n");
101  }
102 
103  residual_.matbalscale.resize(fluid_.numPhases() + 1, 0.0031); // use the same as gas
104 
105  }
106  }
107 
108 
109 
110 
111 
112  template <class Grid>
113  void
115  {
116  Base::makeConstantState(state);
117  state.solvent_saturation = ADB::constant(state.solvent_saturation.value());
118  }
119 
120 
121 
122 
123 
124  template <class Grid>
125  std::vector<V>
127  const WellState& xw) const
128  {
129  std::vector<V> vars0 = Base::variableStateInitials(x, xw);
130  assert(int(vars0.size()) == fluid_.numPhases() + 2);
131 
132  // Initial polymer concentration.
133  if (has_solvent_) {
134  assert (not x.solvent_saturation().empty());
135  const int nc = x.solvent_saturation().size();
136  const V ss = Eigen::Map<const V>(&x.solvent_saturation()[0], nc);
137  // Solvent belongs after other reservoir vars but before well vars.
138  auto solvent_pos = vars0.begin() + fluid_.numPhases();
139  assert(solvent_pos == vars0.end() - 2);
140  vars0.insert(solvent_pos, ss);
141  }
142  return vars0;
143  }
144 
145 
146 
147 
148 
149  template <class Grid>
150  std::vector<int>
152  {
153  std::vector<int> ind = Base::variableStateIndices();
154  assert(ind.size() == 5);
155  if (has_solvent_) {
156  ind.resize(6);
157  // Solvent belongs after other reservoir vars but before well vars.
158  ind[Solvent] = fluid_.numPhases();
159  // Solvent is pushing back the well vars.
160  ++ind[Qs];
161  ++ind[Bhp];
162  }
163  return ind;
164  }
165 
166 
167 
168 
169  template <class Grid>
172  const std::vector<int>& indices,
173  std::vector<ADB>& vars) const
174  {
175  SolutionState state = Base::variableStateExtractVars(x, indices, vars);
176  if (has_solvent_) {
177  state.solvent_saturation = std::move(vars[indices[Solvent]]);
178  if (active_[ Oil ]) {
179  // Note that so is never a primary variable.
180  const Opm::PhaseUsage pu = fluid_.phaseUsage();
181  state.saturation[pu.phase_pos[ Oil ]] -= state.solvent_saturation;
182  }
183  }
184  return state;
185  }
186 
187 
188 
189 
190 
191  template <class Grid>
192  void
194  const int aix )
195  {
196  Base::computeAccum(state, aix);
197 
198  // Compute accumulation of the solvent
199  if (has_solvent_) {
200  const ADB& press = state.pressure;
201  const ADB& ss = state.solvent_saturation;
202  const ADB pv_mult = poroMult(press); // also computed in Base::computeAccum, could be optimized.
203  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
204 
205  const ADB& pg = state.canonical_phase_pressures[pu.phase_pos[Gas]];
206  rq_[solvent_pos_].b = solvent_props_.bSolvent(pg,cells_);
207  rq_[solvent_pos_].accum[aix] = pv_mult * rq_[solvent_pos_].b * ss;
208  }
209  }
210 
211 
212 
213 
214 
215  template <class Grid>
216  void
219  {
220 
221  Base::assembleMassBalanceEq(state);
222 
223  if (has_solvent_) {
224  residual_.material_balance_eq[ solvent_pos_ ] =
225  pvdt_ * (rq_[solvent_pos_].accum[1] - rq_[solvent_pos_].accum[0])
226  + ops_.div*rq_[solvent_pos_].mflux;
227  }
228 
229  }
230 
231  template <class Grid>
232  void
234  {
235  Base::updateEquationsScaling();
236  assert(MaxNumPhases + 1 == residual_.matbalscale.size());
237  if (has_solvent_) {
238  const ADB& temp_b = rq_[solvent_pos_].b;
239  ADB::V B = 1. / temp_b.value();
240  residual_.matbalscale[solvent_pos_] = B.mean();
241  }
242  }
243 
244  template <class Grid>
246  const SolutionState& state,
247  WellState& xw)
248 
249  {
250 
251  // Add well contributions to solvent mass balance equation
252 
253  Base::addWellContributionToMassBalanceEq(cq_s, state, xw);
254 
255  if (has_solvent_) {
256  const int nperf = wells().well_connpos[wells().number_of_wells];
257  const int nc = Opm::AutoDiffGrid::numCells(grid_);
258 
259  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
260  const ADB zero = ADB::constant(V::Zero(nc));
261  const ADB& ss = state.solvent_saturation;
262  const ADB& sg = (active_[ Gas ]
263  ? state.saturation[ pu.phase_pos[ Gas ] ]
264  : zero);
265 
266  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
267  Selector<double> zero_selector(ss.value() + sg.value(), Selector<double>::Zero);
268  ADB F_solvent = subset(zero_selector.select(ss, ss / (ss + sg)),well_cells);
269 
270  const int nw = wells().number_of_wells;
271  V injectedSolventFraction = Eigen::Map<const V>(&xw.solventFraction()[0], nperf);
272 
273  V isProducer = V::Zero(nperf);
274  V ones = V::Constant(nperf,1.0);
275  for (int w = 0; w < nw; ++w) {
276  if(wells().type[w] == PRODUCER) {
277  for (int perf = wells().well_connpos[w]; perf < wells().well_connpos[w+1]; ++perf) {
278  isProducer[perf] = 1;
279  }
280  }
281  }
282 
283  const ADB& rs_perfcells = subset(state.rs, well_cells);
284  int gas_pos = fluid_.phaseUsage().phase_pos[Gas];
285  int oil_pos = fluid_.phaseUsage().phase_pos[Oil];
286  // remove contribution from the dissolved gas.
287  // TODO compensate for gas in the oil phase
288  assert(!has_vapoil_);
289  const ADB cq_s_solvent = (isProducer * F_solvent + (ones - isProducer) * injectedSolventFraction) * (cq_s[gas_pos] - rs_perfcells * cq_s[oil_pos]);
290 
291  // Solvent contribution to the mass balance equation is given as a fraction
292  // of the gas contribution.
293  residual_.material_balance_eq[solvent_pos_] -= superset(cq_s_solvent, well_cells, nc);
294 
295  // The gas contribution must be reduced accordingly for the total contribution to be
296  // the same.
297  residual_.material_balance_eq[gas_pos] += superset(cq_s_solvent, well_cells, nc);
298 
299  }
300  }
301 
302  template <class Grid>
304  const WellState& xw)
305  {
306  if( ! Base::localWellsActive() ) return ;
307 
308  using namespace Opm::AutoDiffGrid;
309  // 1. Compute properties required by computeConnectionPressureDelta().
310  // Note that some of the complexity of this part is due to the function
311  // taking std::vector<double> arguments, and not Eigen objects.
312  const int nperf = wells().well_connpos[wells().number_of_wells];
313  const int nw = wells().number_of_wells;
314  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
315 
316  // Compute the average pressure in each well block
317  const V perf_press = Eigen::Map<const V>(xw.perfPress().data(), nperf);
318  V avg_press = perf_press*0;
319  for (int w = 0; w < nw; ++w) {
320  for (int perf = wells().well_connpos[w]; perf < wells().well_connpos[w+1]; ++perf) {
321  const double p_above = perf == wells().well_connpos[w] ? state.bhp.value()[w] : perf_press[perf - 1];
322  const double p_avg = (perf_press[perf] + p_above)/2;
323  avg_press[perf] = p_avg;
324  }
325  }
326 
327  // Use cell values for the temperature as the wells don't knows its temperature yet.
328  const ADB perf_temp = subset(state.temperature, well_cells);
329 
330  // Surface density.
331  const PhaseUsage& pu = fluid_.phaseUsage();
332  //std::vector<double> surf_dens(fluid_.surfaceDensity(), fluid_.surfaceDensity() + pu.num_phases);
333  DataBlock surf_dens(nperf, pu.num_phases);
334  for (int phase = 0; phase < pu.num_phases; ++ phase) {
335  surf_dens.col(phase) = V::Constant(nperf, fluid_.surfaceDensity()[pu.phase_pos[phase]]);
336  }
337 
338  // Compute b, rsmax, rvmax values for perforations.
339  // Evaluate the properties using average well block pressures
340  // and cell values for rs, rv, phase condition and temperature.
341  const ADB avg_press_ad = ADB::constant(avg_press);
342  std::vector<PhasePresence> perf_cond(nperf);
343  const std::vector<PhasePresence>& pc = phaseCondition();
344  for (int perf = 0; perf < nperf; ++perf) {
345  perf_cond[perf] = pc[well_cells[perf]];
346  }
347 
348  DataBlock b(nperf, pu.num_phases);
349  std::vector<double> rsmax_perf(nperf, 0.0);
350  std::vector<double> rvmax_perf(nperf, 0.0);
351  if (pu.phase_used[BlackoilPhases::Aqua]) {
352  const V bw = fluid_.bWat(avg_press_ad, perf_temp, well_cells).value();
353  b.col(pu.phase_pos[BlackoilPhases::Aqua]) = bw;
354  }
355  assert(active_[Oil]);
356  const V perf_so = subset(state.saturation[pu.phase_pos[Oil]].value(), well_cells);
357  if (pu.phase_used[BlackoilPhases::Liquid]) {
358  const ADB perf_rs = subset(state.rs, well_cells);
359  const V bo = fluid_.bOil(avg_press_ad, perf_temp, perf_rs, perf_cond, well_cells).value();
360  b.col(pu.phase_pos[BlackoilPhases::Liquid]) = bo;
361  const V rssat = fluidRsSat(avg_press, perf_so, well_cells);
362  rsmax_perf.assign(rssat.data(), rssat.data() + nperf);
363  }
364  if (pu.phase_used[BlackoilPhases::Vapour]) {
365  const ADB perf_rv = subset(state.rv, well_cells);
366  V bg = fluid_.bGas(avg_press_ad, perf_temp, perf_rv, perf_cond, well_cells).value();
367 
368  if (has_solvent_) {
369  const V bs = solvent_props_.bSolvent(avg_press_ad,well_cells).value();
370  // A weighted sum of the b-factors of gas and solvent are used.
371  const int nc = Opm::AutoDiffGrid::numCells(grid_);
372 
373  const ADB zero = ADB::constant(V::Zero(nc));
374  const ADB& ss = state.solvent_saturation;
375  const ADB& sg = (active_[ Gas ]
376  ? state.saturation[ pu.phase_pos[ Gas ] ]
377  : zero);
378 
379  Selector<double> zero_selector(ss.value() + sg.value(), Selector<double>::Zero);
380  V F_solvent = subset(zero_selector.select(ss, ss / (ss + sg)),well_cells).value();
381 
382  V injectedSolventFraction = Eigen::Map<const V>(&xw.solventFraction()[0], nperf);
383 
384  V isProducer = V::Zero(nperf);
385  V ones = V::Constant(nperf,1.0);
386  for (int w = 0; w < nw; ++w) {
387  if(wells().type[w] == PRODUCER) {
388  for (int perf = wells().well_connpos[w]; perf < wells().well_connpos[w+1]; ++perf) {
389  isProducer[perf] = 1;
390  }
391  }
392  }
393  F_solvent = isProducer * F_solvent + (ones - isProducer) * injectedSolventFraction;
394 
395  bg = bg * (ones - F_solvent);
396  bg = bg + F_solvent * bs;
397 
398  const V& rhog = surf_dens.col(pu.phase_pos[BlackoilPhases::Vapour]);
399  const V& rhos = solvent_props_.solventSurfaceDensity(well_cells);
400  surf_dens.col(pu.phase_pos[BlackoilPhases::Vapour]) = ( (ones - F_solvent) * rhog ) + (F_solvent * rhos);
401  }
402  b.col(pu.phase_pos[BlackoilPhases::Vapour]) = bg;
403 
404  const V rvsat = fluidRvSat(avg_press, perf_so, well_cells);
405  rvmax_perf.assign(rvsat.data(), rvsat.data() + nperf);
406  }
407 
408  // b and surf_dens_perf is row major, so can just copy data.
409  std::vector<double> b_perf(b.data(), b.data() + nperf * pu.num_phases);
410  std::vector<double> surf_dens_perf(surf_dens.data(), surf_dens.data() + nperf * pu.num_phases);
411 
412  // Extract well connection depths.
413  const V depth = cellCentroidsZToEigen(grid_);
414  const V pdepth = subset(depth, well_cells);
415  std::vector<double> perf_depth(pdepth.data(), pdepth.data() + nperf);
416 
417  // Gravity
418  double grav = detail::getGravity(geo_.gravity(), dimensions(grid_));
419 
420  // 2. Compute densities
421  std::vector<double> cd =
423  wells(), xw, fluid_.phaseUsage(),
424  b_perf, rsmax_perf, rvmax_perf, surf_dens_perf);
425 
426  // 3. Compute pressure deltas
427  std::vector<double> cdp =
429  wells(), perf_depth, cd, grav);
430 
431  // 4. Store the results
432  Base::well_perforation_densities_ = Eigen::Map<const V>(cd.data(), nperf);
433  Base::well_perforation_pressure_diffs_ = Eigen::Map<const V>(cdp.data(), nperf);
434  }
435 
436 
437 
438 
439 
440 
441  template <class Grid>
443  ReservoirState& reservoir_state,
444  WellState& well_state)
445  {
446 
447  if (has_solvent_) {
448  // Extract solvent change.
449  const int np = fluid_.numPhases();
450  const int nc = Opm::AutoDiffGrid::numCells(grid_);
451  const V zero = V::Zero(nc);
452  const int solvent_start = nc * np;
453  const V dss = subset(dx, Span(nc, 1, solvent_start));
454 
455  // Create new dx with the dss part deleted.
456  V modified_dx = V::Zero(dx.size() - nc);
457  modified_dx.head(solvent_start) = dx.head(solvent_start);
458  const int tail_len = dx.size() - solvent_start - nc;
459  modified_dx.tail(tail_len) = dx.tail(tail_len);
460 
461  // Call base version.
462  Base::updateState(modified_dx, reservoir_state, well_state);
463 
464  // Update solvent.
465  const V ss_old = Eigen::Map<const V>(&reservoir_state.solvent_saturation()[0], nc, 1);
466  const V ss = (ss_old - dss).max(zero);
467  std::copy(&ss[0], &ss[0] + nc, reservoir_state.solvent_saturation().begin());
468 
469  // adjust oil saturation
470  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
471  const int oilpos = pu.phase_pos[ Oil ];
472  for (int c = 0; c < nc; ++c) {
473  reservoir_state.saturation()[c*np + oilpos] = 1 - ss[c];
474  if (pu.phase_used[ Gas ]) {
475  const int gaspos = pu.phase_pos[ Gas ];
476  reservoir_state.saturation()[c*np + oilpos] -= reservoir_state.saturation()[c*np + gaspos];
477  }
478  if (pu.phase_used[ Water ]) {
479  const int waterpos = pu.phase_pos[ Water ];
480  reservoir_state.saturation()[c*np + oilpos] -= reservoir_state.saturation()[c*np + waterpos];
481  }
482  }
483 
484  } else {
485  // Just forward call to base version.
486  Base::updateState(dx, reservoir_state, well_state);
487  }
488  }
489 
490 
491 
492 
493 
494  template <class Grid>
495  void
497  const V& transi,
498  const ADB& kr ,
499  const ADB& phasePressure,
500  const SolutionState& state)
501  {
502  Base::computeMassFlux(actph, transi, kr, phasePressure, state);
503 
504  const int canonicalPhaseIdx = canph_[ actph ];
505  if (canonicalPhaseIdx == Gas) {
506  if (has_solvent_) {
507  const int nc = Opm::UgGridHelpers::numCells(grid_);
508 
509  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
510  const ADB zero = ADB::constant(V::Zero(nc));
511  const ADB& ss = state.solvent_saturation;
512  const ADB& sg = (active_[ Gas ]
513  ? state.saturation[ pu.phase_pos[ Gas ] ]
514  : zero);
515 
516  Selector<double> zero_selector(ss.value() + sg.value(), Selector<double>::Zero);
517  ADB F_solvent = zero_selector.select(ss, ss / (ss + sg));
518  V ones = V::Constant(nc, 1.0);
519 
520  const ADB tr_mult = transMult(state.pressure);
521  const ADB mu = solvent_props_.muSolvent(phasePressure,cells_);
522 
523  rq_[solvent_pos_].mob = solvent_props_.solventRelPermMultiplier(F_solvent, cells_) * tr_mult * kr / mu;
524 
525  const ADB rho_solvent = solvent_props_.solventSurfaceDensity(cells_) * rq_[solvent_pos_].b;
526  const ADB rhoavg_solvent = ops_.caver * rho_solvent;
527  rq_[ solvent_pos_ ].dh = ops_.ngrad * phasePressure - geo_.gravity()[2] * (rhoavg_solvent * (ops_.ngrad * geo_.z().matrix()));
528 
529  UpwindSelector<double> upwind_solvent(grid_, ops_, rq_[solvent_pos_].dh.value());
530  // Compute solvent flux.
531  rq_[solvent_pos_].mflux = upwind_solvent.select(rq_[solvent_pos_].b * rq_[solvent_pos_].mob) * (transi * rq_[solvent_pos_].dh);
532 
533  // Update gas mobility and flux
534  rq_[actph].mob = solvent_props_.gasRelPermMultiplier( (ones - F_solvent) , cells_) * rq_[actph].mob;
535 
536  const ADB& b = rq_[ actph ].b;
537  const ADB& mob = rq_[ actph ].mob;
538  const ADB& dh = rq_[ actph ].dh;
539  UpwindSelector<double> upwind_gas(grid_, ops_, dh.value());
540  rq_[ actph ].mflux = upwind_gas.select(b * mob) * (transi * dh);
541  }
542  }
543 
544  }
545 
546  template <class Grid>
547  std::vector<ADB>
549  {
550  using namespace Opm::AutoDiffGrid;
551  const int nc = numCells(grid_);
552 
553  const ADB zero = ADB::constant(V::Zero(nc));
554 
555  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
556  const ADB& sw = (active_[ Water ]
557  ? state.saturation[ pu.phase_pos[ Water ] ]
558  : zero);
559 
560  const ADB& so = (active_[ Oil ]
561  ? state.saturation[ pu.phase_pos[ Oil ] ]
562  : zero);
563 
564  const ADB& sg = (active_[ Gas ]
565  ? state.saturation[ pu.phase_pos[ Gas ] ]
566  : zero);
567 
568  if (has_solvent_) {
569  const ADB& ss = state.solvent_saturation;
570  return fluid_.relperm(sw, so, sg+ss, cells_);
571  } else {
572  return fluid_.relperm(sw, so, sg, cells_);
573  }
574 
575  }
576 
577 
578  template <class Grid>
579  void
581  WellState& well_state,
582  const bool initial_assembly)
583  {
584 
585  using namespace Opm::AutoDiffGrid;
586 
587  // Possibly switch well controls and updating well state to
588  // get reasonable initial conditions for the wells
589  updateWellControls(well_state);
590 
591  // Create the primary variables.
592  SolutionState state = variableState(reservoir_state, well_state);
593 
594  if (initial_assembly) {
595  // Create the (constant, derivativeless) initial state.
596  SolutionState state0 = state;
597  makeConstantState(state0);
598  // Compute initial accumulation contributions
599  // and well connection pressures.
600  computeAccum(state0, 0);
601  computeWellConnectionPressures(state0, well_state);
602  }
603 
604  // -------- Mass balance equations --------
605  assembleMassBalanceEq(state);
606 
607  // -------- Well equations ----------
608  if ( ! wellsActive() ) {
609  return;
610  }
611 
612  V aliveWells;
613 
614  const int np = wells().number_of_phases;
615  std::vector<ADB> cq_s(np, ADB::null());
616 
617  const int nw = wells().number_of_wells;
618  const int nperf = wells().well_connpos[nw];
619  const std::vector<int> well_cells(wells().well_cells, wells().well_cells + nperf);
620 
621  std::vector<ADB> mob_perfcells(np, ADB::null());
622  std::vector<ADB> b_perfcells(np, ADB::null());
623  for (int phase = 0; phase < np; ++phase) {
624  mob_perfcells[phase] = subset(rq_[phase].mob, well_cells);
625  b_perfcells[phase] = subset(rq_[phase].b, well_cells);
626  }
627 
628  if (has_solvent_) {
629  int gas_pos = fluid_.phaseUsage().phase_pos[Gas];
630  // Gas and solvent is combinded and solved together
631  // The input in the well equation is then the
632  // total gas phase = hydro carbon gas + solvent gas
633 
634  // The total mobility is the sum of the solvent and gas mobiliy
635  mob_perfcells[gas_pos] += subset(rq_[solvent_pos_].mob, well_cells);
636 
637  // A weighted sum of the b-factors of gas and solvent are used.
638  const int nc = Opm::AutoDiffGrid::numCells(grid_);
639 
640  const Opm::PhaseUsage& pu = fluid_.phaseUsage();
641  const ADB zero = ADB::constant(V::Zero(nc));
642  const ADB& ss = state.solvent_saturation;
643  const ADB& sg = (active_[ Gas ]
644  ? state.saturation[ pu.phase_pos[ Gas ] ]
645  : zero);
646 
647  Selector<double> zero_selector(ss.value() + sg.value(), Selector<double>::Zero);
648  ADB F_solvent = subset(zero_selector.select(ss, ss / (ss + sg)),well_cells);
649  V ones = V::Constant(nperf,1.0);
650  b_perfcells[gas_pos] = (ones - F_solvent) * b_perfcells[gas_pos];
651  b_perfcells[gas_pos] += (F_solvent * subset(rq_[solvent_pos_].b, well_cells));
652  }
653  if (param_.solve_welleq_initially_ && initial_assembly) {
654  // solve the well equations as a pre-processing step
655  Base::solveWellEq(mob_perfcells, b_perfcells, state, well_state);
656  }
657 
658  Base::computeWellFlux(state, mob_perfcells, b_perfcells, aliveWells, cq_s);
659  Base::updatePerfPhaseRatesAndPressures(cq_s, state, well_state);
660  Base::addWellFluxEq(cq_s, state);
661  addWellContributionToMassBalanceEq(cq_s, state, well_state);
662  Base::addWellControlEq(state, well_state, aliveWells);
663 
664  }
665 
666 
667 }
668 
669 
670 #endif // OPM_BLACKOILSOLVENT_IMPL_HEADER_INCLUDED
Definition: GeoProps.hpp:53
Base::SolutionState SolutionState
Definition: BlackoilSolventModel.hpp:101
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
std::vector< ADB > material_balance_eq
Definition: LinearisedBlackoilResidual.hpp:54
LinearisedBlackoilResidual residual_
Definition: BlackoilModelBase.hpp:279
Definition: BlackoilPropsAdInterface.hpp:38
std::vector< double > matbalscale
Definition: LinearisedBlackoilResidual.hpp:66
Eigen::Array< Scalar, Eigen::Dynamic, 1 > V
Underlying type for values.
Definition: AutoDiffBlock.hpp:98
Definition: BlackoilModelEnums.hpp:47
Definition: AdditionalObjectDeleter.hpp:22
ModelTraits< BlackoilSolventModel< Grid > >::ModelParameters ModelParameters
Definition: BlackoilModelBase.hpp:108
void computeAccum(const SolutionState &state, const int aix)
Definition: BlackoilSolventModel_impl.hpp:193
static AutoDiffBlock null()
Construct an empty AutoDiffBlock.
Definition: AutoDiffBlock.hpp:103
std::vector< std::string > material_name_
Definition: BlackoilModelBase.hpp:286
std::vector< V > variableStateInitials(const ReservoirState &x, const WellState &xw) const
Definition: BlackoilSolventModel_impl.hpp:126
int solventPos(const PU &pu)
Definition: BlackoilSolventModel_impl.hpp:55
Definition: BlackoilModelEnums.hpp:32
void makeConstantState(SolutionState &state) const
Definition: BlackoilSolventModel_impl.hpp:114
Definition: AutoDiffHelpers.hpp:617
const int solvent_pos_
Definition: BlackoilSolventModel.hpp:107
virtual int numPhases() const =0
Definition: BlackoilModelEnums.hpp:46
Definition: GridHelpers.hpp:47
Selection. Choose first of two elements if selection basis element is nonnegative.
Definition: AutoDiffHelpers.hpp:359
static std::vector< double > computeConnectionPressureDelta(const Wells &wells, const std::vector< double > &z_perf, const std::vector< double > &dens_perf, const double gravity)
const BlackoilPropsAdInterface & fluid_
Definition: BlackoilModelBase.hpp:250
void assemble(const ReservoirState &reservoir_state, WellState &well_state, const bool initial_assembly)
Definition: BlackoilSolventModel_impl.hpp:580
void addWellContributionToMassBalanceEq(const std::vector< ADB > &cq_s, const SolutionState &state, WellState &xw)
Definition: BlackoilSolventModel_impl.hpp:245
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
Definition: BlackoilModelEnums.hpp:30
SolutionState variableStateExtractVars(const ReservoirState &x, const std::vector< int > &indices, std::vector< ADB > &vars) const
Definition: BlackoilSolventModel_impl.hpp:171
Base::WellState WellState
Definition: BlackoilSolventModel.hpp:46
void computeMassFlux(const int actph, const V &transi, const ADB &kr, const ADB &p, const SolutionState &state)
Definition: BlackoilSolventModel_impl.hpp:496
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.
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
const bool has_vapoil_
Definition: BlackoilModelBase.hpp:264
void updateState(const V &dx, ReservoirState &reservoir_state, WellState &well_state)
Definition: BlackoilSolventModel_impl.hpp:442
void computeWellConnectionPressures(const SolutionState &state, const WellState &xw)
Definition: BlackoilSolventModel_impl.hpp:303
void updateEquationsScaling()
Definition: BlackoilSolventModel_impl.hpp:233
Definition: AutoDiffHelpers.hpp:176
std::vector< ReservoirResidualQuant > rq_
Definition: BlackoilModelBase.hpp:271
double getGravity(const double *g, const int dim)
Definition: BlackoilModelBase_impl.hpp:698
BlackoilSolventModel(const typename Base::ModelParameters &param, const Grid &grid, const BlackoilPropsAdInterface &fluid, const DerivedGeology &geo, const RockCompressibility *rock_comp_props, const SolventPropsAdFromDeck &solvent_props, const Wells *wells, const NewtonIterationBlackoilInterface &linsolver, const EclipseStateConstPtr eclState, const bool has_disgas, const bool has_vapoil, const bool terminal_output, const bool has_solvent)
Definition: BlackoilSolventModel_impl.hpp:73
Definition: SolventPropsAdFromDeck.hpp:38
void assembleMassBalanceEq(const SolutionState &state)
Definition: BlackoilSolventModel_impl.hpp:218
const bool has_solvent_
Definition: BlackoilSolventModel.hpp:106
Base::ReservoirState ReservoirState
Definition: BlackoilSolventModel.hpp:45
std::vector< ADB > computeRelPerm(const SolutionState &state) const
Definition: BlackoilSolventModel_impl.hpp:548
std::vector< int > variableStateIndices() const
Definition: BlackoilSolventModel_impl.hpp:151
ADB::V V
Definition: BlackoilModelBase.hpp:103
const V & value() const
Function value.
Definition: AutoDiffBlock.hpp:436
Base::DataBlock DataBlock
Definition: BlackoilSolventModel.hpp:102
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)
Definition: BlackoilModelEnums.hpp:31