@@ -138,27 +138,73 @@ public:
138
138
if (numberOfEASParameters != 0 )
139
139
easApplicabilityCheck ();
140
140
easVariant_.setEASType (numberOfEASParameters);
141
+ initializeState ();
141
142
}
142
143
144
+ /* *
145
+ * \brief Gets the internal state variable alpha for the EAS element.
146
+ *
147
+ * \return Internal state variable (alpha).
148
+ */
149
+ const auto & alpha () const { return alpha_; }
150
+
143
151
protected:
144
152
void bindImpl () {
145
153
assert (underlying ().localView ().bound ());
146
154
easVariant_.bind (underlying ().localView ().element ().geometry ());
155
+ initializeState ();
156
+ }
157
+
158
+ /* *
159
+ * \brief Updates the internal state variable alpha_ at the end of an iteration
160
+ * when NonLinearSolverMessages::SOLUTION_UPDATED is notified by the non-linear solver.
161
+ * See \cite bischoffShearDeformableShell1997b and \cite klinkelGeometricalNonlinearBrick1997 for implementation
162
+ * details.
163
+ *
164
+ * \param par The Requirement object.
165
+ * \param correction The correction in displacement (DeltaD) vector passed based on which the internal state variable
166
+ * alpha is to be updated.
167
+ */
168
+ void updateStateImpl (const Requirement& par, typename Traits::template VectorTypeConst<> correction) {
169
+ using ScalarType = Traits::ctype;
170
+ if (isDisplacementBased ())
171
+ return ;
172
+ const auto & Rtilde = calculateRtilde<ScalarType>(par);
173
+ const auto localdxBlock = Ikarus::FEHelper::localSolutionBlockVector<Traits, Eigen::VectorXd, double >(
174
+ correction, underlying ().localView ());
175
+ const auto localdx = Dune::viewAsFlatEigenVector (localdxBlock);
176
+
177
+ decltype (auto ) LMat = [this ]() -> decltype (auto ) {
178
+ if constexpr (std::is_same_v<ScalarType, double >)
179
+ return [this ]() -> Eigen::MatrixXd& { return L_; }();
180
+ else
181
+ return Eigen::MatrixX<ScalarType>{};
182
+ }();
183
+
184
+ auto correctAlpha = [&]<typename EAST>(const EAST& easFunction) {
185
+ constexpr int enhancedStrainSize = EAST::enhancedStrainSize;
186
+ Eigen::Matrix<double , enhancedStrainSize, enhancedStrainSize> D;
187
+ calculateDAndLMatrix (easFunction, par, D, LMat);
188
+ const decltype (alpha_) updateAlpha = D.inverse () * (Rtilde + (LMat * localdx).eval ());
189
+ this ->alpha_ -= updateAlpha;
190
+ };
191
+
192
+ easVariant_ (correctAlpha);
147
193
}
148
194
149
- public:
150
- protected:
151
195
inline void easApplicabilityCheck () const {
152
196
const auto & numberOfNodes = underlying ().numberOfNodes ();
153
197
assert (not (not ((numberOfNodes == 4 and Traits::mydim == 2 ) or (numberOfNodes == 8 and Traits::mydim == 3 )) and
154
198
(not isDisplacementBased ())) &&
155
- " EAS only supported for Q1 or H1 elements" );
199
+ " EAS is only supported for Q1 or H1 elements" );
156
200
}
157
201
158
202
template <typename ScalarType>
159
203
void calculateMatrixImpl (
160
204
const Requirement& par, const MatrixAffordance& affordance, typename Traits::template MatrixType<> K,
161
205
const std::optional<std::reference_wrapper<const Eigen::VectorX<ScalarType>>>& dx = std::nullopt) const {
206
+ if (affordance != MatrixAffordance::stiffness)
207
+ DUNE_THROW (Dune::NotImplemented, " MatrixAffordance not implemented: " + toString (affordance));
162
208
using namespace Dune ::DerivativeDirections;
163
209
using namespace Dune ;
164
210
easApplicabilityCheck ();
@@ -172,10 +218,30 @@ protected:
172
218
return [this ]() -> Eigen::MatrixXd& { return L_; }();
173
219
}();
174
220
221
+ auto strainFunction = underlying ().strainFunction (par, dx);
222
+ const auto C = underlying ().materialTangentFunction (par);
223
+ const auto geo = underlying ().localView ().element ().geometry ();
224
+ const auto numberOfNodes = underlying ().numberOfNodes ();
225
+
175
226
auto calculateMatrixContribution = [&]<typename EAST>(const EAST& easFunction) {
176
227
typename EAST::DType D;
177
228
calculateDAndLMatrix (easFunction, par, D, LMat, dx);
178
229
230
+ for (const auto & [gpIndex, gp] : strainFunction.viewOverIntegrationPoints ()) {
231
+ const auto M = easFunction.calcM (gp.position ());
232
+ const double intElement = geo.integrationElement (gp.position ()) * gp.weight ();
233
+ const auto EVoigt = strainFunction.evaluate (gpIndex, on (gridElement)).eval ();
234
+ const auto CEval = C (gpIndex);
235
+ auto stresses = (CEval * M * alpha_).eval ();
236
+ for (size_t i = 0 ; i < numberOfNodes; ++i) {
237
+ for (size_t j = 0 ; j < numberOfNodes; ++j) {
238
+ const auto kgIJ =
239
+ strainFunction.evaluateDerivative (gpIndex, wrt (coeff (i, j)), along (stresses), on (gridElement));
240
+ K.template block <Traits::mydim, Traits::mydim>(i * Traits::mydim, j * Traits::mydim) += kgIJ * intElement;
241
+ }
242
+ }
243
+ }
244
+
179
245
K.template triangularView <Eigen::Upper>() -= LMat.transpose () * D.inverse () * LMat;
180
246
K.template triangularView <Eigen::StrictlyLower>() = K.transpose ();
181
247
};
@@ -197,50 +263,59 @@ protected:
197
263
void calculateVectorImpl (
198
264
const Requirement& par, VectorAffordance affordance, typename Traits::template VectorType<ScalarType> force,
199
265
const std::optional<std::reference_wrapper<const Eigen::VectorX<ScalarType>>>& dx = std::nullopt) const {
266
+ if (affordance != VectorAffordance::forces)
267
+ DUNE_THROW (Dune::NotImplemented, " VectorAffordance not implemented: " + toString (affordance));
200
268
easApplicabilityCheck ();
269
+ if (isDisplacementBased ())
270
+ return ;
201
271
using namespace Dune ;
202
272
using namespace Dune ::DerivativeDirections;
203
273
const auto uFunction = underlying ().displacementFunction (par, dx);
204
274
auto strainFunction = underlying ().strainFunction (par, dx);
205
275
const auto & numberOfNodes = underlying ().numberOfNodes ();
276
+ const auto C = underlying ().materialTangentFunction (par);
206
277
207
278
auto calculateForceContribution = [&]<typename EAST>(const EAST& easFunction) {
208
279
typename EAST::DType D;
209
280
calculateDAndLMatrix (easFunction, par, D, L_);
210
281
211
- decltype (auto ) LMat = [this ]() -> decltype (auto ) {
212
- if constexpr (Concepts::AutodiffScalar<ScalarType>)
213
- return Eigen::MatrixX<ScalarType>{};
214
- else
215
- return [this ]() -> Eigen::MatrixXd& { return L_; }();
216
- }();
217
- const auto disp = Dune::viewAsFlatEigenVector (uFunction.coefficientsRef ());
218
- const auto alpha = (-D.inverse () * L_ * disp).eval ();
219
- const auto geo = underlying ().localView ().element ().geometry ();
220
- auto C = underlying ().materialTangentFunction (par);
221
-
282
+ const auto disp = Dune::viewAsFlatEigenVector (uFunction.coefficientsRef ());
283
+ const auto geo = underlying ().localView ().element ().geometry ();
284
+ const auto & Rtilde = calculateRtilde (par, dx);
222
285
for (const auto & [gpIndex, gp] : strainFunction.viewOverIntegrationPoints ()) {
223
286
const auto M = easFunction.calcM (gp.position ());
224
287
const double intElement = geo.integrationElement (gp.position ()) * gp.weight ();
225
288
const auto CEval = C (gpIndex);
226
- auto stresses = (CEval * M * alpha ).eval ();
289
+ auto stresses = (CEval * M * alpha_ ).eval ();
227
290
for (size_t i = 0 ; i < numberOfNodes; ++i) {
228
291
const auto bopI = strainFunction.evaluateDerivative (gpIndex, wrt (coeff (i)), on (gridElement));
229
292
force.template segment <Traits::worlddim>(Traits::worlddim * i) += bopI.transpose () * stresses * intElement;
230
293
}
231
294
}
295
+ force -= L_.transpose () * D.inverse () * Rtilde;
232
296
};
233
297
easVariant_ (calculateForceContribution);
234
298
}
235
299
236
300
private:
237
301
EAS::Impl::EASVariant<Geometry> easVariant_;
238
302
mutable Eigen::MatrixXd L_;
303
+ Eigen::VectorXd alpha_;
239
304
240
305
// > CRTP
241
306
const auto & underlying () const { return static_cast <const FE&>(*this ); }
242
307
auto & underlying () { return static_cast <FE&>(*this ); }
243
308
309
+ /* *
310
+ * \brief Initializes the internal state variable alpha_ based on the number of EAS parameters.
311
+ */
312
+ void initializeState () {
313
+ if (isDisplacementBased ())
314
+ return ;
315
+ alpha_.resize (numberOfEASParameters ());
316
+ alpha_.setZero ();
317
+ }
318
+
244
319
template <typename ScalarType, int enhancedStrainSize>
245
320
void calculateDAndLMatrix (
246
321
const auto & easFunction, const auto & par, Eigen::Matrix<double , enhancedStrainSize, enhancedStrainSize>& DMat,
@@ -267,6 +342,34 @@ private:
267
342
}
268
343
}
269
344
}
345
+
346
+ template <typename ScalarType>
347
+ Eigen::VectorX<ScalarType> calculateRtilde (
348
+ const Requirement& par,
349
+ const std::optional<std::reference_wrapper<const Eigen::VectorX<ScalarType>>>& dx = std::nullopt) const {
350
+ using namespace Dune ;
351
+ using namespace Dune ::DerivativeDirections;
352
+ const auto geo = underlying ().localView ().element ().geometry ();
353
+ auto strainFunction = underlying ().strainFunction (par, dx);
354
+ const auto C = underlying ().materialTangentFunction (par);
355
+ Eigen::VectorX<ScalarType> Rtilde;
356
+ Rtilde.setZero (numberOfEASParameters ());
357
+
358
+ auto calculateRtildeContribution = [&]<typename EAST>(const EAST& easFunction) {
359
+ for (const auto & [gpIndex, gp] : strainFunction.viewOverIntegrationPoints ()) {
360
+ const auto M = easFunction.calcM (gp.position ());
361
+ const double intElement = geo.integrationElement (gp.position ()) * gp.weight ();
362
+ const auto EVoigt = (strainFunction.evaluate (gpIndex, on (gridElement))).eval ();
363
+ const auto CEval = C (gpIndex);
364
+ auto stresses = ((CEval * M * alpha_).template cast <ScalarType>()).eval ();
365
+ stresses += underlying ().getStress (EVoigt).eval ();
366
+ Rtilde += (M.transpose () * stresses).eval () * intElement;
367
+ }
368
+ };
369
+
370
+ easVariant_ (calculateRtildeContribution);
371
+ return Rtilde;
372
+ }
270
373
};
271
374
272
375
/* *
0 commit comments