opm-simulators
CompWell_impl.hpp
1 /*
2  Copyright 2024, 2026, SINTEF Digital
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 #include <fmt/format.h>
21 #include <fmt/ranges.h>
22 
23 #include <opm/common/ErrorMacros.hpp>
24 #include <opm/common/OpmLog/OpmLog.hpp>
25 
26 #include <opm/material/fluidstates/CompositionalFluidState.hpp>
27 
28 #include <opm/input/eclipse/EclipseState/Tables/StandardCond.hpp>
29 
30 #include <stdexcept>
31 
32 namespace Opm {
33 
34 template <typename TypeTag>
35 CompWell<TypeTag>::
36 CompWell(const Well& well,
37  int index_of_well,
38  const std::vector<CompConnectionData>& well_connection_data)
39  : CompWellInterface<TypeTag>(well, index_of_well, well_connection_data)
40 {
41 }
42 
43 template <typename TypeTag>
44 void
45 CompWell<TypeTag>::
46 init()
47 {
48  Base::init();
49  well_equations_.init(this->number_of_connection_, this->well_cells_);
50 }
51 
52 template <typename TypeTag>
53 void
54 CompWell<TypeTag>::
55 calculateExplicitQuantities(const Simulator& simulator,
56  const SingleWellState& well_state)
57 {
58  updatePrimaryVariables(simulator, well_state);
59  {
60  // flash calculation in the wellbore to obtain the explicit
61  // component masses
62  auto fluid_state_scalar = this->primary_variables_.template toFluidState<Scalar>();
63 
64  flashFluidState_(fluid_state_scalar);
65 
66  this->component_masses_ = wellboreComponentMasses(fluid_state_scalar, this->wellbore_volume_);
67  }
68 }
69 
70 template <typename TypeTag>
71 void
72 CompWell<TypeTag>::
73 updatePrimaryVariables(const Simulator& /* simulator */,
74  const SingleWellState& well_state)
75 {
76  this->primary_variables_.update(well_state);
77 }
78 
79 template <typename TypeTag>
80 void
81 CompWell<TypeTag>::
82 updateSecondaryQuantities(const Simulator& simulator)
83 {
84  updateTotalMass();
85  updateSurfaceQuantities(simulator);
86 }
87 
88 
89 template <typename TypeTag>
90 void
91 CompWell<TypeTag>::
92 updateTotalMass()
93 {
94  // flash calculation in the wellbore
95  auto fluid_state = this->primary_variables_.template toFluidState<EvalWell>();
96 
97  flashFluidState_(fluid_state);
98 
99  this->new_component_masses_ = wellboreComponentMasses(fluid_state, this->wellbore_volume_);
100 
101  EvalWell total_mass = 0.;
102  for (unsigned compidx = 0; compidx < FluidSystem::numComponents; ++compidx) {
103  total_mass += this->new_component_masses_[compidx];
104  }
105 
106  const auto& so = fluid_state.saturation(FluidSystem::oilPhaseIdx);
107  const auto& sg = fluid_state.saturation(FluidSystem::gasPhaseIdx);
108  const auto& density_oil = fluid_state.density(FluidSystem::oilPhaseIdx);
109  const auto& density_gas = fluid_state.density(FluidSystem::gasPhaseIdx);
110  // TODO: some properties should go to the fluid_state?
111  fluid_density_ = density_oil * so + density_gas * sg;
112 
113  // The AD derivatives of the component masses and mass fractions with respect
114  // to the wellbore primary variables (pressure and composition), including the
115  // dependence that flows through the flash, are checked against finite
116  // differences in tests/test_compwell_jacobian.cpp.
117  for (unsigned compidx = 0; compidx < FluidSystem::numComponents; ++compidx) {
118  mass_fractions_[compidx] = this->new_component_masses_[compidx] / total_mass;
119  }
120 }
121 
122 template <typename TypeTag>
123 void
124 CompWell<TypeTag>::
125 updateSurfaceQuantities(const Simulator& simulator)
126 {
127  const auto& surface_cond = simulator.vanguard().eclState().getTableManager().stCond();
128  if (this->well_ecl_.isInjector()) { // we look for well stream for injection composition
129  const auto& inj_composition = this->well_ecl_.getInjectionProperties().gasInjComposition();
130  FluidState<Scalar> fluid_state;
131  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
132  fluid_state.setMoleFraction(comp_idx, std::max(inj_composition[comp_idx], 1.e-10));
133  }
134  updateSurfaceCondition_(surface_cond, fluid_state);
135  } else { // the composition will be from the wellbore
136  // here, it will use the composition from the wellbore and the pressure and temperature from the surface condition
137  auto fluid_state = this->primary_variables_.template toFluidState<EvalWell>();
138  updateSurfaceCondition_(surface_cond, fluid_state);
139  }
140 }
141 
142 template <typename TypeTag>
143 void
144 CompWell<TypeTag>::
145 calculateSingleConnectionRate(const Simulator& simulator,
146  std::vector<EvalWell>& con_rates) const
147 {
148  constexpr int con_idx = 0; // TODO: to be a function argument for multiple connection wells
149  constexpr int np = 2; // TODO: this will be the number of phases
150  const EvalWell& bhp = this->primary_variables_.getBhp();
151  const unsigned cell_idx = this->well_cells_[0];
152  const auto& int_quantities = simulator.problem().model().cachedIntensiveQuantities(cell_idx, 0);
153  assert(int_quantities);
154  std::vector<EvalWell> mob(np, 0.);
155  getMobility(simulator, con_idx, mob);
156 
157  const Scalar tw = this->well_index_[0]; // only one connection
158 
159  const auto& fluid_state = int_quantities->fluidState();
160 
161  const EvalWell cell_pressure = PrimaryVariables::extendEval(fluid_state.pressure(FluidSystem::oilPhaseIdx));
162  const EvalWell drawdown = cell_pressure - bhp;
163 
164  if (drawdown > 0.) { // producing connection
165  std::vector<EvalWell> cq_v(np);
166  for (unsigned phase_idx = 0; phase_idx < np; ++phase_idx) {
167  cq_v[phase_idx] = - mob[phase_idx] * tw * drawdown;
168  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; comp_idx++) {
169  const EvalWell density = PrimaryVariables::extendEval(fluid_state.density(phase_idx));
170  const EvalWell mass_fraction = PrimaryVariables::extendEval(fluid_state.massFraction(phase_idx, comp_idx));
171  con_rates[comp_idx] += cq_v[phase_idx] * density * mass_fraction;
172  }
173  }
174  } else { // injecting connection
175  EvalWell total_mobility = 0.;
176  for (unsigned phase_idx = 0; phase_idx < np; ++phase_idx) {
177  total_mobility += mob[phase_idx];
178  }
179  EvalWell cq_v = - total_mobility * tw * drawdown;
180  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; comp_idx++) {
181  con_rates[comp_idx] = cq_v * fluid_density_ * mass_fractions_[comp_idx];
182  }
183  }
184 }
185 
186 template <typename TypeTag>
187 void CompWell<TypeTag>::
188 getMobility(const Simulator& simulator,
189  const int connectin_idx,
190  std::vector<EvalWell>& mob) const
191 {
192  const unsigned cell_idx = this->well_cells_[connectin_idx];
193  const auto& int_quants = simulator.problem().model().cachedIntensiveQuantities(cell_idx, 0);
194  assert(int_quants);
195  const auto& material_law_manager = simulator.problem().materialLawManager();
196 
197  // either use mobility of the perforation cell or calculate its own
198  // based on passing the saturation table index
199  const int satid = this->saturation_table_number_[connectin_idx] - 1;
200  const int satid_elem = material_law_manager->satnumRegionIdx(cell_idx);
201 
202  if (satid == satid_elem) {
203  for (unsigned phase_idx = 0; phase_idx < FluidSystem::numPhases; ++phase_idx) {
204  mob[phase_idx] = PrimaryVariables::extendEval(int_quants->mobility(phase_idx));
205  }
206  } else {
207  // TODO: not sure how to handle this at the moment, throw for now
208  OPM_THROW(std::logic_error,
209  "CompWell::getMobility: a connection saturation table differing from the "
210  "cell saturation region is not supported yet");
211  }
212 
213 }
214 
215 template <typename TypeTag>
216 void
217 CompWell<TypeTag>::
218 assembleWellEq(const Simulator& simulator,
219  const SingleWellState& well_state,
220  const double dt)
221 {
222  this->well_equations_.clear();
223 
224  this->updateSecondaryQuantities(simulator);
225 
226  assembleSourceTerm(dt);
227 
228  std::vector<EvalWell> connection_rates(FluidSystem::numComponents, 0.);
229  calculateSingleConnectionRate(simulator, connection_rates);
230  // only one perforation for now
231  auto& con_rates = this->connectionRates_[0];
232  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
233  con_rates[comp_idx] = PrimaryVariables::restrictEval(connection_rates[comp_idx]);
234  }
235 
236  // here we use perf index, need to check how the things are done in the StandardWellAssemble
237  // assemble the well equations related to the production/injection mass rates for each component
238  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
239  // the signs need to be checked
240  this->well_equations_.residual()[0][comp_idx] += connection_rates[comp_idx].value();
241  for (unsigned pvIdx = 0; pvIdx < PrimaryVariables::numWellEq; ++pvIdx) {
242  // C, needs the cell_idx
243  this->well_equations_.C()[0][0][pvIdx][comp_idx] -= connection_rates[comp_idx].derivative(pvIdx + PrimaryVariables::numResEq);
244  this->well_equations_.D()[0][0][comp_idx][pvIdx] += connection_rates[comp_idx].derivative(pvIdx + PrimaryVariables::numResEq);
245  }
246 
247  for (unsigned pvIdx = 0; pvIdx < PrimaryVariables::numResEq; ++pvIdx) {
248  this->well_equations_.B()[0][0][comp_idx][pvIdx] += connection_rates[comp_idx].derivative(pvIdx);
249  }
250  }
251 
252  const auto& summary_state = simulator.vanguard().summaryState();
253  assembleControlEq(well_state, summary_state);
254 
255  this->well_equations_.invert();
256  // there will be num_comp mass balance equations for each component and one for the well control equations
257  // for the mass balance equations, it will be the sum of the connection rates for each component,
258  // add minus the production rate for each component, will equal to the mass change for each component
259 
260 }
261 
262 template <typename TypeTag>
263 void
264 CompWell<TypeTag>::
265 assembleControlEq(const SingleWellState& well_state,
266  const SummaryState& summary_state)
267 {
268  EvalWell control_eq;
269  if (this->well_ecl_.isProducer()) {
270  const auto prod_controls = this->well_ecl_.productionControls(summary_state);
271  assembleControlEqProd(well_state, prod_controls, control_eq);
272  } else {
273  const auto inj_controls = this->well_ecl_.injectionControls(summary_state);
274  assembleControlEqInj(well_state, inj_controls, control_eq);
275  }
276 
277  this->well_equations_.residual()[0][PrimaryVariables::Bhp] = control_eq.value();
278  for (unsigned pvIdx = 0; pvIdx < PrimaryVariables::numWellEq; ++pvIdx) {
279  this->well_equations_.D()[0][0][PrimaryVariables::Bhp][pvIdx] = control_eq.derivative(pvIdx + PrimaryVariables::numResEq);
280  }
281 }
282 
283 template <typename TypeTag>
284 void
285 CompWell<TypeTag>::
286 assembleControlEqProd(const SingleWellState& well_state,
287  const Well::ProductionControls& prod_controls,
288  EvalWell& control_eq) const
289 {
290  // TODO: we only need to pass in the current control?
291  const auto current = well_state.production_cmode;
292 
293  const auto& surface_cond = this->surface_conditions_;
294 
295  switch (current) {
296  case WellProducerCMode::BHP : {
297  const Scalar bhp_limit = prod_controls.bhp_limit;
298  control_eq = this->primary_variables_.getBhp() - bhp_limit;
299  break;
300  }
301  case WellProducerCMode::ORAT : {
302  const Scalar rate_target = prod_controls.oil_rate;
303  const EvalWell& total_rate = this->primary_variables_.getTotalRate();
304  const EvalWell oil_rate = total_rate * surface_cond.volume_fractions_[FluidSystem::oilPhaseIdx];
305  control_eq = oil_rate + rate_target;
306  break;
307  }
308  case WellProducerCMode::GRAT : {
309  const Scalar rate_target = prod_controls.gas_rate;
310  const EvalWell& total_rate = this->primary_variables_.getTotalRate();
311  const EvalWell gas_rate = total_rate * surface_cond.volume_fractions_[FluidSystem::gasPhaseIdx];
312  control_eq = gas_rate + rate_target;
313  break;
314  }
315  default:
316  OPM_THROW(std::logic_error, "only handles BHP, ORAT and GRAT control for producers for now");
317  }
318 }
319 
320 template <typename TypeTag>
321 void
322 CompWell<TypeTag>::
323 assembleControlEqInj(const SingleWellState& well_state,
324  const Well::InjectionControls& inj_controls,
325  EvalWell& control_eq) const
326 {
327  // TODO: we only need to pass in the current control?
328  const auto current = well_state.injection_cmode;
329 
330  switch (current) {
331  case WellInjectorCMode::BHP : {
332  const Scalar bhp_limit = inj_controls.bhp_limit;
333  control_eq = this->primary_variables_.getBhp() - bhp_limit;
334  break;
335  }
336  case WellInjectorCMode::RATE : {
337  const Scalar rate_target = inj_controls.surface_rate;
338  const EvalWell& injection_rate = this->primary_variables_.getTotalRate();
339  control_eq = injection_rate - rate_target;
340  break;
341  }
342  default:
343  OPM_THROW(std::logic_error, "only handles BHP and RATE control for injectors for now");
344  }
345 }
346 
347 
348 template <typename TypeTag>
349 void
350 CompWell<TypeTag>::
351 assembleSourceTerm(const Scalar dt)
352 {
353  // calculating the injection mass rate for each component
354  const EvalWell total_surface_rate = this->primary_variables_.getTotalRate();
355  const EvalWell density = this->surface_conditions_.density();
356  const EvalWell total_mass_rate = total_surface_rate * density;
357  std::array<EvalWell, FluidSystem::numComponents> component_mass_rates;
358  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
359  component_mass_rates[comp_idx] = total_mass_rate * this->surface_conditions_.massFraction(comp_idx);
360  }
361 
362  for (unsigned comp_idx = 0; comp_idx < FluidSystem::numComponents; ++comp_idx) {
363  const EvalWell residual = (this->new_component_masses_[comp_idx] - this->component_masses_[comp_idx]) / dt - component_mass_rates[comp_idx];
364  // let us put it in the well equation
365  for (int pvIdx = 0; pvIdx < PrimaryVariables::numWellEq; ++pvIdx) {
366  this->well_equations_.D()[0][0][comp_idx][pvIdx] += residual.derivative(pvIdx + PrimaryVariables::numResEq);
367  }
368  this->well_equations_.residual()[0][comp_idx] += residual.value();
369  }
370 }
371 
372 template <typename TypeTag>
373 bool
374 CompWell<TypeTag>::
375 iterateWellEq(const Simulator& simulator,
376  const Scalar dt,
377  SingleWellState& well_state)
378 {
379  constexpr int max_iter = 200;
380 
381  int it = 0;
382  bool converged = false;
383 
384  do {
385  updateWellControl(simulator.vanguard().summaryState(), well_state);
386 
387  assembleWellEq(simulator, well_state, dt);
388 
389  // get convergence
390  converged = this->getConvergence();
391 
392  if (converged) {
393  break;
394  }
395 
396  ++it;
397 
398  solveEqAndUpdateWellState(well_state);
399  } while (it < max_iter);
400  return converged;
401 }
402 
403 template <typename TypeTag>
404 void
405 CompWell<TypeTag>::
406 solveEqAndUpdateWellState(SingleWellState& well_state)
407 {
408  BVectorWell dx_well(1);
409 
410  this->well_equations_.solve(dx_well);
411 
412  this->updateWellState(dx_well, well_state);
413 }
414 
415 template<typename TypeTag>
416 void
417 CompWell<TypeTag>::
418 apply(BVector& r) const
419 {
420  this->well_equations_.apply(r);
421 }
422 
423 template <typename TypeTag>
424 void
425 CompWell<TypeTag>::
426 recoverWellSolutionAndUpdateWellState(const BVector& x,
427  SingleWellState& well_state)
428 {
429  BVectorWell xw(1);
430 
431  this->well_equations_.recoverSolutionWell(x, xw);
432 
433  updateWellState(xw, well_state);
434 }
435 
436 template <typename TypeTag>
437 void
438 CompWell<TypeTag>::
439 updatePrimaryVariablesNewton(const BVectorWell& dwells)
440 {
441  this->primary_variables_.updateNewton(dwells);
442 }
443 
444 template <typename TypeTag>
445 void
446 CompWell<TypeTag>::
447 updateWellState(const CompWell::BVectorWell& xw,
448  SingleWellState& well_state)
449 {
450  updatePrimaryVariablesNewton(xw);
451  updateWellStateFromPrimaryVariables(well_state);
452 }
453 
454 template <typename TypeTag>
455 void
456 CompWell<TypeTag>::
457 updateWellStateFromPrimaryVariables(SingleWellState& well_state) const
458 {
459  well_state.bhp = this->primary_variables_.getBhp().value();
460 
461  auto& total_molar_fractions = well_state.total_molar_fractions;
462  const auto fluid_state = this->primary_variables_.template toFluidState<Scalar>();
463  for (int comp_idx = 0; comp_idx < FluidSystem::numComponents - 1; ++comp_idx) {
464  total_molar_fractions[comp_idx] = fluid_state.moleFraction(comp_idx);
465  }
466  const Scalar total_rate = this->primary_variables_.getTotalRate().value();
467  auto& surface_phase_rates = well_state.surface_phase_rates;
468  if (well_state.producer) { // producer
469  const auto& surface_cond = this->surface_conditions_;
470  for (int p = 0; p < FluidSystem::numPhases; ++p) {
471  surface_phase_rates[p] = total_rate * getValue(surface_cond.volume_fractions_[p]);
472  }
473  } else { // injector
474  // only gas injection yet
475  surface_phase_rates[FluidSystem::gasPhaseIdx] = total_rate;
476  }
477 }
478 
479 template <typename TypeTag>
480 bool
481 CompWell<TypeTag>::
482 getConvergence() const
483 {
484  bool converged = true;
485  for (const auto& val : this->well_equations_.residual()[0]) {
486  converged = converged && (std::abs(val) < 1.e-8);
487  }
488  return converged;
489 }
490 
491 template <typename TypeTag>
492 void
493 CompWell<TypeTag>::
494 addWellContributions(SparseMatrixAdapter&) const
495 {
496  assert(false);
497 }
498 
499 template <typename TypeTag>
500 void
501 CompWell<TypeTag>::
502 updateWellControl(const SummaryState& summary_state,
503  SingleWellState& well_state) const
504 {
505  std::string from;
506  if (this->well_ecl_.isInjector()) {
507  from = WellInjectorCMode2String(well_state.injection_cmode);
508  } else {
509  from = WellProducerCMode2String(well_state.production_cmode);
510  }
511  bool changed = false;
512  if (this->well_ecl_.isProducer()) {
513  const auto production_controls = this->well_ecl_.productionControls(summary_state);
514  const auto current_control = well_state.production_cmode;
515 
516  if (production_controls.hasControl(Well::ProducerCMode::BHP) && current_control != WellProducerCMode::BHP) {
517  const Scalar bhp_limit = production_controls.bhp_limit;
518  const Scalar current_bhp = well_state.bhp;
519  if (current_bhp < bhp_limit) {
520  well_state.bhp = bhp_limit;
521  well_state.production_cmode = WellProducerCMode::BHP;
522  changed = true;
523  }
524  }
525 
526  if (!changed && production_controls.hasControl(Well::ProducerCMode::ORAT) && current_control != WellProducerCMode::ORAT) {
527  const Scalar current_rate = -well_state.surface_phase_rates[FluidSystem::oilPhaseIdx];
528  if (current_rate > production_controls.oil_rate) {
529  well_state.production_cmode = WellProducerCMode::ORAT;
530  changed = true;
531  }
532  }
533 
534  if (!changed && production_controls.hasControl(Well::ProducerCMode::WRAT) && current_control != WellProducerCMode::WRAT) {
535  const Scalar current_rate = -well_state.surface_phase_rates[FluidSystem::waterPhaseIdx];
536  if (current_rate > production_controls.water_rate) {
537  well_state.production_cmode = WellProducerCMode::WRAT;
538  changed = true;
539  }
540  }
541 
542  if (!changed && production_controls.hasControl(Well::ProducerCMode::GRAT) && current_control != WellProducerCMode::GRAT) {
543  const Scalar current_rate = -well_state.surface_phase_rates[FluidSystem::gasPhaseIdx];
544  if (current_rate > production_controls.gas_rate) {
545  well_state.production_cmode = WellProducerCMode::GRAT;
546  changed = true;
547  }
548  }
549  } else {
550  const auto injection_controls = this->well_ecl_.injectionControls(summary_state);
551  const auto current_control = well_state.injection_cmode;
552  if (injection_controls.hasControl(Well::InjectorCMode::BHP) && current_control != WellInjectorCMode::BHP) {
553  const Scalar bhp_limit = injection_controls.bhp_limit;
554  const Scalar current_bhp = well_state.bhp;
555  OpmLog::debug(fmt::format("Well {} BHP control check: current_bhp={:.6e}, bhp_limit={:.6e}, exceeds_limit={}",
556  this->well_ecl_.name(), current_bhp, bhp_limit, (current_bhp > bhp_limit)));
557  if (current_bhp > bhp_limit) {
558  well_state.bhp = bhp_limit;
559  well_state.injection_cmode = WellInjectorCMode::BHP;
560  changed = true;
561  }
562  }
563  if (!changed && injection_controls.hasControl(Well::InjectorCMode::RATE) && current_control != WellInjectorCMode::RATE) {
564  // InjectorType injector_type = injection_controls.injector_type;
565  const Scalar rate_limit = injection_controls.surface_rate;
566  // TODO: hack to get the injection rate
567  const Scalar current_rate = std::accumulate(well_state.surface_phase_rates.begin(),
568  well_state.surface_phase_rates.end(), 0.0);
569  OpmLog::debug(fmt::format("Well {} RATE control check: current_rate={:.6e}, rate_limit={:.6e}, bhp={:.6e}, phase_rates=[{}]",
570  this->well_ecl_.name(), current_rate, rate_limit, well_state.bhp,
571  fmt::join(well_state.surface_phase_rates, ", ")));
572  if (current_rate > rate_limit) {
573  OpmLog::debug(fmt::format("Well {} RATE control TRIGGERED: current_rate={:.6e} > rate_limit={:.6e}",
574  this->well_ecl_.name(), current_rate, rate_limit));
575  well_state.injection_cmode = WellInjectorCMode::RATE;
576  changed = true;
577  }
578  }
579  }
580 
581  if (changed) {
582  std::string to;
583  if (this->well_ecl_.isInjector()) {
584  to = WellInjectorCMode2String(well_state.injection_cmode);
585  } else {
586  to = WellProducerCMode2String(well_state.production_cmode);
587  }
588  OpmLog::info(fmt::format("Well {} changed control from {} to {} \n", this->well_ecl_.name(), from, to));
589  }
590 }
591 
592 template <typename TypeTag>
593 template <typename T>
594 void
595 CompWell<TypeTag>::
596 updateSurfaceCondition_(const StandardCond& surface_cond, FluidState<T>& fluid_state)
597 {
598  static_assert(std::is_same_v<T, Scalar> || std::is_same_v<T, EvalWell>, "Unsupported type in CompWell::updateSurfaceCondition_");
599 
600  fluid_state.setTemperature(surface_cond.temperature);
601  fluid_state.setPressure(FluidSystem::oilPhaseIdx, surface_cond.pressure);
602  fluid_state.setPressure(FluidSystem::gasPhaseIdx, surface_cond.pressure);
603 
604  for (int i = 0; i < FluidSystem::numComponents; ++i) {
605  fluid_state.setKvalue(i, fluid_state.wilsonK_(i));
606  }
607 
608  flashFluidState_(fluid_state);
609 
610  for (unsigned compidx = 0; compidx < FluidSystem::numComponents; ++compidx) {
611  this->surface_conditions_.mass_fractions_[FluidSystem::oilPhaseIdx][compidx] =
612  fluid_state.massFraction(FluidSystem::oilPhaseIdx, compidx);
613  this->surface_conditions_.mass_fractions_[FluidSystem::gasPhaseIdx][compidx] =
614  fluid_state.massFraction(FluidSystem::gasPhaseIdx, compidx);
615  }
616  const auto& density_oil = fluid_state.density(FluidSystem::oilPhaseIdx);
617  const auto& density_gas = fluid_state.density(FluidSystem::gasPhaseIdx);
618  this->surface_conditions_.surface_densities_[FluidSystem::oilPhaseIdx] = density_oil;
619  this->surface_conditions_.surface_densities_[FluidSystem::gasPhaseIdx] = density_gas;
620  this->surface_conditions_.volume_fractions_[FluidSystem::oilPhaseIdx] = fluid_state.saturation(FluidSystem::oilPhaseIdx);
621  this->surface_conditions_.volume_fractions_[FluidSystem::gasPhaseIdx] = fluid_state.saturation(FluidSystem::gasPhaseIdx);
622 }
623 
624 template <typename TypeTag>
625 template <typename T>
626 void
627 CompWell<TypeTag>::
628 flashFluidState_(FluidState<T>& fluid_state)
629 {
630  static_assert(std::is_same_v<T, Scalar> || std::is_same_v<T, EvalWell>, "Unsupported type in CompWell::flashFluidState_");
631 
632  // The wellbore flash is a free function so it can be unit tested in
633  // isolation (see tests/test_compwell_jacobian.cpp).
634  flashWellboreFluidState(fluid_state);
635 }
636 
637 } // end of namespace Opm
std::array< T, FluidSystem::numComponents > wellboreComponentMasses(const CompositionalFluidState< T, FluidSystem > &fluid_state, const Scalar wellbore_volume)
Mass [kg] of each component held in the wellbore control volume, given an already-flashed two-phase f...
Definition: CompWellFlash.hpp:113
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
void flashWellboreFluidState(CompositionalFluidState< T, FluidSystem > &fluid_state, const typename FluidSystem::Scalar flash_tolerance=1.e-6)
Flash the wellbore fluid at its current (pressure, temperature, overall composition) and fill in the ...
Definition: CompWellFlash.hpp:54