version 0.4.1
enhancedassumedstrains.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers ikarus@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
10#pragma once
11
12#if HAVE_DUNE_LOCALFEFUNCTIONS
13 #include <dune/localfefunctions/derivativetransformators.hh>
14 #include <dune/localfefunctions/linearAlgebraHelper.hh>
15 #include <dune/localfefunctions/meta.hh>
16
23
24namespace Ikarus {
25
26template <typename PreFE, typename FE, typename ES>
27class EnhancedAssumedStrains;
28
33template <typename ES>
35{
37
38 template <typename PreFE, typename FE>
40};
41
53template <typename PreFE, typename FE, typename ESF>
55 : public std::conditional_t<std::same_as<ESF, EAS::LinearStrain>,
56 ResultTypeBase<ResultTypes::linearStress, ResultTypes::linearStressFull>,
57 ResultTypeBase<ResultTypes::PK2Stress, ResultTypes::PK2StressFull>>
58{
59public:
62 using LocalView = typename Traits::LocalView;
63 using Geometry = typename Traits::Geometry;
64 using GridView = typename Traits::GridView;
67
68 static constexpr int myDim = Traits::mydim;
69
70 template <typename ST>
71 using VectorXOptRef = std::optional<std::reference_wrapper<const Eigen::VectorX<ST>>>;
72
73 template <template <typename, int, int> class RT>
75
80 explicit EnhancedAssumedStrains(const Pre& pre) {
82 "EAS method is only implemented for the total Lagrangian setting.");
83 static_assert(
84 not(FE::strainType == StrainTags::linear) or (std::same_as<EnhancedStrainFunction, EAS::LinearStrain>),
85 "If FE::strainType is linear, then enhancedStrain must also be linear.");
87 }
88
94 bool isDisplacementBased() const { return easVariant_.isDisplacmentBased(); }
95
101 const auto& easVariant() const { return easVariant_; }
102
108 auto numberOfInternalVariables() const { return easVariant_.numberOfInternalVariables(); }
109
124 template <template <typename, int, int> class RT>
125 requires(EnhancedAssumedStrains::template supportsResultType<RT>())
127 Dune::PriorityTag<2>) const {
128 if constexpr (isSameResultType<RT, ResultTypes::linearStress> or isSameResultType<RT, ResultTypes::PK2Stress> or
129 isSameResultType<RT, ResultTypes::linearStressFull> or
130 isSameResultType<RT, ResultTypes::PK2StressFull>) {
131 const auto ufunc = underlying().displacementFunction(req);
132 const auto rFunction = underlying().template resultFunction<RT>();
133 auto disp = Dune::viewAsFlatEigenVector(ufunc.coefficientsRef());
134 const auto geo = underlying().localView().element().geometry();
135
136 RTWrapperType<RT> resultWrapper{};
137 auto calculateAtContribution = [&]<typename EAST>(const EAST& easFunction) {
138 Eigen::VectorXd alpha;
139 alpha.setZero(numberOfInternalVariables());
140 if constexpr (EAST::enhancedStrainSize != 0) {
141 typename EAST::DType D;
142 calculateDAndLMatrix(easFunction, req, D, L_);
143 alpha = -D.inverse() * L_ * disp;
144 }
145 const auto enhancedStrain = EnhancedStrainFunction::value(geo, ufunc, local, easFunction, alpha);
146 resultWrapper = rFunction(enhancedStrain);
147 };
148 easVariant_(calculateAtContribution);
149 return resultWrapper;
150 }
151 DUNE_THROW(Dune::NotImplemented, "The requested result type is not supported");
152 }
153
163 initializeState();
164 }
165
171 const auto& internalVariable() const { return alpha_; }
172
173protected:
174 void bindImpl() {
175 assert(underlying().localView().bound());
176 easVariant_.bind(underlying().localView().element().geometry());
177 initializeState();
178 }
179
190 const std::remove_reference_t<typename Traits::template VectorType<>>& correction) {
191 using ScalarType = Traits::ctype;
193 auto correctAlpha = [&]<typename EAST>(const EAST& easFunction) {
194 if constexpr (EAST::enhancedStrainSize != 0) {
195 const auto& Rtilde = calculateRtilde<ScalarType>(par);
196 const auto localdxBlock = Ikarus::FEHelper::localSolutionBlockVector<Traits, Eigen::VectorXd, double>(
197 correction, underlying().localView());
198 const auto localdx = Dune::viewAsFlatEigenVector(localdxBlock);
199 constexpr int enhancedStrainSize = EAST::enhancedStrainSize;
200 Eigen::Matrix<double, enhancedStrainSize, enhancedStrainSize> D;
201 calculateDAndLMatrix(easFunction, par, D, L_);
202 this->alpha_ -= D.inverse() * (Rtilde + (L_ * localdx));
203 }
204 };
205
206 easVariant_(correctAlpha);
207 }
208
209 inline void easApplicabilityCheck() const {
210 const auto& numberOfNodes = underlying().numberOfNodes();
211 if (not((numberOfNodes == 4 and Traits::mydim == 2) or (numberOfNodes == 9 and Traits::mydim == 2) or
212 (numberOfNodes == 8 and Traits::mydim == 3)) and
213 (not isDisplacementBased()))
214 DUNE_THROW(Dune::NotImplemented, "EAS is only supported for Q1, Q2 and H1 elements");
215 }
216
217 template <typename ScalarType>
218 void calculateMatrixImpl(const Requirement& par, const MatrixAffordance& affordance,
219 typename Traits::template MatrixType<> K,
220 const VectorXOptRef<ScalarType>& dx = std::nullopt) const {
221 if (affordance != MatrixAffordance::stiffness)
222 DUNE_THROW(Dune::NotImplemented, "MatrixAffordance not implemented: " + toString(affordance));
224
225 const auto geo = underlying().localView().element().geometry();
226 const auto& uFunction = underlying().displacementFunction(par, dx);
227 const auto& kMFunction = underlying().template materialStiffnessMatrixFunction<ScalarType>(par, K, dx);
228 const auto& kGFunction = underlying().template geometricStiffnessMatrixFunction<ScalarType>(par, K, dx);
229 const auto numberOfNodes = underlying().numberOfNodes();
230 const auto& localBasis = underlying().localBasis();
231
232 auto calculateMatrixContribution = [&]<typename EAST>(const EAST& easFunction) {
233 for (const auto& [gpIndex, gp] : uFunction.viewOverIntegrationPoints()) {
234 const auto enhancedStrain = EnhancedStrainFunction::value(geo, uFunction, gp.position(), easFunction, alpha_);
235 const auto stresses = underlying().stress(enhancedStrain);
236 for (size_t i = 0; i < numberOfNodes; ++i) {
237 const auto E_dI = EnhancedStrainFunction::template firstDerivative<0>(geo, uFunction, localBasis, gpIndex,
238 gp.position(), easFunction, alpha_, i);
239 for (size_t j = 0; j < numberOfNodes; ++j) {
240 const auto E_dJ = EnhancedStrainFunction::template firstDerivative<0>(
241 geo, uFunction, localBasis, gpIndex, gp.position(), easFunction, alpha_, j);
242 const auto E_dd = EnhancedStrainFunction::template secondDerivative<0>(
243 geo, uFunction, localBasis, gpIndex, gp.position(), stresses, easFunction, alpha_, i, j);
244 kMFunction(enhancedStrain, E_dI, E_dJ, i, j, gp);
245 kGFunction(E_dd, i, j, gp);
246 }
247 }
248 }
249
250 if constexpr (EAST::enhancedStrainSize != 0) {
251 typename EAST::DType D;
252 calculateDAndLMatrix(easFunction, par, D, L_);
253 K.template triangularView<Eigen::Upper>() -= L_.transpose() * D.inverse() * L_;
254 K.template triangularView<Eigen::StrictlyLower>() = K.transpose();
255 }
256 };
257 easVariant_(calculateMatrixContribution);
258 }
259
260 template <typename ScalarType>
261 inline ScalarType calculateScalarImpl(const Requirement& par, ScalarAffordance affordance,
262 const VectorXOptRef<ScalarType>& dx = std::nullopt) const {
265 return underlying().template energyFunction<ScalarType>(par, dx)();
266
267 DUNE_THROW(Dune::NotImplemented,
268 "EAS element do not support any scalar calculations, i.e. they are not derivable from a potential");
269 }
270
271 template <typename ScalarType>
273 typename Traits::template VectorType<ScalarType> force,
274 const VectorXOptRef<ScalarType>& dx = std::nullopt) const {
275 if (affordance != VectorAffordance::forces)
276 DUNE_THROW(Dune::NotImplemented, "VectorAffordance not implemented: " + toString(affordance));
278
279 const auto geo = underlying().localView().element().geometry();
280 const auto& uFunction = underlying().displacementFunction(par, dx);
281 const auto numberOfNodes = underlying().numberOfNodes();
282 const auto& localBasis = underlying().localBasis();
283 const auto fIntFunction = underlying().template internalForcesFunction<ScalarType>(par, force, dx);
284
285 auto calculateForceContribution = [&]<typename EAST>(const EAST& easFunction) {
286 for (const auto& [gpIndex, gp] : uFunction.viewOverIntegrationPoints()) {
287 const auto enhancedStrain = EnhancedStrainFunction::value(geo, uFunction, gp.position(), easFunction, alpha_);
288 const auto stresses = underlying().stress(enhancedStrain);
289 for (size_t i = 0; i < numberOfNodes; ++i) {
290 const auto E_dI = EnhancedStrainFunction::template firstDerivative<0>(geo, uFunction, localBasis, gpIndex,
291 gp.position(), easFunction, alpha_, i);
292 fIntFunction(stresses, E_dI, i, gp);
293 }
294 }
295 if constexpr (EAST::enhancedStrainSize != 0) {
296 // Here, L_ and D doesn't see the ScalarType, while Rtilde sees it. This is needed because only then when we use
297 // automatic differentiation w.r.t to the displacements, we get the correct static-condensed stiffness matrix.
298 // If L_ and D sees the ScalarType, then their derivatives w.r.t. the displacements is also performed which is
299 // then not equivalent to the static-condensed stiffness matrix in general.
300 typename EAST::DType D;
301 calculateDAndLMatrix(easFunction, par, D, L_);
302 const auto& Rtilde = calculateRtilde(par, dx);
303 force -= L_.transpose() * D.inverse() * Rtilde;
304 }
305 };
306 easVariant_(calculateForceContribution);
307 }
308
309 template <typename MT, typename BC>
310 void subscribeToImpl(BC& bc) {
311 if constexpr (std::same_as<MT, NonLinearSolverMessages>) {
312 using NLSState = typename BC::State;
313 underlying().subscribe(bc, [&](NonLinearSolverMessages message, const NLSState& state) {
315 this->updateStateImpl(state.domain, state.correction);
316 });
317 }
318 }
319
320private:
322 mutable Eigen::MatrixXd L_;
323 Eigen::VectorXd alpha_;
324
325 //> CRTP
326 const auto& underlying() const { return static_cast<const FE&>(*this); }
327 auto& underlying() { return static_cast<FE&>(*this); }
328
332 void initializeState() {
333 alpha_.resize(numberOfInternalVariables());
334 alpha_.setZero();
335 }
336
337 template <int enhancedStrainSize>
338 void calculateDAndLMatrix(const auto& easFunction, const auto& par,
339 Eigen::Matrix<double, enhancedStrainSize, enhancedStrainSize>& DMat,
340 Eigen::MatrixX<double>& LMat) const {
341 using namespace Dune;
342 using namespace Dune::DerivativeDirections;
343
344 const auto& uFunction = underlying().displacementFunction(par);
345 const auto geo = underlying().localView().element().geometry();
346 const auto numberOfNodes = underlying().numberOfNodes();
347 const auto& localBasis = underlying().localBasis();
348 DMat.setZero();
349 LMat.setZero(enhancedStrainSize, underlying().localView().size());
350 for (const auto& [gpIndex, gp] : uFunction.viewOverIntegrationPoints()) {
351 const auto enhancedStrain = EnhancedStrainFunction::value(geo, uFunction, gp.position(), easFunction, alpha_);
352 const auto C = underlying().materialTangent(enhancedStrain);
353 const auto stresses = underlying().stress(enhancedStrain);
354 const double intElement = geo.integrationElement(gp.position()) * gp.weight();
355 const auto E_a = EnhancedStrainFunction::template firstDerivative<1>(geo, uFunction, localBasis, gpIndex,
356 gp.position(), easFunction, alpha_);
357 const auto E_aa = EnhancedStrainFunction::template secondDerivative<1>(
358 geo, uFunction, localBasis, gpIndex, gp.position(), stresses, easFunction, alpha_);
359 DMat += (E_a.transpose() * C * E_a + E_aa) * intElement;
360 for (size_t i = 0U; i < numberOfNodes; ++i) {
361 const auto E_dI = EnhancedStrainFunction::template firstDerivative<0>(geo, uFunction, localBasis, gpIndex,
362 gp.position(), easFunction, alpha_, i);
363 const auto E_ad = EnhancedStrainFunction::template secondDerivative<2>(
364 geo, uFunction, localBasis, gpIndex, gp.position(), stresses, easFunction, alpha_, i);
365 LMat.template block<enhancedStrainSize, myDim>(0, myDim * i) +=
366 (E_a.transpose() * C * E_dI + E_ad) * intElement;
367 }
368 }
369 }
370
371 template <typename ScalarType>
372 Eigen::VectorX<ScalarType> calculateRtilde(const Requirement& par,
373 const VectorXOptRef<ScalarType>& dx = std::nullopt) const {
374 const auto geo = underlying().localView().element().geometry();
375 const auto& uFunction = underlying().displacementFunction(par, dx);
376 const auto& localBasis = underlying().localBasis();
377 Eigen::VectorX<ScalarType> Rtilde;
378 Rtilde.setZero(numberOfInternalVariables());
379
380 auto calculateRtildeContribution = [&]<typename EAST>(const EAST& easFunction) {
381 for (const auto& [gpIndex, gp] : uFunction.viewOverIntegrationPoints()) {
382 const auto enhancedStrain = EnhancedStrainFunction::value(geo, uFunction, gp.position(), easFunction, alpha_);
383 const auto E_a = EnhancedStrainFunction::template firstDerivative<1>(geo, uFunction, localBasis, gpIndex,
384 gp.position(), easFunction, alpha_);
385 const double intElement = geo.integrationElement(gp.position()) * gp.weight();
386 auto stresses = underlying().stress(enhancedStrain);
387 Rtilde += (E_a.transpose() * stresses).eval() * intElement;
388 }
389 };
390
391 easVariant_(calculateRtildeContribution);
392 return Rtilde;
393 }
394};
395
402template <typename ES = EAS::LinearStrain>
403auto eas(int numberOfInternalVariables = 0) {
404 EnhancedAssumedStrainsPre<ES> pre(numberOfInternalVariables);
405
406 return pre;
407}
408
409} // namespace Ikarus
410
411#else
412 #error EnhancedAssumedStrains depends on dune-localfefunctions, which is not included
413#endif
Definition of several material related enums.
Definition of the EAS variants.
Definition of the LinearElastic class for finite element mechanics computations.
Enums for observer messages.
NonLinearSolverMessages
Enum class defining non-linear solver-related messages.
Definition: broadcastermessages.hh:22
auto viewAsFlatEigenVector(Dune::BlockVector< ValueType > &blockedVector)
View Dune::BlockVector as an Eigen::Vector.
Definition: linearalgebrahelper.hh:57
Definition: assemblermanipulatorbuildingblocks.hh:22
MatrixAffordance
A strongly typed enum class representing the matrix affordance.
Definition: ferequirements.hh:64
auto eas(int numberOfInternalVariables=0)
A helper function to create an enhanced assumed strain pre finite element.
Definition: enhancedassumedstrains.hh:403
VectorAffordance
A strongly typed enum class representing the vector affordance.
Definition: ferequirements.hh:49
constexpr std::string toString(DBCOption _e)
Definition: dirichletbcenforcement.hh:8
ScalarAffordance
A strongly typed enum class representing the scalar affordance.
Definition: ferequirements.hh:38
Definition: utils/dirichletvalues.hh:30
FE class is a base class for all finite elements.
Definition: febase.hh:79
FETraits< BH, useEigenRef, useFlat > Traits
Definition: febase.hh:38
Class representing the requirements for finite element calculations.
Definition: ferequirements.hh:223
Container that is used for FE Results. It gives access to the stored value, but can also be used to a...
Definition: feresulttypes.hh:164
Traits for handling finite elements.
Definition: fetraits.hh:25
typename Basis::LocalView LocalView
Type of the local view.
Definition: fetraits.hh:42
typename Element::Geometry Geometry
Type of the element geometry.
Definition: fetraits.hh:51
double ctype
Type used for coordinates.
Definition: fetraits.hh:57
typename Basis::GridView GridView
Type of the grid view.
Definition: fetraits.hh:45
static constexpr int mydim
Dimension of the geometry.
Definition: fetraits.hh:63
Wrapper class for using Enhanced Assumed Strains (EAS) with displacement based elements.
Definition: enhancedassumedstrains.hh:58
std::optional< std::reference_wrapper< const Eigen::VectorX< ST > > > VectorXOptRef
Definition: enhancedassumedstrains.hh:71
FERequirements< FESolutions::displacement, FEParameter::loadfactor > Requirement
Definition: enhancedassumedstrains.hh:61
void calculateMatrixImpl(const Requirement &par, const MatrixAffordance &affordance, typename Traits::template MatrixType<> K, const VectorXOptRef< ScalarType > &dx=std::nullopt) const
Definition: enhancedassumedstrains.hh:218
void easApplicabilityCheck() const
Definition: enhancedassumedstrains.hh:209
void calculateVectorImpl(const Requirement &par, VectorAffordance affordance, typename Traits::template VectorType< ScalarType > force, const VectorXOptRef< ScalarType > &dx=std::nullopt) const
Definition: enhancedassumedstrains.hh:272
auto calculateAtImpl(const Requirement &req, const Dune::FieldVector< double, Traits::mydim > &local, Dune::PriorityTag< 2 >) const
Calculates a requested result at a specific local position using the Enhanced Assumed Strains (EAS) m...
Definition: enhancedassumedstrains.hh:126
void bindImpl()
Definition: enhancedassumedstrains.hh:174
ScalarType calculateScalarImpl(const Requirement &par, ScalarAffordance affordance, const VectorXOptRef< ScalarType > &dx=std::nullopt) const
Definition: enhancedassumedstrains.hh:261
ESF EnhancedStrainFunction
Definition: enhancedassumedstrains.hh:66
bool isDisplacementBased() const
Checks if the element is displacement-based and the EAS is turned off.
Definition: enhancedassumedstrains.hh:94
void setEASType(int numberOfInternalVariables)
Sets the EAS type for 2D elements.
Definition: enhancedassumedstrains.hh:159
EnhancedAssumedStrains(const Pre &pre)
Constructor for Enhanced Assumed Strains elements.
Definition: enhancedassumedstrains.hh:80
typename Traits::Geometry Geometry
Definition: enhancedassumedstrains.hh:63
const auto & internalVariable() const
Gets the internal state variable alpha for the EAS element.
Definition: enhancedassumedstrains.hh:171
static constexpr int myDim
Definition: enhancedassumedstrains.hh:68
void subscribeToImpl(BC &bc)
Definition: enhancedassumedstrains.hh:310
const auto & easVariant() const
Gets the variant representing the type of Enhanced Assumed Strains (EAS).
Definition: enhancedassumedstrains.hh:101
typename Traits::GridView GridView
Definition: enhancedassumedstrains.hh:64
typename Traits::LocalView LocalView
Definition: enhancedassumedstrains.hh:62
void updateStateImpl(const Requirement &par, const std::remove_reference_t< typename Traits::template VectorType<> > &correction)
Updates the internal state variable alpha_ at the end of an iteration before the update of the displa...
Definition: enhancedassumedstrains.hh:189
auto numberOfInternalVariables() const
Gets the number of EAS parameters based on the current EAS type.
Definition: enhancedassumedstrains.hh:108
A PreFE struct for Enhanced Assumed Strains.
Definition: enhancedassumedstrains.hh:35
int numberOfParameters
Definition: enhancedassumedstrains.hh:36
void bind(const GEO &geometry)
Definition: easvariants.hh:95
auto numberOfInternalVariables() const
A helper function to get the number of EAS parameters.
Definition: easvariants.hh:79
bool isDisplacmentBased() const
A helper function to identify if the formulation is purely displacement-based, i.e....
Definition: easvariants.hh:88
void setEASType(int numberOfInternalVariables)
Definition: easvariants.hh:90
Definition: utils/dirichletvalues.hh:32
Concept to check if the underlying strain and stress tag correspond to a total Lagrangian formulation...
Definition: utils/concepts.hh:670
Several concepts.