diff --git a/CHANGELOG.md b/CHANGELOG.md index 9337026e8..1664a56ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -84,6 +84,12 @@ SPDX-License-Identifier: LGPL-3.0-or-later ([#337](https://github.com/ikarus-project/ikarus/pull/337)) - `Observers` and `Observables` are replaced with `Broadcasters` and `Listeners`. Existing loggers work almost the same. A noteworthy difference is that, the Broadcaster (e.g. a nonlinear solver) has to be registered to a Listener (e.g. a logger) with `logger.subscribeTo(solver)` ([#349](https://github.com/ikarus-project/ikarus/pull/349)) +- Refactor EAS to handle NonLinearElastic ([#325](https://github.com/ikarus-project/ikarus/pull/325)) + - This also includes a new interface method in the `Mixin` called `updateState` with the respective `impl()` function. + - For EAS, `updateStateImpl()` is used to update the internal variable `alpha_` in a nonlinear analysis. + - Missing functions like `getStress` and `materialTangentFunction` are added to `LinearElastic` and `NonLinearElastic`, respectively. + - `EnhancedAssumedStrains` class now takes a struct denoting the enhanced strain type as a template argument, which implements the + enhanced strain value, its first and second derivatives w.r.t the displacements and the internal variable `alpha_`. ## Release v0.4 (Ganymede) diff --git a/docs/literature.bib b/docs/literature.bib index 982ab13ba..1bb1dbb49 100644 --- a/docs/literature.bib +++ b/docs/literature.bib @@ -107,6 +107,17 @@ @incollection{wunderlich_strategies_1981 pages = {63--89}, } +@article{bischoffShearDeformableShell1997b, + title = {{Shear deformable shell elements for large strains and rotations}}, + author = {Bischoff, M. and Ramm, E.}, + year = {1997}, + journal = {International Journal for Numerical Methods in Engineering}, + volume = {40}, + number = {23}, + pages = {4427-4449}, + doi = {10.1002/(SICI)1097-0207(19971215)40:23<4427::AID-NME268>3.0.CO;2-9}, +} + @article{riks_application_1972, title = {The {Application} of {Newton}’s {Method} to the {Problem} of {Elastic} {Stability}}, volume = {39}, @@ -210,6 +221,14 @@ @book{bonet2008nonlinear doi = {https://doi.org/10.1017/CBO9780511755446} } +@phdthesis{bieberLockingHourglassingNonlinear2024, + title = {Locking and Hourglassing in Nonlinear Finite Element Technology}, + author = {Bieber, Simon}, + year = {2024}, + address = {Stuttgart}, + langid = {english}, + school = {Institut f{\"u}r Baustatik und Baudynamik, Universit{\"a}t Stuttgart} +} @book{trustregion, author = {Conn, Andrew R. and Gould, Nicholas I. M. and Toint, Philippe L.}, diff --git a/ikarus/finiteelements/ferequirements.hh b/ikarus/finiteelements/ferequirements.hh index b314eccf2..edb5f97d1 100644 --- a/ikarus/finiteelements/ferequirements.hh +++ b/ikarus/finiteelements/ferequirements.hh @@ -204,7 +204,7 @@ auto scalarAffordance(VectorAffordance affordanceV) { namespace AffordanceCollections { inline constexpr AffordanceCollection elastoStatics(ScalarAffordance::mechanicalPotentialEnergy, VectorAffordance::forces, MatrixAffordance::stiffness); -} +} // namespace AffordanceCollections /** * \class FERequirements diff --git a/ikarus/finiteelements/mechanics/CMakeLists.txt b/ikarus/finiteelements/mechanics/CMakeLists.txt index 68c915320..d13ba1faf 100644 --- a/ikarus/finiteelements/mechanics/CMakeLists.txt +++ b/ikarus/finiteelements/mechanics/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers mueller@ibb.uni-stuttgart.de # SPDX-License-Identifier: LGPL-3.0-or-later -add_subdirectory(eas) +add_subdirectory(strainenhancements) add_subdirectory(loads) add_subdirectory(materials) # install headers @@ -12,7 +12,6 @@ install( kirchhoffloveshell.hh membranestrains.hh loads.hh - easvariants.hh truss.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ikarus/finiteelements/mechanics ) diff --git a/ikarus/finiteelements/mechanics/eas/eas2d.hh b/ikarus/finiteelements/mechanics/eas/eas2d.hh deleted file mode 100644 index 54cf1bf29..000000000 --- a/ikarus/finiteelements/mechanics/eas/eas2d.hh +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers mueller@ibb.uni-stuttgart.de -// SPDX-License-Identifier: LGPL-3.0-or-later - -/** - * \file eas2d.hh - * \brief Definition of the types of EAS formulations for 2D elements. - * \ingroup eas - */ - -#pragma once - -#include - -namespace Ikarus::EAS { - -/** - * \brief Dummy struct for displacement-based EAS elements, i.e. 0 enhanced modes - */ -template -struct E0 -{ - static constexpr int strainSize = GEO::mydimension * (GEO::mydimension + 1) / 2; - static constexpr int enhancedStrainSize = 0; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - E0() = default; - explicit E0(const GEO& /*geometry*/) {} - - // returns an Eigen zero expression for optimization purposes - static auto calcM(const Dune::FieldVector& /*quadPos*/) { return MType::Zero(); } -}; - -/** - * \brief Q1E4 structure for EAS with linear strains and 4 enhanced modes. - * - * \details The Q1E4 structure represents an implementation of EAS for a - * specific case where linear strains are considered, and the method includes - * enhancement with 4 additional modes to improve the accuracy of finite element solutions. - * - * \tparam GEO The geometry type. - */ -template -struct Q1E4 -{ - static constexpr int strainSize = 3; - static constexpr int enhancedStrainSize = 4; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - Q1E4() = default; - explicit Q1E4(const GEO& geometry) - : geometry_{std::make_optional(geometry)}, - T0InverseTransformed_{calcTransformationMatrix2D(geometry)} {} - - auto calcM(const Dune::FieldVector& quadPos) const { - MType M; - M.setZero(strainSize, enhancedStrainSize); - const double xi = quadPos[0]; - const double eta = quadPos[1]; - M(0, 0) = 2 * xi - 1.0; - M(1, 1) = 2 * eta - 1.0; - M(2, 2) = 2 * xi - 1.0; - M(2, 3) = 2 * eta - 1.0; - const double detJ = geometry_->integrationElement(quadPos); - M = T0InverseTransformed_ / detJ * M; - return M; - } - -private: - std::optional geometry_; - Eigen::Matrix3d T0InverseTransformed_; -}; - -/** - * \brief Structure representing EAS for Q1 with 5 enhanced strains. - * - * This structure defines the EAS for Q1 elements with 5 enhanced strains. - * - * \tparam GEO The geometry type. - */ -template -struct Q1E5 -{ - static constexpr int strainSize = 3; - static constexpr int enhancedStrainSize = 5; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - Q1E5() = default; - explicit Q1E5(const GEO& geometry) - : geometry_{std::make_optional(geometry)}, - T0InverseTransformed_{calcTransformationMatrix2D(geometry)} {} - - auto calcM(const Dune::FieldVector& quadPos) const { - MType M; - M.setZero(); - const double xi = quadPos[0]; - const double eta = quadPos[1]; - M(0, 0) = 2 * xi - 1.0; - M(1, 1) = 2 * eta - 1.0; - M(2, 2) = 2 * xi - 1.0; - M(2, 3) = 2 * eta - 1.0; - M(2, 4) = (2 * xi - 1.0) * (2 * eta - 1.0); - const double detJ = geometry_->integrationElement(quadPos); - M = T0InverseTransformed_ / detJ * M; - return M; - } - -private: - std::optional geometry_; - Eigen::Matrix3d T0InverseTransformed_; -}; - -/** - * \brief Structure representing EAS for Q1 with 7 enhanced strains. - * - * This structure defines the EAS for Q1 elements with 7 enhanced strains. - * - * \tparam GEO The geometry type. - */ -template -struct Q1E7 -{ - static constexpr int strainSize = 3; - static constexpr int enhancedStrainSize = 7; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - Q1E7() = default; - explicit Q1E7(const GEO& geometry) - : geometry_{std::make_optional(geometry)}, - T0InverseTransformed_{calcTransformationMatrix2D(geometry)} {} - - auto calcM(const Dune::FieldVector& quadPos) const { - MType M; - M.setZero(); - const double xi = quadPos[0]; - const double eta = quadPos[1]; - M(0, 0) = 2 * xi - 1.0; - M(1, 1) = 2 * eta - 1.0; - M(2, 2) = 2 * xi - 1.0; - M(2, 3) = 2 * eta - 1.0; - M(0, 4) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(1, 5) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(2, 6) = (2 * xi - 1.0) * (2 * eta - 1.0); - const double detJ = geometry_->integrationElement(quadPos); - M = T0InverseTransformed_ / detJ * M; - return M; - } - -private: - std::optional geometry_; - Eigen::Matrix3d T0InverseTransformed_; -}; - -} // namespace Ikarus::EAS diff --git a/ikarus/finiteelements/mechanics/eas/eas3d.hh b/ikarus/finiteelements/mechanics/eas/eas3d.hh deleted file mode 100644 index 62440c13d..000000000 --- a/ikarus/finiteelements/mechanics/eas/eas3d.hh +++ /dev/null @@ -1,120 +0,0 @@ -// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers mueller@ibb.uni-stuttgart.de -// SPDX-License-Identifier: LGPL-3.0-or-later - -/** - * \file eas3d.hh - * \brief Definition of the types of EAS formulations for 3D elements. - * \ingroup mechanics - */ - -#pragma once - -#include - -namespace Ikarus::EAS { - -/** - * \brief Structure representing EAS for H1 with 9 enhanced strains. - * - * This structure defines the EAS for H1 elements with 9 enhanced strains. - * - * \tparam GEO The geometry type. - */ -template -struct H1E9 -{ - static constexpr int strainSize = 6; - static constexpr int enhancedStrainSize = 9; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - H1E9() = default; - explicit H1E9(const GEO& geometry) - : geometry_{std::make_optional(geometry)}, - T0InverseTransformed_{calcTransformationMatrix3D(geometry)} {} - - auto calcM(const Dune::FieldVector& quadPos) const { - MType M; - M.setZero(); - const double xi = quadPos[0]; - const double eta = quadPos[1]; - const double zeta = quadPos[2]; - M(0, 0) = 2 * xi - 1.0; - M(1, 1) = 2 * eta - 1.0; - M(2, 2) = 2 * zeta - 1.0; - M(3, 3) = 2 * xi - 1.0; - M(3, 4) = 2 * eta - 1.0; - M(4, 5) = 2 * xi - 1.0; - M(4, 6) = 2 * zeta - 1.0; - M(5, 7) = 2 * eta - 1.0; - M(5, 8) = 2 * zeta - 1.0; - const double detJ = geometry_->integrationElement(quadPos); - M = T0InverseTransformed_ / detJ * M; - return M; - } - -private: - std::optional geometry_; - Eigen::Matrix T0InverseTransformed_; -}; - -/** - * \brief Structure representing EAS for H1 with 21 enhanced strains. - * - * This structure defines the EAS for H1 elements with 21 enhanced strains. - * - * \tparam GEO The geometry type. - */ -template -struct H1E21 -{ - static constexpr int strainSize = 6; - static constexpr int enhancedStrainSize = 21; - using MType = Eigen::Matrix; - using DType = Eigen::Matrix; - - H1E21() = default; - explicit H1E21(const GEO& geometry) - : geometry_{std::make_optional(geometry)}, - T0InverseTransformed{calcTransformationMatrix3D(geometry)} {} - - auto calcM(const Dune::FieldVector& quadPos) const { - MType M; - M.setZero(); - const double xi = quadPos[0]; - const double eta = quadPos[1]; - const double zeta = quadPos[2]; - M(0, 0) = 2 * xi - 1.0; - M(1, 1) = 2 * eta - 1.0; - M(2, 2) = 2 * zeta - 1.0; - M(3, 3) = 2 * xi - 1.0; - M(3, 4) = 2 * eta - 1.0; - M(4, 5) = 2 * xi - 1.0; - M(4, 6) = 2 * zeta - 1.0; - M(5, 7) = 2 * eta - 1.0; - M(5, 8) = 2 * zeta - 1.0; - - M(3, 9) = (2 * xi - 1.0) * (2 * zeta - 1.0); - M(3, 10) = (2 * eta - 1.0) * (2 * zeta - 1.0); - M(4, 11) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(4, 12) = (2 * eta - 1.0) * (2 * zeta - 1.0); - M(5, 13) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(5, 14) = (2 * xi - 1.0) * (2 * zeta - 1.0); - - M(0, 15) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(0, 16) = (2 * xi - 1.0) * (2 * zeta - 1.0); - M(1, 17) = (2 * xi - 1.0) * (2 * eta - 1.0); - M(1, 18) = (2 * eta - 1.0) * (2 * zeta - 1.0); - M(2, 19) = (2 * xi - 1.0) * (2 * zeta - 1.0); - M(2, 20) = (2 * eta - 1.0) * (2 * zeta - 1.0); - - const double detJ = geometry_->integrationElement(quadPos); - M = T0InverseTransformed / detJ * M; - return M; - } - -private: - std::optional geometry_; - Eigen::Matrix T0InverseTransformed; -}; -} // namespace Ikarus::EAS diff --git a/ikarus/finiteelements/mechanics/easvariants.hh b/ikarus/finiteelements/mechanics/easvariants.hh deleted file mode 100644 index 92e340f0a..000000000 --- a/ikarus/finiteelements/mechanics/easvariants.hh +++ /dev/null @@ -1,119 +0,0 @@ -// SPDX-FileCopyrightText: 2021-2025 The Ikarus Developers mueller@ibb.uni-stuttgart.de -// SPDX-License-Identifier: LGPL-3.0-or-later - -/** - * \file easvariants.hh - * \brief Definition of the EAS variants. - * \ingroup mechanics - */ - -#pragma once - -#include -#include -#include - -namespace Ikarus::EAS { -namespace Impl { - /** - * \brief EASVariants structure holding variants of different Enhanced Assumed Strains (EAS). - * - * \details EASVariants holds the different variants of EAS formulations for - * both 2D and 3D elements. - * - * \tparam GEO The geometry type. - */ - template - struct Variants - { - static constexpr int worldDim = GEO::coorddimension; - static_assert((worldDim == 2) or (worldDim == 3), "EAS variants are only available 2D and 3D elements."); - - /** \brief Variant type holding different EAS formulations for 2D elements. */ - using EAS2D = std::variant, Q1E4, Q1E5, Q1E7>; - - /** \brief Variant type holding different EAS formulations for 3D elements. */ - using EAS3D = std::variant, H1E9, H1E21>; - - /** \brief Type of the EAS variant depending on the grid dimension. */ - using type = std::conditional_t; - }; - - /** - * \brief Wrapper around the EAS variant, contains helper functions - * \tparam Geometry the Geometry type of the udderlying grid element - */ - template - struct EASVariant - { - using Variant = Impl::Variants::type; - - /** - * \brief Executes a function F on the variant, if `enhancedStrainSize` is not zero - * \tparam F the Type of the function F - * \param f the function, which takes the eas element as an argument - */ - template - void operator()(F&& f) const { - std::visit( - [&](const EAST& easFunction) { - if constexpr (EAST::enhancedStrainSize != 0) - f(easFunction); - }, - var_); - } - - auto numberOfEASParameters() const { - return std::visit([](const EAST&) -> int { return EAST::enhancedStrainSize; }, var_); - } - bool isDisplacmentBased() const { return numberOfEASParameters() == 0; } - void setEASType(int numberOfEASParameters) { - numberOfEASParameters_ = numberOfEASParameters; - if (geometry_) - createEASType(); - } - void bind(const Geometry& geometry) { - geometry_ = std::make_optional(geometry); - createEASType(); - } - - private: - void createEASType() { - if (numberOfEASParameters_ == 0) { - var_ = E0(geometry_.value()); - return; - } - - if constexpr (Geometry::mydimension == 2) { - switch (numberOfEASParameters_) { - case 4: - var_ = Q1E4(geometry_.value()); - break; - case 5: - var_ = Q1E5(geometry_.value()); - break; - case 7: - var_ = Q1E7(geometry_.value()); - break; - default: - DUNE_THROW(Dune::NotImplemented, "The given EAS parameters are not available for the 2D case."); - } - } else if constexpr (Geometry::mydimension == 3) { - switch (numberOfEASParameters_) { - case 9: - var_ = H1E9(geometry_.value()); - break; - case 21: - var_ = H1E21(geometry_.value()); - break; - default: - DUNE_THROW(Dune::NotImplemented, "The given EAS parameters are not available for the 3D case."); - } - } - } - std::optional geometry_; - Variant var_; - int numberOfEASParameters_; - }; -} // namespace Impl -} // namespace Ikarus::EAS diff --git a/ikarus/finiteelements/mechanics/enhancedassumedstrains.hh b/ikarus/finiteelements/mechanics/enhancedassumedstrains.hh index 1e69a1ff5..01e01cbe0 100644 --- a/ikarus/finiteelements/mechanics/enhancedassumedstrains.hh +++ b/ikarus/finiteelements/mechanics/enhancedassumedstrains.hh @@ -4,7 +4,7 @@ /** * \file enhancedassumedstrains.hh * \brief Definition of the EAS class. - * \ingroup mechanics + * \ingroup mechanics */ #pragma once @@ -16,24 +16,27 @@ #include #include - #include - #include + #include + #include + #include #include namespace Ikarus { -template +template class EnhancedAssumedStrains; /** * \brief A PreFE struct for Enhanced Assumed Strains. + * \tparam ES The enhanced strain type. */ +template struct EnhancedAssumedStrainsPre { int numberOfParameters{}; template - using Skill = EnhancedAssumedStrains; + using Skill = EnhancedAssumedStrains; }; /** @@ -45,23 +48,42 @@ struct EnhancedAssumedStrainsPre * * \tparam PreFE Type of the pre finite element. * \tparam FE Type of the finite element. + * \tparam ES The enhanced strain type. */ -template +template class EnhancedAssumedStrains + : public std::conditional_t, + ResultTypeBase, + ResultTypeBase> { public: - using Traits = PreFE::Traits; - using Requirement = FERequirements; - using LocalView = typename Traits::LocalView; - using Geometry = typename Traits::Geometry; - using GridView = typename Traits::GridView; - using Pre = EnhancedAssumedStrainsPre; + using Traits = PreFE::Traits; + using Requirement = FERequirements; + using LocalView = typename Traits::LocalView; + using Geometry = typename Traits::Geometry; + using GridView = typename Traits::GridView; + using Pre = EnhancedAssumedStrainsPre; + using EnhancedStrain = ES; + + static constexpr int myDim = Traits::mydim; + + template + using VectorXOptRef = std::optional>>; + + template