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