GEOS
CoupledReservoirAndWellsBase.hpp
Go to the documentation of this file.
1 /*
2  * ------------------------------------------------------------------------------------------------------------
3  * SPDX-License-Identifier: LGPL-2.1-only
4  *
5  * Copyright (c) 2016-2024 Lawrence Livermore National Security LLC
6  * Copyright (c) 2018-2024 TotalEnergies
7  * Copyright (c) 2018-2024 The Board of Trustees of the Leland Stanford Junior University
8  * Copyright (c) 2023-2024 Chevron
9  * Copyright (c) 2019- GEOS/GEOSX Contributors
10  * All rights reserved
11  *
12  * See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
13  * ------------------------------------------------------------------------------------------------------------
14  */
15 
21 #ifndef GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLSBASE_HPP_
22 #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLSBASE_HPP_
23 
26 
27 #include "common/TimingMacros.hpp"
28 #include "constitutive/permeability/PermeabilityFields.hpp"
29 #include "constitutive/permeability/PermeabilityBase.hpp"
31 #include "mesh/DomainPartition.hpp"
32 #include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
34 
35 namespace geos
36 {
37 
38 namespace coupledReservoirAndWellsInternal
39 {
51 void
53  DomainPartition & domain,
54  DofManager & dofManager,
55  arrayView1d< localIndex > const & rowLengths,
56  integer const resNumDof,
57  integer const wellNumDof,
58  string const & resElemDofName,
59  string const & wellElemDofName );
60 
68 bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver,
69  WellManager const * const wellSolver,
70  DomainPartition const & domain );
71 
72 }
73 
74 template< typename RESERVOIR_SOLVER, typename WELL_SOLVER >
75 class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WELL_SOLVER >
76 {
77 public:
78 
80  using Base::m_solvers;
81  using Base::m_names;
82  using Base::m_dofManager;
83  using Base::m_localMatrix;
84  using Base::m_rhs;
85  using Base::m_solution;
86 
87  enum class SolverType : integer
88  {
89  Reservoir = 0,
90  Well = 1
91  };
92 
94  static string coupledSolverAttributePrefix() { return "reservoirAndWells"; }
95 
101  CoupledReservoirAndWellsBase ( const string & name,
102  dataRepository::Group * const parent )
103  : Base( name, parent ),
105  {
106  this->template getWrapper< string >( Base::viewKeyStruct::discretizationString() ).
107  setInputFlag( dataRepository::InputFlags::FALSE );
108  }
109 
117  virtual void setSparsityPattern( DomainPartition & domain,
118  DofManager & dofManager,
119  CRSMatrix< real64, globalIndex > & localMatrix,
120  SparsityPattern< globalIndex > & pattern ) override
121  {
122  // Set the reservoir sparsity pattern without reservoir-well coupling
123  SparsityPattern< globalIndex > patternDiag;
124  reservoirSolver()->setSparsityPattern( domain, dofManager, localMatrix, patternDiag );
125 
126  // Get the original row lengths (diagonal blocks only)
127  array1d< localIndex > rowLengths( patternDiag.numRows());
128  for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow )
129  {
130  rowLengths[localRow] = patternDiag.numNonZeros( localRow );
131  }
132 
133  // Add the number of nonzeros induced by coupling on perforations
134  addCouplingNumNonzeros( domain, dofManager, rowLengths.toView());
135 
136  // Create a new pattern with enough capacity for coupled matrix
137  pattern.resizeFromRowCapacities< parallelHostPolicy >( patternDiag.numRows(), patternDiag.numColumns(), rowLengths.data());
138 
139  // Copy the original nonzeros
140  appendSparsityPattern( pattern, patternDiag );
141 
142  // Add the nonzeros from coupling
143  addCouplingSparsityPattern( domain, dofManager, pattern.toView());
144  }
145 
152  RESERVOIR_SOLVER *
153  reservoirSolver() const { return std::get< toUnderlying( SolverType::Reservoir ) >( m_solvers ); }
154 
159  WELL_SOLVER *
160  wellSolver() const { return std::get< toUnderlying( SolverType::Well ) >( m_solvers ); }
161 
162  virtual void
164  {
166 
167  DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" );
168 
169  // Validate well perforations: Ensure that each perforation is in a region targeted by the solver
170  if( !validateWellPerforations( domain ))
171  {
172  GEOS_ERROR( GEOS_FMT( "{}: well perforations validation failed, bad perforations found", this->getName()));
173  }
174  }
175 
176  virtual void
178  {
180 
181  // assume that reservoir solver discretization is the primary one
182  this->m_discretizationName = reservoirSolver()->getDiscretizationName();
183 
184  setMGRStrategy();
185  }
186 
187  virtual void
188  implicitStepSetup( real64 const & time_n,
189  real64 const & dt,
190  DomainPartition & domain ) override
191  {
192  Base::implicitStepSetup( time_n, dt, domain );
193 
194  // we delay the computation of the transmissibility until the last minute
195  // because we want to make sure that the permeability has been updated (in the flow solver)
196  // this is necessary for some permeability models (like Karman-Kozeny) that do not use the imported permeability
197  // ultimately, we may want to use this mechanism to update the well transmissibility at each time step (if needed)
199  {
200  computeWellTransmissibility( domain );
202  }
203  }
204 
205  void initializeState( DomainPartition & domain ) const { return reservoirSolver()->initializeState( domain ); }
206 
207  void
208  assembleFluxTerms( real64 const dt,
209  DomainPartition const & domain,
210  DofManager const & dofManager,
211  CRSMatrixView< real64, globalIndex const > const & localMatrix,
212  arrayView1d< real64 > const & localRhs ) const
213  { reservoirSolver()->assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); }
214 
215  void
216  assembleStabilizedFluxTerms( real64 const dt,
217  DomainPartition const & domain,
218  DofManager const & dofManager,
219  CRSMatrixView< real64, globalIndex const > const & localMatrix,
220  arrayView1d< real64 > const & localRhs ) const
221  { reservoirSolver()->assembleStabilizedFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); }
222 
223  real64 updateFluidState( ElementSubRegionBase & subRegion ) const
224  { return reservoirSolver()->updateFluidState( subRegion ); }
225 
226  template< typename ELEMENT_SUB_REGION >
227  void updatePorosityAndPermeability( ELEMENT_SUB_REGION & subRegion ) const
228  { reservoirSolver()->updatePorosityAndPermeability( subRegion ); }
229 
230  void updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const
231  { reservoirSolver()->updateSolidInternalEnergyModel( dataGroup ); }
232 
233  integer & isThermal() { return reservoirSolver()->isThermal(); }
234 
235  void enableJumpStabilization()
236  { reservoirSolver()->enableJumpStabilization(); }
237 
238  void enableFixedStressPoromechanicsUpdate()
239  { reservoirSolver()->enableFixedStressPoromechanicsUpdate(); }
240 
241  void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep )
242  {
243  reservoirSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep );
244  wellSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep );
245  }
246 
247  virtual void saveSequentialIterationState( DomainPartition & domain ) override
248  { reservoirSolver()->saveSequentialIterationState( domain ); }
249 
250 protected:
251 
258  void
260  DofManager & dofManager,
261  arrayView1d< localIndex > const & rowLengths ) const
262  {
263  coupledReservoirAndWellsInternal::
264  addCouplingNumNonzeros( this,
265  domain,
266  dofManager,
267  rowLengths,
268  wellSolver()->numDofPerResElement(),
269  wellSolver()->numDofPerWellElement(),
270  wellSolver()->resElementDofName(),
271  wellSolver()->wellElementDofName() );
272  }
273 
280  virtual void
282  DofManager const & dofManager,
283  SparsityPatternView< globalIndex > const & pattern ) const = 0;
284 
285  virtual void setMGRStrategy()
286  {
288  GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName()));
289  }
290 
293 
294 private:
295 
301  bool validateWellPerforations( DomainPartition const & domain ) const
302  {
303  return coupledReservoirAndWellsInternal::validateWellPerforations( reservoirSolver(), wellSolver(), domain );
304  }
305 
310  void computeWellTransmissibility( DomainPartition & domain ) const
311  {
312  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&] ( string const &,
313  MeshLevel & meshLevel,
314  string_array const & regionNames )
315  {
316  ElementRegionManager & elemManager = meshLevel.getElemManager();
317 
318  ElementRegionManager::ElementViewAccessor< arrayView2d< real64 > > const elemCenter =
319  elemManager.constructViewAccessor< array2d< real64 >, arrayView2d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementCenterString() );
320 
321  // loop over the wells
322  elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
323  WellElementSubRegion & subRegion )
324  {
325  array1d< array1d< arrayView3d< real64 const > > > const permeability =
326  elemManager.constructMaterialFieldAccessor< constitutive::PermeabilityBase,
327  fields::permeability::permeability >();
328 
329  PerforationData & perforationData = *subRegion.getPerforationData();
330  WellControls const & wellControls = wellSolver()->getWellControls( subRegion );
331 
332  // compute the Peaceman index (if not read from XML)
333  perforationData.computeWellTransmissibility( meshLevel, subRegion, permeability );
334 
335  // if the log level is 1, we output the value of the transmissibilities
336  if( wellControls.getLogLevel() >= 2 )
337  {
338  arrayView2d< real64 const > const perfLocation =
339  perforationData.getField< fields::perforation::location >();
340  arrayView1d< real64 const > const perfTrans =
341  perforationData.getField< fields::perforation::wellTransmissibility >();
342 
343  // get the element region, subregion, index
344  arrayView1d< localIndex const > const resElemRegion =
345  perforationData.getField< fields::perforation::reservoirElementRegion >();
346  arrayView1d< localIndex const > const resElemSubRegion =
347  perforationData.getField< fields::perforation::reservoirElementSubRegion >();
348  arrayView1d< localIndex const > const resElemIndex =
349  perforationData.getField< fields::perforation::reservoirElementIndex >();
350 
351  GEOS_UNUSED_VAR( perfLocation ); // unused if geos_error_if is nulld
352  GEOS_UNUSED_VAR( perfTrans ); // unused if geos_error_if is nulld
353  GEOS_UNUSED_VAR( resElemRegion ); // unused if geos_error_if is nulld
354  GEOS_UNUSED_VAR( resElemSubRegion ); // unused if geos_error_if is nulld
355  GEOS_UNUSED_VAR( resElemIndex ); // unused if geos_error_if is nulld
356 
357  forAll< serialPolicy >( perforationData.size(), [=, this] ( localIndex const iperf )
358  {
359  GEOS_UNUSED_VAR( iperf ); // unused if geos_error_if is nulld
360  GEOS_LOG_RANK( GEOS_FMT( "{}: perforation at ({},{},{}), perforated element center = ({},{},{}), transmissibility = {} [{}]",
361  this->getName(), perfLocation[iperf][0], perfLocation[iperf][1], perfLocation[iperf][2],
362  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][0],
363  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][1],
364  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][2],
365  perfTrans[iperf], getSymbol( units::Transmissibility ) ) );
366  } );
367  }
368  } );
369  } );
370  }
371 
372 };
373 
374 
375 } /* namespace geos */
376 
377 #endif /* GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLSBASE_HPP_ */
bool validateWellPerforations(PhysicsSolverBase const *const reservoirSolver, WellManager const *const wellSolver, DomainPartition const &domain)
Validate the well perforations ensuring that each perforation is located in a reservoir region that i...
void addCouplingNumNonzeros(PhysicsSolverBase const *const solver, DomainPartition &domain, DofManager &dofManager, arrayView1d< localIndex > const &rowLengths, integer const resNumDof, integer const wellNumDof, string const &resElemDofName, string const &wellElemDofName)
Utility function for the implementation details of addCouplingNumZeros.
#define GEOS_ERROR(...)
Raise a hard error and terminate the program.
Definition: Logger.hpp:225
bool m_isWellTransmissibilityComputed
Flag to determine whether the well transmissibility needs to be computed.
virtual void initializePostInitialConditionsPreSubGroups() override
Called by InitializePostInitialConditions() prior to initializing sub-Groups.
virtual void addCouplingSparsityPattern(DomainPartition const &domain, DofManager const &dofManager, SparsityPatternView< globalIndex > const &pattern) const =0
static string coupledSolverAttributePrefix()
String used to form the solverName used to register solvers in CoupledSolver.
CoupledReservoirAndWellsBase(const string &name, dataRepository::Group *const parent)
main constructor for ManagedGroup Objects
WELL_SOLVER * wellSolver() const
accessor for the pointer to the well solver
void addCouplingNumNonzeros(DomainPartition &domain, DofManager &dofManager, arrayView1d< localIndex > const &rowLengths) const
virtual void saveSequentialIterationState(DomainPartition &domain) override
Save the state of the solver for sequential iteration.
virtual void implicitStepSetup(real64 const &time_n, real64 const &dt, DomainPartition &domain) override
function to perform setup for implicit timestep
RESERVOIR_SOLVER * reservoirSolver() const
accessor for the pointer to the reservoir solver
std::array< string, sizeof...(SOLVERS) > m_names
Names of the single-physics solvers.
std::tuple< SOLVERS *... > m_solvers
Pointers of the single-physics solvers.
The DoFManager is responsible for allocating global dofs, constructing sparsity patterns,...
Definition: DofManager.hpp:45
Partition of the decomposed physical domain. It also manages the connexion information to its neighbo...
Group const & getMeshBodies() const
Get the mesh bodies, const version.
Class facilitating the representation of a multi-level discretization of a MeshBody.
Definition: MeshLevel.hpp:42
Base class for all physics solvers.
virtual string getCatalogName() const =0
string m_discretizationName
name of the FV discretization object in the data repository
CRSMatrix< real64, globalIndex > m_localMatrix
Local system matrix and rhs.
DofManager m_dofManager
Data structure to handle degrees of freedom.
ParallelVector m_solution
System solution vector.
ParallelVector m_rhs
System right-hand side vector.
LinearSolverParametersInput m_linearSolverParameters
Linear solver parameters.
string const & getName() const
Get group name.
Definition: Group.hpp:1329
virtual void initializePostInitialConditionsPreSubGroups()
Called by InitializePostInitialConditions() prior to initializing sub-Groups.
Definition: Group.hpp:1556
virtual void implicitStepSetup(real64 const &time_n, real64 const &dt, DomainPartition &domain) override
virtual void setSparsityPattern(DomainPartition &domain, DofManager &dofManager, CRSMatrix< real64, globalIndex > &localMatrix, SparsityPattern< globalIndex > &pattern) override
Set the sparsity pattern of the linear system matrix.
@ FALSE
Not read from input.
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:179
stdVector< string > string_array
A 1-dimensional array of geos::string types.
Definition: DataTypes.hpp:361
LvArray::CRSMatrix< T, COL_INDEX, INDEX_TYPE, LvArray::ChaiBuffer > CRSMatrix
Alias for CRS Matrix class.
Definition: DataTypes.hpp:305
LvArray::SparsityPatternView< COL_INDEX, INDEX_TYPE const, LvArray::ChaiBuffer > SparsityPatternView
Alias for Sparsity pattern View.
Definition: DataTypes.hpp:301
LvArray::SparsityPattern< COL_INDEX, INDEX_TYPE, LvArray::ChaiBuffer > SparsityPattern
Alias for Sparsity pattern class.
Definition: DataTypes.hpp:297
double real64
64-bit floating point type.
Definition: DataTypes.hpp:98
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:84
void appendSparsityPattern(SparsityPattern< globalIndex > &target, SparsityPattern< globalIndex > const &source)
Append all entries from one sparsity pattern to another.
int integer
Signed integer type.
Definition: DataTypes.hpp:81
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:175
@ mgr
Multigrid reduction (Hypre only)
PreconditionerType preconditionerType
Preconditioner type.