version 0.4.4
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.
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
NonLinearSolverMessages
Enum class defining non-linear solver-related messages.
Definition: broadcastermessages.hh:22
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:694
Several concepts.