GEOS
ExplicitRateAndStateKernels.hpp
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) 2018-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 
16 #ifndef GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_KERNELS_EXPLICITRATEANDSTATEKERNELS_HPP_
17 #define GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_KERNELS_EXPLICITRATEANDSTATEKERNELS_HPP_
18 
19 #include "RateAndStateKernelsBase.hpp"
20 #include "denseLinearAlgebra/denseLASolvers.hpp"
22 
23 namespace geos
24 {
25 
26 namespace rateAndStateKernels
27 {
28 
37 {
38 public:
39 
41  constitutive::RateAndStateFriction const & frictionLaw,
42  real64 const shearImpedance ):
43  m_slipRate( subRegion.getField< fields::rateAndState::slipRate >() ),
44  m_stateVariable( subRegion.getField< fields::rateAndState::stateVariable >() ),
45  m_normalTraction( subRegion.getField< fields::rateAndState::normalTraction >() ),
46  m_shearTraction( subRegion.getField< fields::rateAndState::shearTraction >() ),
47  m_slipVelocity( subRegion.getField< fields::rateAndState::slipVelocity >() ),
48  m_shearImpedance( shearImpedance ),
49  m_frictionLaw( frictionLaw.createKernelUpdates() )
50  {}
51 
57  {
58 public:
59 
60  StackVariables() = default;
61 
62  real64 jacobian{};
63  real64 rhs{};
64 
65  };
66 
68  void setup( localIndex const k,
69  real64 const dt,
70  StackVariables & stack ) const
71  {
72  GEOS_UNUSED_VAR( dt );
73  real64 const normalTraction = m_normalTraction[k];
74  real64 const shearTractionMagnitude = LvArray::tensorOps::l2Norm< 2 >( m_shearTraction[k] );
75 
76  // Slip rate is bracketed between [0, shear traction magnitude / shear impedance]
77  // If slip rate is outside the bracket, re-initialize to the middle value
78  real64 const upperBound = shearTractionMagnitude/m_shearImpedance;
79  real64 const bracketedSlipRate = m_slipRate[k] > upperBound ? 0.5*upperBound : m_slipRate[k];
80 
81  stack.rhs = shearTractionMagnitude - m_shearImpedance *bracketedSlipRate - normalTraction * m_frictionLaw.frictionCoefficient( k, bracketedSlipRate, m_stateVariable[k] );
82  stack.jacobian = -m_shearImpedance - normalTraction * m_frictionLaw.dFrictionCoefficient_dSlipRate( k, bracketedSlipRate, m_stateVariable[k] );
83  }
84 
86  void solve( localIndex const k,
87  StackVariables & stack ) const
88  {
89  m_slipRate[k] -= stack.rhs/stack.jacobian;
90 
91  // Slip rate is bracketed between [0, shear traction magnitude / shear impedance]
92  // Check that the update did not end outside of the bracket.
93  real64 const shearTractionMagnitude = LvArray::tensorOps::l2Norm< 2 >( m_shearTraction[k] );
94  real64 const upperBound = shearTractionMagnitude/m_shearImpedance;
95  if( m_slipRate[k] > upperBound ) m_slipRate[k] = 0.5*upperBound;
96 
97  }
98 
99 
101  camp::tuple< int, real64 > checkConvergence( StackVariables const & stack,
102  real64 const tol ) const
103  {
104  real64 const residualNorm = LvArray::math::abs( stack.rhs );
105  int const converged = residualNorm < tol ? 1 : 0;
106  camp::tuple< int, real64 > result { converged, residualNorm };
107  return result;
108  }
109 
111  void projectSlipRate( localIndex const k ) const
112  {
113  real64 const frictionCoefficient = m_frictionLaw.frictionCoefficient( k, m_slipRate[k], m_stateVariable[k] );
114  projectSlipRateBase( k, frictionCoefficient, m_shearImpedance, m_normalTraction, m_shearTraction, m_slipRate, m_slipVelocity );
115  }
116 
118  void udpateVariables( localIndex const k ) const
119  {
120  projectSlipRate( k );
121  }
122 
124  void resetState( localIndex const k ) const
125  {
126  GEOS_UNUSED_VAR( k );
127  }
128 
134  template< typename POLICY >
135  static real64
138  real64 dt,
139  integer const maxNewtonIter,
140  real64 const newtonTol )
141  {
143 
144  newtonSolve< POLICY >( subRegion, kernel, dt, maxNewtonIter, newtonTol );
145 
146  forAll< POLICY >( subRegion.size(), [=] GEOS_HOST_DEVICE ( localIndex const k )
147  {
148  kernel.projectSlipRate( k );
149  } );
150  return dt;
151  }
152 
153 private:
154 
155  arrayView1d< real64 > const m_slipRate;
156 
157  arrayView1d< real64 > const m_stateVariable;
158 
159  arrayView1d< real64 const > const m_normalTraction;
160 
161  arrayView2d< real64 const > const m_shearTraction;
162 
163  arrayView2d< real64 > const m_slipVelocity;
164 
165  real64 const m_shearImpedance;
166 
167  constitutive::RateAndStateFriction::KernelWrapper m_frictionLaw;
168 
169 };
170 
177 {
178  integer constexpr static algHighOrder = 3; // High-order update order
179  integer constexpr static algLowOrder = 2; // Low-order update order
180  integer constexpr static numStages = 3; // Number of stages
181  real64 const a[2][2] = { { 1.0/2.0, 0.0 }, // Coefficients for stage value updates
182  { -1.0, 2.0 } }; // (lower-triangular part of table).
183  real64 const c[3] = { 0.0, 1.0/2.0, 1.0 }; // Coefficients for time increments of substages
184  real64 const b[3] = { 1.0/6.0, 4.0/6.0, 1.0/6.0 }; // Quadrature weights used to step the solution to next time
185  real64 const bStar[3] = { 1.0/2.0, 0.0, 1.0/2.0 }; // Quadrature weights used for low-order comparision solution
186  real64 constexpr static FSAL = false; // Not first same as last
187 };
188 
193 {
194  integer constexpr static algHighOrder = 3; // High-order update order
195  integer constexpr static algLowOrder = 2; // Low-order update order
196  integer constexpr static numStages = 4; // Number of stages
197  real64 const a[3][3] = { { 1.0/2.0, 0.0, 0.0 }, // Coefficients for stage value updates
198  { 0.0, 3.0/4.0, 0.0 }, // (lower-triangular part of table).
199  { 2.0/9.0, 1.0/3.0, 4.0/9.0 } };
200  real64 const c[4] = { 0.0, 1.0/2.0, 3.0/4.0, 1.0 }; // Coefficients for time increments of substages
201  real64 const b[4] = { 2.0/9.0, 1.0/3.0, 4.0/9.0, 0.0 }; // Quadrature weights used to step the solution to next time
202  real64 const bStar[4] = { 7.0/24.0, 1.0/4.0, 1.0/3.0, 1.0/8.0}; // Quadrature weights used for low-order comparision solution
203  bool constexpr static FSAL = true; // First same as last (can reuse the last stage rate in next
204  // update)
205 };
206 
214 template< typename TABLE_TYPE >
216 {
217 
218 public:
220  constitutive::RateAndStateFriction const & frictionLaw,
221  TABLE_TYPE butcherTable ):
222  m_stateVariable( subRegion.getField< fields::rateAndState::stateVariable >() ),
223  m_stateVariable_n( subRegion.getField< fields::rateAndState::stateVariable_n >() ),
224  m_slipRate( subRegion.getField< fields::rateAndState::slipRate >() ),
225  m_slipVelocity( subRegion.getField< fields::rateAndState::slipVelocity >() ),
226  m_slipVelocity_n( subRegion.getField< fields::rateAndState::slipVelocity_n >() ),
227  m_deltaSlip( subRegion.getField< fields::contact::deltaSlip >() ),
228  m_deltaSlip_n( subRegion.getField< fields::contact::deltaSlip_n >() ),
229  m_dispJump( subRegion.getField< fields::contact::dispJump >() ),
230  m_dispJump_n( subRegion.getField< fields::contact::dispJump_n >() ),
231  m_error( subRegion.getField< fields::rateAndState::error >() ),
232  m_stageRates( subRegion.getField< fields::rateAndState::rungeKuttaStageRates >() ),
233  m_frictionLaw( frictionLaw.createKernelUpdates() ),
234  m_butcherTable( butcherTable )
235  {}
236 
241  void initialize( localIndex const k ) const
242  {
243  LvArray::tensorOps::copy< 2 >( m_slipVelocity[k], m_slipVelocity_n[k] );
244  m_slipRate[k] = LvArray::tensorOps::l2Norm< 2 >( m_slipVelocity_n[k] );
245  m_stateVariable[k] = m_stateVariable_n[k];
246  }
247 
253  void updateStageRatesFSAL( localIndex const k ) const
254  {
255  LvArray::tensorOps::copy< 3 >( m_stageRates[k][0], m_stageRates[k][m_butcherTable.numStages-1] );
256  }
257 
262  void updateStageRates( localIndex const k, integer const stageIndex ) const
263  {
264  m_stageRates[k][stageIndex][0] = m_slipVelocity[k][0];
265  m_stageRates[k][stageIndex][1] = m_slipVelocity[k][1];
266  m_stageRates[k][stageIndex][2] = m_frictionLaw.stateEvolution( k, m_slipRate[k], m_stateVariable[k] );
267  }
268 
273  void updateStageValues( localIndex const k, integer const stageIndex, real64 const dt ) const
274  {
275 
276  real64 stateVariableIncrement = 0.0;
277  real64 deltaSlipIncrement[2] = {0.0, 0.0};
278 
279  for( integer i = 0; i < stageIndex; i++ )
280  {
281  deltaSlipIncrement[0] += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][0];
282  deltaSlipIncrement[1] += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][1];
283  stateVariableIncrement += m_butcherTable.a[stageIndex-1][i] * m_stageRates[k][i][2];
284  }
285  m_deltaSlip[k][0] = m_deltaSlip_n[k][0] + dt*deltaSlipIncrement[0];
286  m_deltaSlip[k][1] = m_deltaSlip_n[k][1] + dt*deltaSlipIncrement[1];
287  m_stateVariable[k] = m_stateVariable_n[k] + dt*stateVariableIncrement;
288 
289  m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0];
290  m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1];
291  }
292 
298  void updateSolutionAndLocalError( localIndex const k, real64 const dt, real64 const absTol, real64 const relTol ) const
299  {
300 
301  real64 deltaSlipIncrement[2] = {0.0, 0.0};
302  real64 deltaSlipIncrementLowOrder[2] = {0.0, 0.0};
303 
304  real64 stateVariableIncrement = 0.0;
305  real64 stateVariableIncrementLowOrder = 0.0;
306 
307  for( localIndex i = 0; i < m_butcherTable.numStages; i++ )
308  {
309 
310  // High order update of solution
311  deltaSlipIncrement[0] += m_butcherTable.b[i] * m_stageRates[k][i][0];
312  deltaSlipIncrement[1] += m_butcherTable.b[i] * m_stageRates[k][i][1];
313  stateVariableIncrement += m_butcherTable.b[i] * m_stageRates[k][i][2];
314 
315  // Low order update for error
316  deltaSlipIncrementLowOrder[0] += m_butcherTable.bStar[i] * m_stageRates[k][i][0];
317  deltaSlipIncrementLowOrder[1] += m_butcherTable.bStar[i] * m_stageRates[k][i][1];
318  stateVariableIncrementLowOrder += m_butcherTable.bStar[i] * m_stageRates[k][i][2];
319  }
320 
321  m_deltaSlip[k][0] = m_deltaSlip_n[k][0] + dt * deltaSlipIncrement[0];
322  m_deltaSlip[k][1] = m_deltaSlip_n[k][1] + dt * deltaSlipIncrement[1];
323  m_stateVariable[k] = m_stateVariable_n[k] + dt * stateVariableIncrement;
324 
325  real64 const deltaSlipLowOrder[2] = {m_deltaSlip_n[k][0] + dt * deltaSlipIncrementLowOrder[0],
326  m_deltaSlip_n[k][1] + dt * deltaSlipIncrementLowOrder[1]};
327  real64 const stateVariableLowOrder = m_stateVariable_n[k] + dt * stateVariableIncrementLowOrder;
328 
329  m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0];
330  m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1];
331 
332  // Compute error
333  m_error[k][0] = computeError( m_deltaSlip[k][0], deltaSlipLowOrder[0], absTol, relTol );
334  m_error[k][1] = computeError( m_deltaSlip[k][1], deltaSlipLowOrder[1], absTol, relTol );
335  m_error[k][2] = computeError( m_stateVariable[k], stateVariableLowOrder, absTol, relTol );
336  }
337 
343  void updateSolutionAndLocalErrorFSAL( localIndex const k, real64 const dt, real64 const absTol, real64 const relTol ) const
344  {
345 
346  real64 deltaSlipIncrementLowOrder[2] = {0.0, 0.0};
347  real64 stateVariableIncrementLowOrder = 0.0;
348 
349  for( localIndex i = 0; i < m_butcherTable.numStages; i++ )
350  {
351  // In FSAL algorithms the last RK substage update coincides with the
352  // high-order update. Only need to compute increments for the the
353  // low-order updates for error computation.
354  deltaSlipIncrementLowOrder[0] += m_butcherTable.bStar[i] * m_stageRates[k][i][0];
355  deltaSlipIncrementLowOrder[1] += m_butcherTable.bStar[i] * m_stageRates[k][i][1];
356  stateVariableIncrementLowOrder += m_butcherTable.bStar[i] * m_stageRates[k][i][2];
357  }
358 
359  real64 const deltaSlipLowOrder[2] = {m_deltaSlip_n[k][0] + dt * deltaSlipIncrementLowOrder[0],
360  m_deltaSlip_n[k][1] + dt * deltaSlipIncrementLowOrder[1]};
361  real64 const stateVariableLowOrder = m_stateVariable_n[k] + dt * stateVariableIncrementLowOrder;
362 
363  m_dispJump[k][1] = m_dispJump_n[k][1] + m_deltaSlip[k][0];
364  m_dispJump[k][2] = m_dispJump_n[k][2] + m_deltaSlip[k][1];
365 
366  // Compute error
367  m_error[k][0] = computeError( m_deltaSlip[k][0], deltaSlipLowOrder[0], absTol, relTol );
368  m_error[k][1] = computeError( m_deltaSlip[k][1], deltaSlipLowOrder[1], absTol, relTol );
369  m_error[k][2] = computeError( m_stateVariable[k], stateVariableLowOrder, absTol, relTol );
370  }
371 
376  real64 computeError( real64 const highOrderApprox, real64 const lowOrderApprox, real64 const absTol, real64 const relTol ) const
377  {
378  return (highOrderApprox - lowOrderApprox) /
379  ( absTol + relTol * LvArray::math::max( LvArray::math::abs( highOrderApprox ), LvArray::math::abs( lowOrderApprox ) ));
380  }
381 
382 private:
383 
385  arrayView1d< real64 > const m_stateVariable;
386 
388  arrayView1d< real64 > const m_stateVariable_n;
389 
391  arrayView1d< real64 > const m_slipRate;
392 
394  arrayView2d< real64 > const m_slipVelocity;
395 
397  arrayView2d< real64 > const m_slipVelocity_n;
398 
400  arrayView2d< real64 > const m_deltaSlip;
401 
403  arrayView2d< real64 > const m_deltaSlip_n;
404 
406  arrayView2d< real64 > const m_dispJump;
407 
409  arrayView2d< real64 > const m_dispJump_n;
410 
412  arrayView2d< real64 > const m_error;
413 
415  arrayView3d< real64 > const m_stageRates;
416 
418  constitutive::RateAndStateFriction::KernelWrapper m_frictionLaw;
419 
421  TABLE_TYPE m_butcherTable;
422 };
423 
424 } /* namespace rateAndStateKernels */
425 
426 } /* namespace geos */
427 
428 #endif /* GEOS_PHYSICSSOLVERS_INDUCEDSEISMICITY_KERNELS_EXPLICITRATEANDSTATEKERNELS_HPP_ */
#define GEOS_HOST_DEVICE
Marks a host-device function.
Definition: GeosxMacros.hpp:49
#define GEOS_UNUSED_VAR(...)
Mark an unused variable and silence compiler warnings.
Definition: GeosxMacros.hpp:84
#define GEOS_MARK_FUNCTION
Mark function with both Caliper and NVTX if enabled.
GEOS_DECLTYPE_AUTO_RETURN getField() const
Get a view to the field associated with a trait from this ObjectManagerBase.
localIndex size() const
Get the "size" of the group, which determines the number of elements in resizable wrappers.
Definition: Group.hpp:1317
Runge-Kutta method used to time integrate slip and state. Uses of a high order update used to integra...
GEOS_HOST_DEVICE real64 computeError(real64 const highOrderApprox, real64 const lowOrderApprox, real64 const absTol, real64 const relTol) const
Computes the relative error scaled by error tolerances.
GEOS_HOST_DEVICE void updateSolutionAndLocalError(localIndex const k, real64 const dt, real64 const absTol, real64 const relTol) const
Updates slip, state and displacement jump to the next time computes error the local error in the time...
GEOS_HOST_DEVICE void updateStageRates(localIndex const k, integer const stageIndex) const
Updates the stage rates rates (the right-hand-side of the ODEs for slip and state)
GEOS_HOST_DEVICE void updateStageRatesFSAL(localIndex const k) const
Re-uses the last stage rate from the previous time step as the first in the next update....
GEOS_HOST_DEVICE void updateStageValues(localIndex const k, integer const stageIndex, real64 const dt) const
Update stage values (slip, state and displacement jump) to a Runge-Kutta substage.
GEOS_HOST_DEVICE void initialize(localIndex const k) const
Initialize slip and state buffers.
GEOS_HOST_DEVICE void updateSolutionAndLocalErrorFSAL(localIndex const k, real64 const dt, real64 const absTol, real64 const relTol) const
Updates slip, state and displacement jump to the next time computes error the local error in the time...
static real64 solveRateAndStateEquation(SurfaceElementSubRegion &subRegion, ExplicitRateAndStateKernel &kernel, real64 dt, integer const maxNewtonIter, real64 const newtonTol)
Performs the kernel launch.
ArrayView< T, 1 > arrayView1d
Alias for 1D array view.
Definition: DataTypes.hpp:180
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
ArrayView< T, 2, USD > arrayView2d
Alias for 2D array view.
Definition: DataTypes.hpp:196
ArrayView< T, 3, USD > arrayView3d
Alias for 3D array view.
Definition: DataTypes.hpp:212
Butcher table for the BogackiShampine 3(2) method.
Butcher table for embedded RK3(2) method using Kuttas third order method for the high-order update,...