GEOS
PoromechanicsSolver.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_POROMECHANICSSOLVER_HPP_
22 #define GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSSOLVER_HPP_
23 
29 #include "constitutive/solid/CoupledSolidBase.hpp"
30 #include "constitutive/contact/HydraulicApertureBase.hpp"
31 #include "mesh/DomainPartition.hpp"
33 #include "codingUtilities/Utilities.hpp"
34 
35 namespace geos
36 {
37 
38 namespace stabilization
39 {
40 enum class StabilizationType : integer
41 {
42  None,
43  Global,
44  Local,
45 };
46 
47 ENUM_STRINGS( StabilizationType,
48  "None",
49  "Global",
50  "Local" );
51 }
52 
53 
54 template< typename FLOW_SOLVER, typename MECHANICS_SOLVER = SolidMechanicsLagrangianFEM >
55 class PoromechanicsSolver : public CoupledSolver< FLOW_SOLVER, MECHANICS_SOLVER >
56 {
57 public:
58 
60  using Base::m_solvers;
61  using Base::m_dofManager;
62  using Base::m_localMatrix;
63  using Base::m_rhs;
64  using Base::m_solution;
65 
66  enum class SolverType : integer
67  {
68  Flow = 0,
69  SolidMechanics = 1
70  };
71 
73  static string coupledSolverAttributePrefix() { return "poromechanics"; }
74 
80  PoromechanicsSolver( const string & name,
81  dataRepository::Group * const parent )
82  : Base( name, parent ),
83  m_isThermal( 0 ),
85  {
87  setApplyDefaultValue( 0 ).
89  setDescription( "Flag indicating whether the problem is thermal or not. Set isThermal=\"1\" to enable the thermal coupling" );
90 
93  setDescription( "StabilizationType. Options are:\n" +
94  toString( stabilization::StabilizationType::None ) + "- Add no stabilization to mass equation \n" +
95  toString( stabilization::StabilizationType::Global ) + "- Add jump stabilization to all faces \n" +
96  toString( stabilization::StabilizationType::Local ) + "- Add jump stabilization on interior of macro elements" );
97 
99  setRTTypeName( rtTypes::CustomTypes::groupNameRefArray ).
100  setInputFlag( dataRepository::InputFlags::OPTIONAL ).
101  setDescription( "Regions where stabilization is applied." );
102 
104  setApplyDefaultValue( 1.0 ).
105  setInputFlag( dataRepository::InputFlags::OPTIONAL ).
106  setDescription( "Constant multiplier of stabilization strength" );
107 
108  LinearSolverParameters & linearSolverParameters = this->m_linearSolverParameters.get();
109  linearSolverParameters.dofsPerNode = 3;
110  linearSolverParameters.multiscale.label = "poro";
111  }
112 
113  virtual void postInputInitialization() override
114  {
116 
118  GEOS_FMT( "The attribute `{}` of solid mechanics solver `{}` must be `{}`",
119  SolidMechanicsLagrangianFEM::viewKeyStruct::timeIntegrationOptionString(),
120  this->solidMechanicsSolver()->getName(),
123 
124  // Sequential coupling uses the subsolver linear systems directly, so the
125  // coupled solver does not need a top-level MGR strategy.
127  {
128  setMGRStrategy();
129  }
130  }
131 
132  virtual void setConstitutiveNamesCallSuper( ElementSubRegionBase & subRegion ) const override final
133  {
135 
136  this->template setConstitutiveName< constitutive::CoupledSolidBase >( subRegion,
137  viewKeyStruct::porousMaterialNamesString(), "coupled solid" );
138 
139  // This is needed by the way the surface generator currently does things.
140  this->template setConstitutiveName< constitutive::PorosityBase >( subRegion,
141  constitutive::CoupledSolidBase::viewKeyStruct::porosityModelNameString(), "porosity" );
142 
143  if( dynamic_cast< SurfaceElementSubRegion * >( &subRegion ) )
144  {
145  this->template setConstitutiveName< constitutive::HydraulicApertureBase >( subRegion,
146  viewKeyStruct::hydraulicApertureRelationNameString(), "hydraulic aperture" );
147  }
148  }
149 
150  virtual void initializePreSubGroups() override
151  {
153 
154  GEOS_THROW_IF( this->m_isThermal && !this->flowSolver()->isThermal(),
155  GEOS_FMT( "The attribute `{}` of the flow solver must be thermal since the poromechanics solver is thermal",
156  this->flowSolver()->getName() ),
157  InputError, this->flowSolver()->getDataContext() );
158 
159  GEOS_THROW_IF( m_stabilizationType == stabilization::StabilizationType::Local,
160  GEOS_FMT( "{}: Local stabilization has been temporarily disabled",
163 
164  DomainPartition & domain = this->template getGroupByPath< DomainPartition >( "/Problem/domain" );
165 
166  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&] ( string const &,
167  MeshLevel & mesh,
168  string_array const & regionNames )
169  {
170  ElementRegionManager & elementRegionManager = mesh.getElemManager();
171  elementRegionManager.forElementSubRegions< CellElementSubRegion >( regionNames,
172  [&]( localIndex const,
173  ElementSubRegionBase & subRegion )
174  {
175  if( subRegion.hasField< fields::poromechanics::bulkDensity >() )
176  {
177  // get the solid model to know the number of quadrature points and resize the bulk density
178  constitutive::CoupledSolidBase const & solid =
179  this->template getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion,
180  subRegion.getReference< string >( viewKeyStruct::porousMaterialNamesString() ) );
181  subRegion.getField< fields::poromechanics::bulkDensity >().resizeDimension< 1 >( solid.getDensity().size( 1 ) );
182  }
183  } );
184  } );
185  }
186 
187  virtual void registerDataOnMesh( dataRepository::Group & meshBodies ) override
188  {
189  Base::registerDataOnMesh( meshBodies );
190 
191  if( this->getNonlinearSolverParameters().m_couplingType == NonlinearSolverParameters::CouplingType::Sequential )
192  {
193  // to let the solid mechanics solver that there is a pressure and temperature RHS in the mechanics solve
194  solidMechanicsSolver()->enableFixedStressPoromechanicsUpdate();
195  // to let the flow solver that saving pressure_k and temperature_k is necessary (for the fixed-stress porosity terms)
196  flowSolver()->enableFixedStressPoromechanicsUpdate();
197  }
198 
199  if( m_stabilizationType == stabilization::StabilizationType::Global || m_stabilizationType == stabilization::StabilizationType::Local )
200  {
201  flowSolver()->enableJumpStabilization();
202  }
203 
204  this->forDiscretizationOnMeshTargets( meshBodies, [&] ( string const &,
205  MeshLevel & mesh,
206  string_array const & regionNames )
207  {
208  ElementRegionManager & elemManager = mesh.getElemManager();
209 
210  elemManager.forElementSubRegions< CellElementSubRegion >( regionNames,
211  [&]( localIndex const,
212  ElementSubRegionBase & subRegion )
213  {
214  subRegion.registerWrapper< string >( viewKeyStruct::porousMaterialNamesString() ).
215  setPlotLevel( dataRepository::PlotLevel::NOPLOT ).
216  setRestartFlags( dataRepository::RestartFlags::NO_WRITE ).
217  setSizedFromParent( 0 );
218 
219  // This is needed by the way the surface generator currently does things.
220  subRegion.registerWrapper< string >( constitutive::CoupledSolidBase::viewKeyStruct::porosityModelNameString() ).
221  setPlotLevel( dataRepository::PlotLevel::NOPLOT ).
222  setRestartFlags( dataRepository::RestartFlags::NO_WRITE ).
223  setSizedFromParent( 0 );
224 
225  // register the bulk density for use in the solid mechanics solver
226  // ideally we would resize it here as well, but the solid model name is not available yet (see below)
227  subRegion.registerField< fields::poromechanics::bulkDensity >( this->getName() );
228 
229  if( m_stabilizationType == stabilization::StabilizationType::Global || m_stabilizationType == stabilization::StabilizationType::Local )
230  {
231  subRegion.registerField< fields::flow::macroElementIndex >( this->getName());
232  subRegion.registerField< fields::flow::elementStabConstant >( this->getName());
233  }
234  } );
235  } );
236  }
237 
238  virtual void implicitStepSetup( real64 const & time_n,
239  real64 const & dt,
240  DomainPartition & domain ) override
241  {
242  flowSolver()->setKeepVariablesConstantDuringInitStep( m_performStressInitialization );
243 
244  if( this->m_stabilizationType == stabilization::StabilizationType::Global || this->m_stabilizationType == stabilization::StabilizationType::Local )
245  {
246  this->updateStabilizationParameters( domain );
247  }
248 
249  Base::implicitStepSetup( time_n, dt, domain );
250  }
251 
252  virtual void setupDofs( DomainPartition const & domain,
253  DofManager & dofManager ) const override
254  {
255  // note that the order of operations matters a lot here (for instance for the MGR labels)
256  // we must set up dofs for solid mechanics first, and then for flow
257  // that's the reason why this function is here and not in CoupledSolvers.hpp
258  solidMechanicsSolver()->setupDofs( domain, dofManager );
259  flowSolver()->setupDofs( domain, dofManager );
260  this->setupCoupling( domain, dofManager );
261  }
262 
263  virtual void setupCoupling( DomainPartition const & GEOS_UNUSED_PARAM( domain ),
264  DofManager & dofManager ) const override
265  {
266  dofManager.addCoupling( fields::solidMechanics::totalDisplacement::key(),
267  getFlowDofKey(),
269  }
270 
271  virtual void assembleSystem( real64 const time,
272  real64 const dt,
273  DomainPartition & domain,
274  DofManager const & dofManager,
275  CRSMatrixView< real64, globalIndex const > const & localMatrix,
276  arrayView1d< real64 > const & localRhs ) override
277  {
279 
280  // Steps 1 and 2: compute element-based terms (mechanics and local flow terms)
281  assembleElementBasedTerms( time,
282  dt,
283  domain,
284  dofManager,
285  localMatrix,
286  localRhs );
287 
288  // Step 3: compute the fluxes (face-based contributions)
289 
290  if( m_stabilizationType == stabilization::StabilizationType::Global ||
291  m_stabilizationType == stabilization::StabilizationType::Local )
292  {
293  this->flowSolver()->assembleStabilizedFluxTerms( dt,
294  domain,
295  dofManager,
296  localMatrix,
297  localRhs );
298  }
299  else
300  {
301  this->flowSolver()->assembleFluxTerms( dt,
302  domain,
303  dofManager,
304  localMatrix,
305  localRhs );
306  }
307  }
308 
309  virtual void assembleElementBasedTerms( real64 const time_n,
310  real64 const dt,
311  DomainPartition & domain,
312  DofManager const & dofManager,
313  CRSMatrixView< real64, globalIndex const > const & localMatrix,
314  arrayView1d< real64 > const & localRhs ) = 0;
315 
316  virtual bool checkSequentialConvergence( integer const cycleNumber,
317  integer const iter,
318  real64 const & time_n,
319  real64 const & dt,
320  DomainPartition & domain ) override
321  {
322  // always force outer loop for initialization
323  auto & subcycling = this->getNonlinearSolverParameters().m_subcyclingOption;
324  auto const subcycling_orig = subcycling;
325  if( m_performStressInitialization )
326  subcycling = 1;
327  bool isConverged = Base::checkSequentialConvergence( cycleNumber, iter, time_n, dt, domain );
328 
329  // restore original
330  subcycling = subcycling_orig;
331 
332  return isConverged;
333  }
334 
339  MECHANICS_SOLVER * solidMechanicsSolver() const
340  {
341  return std::get< toUnderlying( SolverType::SolidMechanics ) >( m_solvers );
342  }
343 
348  FLOW_SOLVER * flowSolver() const
349  {
350  return std::get< toUnderlying( SolverType::Flow ) >( m_solvers );
351  }
352 
353  /*
354  * @brief Utility function to set the stress initialization flag
355  * @param[in] performStressInitialization true if the solver has to initialize stress, false otherwise
356  */
357  void setStressInitialization( bool const performStressInitialization )
358  {
359  m_performStressInitialization = performStressInitialization;
360  solidMechanicsSolver()->setStressInitialization( performStressInitialization );
361  }
362 
364  {
366  constexpr static char const * porousMaterialNamesString() { return "porousMaterialNames"; }
367 
369  constexpr static char const * isThermalString() { return "isThermal"; }
370 
372  constexpr static char const * stabilizationTypeString() {return "stabilizationType"; }
373 
375  constexpr static const char * stabilizationRegionNamesString() {return "stabilizationRegionNames"; }
376 
378  constexpr static const char * stabilizationMultiplierString() {return "stabilizationMultiplier"; }
379 
381  static constexpr char const * hydraulicApertureRelationNameString() {return "hydraulicApertureRelationName"; }
382 
383  };
384 
385  void updateStabilizationParameters( DomainPartition & domain ) const
386  {
387  // Step 1: we loop over the regions where stabilization is active and collect their name
388  set< string > regionFilter;
389  for( string const & regionName : m_stabilizationRegionNames )
390  {
391  regionFilter.insert( regionName );
392  }
393 
394  // Step 2: loop over target regions of solver, and tag the elements belonging to the stabilization regions
395  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&] ( string const &,
396  MeshLevel & mesh,
397  string_array const & targetRegionNames )
398  {
399  //keep only target regions in filter
400  string_array filteredTargetRegionNames;
401  filteredTargetRegionNames.reserve( targetRegionNames.size() );
402 
403  for( string const & targetRegionName : targetRegionNames )
404  {
405  if( regionFilter.count( targetRegionName ) )
406  {
407  filteredTargetRegionNames.emplace_back( targetRegionName );
408  }
409  }
410 
411  // Loop over elements and update stabilization constant
412  mesh.getElemManager().forElementSubRegions( filteredTargetRegionNames, [&]( localIndex const,
413  ElementSubRegionBase & subRegion )
414  {
415  arrayView1d< integer > const macroElementIndex = subRegion.getField< fields::flow::macroElementIndex >();
416  arrayView1d< real64 > const elementStabConstant = subRegion.getField< fields::flow::elementStabConstant >();
417 
418  constitutive::CoupledSolidBase const & porousSolid =
419  this->template getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion,
420  subRegion.getReference< string >( viewKeyStruct::porousMaterialNamesString() ) );
421 
422  arrayView1d< real64 const > const bulkModulus = porousSolid.getBulkModulus();
423  arrayView1d< real64 const > const shearModulus = porousSolid.getShearModulus();
424  arrayView1d< real64 const > const biotCoefficient = porousSolid.getBiotCoefficient();
425 
426  real64 const stabilizationMultiplier = m_stabilizationMultiplier;
427 
428  forAll< parallelDevicePolicy<> >( subRegion.size(), [bulkModulus,
429  shearModulus,
430  biotCoefficient,
431  stabilizationMultiplier,
432  macroElementIndex,
433  elementStabConstant] GEOS_HOST_DEVICE ( localIndex const ei )
434 
435  {
436  real64 const bM = bulkModulus[ei];
437  real64 const sM = shearModulus[ei];
438  real64 const bC = biotCoefficient[ei];
439 
440  macroElementIndex[ei] = 1;
441  elementStabConstant[ei] = stabilizationMultiplier * 9.0 * (bC * bC) / (32.0 * (10.0 * sM / 3.0 + bM));
442  } );
443  } );
444  } );
445 
446  }
447 
448  void updateBulkDensity( DomainPartition & domain )
449  {
450  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&]( string const &,
451  MeshLevel & mesh,
452  string_array const & regionNames )
453  {
454  mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const,
455  auto & subRegion )
456  {
457  // update the bulk density
458  // TODO: ideally, we would not recompute the bulk density, but a more general "rhs" containing the body force and the
459  // pressure/temperature terms
460  updateBulkDensity( subRegion );
461  } );
462  } );
463  }
464 
465 protected:
466 
468  {
469  Base::initializePostInitialConditionsPreSubGroups();
470 
471  string_array const & poromechanicsTargetRegionNames =
472  this->template getReference< string_array >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() );
473  string_array const & solidMechanicsTargetRegionNames =
474  this->solidMechanicsSolver()->template getReference< string_array >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() );
475  string_array const & flowTargetRegionNames =
476  this->flowSolver()->template getReference< string_array >( PhysicsSolverBase::viewKeyStruct::targetRegionsString() );
477  for( size_t i = 0; i < poromechanicsTargetRegionNames.size(); ++i )
478  {
479  GEOS_THROW_IF( std::find( solidMechanicsTargetRegionNames.begin(), solidMechanicsTargetRegionNames.end(),
480  poromechanicsTargetRegionNames[i] )
481  == solidMechanicsTargetRegionNames.end(),
482  GEOS_FMT( "Region {} must be a target region of {}",
483  poromechanicsTargetRegionNames[i], this->solidMechanicsSolver()->getName() ),
484  InputError, this->getDataContext(), this->solidMechanicsSolver()->getDataContext());
485  GEOS_THROW_IF( std::find( flowTargetRegionNames.begin(), flowTargetRegionNames.end(), poromechanicsTargetRegionNames[i] )
486  == flowTargetRegionNames.end(),
487  GEOS_FMT( "Region `{}` must be a target region of `{}`",
488  poromechanicsTargetRegionNames[i], this->flowSolver()->getCatalogName() ),
489  InputError, this->getDataContext(), this->flowSolver()->getDataContext() );
490  }
491  }
492 
493  template< typename TYPE_LIST,
494  typename KERNEL_WRAPPER,
495  typename ... PARAMS >
496  real64 assemblyLaunch( MeshLevel & mesh,
497  DofManager const & dofManager,
498  string_array const & regionNames,
499  string const & materialNamesString,
500  CRSMatrixView< real64, globalIndex const > const & localMatrix,
501  arrayView1d< real64 > const & localRhs,
502  real64 const dt,
503  PARAMS && ... params )
504  {
506 
507  NodeManager const & nodeManager = mesh.getNodeManager();
508 
509  string const dofKey = dofManager.getKey( fields::solidMechanics::totalDisplacement::key() );
510  arrayView1d< globalIndex const > const & dofNumber = nodeManager.getReference< globalIndex_array >( dofKey );
511 
512  real64 const gravityVectorData[3] = LVARRAY_TENSOROPS_INIT_LOCAL_3( this->gravityVector() );
513 
514  KERNEL_WRAPPER kernelWrapper( dofNumber,
515  dofManager.rankOffset(),
516  localMatrix,
517  localRhs,
518  dt,
519  gravityVectorData,
520  std::forward< PARAMS >( params )... );
521 
522  return finiteElement::
523  regionBasedKernelApplication< parallelDevicePolicy< >,
524  TYPE_LIST >( mesh,
525  regionNames,
526  this->solidMechanicsSolver()->getDiscretizationName(),
527  materialNamesString,
528  kernelWrapper );
529  }
530 
531  /* Implementation of Nonlinear Acceleration (Aitken) of averageMeanTotalStressIncrement */
532 
533  void recordAverageMeanTotalStressIncrement( DomainPartition & domain,
534  array1d< real64 > & averageMeanTotalStressIncrement )
535  {
536  averageMeanTotalStressIncrement.resize( 0 );
537  this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
538  MeshLevel & mesh,
539  string_array const & regionNames )
540  {
541  mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const,
542  auto & subRegion )
543  {
544  // get the solid model (to access stress increment)
545  string const & solidName =
546  subRegion.template getReference< string >( viewKeyStruct::porousMaterialNamesString() );
547  constitutive::CoupledSolidBase & solid =
548  this->template getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion, solidName );
549 
550  arrayView1d< const real64 > const & averageMeanTotalStressIncrement_k = solid.getAverageMeanTotalStressIncrement_k();
551  for( localIndex k = 0; k < localIndex( averageMeanTotalStressIncrement_k.size()); k++ )
552  {
553  averageMeanTotalStressIncrement.emplace_back( averageMeanTotalStressIncrement_k[k] );
554  }
555  } );
556  } );
557  }
558 
559  void applyAcceleratedAverageMeanTotalStressIncrement( DomainPartition & domain,
560  array1d< real64 > & averageMeanTotalStressIncrement )
561  {
562  integer i = 0;
563  this->forDiscretizationOnMeshTargets( domain.getMeshBodies(), [&]( string const &,
564  MeshLevel & mesh,
565  string_array const & regionNames )
566  {
567  mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const,
568  auto & subRegion )
569  {
570  // get the solid model (to access stress increment)
571  string const & solidName = subRegion.template getReference< string >( viewKeyStruct::porousMaterialNamesString() );
572  constitutive::CoupledSolidBase & solid =
573  this->template getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion, solidName );
574  auto & porosityModel = dynamic_cast< constitutive::BiotPorosity const & >( solid.getBasePorosityModel());
575  arrayView1d< real64 > const & averageMeanTotalStressIncrement_k = solid.getAverageMeanTotalStressIncrement_k();
576  for( localIndex k = 0; k < localIndex( averageMeanTotalStressIncrement_k.size()); k++ )
577  {
578  porosityModel.updateAverageMeanTotalStressIncrement( k, averageMeanTotalStressIncrement[i] );
579  i++;
580  }
581  } );
582  } );
583  }
584 
585  real64 computeAitkenRelaxationFactor( array1d< real64 > const & s0,
586  array1d< real64 > const & s1,
587  array1d< real64 > const & s1_tilde,
588  array1d< real64 > const & s2_tilde,
589  real64 const omega0 )
590  {
591  array1d< real64 > r1 = axpy( s1_tilde, s0, -1.0 );
592  array1d< real64 > r2 = axpy( s2_tilde, s1, -1.0 );
593 
594  // diff = r2 - r1
595  array1d< real64 > diff = axpy( r2, r1, -1.0 );
596 
597  real64 const denom = dot( diff, diff );
598  real64 const numer = dot( r1, diff );
599 
600  real64 omega1 = 1.0;
601  if( !isZero( denom ))
602  {
603  omega1 = -1.0 * omega0 * numer / denom;
604  }
605  return omega1;
606  }
607 
608  array1d< real64 > computeUpdate( array1d< real64 > const & s1,
609  array1d< real64 > const & s2_tilde,
610  real64 const omega1 )
611  {
612  return axpy( scale( s1, 1.0 - omega1 ),
613  scale( s2_tilde, omega1 ),
614  1.0 );
615  }
616 
617  void startSequentialIteration( integer const & iter,
618  DomainPartition & domain ) override
619  {
620  if( this->getNonlinearSolverParameters().m_nonlinearAccelerationType == NonlinearSolverParameters::NonlinearAccelerationType::Aitken )
621  {
622  if( iter == 0 )
623  {
624  recordAverageMeanTotalStressIncrement( domain, m_s1 );
625  }
626  else
627  {
628  m_s0 = m_s1;
629  m_s1 = m_s2;
630  m_s1_tilde = m_s2_tilde;
631  m_omega0 = m_omega1;
632  }
633  }
634  }
635 
636  void finishSequentialIteration( integer const & iter,
637  DomainPartition & domain ) override
638  {
639  if( this->getNonlinearSolverParameters().m_nonlinearAccelerationType == NonlinearSolverParameters::NonlinearAccelerationType::Aitken )
640  {
641  if( iter == 0 )
642  {
643  m_s2 = m_s2_tilde;
644  m_omega1 = 1.0;
645  }
646  else
647  {
648  m_omega1 = computeAitkenRelaxationFactor( m_s0, m_s1, m_s1_tilde, m_s2_tilde, m_omega0 );
649  m_s2 = computeUpdate( m_s1, m_s2_tilde, m_omega1 );
650  applyAcceleratedAverageMeanTotalStressIncrement( domain, m_s2 );
651  }
652  }
653  }
654 
655  virtual void mapSolutionBetweenSolvers( DomainPartition & domain, integer const solverType ) override
656  {
658 
660  if( solverType == static_cast< integer >( SolverType::Flow ) )
661  {
662  updateBulkDensity( domain );
663  }
664 
666  if( solverType == static_cast< integer >( SolverType::SolidMechanics )
667  && !m_performStressInitialization ) // do not update during poromechanics initialization
668  {
669  // compute the average of the mean total stress increment over quadrature points
670  averageMeanTotalStressIncrement( domain );
671 
672  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&]( string const &,
673  MeshLevel & mesh,
674  string_array const & regionNames )
675  {
676 
677 
678  mesh.getElemManager().forElementSubRegions< CellElementSubRegion, SurfaceElementSubRegion >( regionNames, [&]( localIndex const,
679  auto & subRegion )
680  {
681  // update the porosity after a change in displacement (after mechanics solve)
682  // or a change in pressure/temperature (after a flow solve)
683  flowSolver()->updatePorosityAndPermeability( subRegion );
684  } );
685  mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const,
686  auto & subRegion )
687 
688  {
689  // update bulk density to reflect porosity change into mechanics
690  updateBulkDensity( subRegion );
691  } );
692  } );
693  }
694 
695  // needed to perform nonlinear acceleration
696  if( solverType == static_cast< integer >( SolverType::SolidMechanics ) &&
697  this->getNonlinearSolverParameters().m_nonlinearAccelerationType== NonlinearSolverParameters::NonlinearAccelerationType::Aitken )
698  {
699  recordAverageMeanTotalStressIncrement( domain, m_s2_tilde );
700  }
701  }
702 
708  {
709  this->template forDiscretizationOnMeshTargets<>( domain.getMeshBodies(), [&]( string const &,
710  MeshLevel & mesh,
711  string_array const & regionNames )
712  {
713  mesh.getElemManager().forElementSubRegions< CellElementSubRegion >( regionNames, [&]( localIndex const,
714  auto & subRegion )
715  {
716  // get the solid model (to access stress increment)
717  string const & solidName = subRegion.template getReference< string >( viewKeyStruct::porousMaterialNamesString() );
718  constitutive::CoupledSolidBase & solid =
719  this->template getConstitutiveModel< constitutive::CoupledSolidBase >( subRegion, solidName );
720 
721  arrayView2d< real64 const > const meanTotalStressIncrement_k = solid.getMeanTotalStressIncrement_k();
722  arrayView1d< real64 > const averageMeanTotalStressIncrement_k = solid.getAverageMeanTotalStressIncrement_k();
723 
724  finiteElement::FiniteElementBase & subRegionFE =
725  subRegion.template getReference< finiteElement::FiniteElementBase >( solidMechanicsSolver()->getDiscretizationName() );
726 
727  // determine the finite element type
728  finiteElement::FiniteElementDispatchHandler< BASE_FE_TYPES >::
729  dispatch3D( subRegionFE, [&] ( auto const finiteElement )
730  {
731  using FE_TYPE = decltype( finiteElement );
732 
733  // call the factory and launch the kernel
734  AverageOverQuadraturePoints1DKernelFactory::
735  createAndLaunch< CellElementSubRegion,
736  FE_TYPE,
737  parallelDevicePolicy<> >( mesh.getNodeManager(),
738  mesh.getEdgeManager(),
739  mesh.getFaceManager(),
740  subRegion,
741  finiteElement,
742  meanTotalStressIncrement_k,
743  averageMeanTotalStressIncrement_k );
744  } );
745  } );
746  } );
747  }
748 
749  virtual void setMGRStrategy() = 0;
750 
751  virtual void updateBulkDensity( ElementSubRegionBase & subRegion ) = 0;
752 
753  virtual string getFlowDofKey() const = 0;
754 
755  virtual void validateNonlinearAcceleration() override
756  {
757  if( MpiWrapper::commSize( MPI_COMM_GEOS ) > 1 )
758  {
759  GEOS_ERROR( "Nonlinear acceleration is not implemented for MPI runs" );
760  }
761  }
762 
765 
768 
770  stabilization::StabilizationType m_stabilizationType;
771 
774 
777 
779  array1d< real64 > m_s0; // Accelerated averageMeanTotalStresIncrement @ outer iteration v ( two iterations ago )
780  array1d< real64 > m_s1; // Accelerated averageMeanTotalStresIncrement @ outer iteration v + 1 ( previous iteration )
781  array1d< real64 > m_s1_tilde; // Unaccelerated averageMeanTotalStresIncrement @ outer iteration v + 1 ( previous iteration )
782  array1d< real64 > m_s2; // Accelerated averageMeanTotalStresIncrement @ outer iteration v + 2 ( current iteration )
783  array1d< real64 > m_s2_tilde; // Unaccelerated averageMeanTotalStresIncrement @ outer iteration v + 1 ( current iteration )
784  real64 m_omega0; // Old Aitken relaxation factor
785  real64 m_omega1; // New Aitken relaxation factor
786 
787 };
788 
789 } /* namespace geos */
790 
791 #endif //GEOS_PHYSICSSOLVERS_MULTIPHYSICS_POROMECHANICSSOLVER_HPP_
#define GEOS_UNUSED_PARAM(X)
Mark an unused argument and silence compiler warnings.
Definition: GeosxMacros.hpp:97
#define GEOS_ERROR(...)
Raise a hard error and terminate the program.
Definition: Logger.hpp:226
#define GEOS_THROW_IF(COND, MSG,...)
Conditionally raise a hard error and terminate the program.
Definition: Logger.hpp:308
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
virtual void initializePreSubGroups() override
Called by Initialize() prior to initializing sub-Groups.
virtual void postInputInitialization() override
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
globalIndex rankOffset(string const &fieldName) const
void addCoupling(string const &rowFieldName, string const &colFieldName, Connector connectivity, stdVector< FieldSupport > const &regions={}, bool symmetric=true)
Add coupling between two fields.
@ Elem
connectivity is element (like in finite elements)
string const & getKey(string const &fieldName) const
Return the key used to record the field in the DofManager.
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.
The ElementRegionManager class provides an interface to ObjectManagerBase in order to manage ElementR...
void forElementSubRegions(LAMBDA &&lambda)
This function is used to launch kernel function over the element subregions of all the subregion type...
Class facilitating the representation of a multi-level discretization of a MeshBody.
Definition: MeshLevel.hpp:42
NodeManager const & getNodeManager() const
Get the node manager.
Definition: MeshLevel.hpp:155
ElementRegionManager const & getElemManager() const
Get the element region manager.
Definition: MeshLevel.hpp:207
The NodeManager class provides an interface to ObjectManagerBase in order to manage node data.
Definition: NodeManager.hpp:46
virtual void setConstitutiveNamesCallSuper(ElementSubRegionBase &subRegion) const
This function sets constitutive name fields on an ElementSubRegionBase, and calls the base function i...
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.
NonlinearSolverParameters & getNonlinearSolverParameters()
accessor for the nonlinear solver parameters.
LinearSolverParametersInput m_linearSolverParameters
Linear solver parameters.
array1d< real64 > m_s0
Member variables needed for Nonlinear Acceleration ( Aitken ). Naming convention follows ( Jiang & Tc...
virtual void implicitStepSetup(real64 const &time_n, real64 const &dt, DomainPartition &domain) override
function to perform setup for implicit timestep
real64 m_stabilizationMultiplier
Stabilization Multiplier.
virtual void initializePreSubGroups() override
Called by Initialize() prior to initializing sub-Groups.
stabilization::StabilizationType m_stabilizationType
Type of stabilization used.
virtual void postInputInitialization() override
FLOW_SOLVER * flowSolver() const
accessor for the pointer to the flow solver
PoromechanicsSolver(const string &name, dataRepository::Group *const parent)
main constructor for CoupledSolver Objects
virtual void initializePostInitialConditionsPreSubGroups() override
Called by InitializePostInitialConditions() prior to initializing sub-Groups.
virtual void setConstitutiveNamesCallSuper(ElementSubRegionBase &subRegion) const override final
This function sets constitutive name fields on an ElementSubRegionBase, and calls the base function i...
MECHANICS_SOLVER * solidMechanicsSolver() const
accessor for the pointer to the solid mechanics solver
virtual void mapSolutionBetweenSolvers(DomainPartition &domain, integer const solverType) override
Maps the solution obtained from one solver to the fields used by the other solver(s)
integer m_isThermal
Flag to determine whether or not this is a thermal simulation.
bool m_performStressInitialization
Flag to indicate that the solver is going to perform stress initialization.
string_array m_stabilizationRegionNames
Names of regions where stabilization applied.
virtual void setupDofs(DomainPartition const &domain, DofManager &dofManager) const override
Populate degree-of-freedom manager with fields relevant to this solver.
virtual void registerDataOnMesh(dataRepository::Group &meshBodies) override
Register wrappers that contain data on the mesh objects.
virtual void assembleSystem(real64 const time, real64 const dt, DomainPartition &domain, DofManager const &dofManager, CRSMatrixView< real64, globalIndex const > const &localMatrix, arrayView1d< real64 > const &localRhs) override
function to assemble the linear system matrix and rhs
void averageMeanTotalStressIncrement(DomainPartition &domain)
Helper function to average the mean total stress increment over quadrature points.
static string coupledSolverAttributePrefix()
String used to form the solverName used to register solvers in CoupledSolver.
Wrapper< TBASE > & registerWrapper(string const &name, wrapperMap::KeyIndex::index_type *const rkey=nullptr)
Create and register a Wrapper around a new object.
DataContext const & getDataContext() const
Definition: Group.hpp:1343
string const & getName() const
Get group name.
Definition: Group.hpp:1329
GEOS_DECLTYPE_AUTO_RETURN getReference(LOOKUP_TYPE const &lookup) const
Look up a wrapper and get reference to wrapped object.
Definition: Group.hpp:1273
DataContext const & getWrapperDataContext(KEY key) const
Definition: Group.hpp:1354
@ NOPLOT
Do not ever write to plot file.
@ OPTIONAL
Optional in input.
@ NO_WRITE
Do not write into restart.
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
int MPI_COMM_GEOS
Global MPI communicator used by GEOSX.
array1d< globalIndex > globalIndex_array
A 1-dimensional array of geos::globalIndex types.
Definition: DataTypes.hpp:370
std::set< T > set
A set of local indices.
Definition: DataTypes.hpp:262
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
LvArray::CRSMatrixView< T, COL_INDEX, INDEX_TYPE const, LvArray::ChaiBuffer > CRSMatrixView
Alias for CRS Matrix View.
Definition: DataTypes.hpp:309
int integer
Signed integer type.
Definition: DataTypes.hpp:81
Array< T, 1 > array1d
Alias for 1D array.
Definition: DataTypes.hpp:175
ENUM_STRINGS(LinearSolverParameters::SolverType, "direct", "cg", "gmres", "fgmres", "bicgstab", "richardson", "preconditioner")
Declare strings associated with enumeration values.
Provides enum <-> string conversion facilities.
Exception class used to report errors in user input.
string label
User-displayed label of the scheme.
Set of parameters for a linear solver or preconditioner.
integer dofsPerNode
Dofs per node (or support location) for non-scalar problems.
struct geos::LinearSolverParameters::Multiscale multiscale
Multiscale preconditioner parameters.
constexpr static char const * porousMaterialNamesString()
Names of the porous materials.
constexpr static const char * stabilizationRegionNamesString()
Name of regions on which stabilization applied.
static constexpr char const * hydraulicApertureRelationNameString()
Name of the hydraulicApertureRelationName.
constexpr static char const * isThermalString()
Flag to indicate that the simulation is thermal.
constexpr static char const * stabilizationTypeString()
Type of pressure stabilization.
constexpr static const char * stabilizationMultiplierString()
Multiplier on stabilization strength.
Structure to hold scoped key names.
Definition: Group.hpp:1446