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 
25 
26 #include "common/TimingMacros.hpp"
27 #include "constitutive/permeability/PermeabilityFields.hpp"
28 #include "constitutive/permeability/PermeabilityBase.hpp"
30 #include "mesh/DomainPartition.hpp"
31 #include "physicsSolvers/fluidFlow/wells/WellControls.hpp"
33 
34 namespace geos
35 {
36 
37 namespace coupledReservoirAndWellsInternal
38 {
50 void
52  DomainPartition & domain,
53  DofManager & dofManager,
54  arrayView1d< localIndex > const & rowLengths,
55  integer const resNumDof,
56  integer const wellNumDof,
57  string const & resElemDofName,
58  string const & wellElemDofName );
59 
67 bool validateWellPerforations( PhysicsSolverBase const * const reservoirSolver,
68  WellSolverBase const * const wellSolver,
69  DomainPartition const & domain );
70 
71 }
72 
73 template< typename RESERVOIR_SOLVER, typename WELL_SOLVER >
74 class CoupledReservoirAndWellsBase : public CoupledSolver< RESERVOIR_SOLVER, WELL_SOLVER >
75 {
76 public:
77 
79  using Base::m_solvers;
80  using Base::m_names;
81  using Base::m_dofManager;
82  using Base::m_localMatrix;
83  using Base::m_rhs;
84  using Base::m_solution;
85 
86  enum class SolverType : integer
87  {
88  Reservoir = 0,
89  Well = 1
90  };
91 
93  static string coupledSolverAttributePrefix() { return "reservoirAndWells"; }
94 
100  CoupledReservoirAndWellsBase ( const string & name,
101  dataRepository::Group * const parent )
102  : Base( name, parent ),
104  {
105  this->template getWrapper< string >( Base::viewKeyStruct::discretizationString() ).
106  setInputFlag( dataRepository::InputFlags::FALSE );
107  }
108 
112  virtual ~CoupledReservoirAndWellsBase () override {}
113 
121  virtual void
123  DofManager & dofManager,
124  CRSMatrix< real64, globalIndex > & localMatrix,
125  ParallelVector & rhs,
126  ParallelVector & solution,
127  bool const setSparsity = true ) override
128  {
130 
131  // call reservoir solver setup (needed in case of SinglePhasePoromechanicsConformingFractures)
132  reservoirSolver()->setupSystem( domain, dofManager, localMatrix, rhs, solution, setSparsity );
133 
134  dofManager.setDomain( domain );
135 
136  Base::setupDofs( domain, dofManager );
137  dofManager.reorderByRank();
138 
139  // Set the sparsity pattern without reservoir-well coupling
140  SparsityPattern< globalIndex > patternDiag;
141  dofManager.setSparsityPattern( patternDiag );
142 
143  // Get the original row lengths (diagonal blocks only)
144  array1d< localIndex > rowLengths( patternDiag.numRows() );
145  for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow )
146  {
147  rowLengths[localRow] = patternDiag.numNonZeros( localRow );
148  }
149 
150  // Add the number of nonzeros induced by coupling on perforations
151  addCouplingNumNonzeros( domain, dofManager, rowLengths.toView() );
152 
153  // Create a new pattern with enough capacity for coupled matrix
155  pattern.resizeFromRowCapacities< parallelHostPolicy >( patternDiag.numRows(), patternDiag.numColumns(), rowLengths.data() );
156 
157  // Copy the original nonzeros
158  for( localIndex localRow = 0; localRow < patternDiag.numRows(); ++localRow )
159  {
160  globalIndex const * cols = patternDiag.getColumns( localRow ).dataIfContiguous();
161  pattern.insertNonZeros( localRow, cols, cols + patternDiag.numNonZeros( localRow ) );
162  }
163 
164  // Add the nonzeros from coupling
165  addCouplingSparsityPattern( domain, dofManager, pattern.toView() );
166 
167  // Finally, steal the pattern into a CRS matrix
168  localMatrix.assimilate< parallelDevicePolicy<> >( std::move( pattern ) );
169  localMatrix.setName( this->getName() + "/localMatrix" );
170 
171  rhs.setName( this->getName() + "/rhs" );
172  rhs.create( dofManager.numLocalDofs(), MPI_COMM_GEOS );
173 
174  solution.setName( this->getName() + "/solution" );
175  solution.create( dofManager.numLocalDofs(), MPI_COMM_GEOS );
176  }
177 
184  RESERVOIR_SOLVER *
185  reservoirSolver() const { return std::get< toUnderlying( SolverType::Reservoir ) >( m_solvers ); }
186 
191  WELL_SOLVER *
192  wellSolver() const { return std::get< toUnderlying( SolverType::Well ) >( m_solvers ); }
193 
194  virtual void
196  {
198 
199  DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" );
200 
201  // Validate well perforations: Ensure that each perforation is in a region targeted by the solver
202  if( !validateWellPerforations( domain ))
203  {
204  GEOS_ERROR( GEOS_FMT( "{}: well perforations validation failed, bad perforations found", this->getName()));
205  }
206  }
207 
208  virtual void
210  {
212 
213  setMGRStrategy();
214  }
215 
216  virtual void
217  implicitStepSetup( real64 const & time_n,
218  real64 const & dt,
219  DomainPartition & domain ) override
220  {
221  Base::implicitStepSetup( time_n, dt, domain );
222 
223  // we delay the computation of the transmissibility until the last minute
224  // because we want to make sure that the permeability has been updated (in the flow solver)
225  // this is necessary for some permeability models (like Karman-Kozeny) that do not use the imported permeability
226  // ultimately, we may want to use this mechanism to update the well transmissibility at each time step (if needed)
228  {
229  computeWellTransmissibility( domain );
231  }
232  }
233 
234  void
235  assembleFluxTerms( real64 const dt,
236  DomainPartition const & domain,
237  DofManager const & dofManager,
238  CRSMatrixView< real64, globalIndex const > const & localMatrix,
239  arrayView1d< real64 > const & localRhs ) const
240  { reservoirSolver()->assembleFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); }
241 
242  void
243  assembleStabilizedFluxTerms( real64 const dt,
244  DomainPartition const & domain,
245  DofManager const & dofManager,
246  CRSMatrixView< real64, globalIndex const > const & localMatrix,
247  arrayView1d< real64 > const & localRhs ) const
248  { reservoirSolver()->assembleStabilizedFluxTerms( dt, domain, dofManager, localMatrix, localRhs ); }
249 
250  real64 updateFluidState( ElementSubRegionBase & subRegion ) const
251  { return reservoirSolver()->updateFluidState( subRegion ); }
252  void updatePorosityAndPermeability( CellElementSubRegion & subRegion ) const
253  { reservoirSolver()->updatePorosityAndPermeability( subRegion ); }
254  void updateSolidInternalEnergyModel( ObjectManagerBase & dataGroup ) const
255  { reservoirSolver()->updateSolidInternalEnergyModel( dataGroup ); }
256 
257  integer & isThermal() { return reservoirSolver()->isThermal(); }
258 
259  void enableJumpStabilization()
260  { reservoirSolver()->enableJumpStabilization(); }
261 
262  void enableFixedStressPoromechanicsUpdate()
263  { reservoirSolver()->enableFixedStressPoromechanicsUpdate(); }
264 
265  void setKeepVariablesConstantDuringInitStep( bool const keepVariablesConstantDuringInitStep )
266  {
267  reservoirSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep );
268  wellSolver()->setKeepVariablesConstantDuringInitStep( keepVariablesConstantDuringInitStep );
269  }
270 
271  virtual void saveSequentialIterationState( DomainPartition & domain ) override
272  { reservoirSolver()->saveSequentialIterationState( domain ); }
273 
274 protected:
275 
282  void
284  DofManager & dofManager,
285  arrayView1d< localIndex > const & rowLengths ) const
286  {
287  coupledReservoirAndWellsInternal::
288  addCouplingNumNonzeros( this,
289  domain,
290  dofManager,
291  rowLengths,
292  wellSolver()->numDofPerResElement(),
293  wellSolver()->numDofPerWellElement(),
294  wellSolver()->resElementDofName(),
295  wellSolver()->wellElementDofName() );
296  }
297 
304  virtual void
306  DofManager const & dofManager,
307  SparsityPatternView< globalIndex > const & pattern ) const = 0;
308 
309  virtual void setMGRStrategy()
310  {
312  GEOS_ERROR( GEOS_FMT( "{}: MGR strategy is not implemented for {}", this->getName(), this->getCatalogName()));
313  }
314 
317 
318 private:
319 
325  bool validateWellPerforations( DomainPartition const & domain ) const
326  {
327  return coupledReservoirAndWellsInternal::validateWellPerforations( reservoirSolver(), wellSolver(), domain );
328  }
329 
334  void computeWellTransmissibility( DomainPartition & domain ) const
335  {
336  this->template forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&] ( string const &,
337  MeshLevel & meshLevel,
338  arrayView1d< string const > const & regionNames )
339  {
340  ElementRegionManager & elemManager = meshLevel.getElemManager();
341 
342  ElementRegionManager::ElementViewAccessor< arrayView2d< real64 > > const elemCenter =
343  elemManager.constructViewAccessor< array2d< real64 >, arrayView2d< real64 > >( ElementSubRegionBase::viewKeyStruct::elementCenterString() );
344 
345  // loop over the wells
346  elemManager.forElementSubRegions< WellElementSubRegion >( regionNames, [&]( localIndex const,
347  WellElementSubRegion & subRegion )
348  {
349  array1d< array1d< arrayView3d< real64 const > > > const permeability =
350  elemManager.constructMaterialFieldAccessor< constitutive::PermeabilityBase,
351  fields::permeability::permeability >();
352 
353  PerforationData & perforationData = *subRegion.getPerforationData();
354  WellControls const & wellControls = wellSolver()->getWellControls( subRegion );
355 
356  // compute the Peaceman index (if not read from XML)
357  perforationData.computeWellTransmissibility( meshLevel, subRegion, permeability );
358 
359  // if the log level is 1, we output the value of the transmissibilities
360  if( wellControls.getLogLevel() >= 2 )
361  {
362  arrayView2d< real64 const > const perfLocation =
363  perforationData.getField< fields::perforation::location >();
364  arrayView1d< real64 const > const perfTrans =
365  perforationData.getField< fields::perforation::wellTransmissibility >();
366 
367  // get the element region, subregion, index
368  arrayView1d< localIndex const > const resElemRegion =
369  perforationData.getField< fields::perforation::reservoirElementRegion >();
370  arrayView1d< localIndex const > const resElemSubRegion =
371  perforationData.getField< fields::perforation::reservoirElementSubRegion >();
372  arrayView1d< localIndex const > const resElemIndex =
373  perforationData.getField< fields::perforation::reservoirElementIndex >();
374 
375  GEOS_UNUSED_VAR( perfLocation ); // unused if geos_error_if is nulld
376  GEOS_UNUSED_VAR( perfTrans ); // unused if geos_error_if is nulld
377  GEOS_UNUSED_VAR( resElemRegion ); // unused if geos_error_if is nulld
378  GEOS_UNUSED_VAR( resElemSubRegion ); // unused if geos_error_if is nulld
379  GEOS_UNUSED_VAR( resElemIndex ); // unused if geos_error_if is nulld
380 
381  forAll< serialPolicy >( perforationData.size(), [=] ( localIndex const iperf )
382  {
383  GEOS_UNUSED_VAR( iperf ); // unused if geos_error_if is nulld
384  GEOS_LOG_RANK( GEOS_FMT( "{}: perforation at ({},{},{}), perforated element center = ({},{},{}), transmissibility = {} [{}]",
385  this->getName(), perfLocation[iperf][0], perfLocation[iperf][1], perfLocation[iperf][2],
386  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][0],
387  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][1],
388  elemCenter[resElemRegion[iperf]][resElemSubRegion[iperf]][resElemIndex[iperf]][2],
389  perfTrans[iperf], getSymbol( units::Transmissibility ) ) );
390  } );
391  }
392  } );
393  } );
394  }
395 
396 };
397 
398 
399 } /* namespace geos */
400 
401 #endif /* GEOS_PHYSICSSOLVERS_MULTIPHYSICS_COUPLEDRESERVOIRANDWELLSBASE_HPP_ */
bool validateWellPerforations(PhysicsSolverBase const *const reservoirSolver, WellSolverBase 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(msg)
Raise a hard error and terminate the program.
Definition: Logger.hpp:157
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
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
virtual ~CoupledReservoirAndWellsBase() override
default destructor
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:44
void setSparsityPattern(SparsityPattern< globalIndex > &pattern) const
Populate sparsity pattern of the entire system matrix.
void reorderByRank()
Finish populating fields and apply appropriate dof renumbering.
localIndex numLocalDofs(string const &fieldName) const
void setDomain(DomainPartition &domain)
Assign a domain.
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
void forDiscretizationOnMeshTargets(Group const &meshBodies, LAMBDA &&lambda) const
Loop over the target discretization on all mesh targets and apply callback.
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:1552
virtual void implicitStepSetup(real64 const &time_n, real64 const &dt, DomainPartition &domain) override
virtual void setupSystem(DomainPartition &domain, DofManager &dofManager, CRSMatrix< real64, globalIndex > &localMatrix, ParallelVector &rhs, ParallelVector &solution, bool const setSparsity=true) override
Set up the linear system (DOF indices and sparsity patterns)
void setupDofs(DomainPartition const &domain, DofManager &dofManager) const override
@ FALSE
Not read from input.
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:180
int MPI_COMM_GEOS
Global MPI communicator used by GEOSX.
LvArray::CRSMatrixView< T, COL_INDEX, localIndex const, LvArray::ChaiBuffer > CRSMatrixView
Alias for CRS Matrix View.
Definition: DataTypes.hpp:310
GEOS_GLOBALINDEX_TYPE globalIndex
Global index type (for indexing objects across MPI partitions).
Definition: DataTypes.hpp:88
LvArray::SparsityPatternView< COL_INDEX, INDEX_TYPE const, LvArray::ChaiBuffer > SparsityPatternView
Alias for Sparsity pattern View.
Definition: DataTypes.hpp:302
LvArray::SparsityPattern< COL_INDEX, INDEX_TYPE, LvArray::ChaiBuffer > SparsityPattern
Alias for Sparsity pattern class.
Definition: DataTypes.hpp:298
double real64
64-bit floating point type.
Definition: DataTypes.hpp:99
GEOS_LOCALINDEX_TYPE localIndex
Local index type (for indexing objects within an MPI partition).
Definition: DataTypes.hpp:85
std::int32_t integer
Signed integer type.
Definition: DataTypes.hpp:82
LvArray::CRSMatrix< T, COL_INDEX, localIndex, LvArray::ChaiBuffer > CRSMatrix
Alias for CRS Matrix class.
Definition: DataTypes.hpp:306
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:176
LAInterface::ParallelVector ParallelVector
Alias for ParallelVector.
@ mgr
Multigrid reduction (Hypre only)
PreconditionerType preconditionerType
Preconditioner type.