opm-simulators
MultisegmentWell.hpp
1 /*
2  Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
3  Copyright 2017 Statoil ASA.
4 
5  This file is part of the Open Porous Media project (OPM).
6 
7  OPM is free software: you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation, either version 3 of the License, or
10  (at your option) any later version.
11 
12  OPM is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with OPM. If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 
22 #ifndef OPM_MULTISEGMENTWELL_HEADER_INCLUDED
23 #define OPM_MULTISEGMENTWELL_HEADER_INCLUDED
24 
26 
27 #include <opm/common/Exceptions.hpp>
28 #include <opm/simulators/wells/WellInterface.hpp>
29 #include <opm/simulators/wells/MultisegmentWellEval.hpp>
30 
31 #include <limits>
32 #include <string_view>
33 
34 namespace Opm {
35 
36  class DeferredLogger;
37 
38  template<typename TypeTag>
39  class MultisegmentWell : public WellInterface<TypeTag>
40  , public MultisegmentWellEval<GetPropType<TypeTag, Properties::FluidSystem>,
41  GetPropType<TypeTag, Properties::Indices>>
42  {
43  public:
47 
48  using typename Base::Simulator;
49  using typename Base::IntensiveQuantities;
50  using typename Base::FluidSystem;
51  using typename Base::IndexTraits;
52  using typename Base::ModelParameters;
53  using typename Base::MaterialLaw;
54  using typename Base::Indices;
55  using typename Base::RateConverterType;
56  using typename Base::SparseMatrixAdapter;
57  using typename Base::FluidState;
58  using typename Base::WellStateType;
59  using typename Base::GroupStateHelperType;
60 
61  using Base::has_solvent;
62  using Base::has_polymer;
63  using Base::has_energy;
64  using Base::has_brine;
65  using Base::Water;
66  using Base::Oil;
67  using Base::Gas;
68 
69  using typename Base::Scalar;
70 
71  // True when the composition switch primary variable is active, i.e. both oil and
72  // gas phases are present so that Rs/Rv are stored in the fluid state. Matches the
73  // fluid state's enableDissolution flag (see WellInterface::BlackOilFluidStateType).
74  static constexpr bool compositionSwitchEnabled =
75  Indices::compositionSwitchIdx != std::numeric_limits<unsigned>::max();
76 
77  // Scales the well-side energy equation onto the mass-balance residual
78  // scale. Reuses the reservoir energy factor so both live on the same scale.
79  static constexpr Scalar energy_scaling_factor_ =
80  getPropValue<TypeTag, Properties::BlackOilEnergyScalingFactor>();
81 
83  using typename Base::BVector;
84  using typename Base::Eval;
85 
86  using typename MSWEval::Equations;
87  using typename MSWEval::EvalWell;
88  using typename MSWEval::BVectorWell;
89  using MSWEval::SPres;
90  using typename Base::PressureMatrix;
91  using FSInfo = std::tuple<Scalar, Scalar>;
92 
93  using BMatrix = typename Base::BMatrix;
94  using CMatrix = typename Base::CMatrix;
95  using DMatrix = typename Base::DMatrix;
96  using WVector = typename Base::WVector;
97 
98  // a fluid state to calculate the properties inside the wellbore for each segment
99  // it will be probably used for more things, but at the moment, it is for the enthalpy
100  // calculation in the wellbore.
101  template <typename ValueType>
102  using SegmentFluidState = Base::template BlackOilFluidStateType<ValueType>;
103 
104  MultisegmentWell(const Well& well,
105  const ParallelWellInfo<Scalar>& pw_info,
106  const int time_step,
107  const ModelParameters& param,
108  const RateConverterType& rate_converter,
109  const int pvtRegionIdx,
110  const int num_conservation_quantities,
111  const int num_phases,
112  const int index_of_well,
113  const std::vector<PerforationData<Scalar>>& perf_data);
114 
115  void init(const std::vector<Scalar>& depth_arg,
116  const Scalar gravity_arg,
117  const std::vector<Scalar>& B_avg,
118  const bool changed_to_open_this_step) override;
119 
121  void updateWellStateWithTarget(const Simulator& simulator,
122  const GroupStateHelperType& groupStateHelper,
123  WellStateType& well_state) const override;
124 
126  void scaleSegmentRatesAndPressure(WellStateType& well_state) const override;
127 
130  const std::vector<Scalar>& B_avg,
131  const bool relax_tolerance) const override;
132 
134  void apply(const BVector& x, BVector& Ax) const override;
136  void apply(BVector& r) const override;
137 
140  void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
141  const BVector& x,
142  const GroupStateHelperType& groupStateHelper,
143  WellStateType& well_state) override;
144 
146  void computeWellPotentials(const Simulator& simulator,
147  const WellStateType& well_state,
148  const GroupStateHelperType& groupStateHelper,
149  std::vector<Scalar>& well_potentials) override;
150 
151  void updatePrimaryVariables(const GroupStateHelperType& groupStateHelper) override;
152 
153  void solveEqAndUpdateWellState(const Simulator& simulator,
154  const GroupStateHelperType& groupStateHelper,
155  WellStateType& well_state) override; // const?
156 
157  void calculateExplicitQuantities(const Simulator& simulator,
158  const GroupStateHelperType& groupStateHelper) override; // should be const?
159 
160  void updateIPRImplicit(const Simulator& simulator,
161  const GroupStateHelperType& groupStateHelper,
162  WellStateType& well_state) override;
163 
164  void updateProductivityIndex(const Simulator& simulator,
165  const WellProdIndexCalculator<Scalar>& wellPICalc,
166  WellStateType& well_state,
167  DeferredLogger& deferred_logger) const override;
168 
169  Scalar connectionDensity(const int globalConnIdx,
170  const int openConnIdx) const override;
171 
172  void addWellContributions(SparseMatrixAdapter& jacobian) const override;
173 
174  void addWellPressureEquations(PressureMatrix& mat,
175  const BVector& x,
176  const int pressureVarIndex,
177  const bool use_well_weights,
178  const WellStateType& well_state) const override;
179 
180  std::vector<Scalar>
181  computeCurrentWellRates(const Simulator& simulator,
182  DeferredLogger& deferred_logger) const override;
183 
184  std::optional<Scalar>
185  computeBhpAtThpLimitProdWithAlq(const Simulator& simulator,
186  const GroupStateHelperType& groupStateHelper,
187  const SummaryState& summary_state,
188  const Scalar alq_value,
189  bool iterate_if_no_solution) const override;
190 
191  std::vector<Scalar> getPrimaryVars() const override;
192 
193  int setPrimaryVars(typename std::vector<Scalar>::const_iterator it) override;
194  void addBCDMatrix(std::vector<typename Base::BMatrix>& b_matrices,
195  std::vector<typename Base::CMatrix>& c_matrices,
196  std::vector<typename Base::DMatrix>& d_matrices,
197  Opm::SparseTable<int>& wcells) const override
198  {
199  // System_cpr preconditioner is only supported when well DOF dimensions
200  // match between WellInterface and MultisegmentWellEval (standard 3-phase blackoil).
201  if constexpr (Base::numWellDofs == MSWEval::numWellDofs) {
202  MSWEval::addBCDMatrix(b_matrices, c_matrices, d_matrices, wcells);
203  } else {
204  OPM_THROW(std::runtime_error,
205  "system_cpr preconditioner with multisegment wells is only supported for standard "
206  "3-phase blackoil (Indices::numEq == 3). This model has different equation count.");
207  }
208  }
209 
210  void getScaledWellFractions(std::vector<Scalar>& scaled_fractions,
211  DeferredLogger& deferred_logger) const override;
212 
213  protected:
214  // regularize msw equation
215  bool regularize_;
216 
217  // the initial amount of fluids in each segment under surface condition
218  std::vector<std::vector<Scalar> > segment_fluid_initial_;
219  // total energy inside the segments at the beginning of the time step
220  std::vector<Scalar> segment_initial_energy_;
221 
222  // segment fluid state
223  std::vector<SegmentFluidState<EvalWell>> segment_fluid_state_;
224 
225  // fluid state under the wellhead condition, it is used to calculate the enthalpy
226  // under operation condition for energy injection
227  // because BHP will be involved, we use EvalWell type here
228  SegmentFluidState<EvalWell> wellhead_fluid_state_;
229 
230  mutable int debug_cost_counter_ = 0;
231 
232  // updating the well_state based on well solution dwells
233  void updateWellState(const Simulator& simulator,
234  const BVectorWell& dwells,
235  const GroupStateHelperType& groupStateHelper,
236  WellStateType& well_state,
237  const Scalar relaxation_factor = 1.0);
238 
239  // computing the accumulation term for later use in well mass equations
240  void computeInitialSegmentFluids(const FSInfo& info, DeferredLogger& deferred_logger);
241 
242  // compute the pressure difference between the perforation and cell center
243  void computePerfCellPressDiffs(const Simulator& simulator);
244 
245  template<class Value>
246  void computePerfRate(const IntensiveQuantities& int_quants,
247  const std::vector<Value>& mob_perfcells,
248  const std::vector<Value>& Tw,
249  const int seg,
250  const int perf,
251  const Value& segment_pressure,
252  const bool& allow_cf,
253  std::vector<Value>& cq_s,
254  Value& perf_press,
255  PerforationRates<Scalar>& perf_rates,
256  DeferredLogger& deferred_logger) const;
257 
258  template<class Value>
259  void computePerfRate(const Value& pressure_cell,
260  const Value& rs,
261  const Value& rv,
262  const std::vector<Value>& b_perfcells,
263  const std::vector<Value>& mob_perfcells,
264  const std::vector<Value>& Tw,
265  const int perf,
266  const Value& segment_pressure,
267  const Value& segment_density,
268  const bool& allow_cf,
269  const std::vector<Value>& cmix_s,
270  std::vector<Value>& cq_s,
271  Value& perf_press,
272  PerforationRates<Scalar>& perf_rates,
273  DeferredLogger& deferred_logger) const;
274 
275  // compute the fluid properties, such as densities, viscosities, and so on, in the segments
276  // They will be treated implicitly, so they need to be of Evaluation type
277  void computeSegmentFluidProperties(const Simulator& simulator,
278  DeferredLogger& deferred_logger);
279 
280  // get the transmissibility multiplier for specific perforation
281  template<class Value>
282  void getTransMult(Value& trans_mult,
283  const Simulator& simulator,
284  const int cell_indx) const;
285 
286  // get the mobility for specific perforation
287  template<class Value>
288  void getMobility(const Simulator& simulator,
289  const int local_perf_index,
290  std::vector<Value>& mob,
291  DeferredLogger& deferred_logger) const;
292 
293  void computeWellRatesAtBhpLimit(const Simulator& simulator,
294  const GroupStateHelperType& groupStateHelper,
295  std::vector<Scalar>& well_flux) const;
296 
297  void computeWellRatesWithBhp(const Simulator& simulator,
298  const Scalar& bhp,
299  std::vector<Scalar>& well_flux,
300  DeferredLogger& deferred_logger) const override;
301 
302  void computeWellRatesWithBhpIterations(const Simulator& simulator,
303  const Scalar& bhp,
304  const GroupStateHelperType& groupStateHelper,
305  std::vector<Scalar>& well_flux) const override;
306 
307  std::vector<Scalar>
308  computeWellPotentialWithTHP(const WellStateType& well_state,
309  const Simulator& simulator,
310  const GroupStateHelperType& groupStateHelper) const;
311 
312  bool computeWellPotentialsImplicit(const Simulator& simulator,
313  const GroupStateHelperType& groupStateHelper,
314  std::vector<Scalar>& well_potentials) const;
315 
316  Scalar getRefDensity() const override;
317 
318  bool iterateWellEqWithControl(const Simulator& simulator,
319  const double dt,
320  const Well::InjectionControls& inj_controls,
321  const Well::ProductionControls& prod_controls,
322  const GroupStateHelperType& groupStateHelper,
323  WellStateType& well_state) override;
324 
325  bool iterateWellEqWithSwitching(const Simulator& simulator,
326  const double dt,
327  const Well::InjectionControls& inj_controls,
328  const Well::ProductionControls& prod_controls,
329  const GroupStateHelperType& groupStateHelper,
330  WellStateType& well_state,
331  const bool fixed_control,
332  const bool fixed_status,
333  const bool solving_with_zero_rate) override;
334 
335  void assembleWellEqWithoutIteration(const Simulator& simulator,
336  const GroupStateHelperType& groupStateHelper,
337  const double dt,
338  const Well::InjectionControls& inj_controls,
339  const Well::ProductionControls& prod_controls,
340  WellStateType& well_state,
341  const bool solving_with_zero_rate) override;
342 
343  void updateWaterThroughput(const double dt, WellStateType& well_state) const override;
344 
345  EvalWell getSegmentSurfaceVolume(const int seg_idx,
346  const FSInfo& info,
347  DeferredLogger& deferred_logger) const;
348 
349  // turn on crossflow to avoid singular well equations
350  // when the well is banned from cross-flow and the BHP is not properly initialized,
351  // we turn on crossflow to avoid singular well equations. It can result in wrong-signed
352  // well rates, it can cause problem for THP calculation
353  // TODO: looking for better alternative to avoid wrong-signed well rates
354  bool openCrossFlowAvoidSingularity(const Simulator& simulator) const;
355 
356  // for a well, when all drawdown are in the wrong direction, then this well will not
357  // be able to produce/inject .
358  bool allDrawDownWrongDirection(const Simulator& simulator) const;
359 
360  std::optional<Scalar>
361  computeBhpAtThpLimitProd(const WellStateType& well_state,
362  const Simulator& ebos_simulator,
363  const GroupStateHelperType& groupStateHelper,
364  const SummaryState& summary_state) const;
365 
366  std::optional<Scalar>
367  computeBhpAtThpLimitInj(const Simulator& ebos_simulator,
368  const GroupStateHelperType& groupStateHelper,
369  const SummaryState& summary_state) const;
370 
371  Scalar maxPerfPress(const Simulator& simulator) const override;
372 
373  // check whether the well is operable under BHP limit with current reservoir condition
374  void checkOperabilityUnderBHPLimit(const WellStateType& well_state,
375  const Simulator& ebos_simulator,
376  DeferredLogger& deferred_logger) override;
377 
378  // check whether the well is operable under THP limit with current reservoir condition
379  void checkOperabilityUnderTHPLimit(const Simulator& ebos_simulator,
380  const WellStateType& well_state,
381  const GroupStateHelperType& groupStateHelper) override;
382 
383  // updating the inflow based on the current reservoir condition
384  void updateIPR(const Simulator& ebos_simulator,
385  DeferredLogger& deferred_logger) const override;
386 
387  FSInfo getFirstPerforationFluidStateInfo(const Simulator& simulator) const;
388 
389  // this function can potentially be shared between multisegment wells and standard wells
390  // TODO: this function largely overlaps with calculatePhaseProperties(), some refactoring/unification should be done
391  template <typename ValueType = EvalWell>
392  SegmentFluidState<ValueType>
393  createFluidState(const std::vector<ValueType>& fluid_composition,
394  const ValueType& pressure,
395  const ValueType& temperature,
396  const ValueType& saltConcentration,
397  DeferredLogger& deferred_logger) const;
398 
399  SegmentFluidState<EvalWell>
400  createSegmentFluidState(int seg, const FSInfo& info, DeferredLogger& deferred_logger) const;
401 
402  void computeInitialSegmentEnergy();
403 
404  // assemble the energy equation contribution for a single perforation/connection
405  void assemblePerforationEnergyEq(const IntensiveQuantities& int_quants,
406  const std::vector<EvalWell>& cq_s,
407  const int seg,
408  const int local_perf_index,
409  DeferredLogger& deferred_logger);
410 
411  void updateWellHeadCondition(const Simulator& simulator,
412  const Scalar first_perf_temperature,
413  const Scalar first_perf_salt_concentration,
414  DeferredLogger& deferred_logger);
415 
416  void updateSegmentFluidState(const FSInfo& info, DeferredLogger& deferred_logger);
417 
418  template <typename ValueType = EvalWell>
419  ValueType computeSegmentEnergy(int seg) const;
420 
421  // Convert per-component surface volumetric rates to a phase reservoir
422  // volumetric rate, using @p fs (upwind) for the rs/rv coupling. If
423  // (1 - rs*rv) <= 0, falls back to rate / invB (drops the cross-terms but
424  // keeps @p fs's invB; Rs/Rv unchanged) and logs a @p context debug message.
425  // @p fs may be a wellbore SegmentFluidState (EvalWell) or a reservoir-cell
426  // fluid state (Eval, extended to EvalWell on the fly).
427  // @return the reservoir volumetric rate of @p phaseIdx.
428  template <typename FluidStateT>
429  EvalWell surfaceToReservoirRate(unsigned phaseIdx,
430  const FluidStateT& fs,
431  const std::vector<EvalWell>& surface_rates,
432  int seg,
433  std::string_view context,
434  DeferredLogger& deferred_logger) const;
435 
436  // Compute the energy flux carried by fluid flowing from segment
437  // @p seg toward its outlet, using @p upwind_fs as the upwind
438  // fluid state. @p context is used in diagnostic messages.
439  // @return the energy flux as sum_phases(reservoir_rate * enthalpy * density).
440  EvalWell computeSegmentEnergyRate(int seg,
441  int upwind_seg,
442  const SegmentFluidState<EvalWell>& upwind_fs,
443  std::string_view context,
444  DeferredLogger& deferred_logger) const;
445  };
446 
447 } // namespace Opm
448 
449 #include "MultisegmentWell_impl.hpp"
450 
451 #endif // OPM_MULTISEGMENTWELL_HEADER_INCLUDED
ConvergenceReport getWellConvergence(const GroupStateHelperType &groupStateHelper, const std::vector< Scalar > &B_avg, const bool relax_tolerance) const override
check whether the well equations get converged for this well
Definition: MultisegmentWell_impl.hpp:201
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...))
Definition: propertysystem.hh:233
void computeWellPotentials(const Simulator &simulator, const WellStateType &well_state, const GroupStateHelperType &groupStateHelper, std::vector< Scalar > &well_potentials) override
computing the well potentials for group control
Definition: MultisegmentWell_impl.hpp:299
Defines the common properties required by the porous medium multi-phase models.
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Definition: BlackoilWellModelConstraints.hpp:37
void getScaledWellFractions(std::vector< Scalar > &scaled_fractions, DeferredLogger &deferred_logger) const override
Get scaled well fractions from primary variables Implemented by derived classes that have access to p...
Definition: MultisegmentWell_impl.hpp:2445
void scaleSegmentRatesAndPressure(WellStateType &well_state) const override
updating the segment pressure and rates based the current bhp and well rates
Definition: MultisegmentWell_impl.hpp:171
Definition: BlackoilWellModelGasLift.hpp:38
Definition: PerforationData.hpp:55
void apply(const BVector &x, BVector &Ax) const override
Ax = Ax - C D^-1 B x.
Definition: MultisegmentWell_impl.hpp:227
Definition: MultisegmentWellEval.hpp:48
Class encapsulating some information about parallel wells.
Definition: MSWellHelpers.hpp:34
std::vector< Scalar > computeCurrentWellRates(const Simulator &simulator, DeferredLogger &deferred_logger) const override
Compute well rates based on current reservoir conditions and well variables.
Definition: MultisegmentWell_impl.hpp:2364
Definition: DeferredLogger.hpp:56
Collect per-connection static information to enable calculating connection-level or well-level produc...
Definition: WellProdIndexCalculator.hpp:36
Static data associated with a well perforation.
Definition: BlackoilWellModelRestart.hpp:41
void recoverWellSolutionAndUpdateWellState(const Simulator &simulator, const BVector &x, const GroupStateHelperType &groupStateHelper, WellStateType &well_state) override
using the solution x to recover the solution xw for wells and applying xw to update Well State ...
Definition: MultisegmentWell_impl.hpp:262
void updateWellStateWithTarget(const Simulator &simulator, const GroupStateHelperType &groupStateHelper, WellStateType &well_state) const override
updating the well state based the current control mode
Definition: MultisegmentWell_impl.hpp:182
Represents the convergence status of the whole simulator, to make it possible to query and store the ...
Definition: ConvergenceReport.hpp:37
The state of a set of wells, tailored for use by the fully implicit blackoil simulator.
Definition: TemperatureModel.hpp:65
Definition: MultisegmentWell.hpp:39