-
Notifications
You must be signed in to change notification settings - Fork 91
/
Copy pathSolidMechanicsSmallStrainQuasiStaticKernel.hpp
339 lines (288 loc) · 12.3 KB
/
SolidMechanicsSmallStrainQuasiStaticKernel.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
/*
* ------------------------------------------------------------------------------------------------------------
* SPDX-License-Identifier: LGPL-2.1-only
*
* Copyright (c) 2018-2020 Lawrence Livermore National Security LLC
* Copyright (c) 2018-2020 The Board of Trustees of the Leland Stanford Junior University
* Copyright (c) 2018-2020 Total, S.A
* Copyright (c) 2019- GEOSX Contributors
* All rights reserved
*
* See top level LICENSE, COPYRIGHT, CONTRIBUTORS, NOTICE, and ACKNOWLEDGEMENTS files for details.
* ------------------------------------------------------------------------------------------------------------
*/
/**
* @file SolidMechanicsSmallStrainQuasiStaticKernel.hpp
*/
#ifndef GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSSMALLSTRAINQUASISTATIC_HPP_
#define GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSSMALLSTRAINQUASISTATIC_HPP_
#include "finiteElement/kernelInterface/ImplicitKernelBase.hpp"
namespace geosx
{
namespace SolidMechanicsLagrangianFEMKernels
{
/**
* @brief Implements kernels for solving quasi-static equilibrium.
* @copydoc geosx::finiteElement::ImplicitKernelBase
* @tparam NUM_NODES_PER_ELEM The number of nodes per element for the
* @p SUBREGION_TYPE.
* @tparam UNUSED An unused parameter since we are assuming that the test and
* trial space have the same number of support points.
*
* ### QuasiStatic Description
* Implements the KernelBase interface functions required for solving the
* quasi-static equilibrium equations using one of the
* "finite element kernel application" functions such as
* geosx::finiteElement::RegionBasedKernelApplication.
*
* In this implementation, the template parameter @p NUM_NODES_PER_ELEM is used
* in place of both @p NUM_TEST_SUPPORT_POINTS_PER_ELEM and
* @p NUM_TRIAL_SUPPORT_POINTS_PER_ELEM, which are assumed to be equal. This
* results in the @p UNUSED template parameter as only the NUM_NODES_PER_ELEM
* is passed to the ImplicitKernelBase template to form the base class.
*
* Additionally, the number of degrees of freedom per support point for both
* the test and trial spaces are specified as `3` when specifying the base
* class.
*/
template< typename SUBREGION_TYPE,
typename CONSTITUTIVE_TYPE,
typename FE_TYPE >
class QuasiStatic :
public finiteElement::ImplicitKernelBase< SUBREGION_TYPE,
CONSTITUTIVE_TYPE,
FE_TYPE,
3,
3 >
{
public:
/// Alias for the base class;
using Base = finiteElement::ImplicitKernelBase< SUBREGION_TYPE,
CONSTITUTIVE_TYPE,
FE_TYPE,
3,
3 >;
/// Number of nodes per element...which is equal to the
/// numTestSupportPointPerElem and numTrialSupportPointPerElem by definition.
static constexpr int numNodesPerElem = Base::numTestSupportPointsPerElem;
using Base::numDofPerTestSupportPoint;
using Base::numDofPerTrialSupportPoint;
using Base::m_dofNumber;
using Base::m_dofRankOffset;
using Base::m_matrix;
using Base::m_rhs;
using Base::m_elemsToNodes;
using Base::m_constitutiveUpdate;
using Base::m_finiteElementSpace;
/**
* @brief Constructor
* @copydoc geosx::finiteElement::ImplicitKernelBase::ImplicitKernelBase
* @param inputGravityVector The gravity vector.
*/
QuasiStatic( NodeManager const & nodeManager,
EdgeManager const & edgeManager,
FaceManager const & faceManager,
SUBREGION_TYPE const & elementSubRegion,
FE_TYPE const & finiteElementSpace,
CONSTITUTIVE_TYPE * const inputConstitutiveType,
arrayView1d< globalIndex const > const & inputDofNumber,
globalIndex const rankOffset,
CRSMatrixView< real64, globalIndex const > const & inputMatrix,
arrayView1d< real64 > const & inputRhs,
real64 const (&inputGravityVector)[3] ):
Base( nodeManager,
edgeManager,
faceManager,
elementSubRegion,
finiteElementSpace,
inputConstitutiveType,
inputDofNumber,
rankOffset,
inputMatrix,
inputRhs ),
m_X( nodeManager.referencePosition()),
m_disp( nodeManager.totalDisplacement()),
m_uhat( nodeManager.incrementalDisplacement()),
m_gravityVector{ inputGravityVector[0], inputGravityVector[1], inputGravityVector[2] },
m_density( inputConstitutiveType->getDensity() )
{}
//*****************************************************************************
/**
* @class StackVariables
* @copydoc geosx::finiteElement::ImplicitKernelBase::StackVariables
*
* Adds a stack array for the displacement, incremental displacement, and the
* constitutive stiffness.
*/
struct StackVariables : public Base::StackVariables
{
public:
/// Constructor.
GEOSX_HOST_DEVICE
StackVariables():
Base::StackVariables(),
xLocal(),
u_local(),
uhat_local(),
constitutiveStiffness()
{}
#if !defined(CALC_FEM_SHAPE_IN_KERNEL)
/// Dummy
int xLocal;
#else
/// C-array stack storage for element local the nodal positions.
real64 xLocal[ numNodesPerElem ][ 3 ];
#endif
/// Stack storage for the element local nodal displacement
real64 u_local[numNodesPerElem][numDofPerTrialSupportPoint];
/// Stack storage for the element local nodal incremental displacement
real64 uhat_local[numNodesPerElem][numDofPerTrialSupportPoint];
/// Stack storage for the constitutive stiffness at a quadrature point.
real64 constitutiveStiffness[ 6 ][ 6 ];
};
//*****************************************************************************
/**
* @brief Copy global values from primary field to a local stack array.
* @copydoc ::geosx::finiteElement::ImplicitKernelBase::setup
*
* For the QuasiStatic implementation, global values from the displacement,
* incremental displacement, and degree of freedom numbers are placed into
* element local stack storage.
*/
GEOSX_HOST_DEVICE
GEOSX_FORCE_INLINE
void setup( localIndex const k,
StackVariables & stack ) const
{
for( localIndex a=0; a<numNodesPerElem; ++a )
{
localIndex const localNodeIndex = m_elemsToNodes( k, a );
for( int i=0; i<3; ++i )
{
#if defined(CALC_FEM_SHAPE_IN_KERNEL)
stack.xLocal[ a ][ i ] = m_X[ localNodeIndex ][ i ];
#endif
stack.u_local[ a ][i] = m_disp[ localNodeIndex ][i];
stack.uhat_local[ a ][i] = m_uhat[ localNodeIndex ][i];
stack.localRowDofIndex[a*3+i] = m_dofNumber[localNodeIndex]+i;
stack.localColDofIndex[a*3+i] = m_dofNumber[localNodeIndex]+i;
}
}
}
/**
* @brief Internal struct to provide no-op defaults used in the inclusion
* of lambda functions into kernel component functions.
* @struct NoOpFunctors
*/
struct NoOpFunctors
{
/**
* @brief operator() no-op used for adding an additional dynamics term
* inside the jacobian assembly loop.
* @param a Node index for the row.
* @param b Node index for the col.
*/
GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE constexpr
void operator() ( localIndex const a, localIndex const b )
{
GEOSX_UNUSED_VAR( a );
GEOSX_UNUSED_VAR( b );
}
/**
* @brief operator() no-op used for modifying the stress tensor prior to
* integrating the divergence to produce nodal forces.
* @param stress The stress array.
*/
GEOSX_HOST_DEVICE GEOSX_FORCE_INLINE constexpr
void operator() ( real64 (& stress)[6] )
{
GEOSX_UNUSED_VAR( stress );
}
};
/**
* @copydoc geosx::finiteElement::KernelBase::quadraturePointKernel
* @tparam STRESS_MODIFIER Type of optional functor to allow for the
* modification of stress prior to integration.
* @param stressModifier An optional functor to allow for the modification
* of stress prior to integration.
* For solid mechanics kernels, the strain increment is calculated, and the
* constitutive update is called. In addition, the constitutive stiffness
* stack variable is filled by the constitutive model.
*/
template< typename STRESS_MODIFIER = NoOpFunctors >
GEOSX_HOST_DEVICE
GEOSX_FORCE_INLINE
void quadraturePointKernel( localIndex const k,
localIndex const q,
StackVariables & stack,
STRESS_MODIFIER && stressModifier = NoOpFunctors{} ) const
{
real64 dNdX[ numNodesPerElem ][ 3 ];
real64 const detJ = m_finiteElementSpace.template getGradN< FE_TYPE >( k, q, stack.xLocal, dNdX );
real64 strainInc[6] = {0};
FE_TYPE::symmetricGradient( dNdX, stack.uhat_local, strainInc );
m_constitutiveUpdate.SmallStrain( k, q, strainInc );
typename CONSTITUTIVE_TYPE::KernelWrapper::DiscretizationOps stiffnessHelper;
m_constitutiveUpdate.setDiscretizationOps( k, q, stiffnessHelper );
stiffnessHelper.template upperBTDB< numNodesPerElem >( dNdX, -detJ, stack.localJacobian );
real64 stress[6];
m_constitutiveUpdate.getStress( k, q, stress );
stressModifier( stress );
real64 const gravityForce[3] = { m_gravityVector[0] * m_density( k, q )* detJ,
m_gravityVector[1] * m_density( k, q )* detJ,
m_gravityVector[2] * m_density( k, q )* detJ };
for( localIndex i=0; i<6; ++i )
{
stress[i] *= -detJ;
}
real64 N[numNodesPerElem];
FE_TYPE::calcN( q, N );
FE_TYPE::plus_gradNajAij_plus_NaFi( dNdX,
stress,
N,
gravityForce,
reinterpret_cast< real64 (&)[numNodesPerElem][3] >(stack.localResidual) );
}
/**
* @copydoc geosx::finiteElement::ImplicitKernelBase::complete
*/
GEOSX_HOST_DEVICE
GEOSX_FORCE_INLINE
real64 complete( localIndex const k,
StackVariables & stack ) const
{
GEOSX_UNUSED_VAR( k );
real64 maxForce = 0;
CONSTITUTIVE_TYPE::KernelWrapper::DiscretizationOps::template fillLowerBTDB< numNodesPerElem >( stack.localJacobian );
for( int localNode = 0; localNode < numNodesPerElem; ++localNode )
{
for( int dim = 0; dim < numDofPerTestSupportPoint; ++dim )
{
localIndex const dof = LvArray::integerConversion< localIndex >( stack.localRowDofIndex[ numDofPerTestSupportPoint * localNode + dim ] - m_dofRankOffset );
if( dof < 0 || dof >= m_matrix.numRows() ) continue;
m_matrix.template addToRowBinarySearchUnsorted< parallelDeviceAtomic >( dof,
stack.localRowDofIndex,
stack.localJacobian[ numDofPerTestSupportPoint * localNode + dim ],
numNodesPerElem * numDofPerTrialSupportPoint );
RAJA::atomicAdd< parallelDeviceAtomic >( &m_rhs[ dof ], stack.localResidual[ numDofPerTestSupportPoint * localNode + dim ] );
maxForce = fmax( maxForce, fabs( stack.localResidual[ numDofPerTestSupportPoint * localNode + dim ] ) );
}
}
return maxForce;
}
protected:
/// The array containing the nodal position array.
arrayView2d< real64 const, nodes::REFERENCE_POSITION_USD > const m_X;
/// The rank-global displacement array.
arrayView2d< real64 const, nodes::TOTAL_DISPLACEMENT_USD > const m_disp;
/// The rank-global incremental displacement array.
arrayView2d< real64 const, nodes::INCR_DISPLACEMENT_USD > const m_uhat;
/// The gravity vector.
real64 const m_gravityVector[3];
/// The rank global density
arrayView2d< real64 const > const m_density;
};
} // namespace SolidMechanicsLagrangianFEMKernels
} // namespace geosx
#include "finiteElement/kernelInterface/SparsityKernelBase.hpp"
#endif // GEOSX_PHYSICSSOLVERS_SOLIDMECHANICS_SOLIDMECHANICSSMALLSTRAINQUASISTATIC_HPP_