version 0.3.7
finiteelements/mechanics/linearelastic.hh
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2021-2024 The Ikarus Developers mueller@ibb.uni-stuttgart.de
2// SPDX-License-Identifier: LGPL-3.0-or-later
3
10#pragma once
11
12#if HAVE_DUNE_LOCALFEFUNCTIONS
13
14# include <iosfwd>
15# include <optional>
16# include <type_traits>
17
18# include <dune/fufem/boundarypatch.hh>
19# include <dune/geometry/quadraturerules.hh>
20# include <dune/localfefunctions/expressions/linearStrainsExpr.hh>
21# include <dune/localfefunctions/impl/standardLocalFunction.hh>
22# include <dune/localfefunctions/manifolds/realTuple.hh>
23
31
32namespace Ikarus {
33
43 template <typename Basis_, typename FERequirements_ = FERequirements<>, bool useEigenRef = false>
44 class LinearElastic : public PowerBasisFE<typename Basis_::FlatBasis> {
45 public:
46 using Basis = Basis_;
47 using FlatBasis = typename Basis::FlatBasis;
48 using BaseDisp = PowerBasisFE<FlatBasis>; // Handles globalIndices function
49 using FERequirementType = FERequirements_;
51 using LocalView = typename FlatBasis::LocalView;
52 using Element = typename LocalView::Element;
54 using Geometry = typename Element::Geometry;
55 using GridView = typename FlatBasis::GridView;
56 static constexpr int myDim = Traits::mydim;
57 static constexpr int worldDim = Traits::worlddim;
58 using LocalBasisType = decltype(std::declval<LocalView>().tree().child(0).finiteElement().localBasis());
59
73 template <typename VolumeLoad = utils::LoadDefault, typename NeumannBoundaryLoad = utils::LoadDefault>
74 LinearElastic(const Basis& globalBasis, const typename LocalView::Element& element, double emod, double nu,
75 VolumeLoad p_volumeLoad = {}, const BoundaryPatch<GridView>* p_neumannBoundary = nullptr,
76 NeumannBoundaryLoad p_neumannBoundaryLoad = {})
77 : BaseDisp(globalBasis.flat(), element), neumannBoundary{p_neumannBoundary}, emod_{emod}, nu_{nu} {
78 this->localView().bind(element);
79 auto& first_child = this->localView().tree().child(0);
80 const auto& fe = first_child.finiteElement();
81 geo_ = std::make_shared<const Geometry>(this->localView().element().geometry());
82 numberOfNodes = fe.size();
83 order = 2 * (fe.localBasis().order());
84 localBasis = Dune::CachedLocalBasis(fe.localBasis());
85 if constexpr (requires { this->localView().element().impl().getQuadratureRule(order); })
86 if (this->localView().element().impl().isTrimmed())
87 localBasis.bind(this->localView().element().impl().getQuadratureRule(order), Dune::bindDerivatives(0, 1));
88 else
89 localBasis.bind(Dune::QuadratureRules<double, myDim>::rule(this->localView().element().type(), order),
90 Dune::bindDerivatives(0, 1));
91 else
92 localBasis.bind(Dune::QuadratureRules<double, myDim>::rule(this->localView().element().type(), order),
93 Dune::bindDerivatives(0, 1));
94
95 if constexpr (!std::is_same_v<VolumeLoad, utils::LoadDefault>) volumeLoad = p_volumeLoad;
96 if constexpr (!std::is_same_v<NeumannBoundaryLoad, utils::LoadDefault>)
97 neumannBoundaryLoad = p_neumannBoundaryLoad;
98
99 assert(((not p_neumannBoundary and not neumannBoundaryLoad) or (p_neumannBoundary and neumannBoundaryLoad))
100 && "If you pass a Neumann boundary you should also pass the function for the Neumann load!");
101 }
110 template <typename ScalarType = double>
112 const std::optional<const Eigen::VectorX<ScalarType>>& dx = std::nullopt) const {
113 const auto& d = par.getGlobalSolution(Ikarus::FESolutions::displacement);
114 auto disp = Ikarus::FEHelper::localSolutionBlockVector<FERequirementType>(d, this->localView(), dx);
115 Dune::StandardLocalFunction uFunction(localBasis, disp, geo_);
116 return uFunction;
117 }
126 template <class ScalarType = double>
128 const std::optional<const Eigen::VectorX<ScalarType>>& dx = std::nullopt) const {
129 return Dune::linearStrains(displacementFunction(par, dx));
130 }
131
137 auto materialTangent() const {
138 if constexpr (myDim == 2)
140 else if constexpr (myDim == 3)
142 }
143
150 auto materialTangentFunction([[maybe_unused]] const FERequirementType& par) const {
151 return [&]([[maybe_unused]] auto gp) { return materialTangent(); };
152 }
153
160 inline double calculateScalar(const FERequirementType& par) const { return calculateScalarImpl<double>(par); }
161
168 inline void calculateVector(const FERequirementType& par, typename Traits::template VectorType<> force) const {
169 calculateVectorImpl<double>(par, force);
170 }
171
178 void calculateMatrix(const FERequirementType& par, typename Traits::template MatrixType<> K) const {
179 const auto eps = strainFunction(par);
180 using namespace Dune::DerivativeDirections;
181 using namespace Dune;
182
183 const auto C = materialTangent();
184 for (const auto& [gpIndex, gp] : eps.viewOverIntegrationPoints()) {
185 const double intElement = geo_->integrationElement(gp.position()) * gp.weight();
186 for (size_t i = 0; i < numberOfNodes; ++i) {
187 const auto bopI = eps.evaluateDerivative(gpIndex, wrt(coeff(i)), on(gridElement));
188 for (size_t j = 0; j < numberOfNodes; ++j) {
189 const auto bopJ = eps.evaluateDerivative(gpIndex, wrt(coeff(j)), on(gridElement));
190 K.template block<myDim, myDim>(i * myDim, j * myDim) += bopI.transpose() * C * bopJ * intElement;
191 }
192 }
193 }
194 }
195
204 ResultTypeMap<double>& result) const {
205 using namespace Dune::Indices;
206 using namespace Dune::DerivativeDirections;
207 using namespace Dune;
208
209 const auto eps = strainFunction(req.getFERequirements());
210 const auto C = materialTangent();
211 auto epsVoigt = eps.evaluate(local, on(gridElement));
212
213 auto linearStress = (C * epsVoigt).eval();
214
217 else
218 DUNE_THROW(Dune::NotImplemented, "The requested result type is NOT implemented.");
219 }
220
221 std::shared_ptr<const Geometry> geo_;
222 Dune::CachedLocalBasis<std::remove_cvref_t<LocalBasisType>> localBasis;
223 std::function<Eigen::Vector<double, worldDim>(const Dune::FieldVector<double, worldDim>&, const double&)>
225 std::function<Eigen::Vector<double, worldDim>(const Dune::FieldVector<double, worldDim>&, const double&)>
227 const BoundaryPatch<GridView>* neumannBoundary;
228 double emod_;
229 double nu_;
230 size_t numberOfNodes{0};
231 int order{};
232
233 protected:
234 template <typename ScalarType>
235 auto calculateScalarImpl(const FERequirementType& par, const std::optional<const Eigen::VectorX<ScalarType>>& dx
236 = std::nullopt) const -> ScalarType {
237 const auto uFunction = displacementFunction(par, dx);
238 const auto eps = strainFunction(par, dx);
239 const auto& lambda = par.getParameter(Ikarus::FEParameter::loadfactor);
240 using namespace Dune::DerivativeDirections;
241 using namespace Dune;
242
243 const auto C = materialTangent();
244
245 ScalarType energy = 0.0;
246 for (const auto& [gpIndex, gp] : eps.viewOverIntegrationPoints()) {
247 const auto EVoigt = eps.evaluate(gpIndex, on(gridElement));
248
249 energy += (0.5 * EVoigt.dot(C * EVoigt)) * geo_->integrationElement(gp.position()) * gp.weight();
250 }
251
252 // External forces volume forces over the domain
253 if (volumeLoad) {
254 for (const auto& [gpIndex, gp] : eps.viewOverIntegrationPoints()) {
255 const auto uVal = uFunction.evaluate(gpIndex);
256 Eigen::Vector<double, Traits::worlddim> fext = volumeLoad(geo_->global(gp.position()), lambda);
257 energy -= uVal.dot(fext) * geo_->integrationElement(gp.position()) * gp.weight();
258 }
259 }
260
261 // line or surface loads, i.e., neumann boundary
262 if (not neumannBoundary and not neumannBoundaryLoad) return energy;
263
264 auto element = this->localView().element();
265 for (auto&& intersection : intersections(neumannBoundary->gridView(), element)) {
266 if (not neumannBoundary->contains(intersection)) continue;
267
268 const auto& quadLine = Dune::QuadratureRules<double, myDim - 1>::rule(intersection.type(), order);
269
270 for (const auto& curQuad : quadLine) {
271 // Local position of the quadrature point
272 const Dune::FieldVector<double, myDim>& quadPos = intersection.geometryInInside().global(curQuad.position());
273
274 const double integrationElement = intersection.geometry().integrationElement(curQuad.position());
275
276 // The value of the local function
277 const auto uVal = uFunction.evaluate(quadPos);
278
279 // Value of the Neumann data at the current position
280 auto neumannValue = neumannBoundaryLoad(intersection.geometry().global(curQuad.position()), lambda);
281
282 energy -= neumannValue.dot(uVal) * curQuad.weight() * integrationElement;
283 }
284 }
285 return energy;
286 }
287
288 template <typename ScalarType>
289 void calculateVectorImpl(const FERequirementType& par, typename Traits::template VectorType<ScalarType> force,
290 const std::optional<const Eigen::VectorX<ScalarType>>& dx = std::nullopt) const {
291 const auto& lambda = par.getParameter(Ikarus::FEParameter::loadfactor);
292 const auto uFunction = displacementFunction(par, dx);
293 const auto eps = strainFunction(par, dx);
294 using namespace Dune::DerivativeDirections;
295 using namespace Dune;
296
297 const auto C = materialTangent();
298
299 // Internal forces
300 for (const auto& [gpIndex, gp] : eps.viewOverIntegrationPoints()) {
301 const double intElement = geo_->integrationElement(gp.position()) * gp.weight();
302 auto stresses = (C * eps.evaluate(gpIndex, on(gridElement))).eval();
303 for (size_t i = 0; i < numberOfNodes; ++i) {
304 const auto bopI = eps.evaluateDerivative(gpIndex, wrt(coeff(i)), on(gridElement));
305 force.template segment<myDim>(myDim * i) += bopI.transpose() * stresses * intElement;
306 }
307 }
308
309 // External forces volume forces over the domain
310 if (volumeLoad) {
311 for (const auto& [gpIndex, gp] : uFunction.viewOverIntegrationPoints()) {
312 Eigen::Vector<double, Traits::worlddim> fext = volumeLoad(geo_->global(gp.position()), lambda);
313 for (size_t i = 0; i < numberOfNodes; ++i) {
314 const auto udCi = uFunction.evaluateDerivative(gpIndex, wrt(coeff(i)));
315 force.template segment<myDim>(myDim * i)
316 -= udCi * fext * geo_->integrationElement(gp.position()) * gp.weight();
317 }
318 }
319 }
320
321 // External forces, boundary forces, i.e., at the Neumann boundary
322 if (not neumannBoundary) return;
323 auto element = this->localView().element();
324 for (auto&& intersection : intersections(neumannBoundary->gridView(), element)) {
325 if (not neumannBoundary->contains(intersection)) continue;
326
327 // Integration rule along the boundary
328 const auto& quadLine = Dune::QuadratureRules<double, myDim - 1>::rule(intersection.type(), order);
329
330 for (const auto& curQuad : quadLine) {
331 const Dune::FieldVector<double, myDim>& quadPos = intersection.geometryInInside().global(curQuad.position());
332
333 const double integrationElement = intersection.geometry().integrationElement(curQuad.position());
334
335 // The value of the local function wrt the i-th coeff
336 for (size_t i = 0; i < numberOfNodes; ++i) {
337 const auto udCi = uFunction.evaluateDerivative(quadPos, wrt(coeff(i)));
338
339 // Value of the Neumann data at the current position
340 auto neumannValue = neumannBoundaryLoad(intersection.geometry().global(curQuad.position()), lambda);
341 force.template segment<myDim>(myDim * i) -= udCi * neumannValue * curQuad.weight() * integrationElement;
342 }
343 }
344 }
345 }
346 };
347} // namespace Ikarus
348
349#else
350# error LinearElastic depends on dune-localfefunctions, which is not included
351#endif
Collection of fallback default functions.
Helper for the autodiff library.
Contains the PowerBasisFE class, which works with a power basis in FlatInterLeaved elements.
Material property functions and conversion utilities.
Definition of the LinearElastic class for finite element mechanics computations.
Header file for material models in Ikarus finite element mechanics.
Definition: simpleassemblers.hh:21
Eigen::Matrix3d planeStressLinearElasticMaterialTangent(double E, double nu)
Computes the plane stress linear elastic material tangent matrix.
Definition: physicshelper.hh:27
Eigen::Matrix< double, 6, 6 > linearElasticMaterialTangent3D(double E, double nu)
Computes the 3D linear elastic material tangent matrix.
Definition: physicshelper.hh:48
Definition: resultevaluators.hh:17
PowerBasisFE class for working with a power basis in FlatInterLeaved elements.
Definition: powerbasisfe.hh:23
const GridElement & gridElement() const
Get the grid element associated with the local view.
Definition: powerbasisfe.hh:78
const LocalView & localView() const
Get the const reference to the local view.
Definition: powerbasisfe.hh:84
Class representing a map of result types to result arrays.
Definition: ferequirements.hh:342
void insertOrAssignResult(ResultType &&resultType, const ResultArray &resultArray)
Insert or assign a result to the map.
Definition: ferequirements.hh:354
Class representing the requirements for obtaining specific results.
Definition: ferequirements.hh:405
const FERequirements & getFERequirements() const
Get the associated finite element requirements.
Definition: ferequirements.hh:535
bool isResultRequested(ResultType &&key) const
Check if a specific result type is requested.
Definition: ferequirements.hh:446
LinearElastic class represents a linear elastic finite element.
Definition: finiteelements/mechanics/linearelastic.hh:44
typename FlatBasis::GridView GridView
Definition: finiteelements/mechanics/linearelastic.hh:55
decltype(std::declval< LocalView >().tree().child(0).finiteElement().localBasis()) LocalBasisType
Definition: finiteelements/mechanics/linearelastic.hh:58
static constexpr int myDim
Definition: finiteelements/mechanics/linearelastic.hh:56
auto materialTangentFunction(const FERequirementType &par) const
Gets the material tangent function for the given FERequirementType.
Definition: finiteelements/mechanics/linearelastic.hh:150
auto calculateScalarImpl(const FERequirementType &par, const std::optional< const Eigen::VectorX< ScalarType > > &dx=std::nullopt) const -> ScalarType
Definition: finiteelements/mechanics/linearelastic.hh:235
FERequirements_ FERequirementType
Definition: finiteelements/mechanics/linearelastic.hh:49
double nu_
Definition: finiteelements/mechanics/linearelastic.hh:229
typename LocalView::Element Element
Definition: finiteelements/mechanics/linearelastic.hh:52
void calculateVector(const FERequirementType &par, typename Traits::template VectorType<> force) const
Calculates the vector force for the given FERequirementType.
Definition: finiteelements/mechanics/linearelastic.hh:168
void calculateVectorImpl(const FERequirementType &par, typename Traits::template VectorType< ScalarType > force, const std::optional< const Eigen::VectorX< ScalarType > > &dx=std::nullopt) const
Definition: finiteelements/mechanics/linearelastic.hh:289
PowerBasisFE< FlatBasis > BaseDisp
Definition: finiteelements/mechanics/linearelastic.hh:48
const BoundaryPatch< GridView > * neumannBoundary
Definition: finiteelements/mechanics/linearelastic.hh:227
void calculateAt(const ResultRequirementsType &req, const Dune::FieldVector< double, Traits::mydim > &local, ResultTypeMap< double > &result) const
Calculates results at a specific local position.
Definition: finiteelements/mechanics/linearelastic.hh:203
Basis_ Basis
Definition: finiteelements/mechanics/linearelastic.hh:46
typename Element::Geometry Geometry
Definition: finiteelements/mechanics/linearelastic.hh:54
static constexpr int worldDim
Definition: finiteelements/mechanics/linearelastic.hh:57
auto displacementFunction(const FERequirementType &par, const std::optional< const Eigen::VectorX< ScalarType > > &dx=std::nullopt) const
Gets the displacement function for the given FERequirementType and optional displacement vector.
Definition: finiteelements/mechanics/linearelastic.hh:111
auto strainFunction(const FERequirementType &par, const std::optional< const Eigen::VectorX< ScalarType > > &dx=std::nullopt) const
Gets the strain function for the given FERequirementType and optional displacement vector.
Definition: finiteelements/mechanics/linearelastic.hh:127
std::function< Eigen::Vector< double, worldDim >(const Dune::FieldVector< double, worldDim > &, const double &)> neumannBoundaryLoad
Definition: finiteelements/mechanics/linearelastic.hh:226
LinearElastic(const Basis &globalBasis, const typename LocalView::Element &element, double emod, double nu, VolumeLoad p_volumeLoad={}, const BoundaryPatch< GridView > *p_neumannBoundary=nullptr, NeumannBoundaryLoad p_neumannBoundaryLoad={})
Constructor for the LinearElastic class.
Definition: finiteelements/mechanics/linearelastic.hh:74
void calculateMatrix(const FERequirementType &par, typename Traits::template MatrixType<> K) const
Calculates the matrix stiffness for the given FERequirementType.
Definition: finiteelements/mechanics/linearelastic.hh:178
int order
Definition: finiteelements/mechanics/linearelastic.hh:231
size_t numberOfNodes
Definition: finiteelements/mechanics/linearelastic.hh:230
Dune::CachedLocalBasis< std::remove_cvref_t< LocalBasisType > > localBasis
Definition: finiteelements/mechanics/linearelastic.hh:222
typename Basis::FlatBasis FlatBasis
Definition: finiteelements/mechanics/linearelastic.hh:47
typename FlatBasis::LocalView LocalView
Definition: finiteelements/mechanics/linearelastic.hh:51
auto materialTangent() const
Gets the material tangent matrix for the linear elastic material.
Definition: finiteelements/mechanics/linearelastic.hh:137
double emod_
Definition: finiteelements/mechanics/linearelastic.hh:228
std::function< Eigen::Vector< double, worldDim >(const Dune::FieldVector< double, worldDim > &, const double &)> volumeLoad
Definition: finiteelements/mechanics/linearelastic.hh:224
std::shared_ptr< const Geometry > geo_
Definition: finiteelements/mechanics/linearelastic.hh:221
double calculateScalar(const FERequirementType &par) const
Calculates the scalar energy for the given FERequirementType.
Definition: finiteelements/mechanics/linearelastic.hh:160
Traits for handling local views.see https://en.wikipedia.org/wiki/Lam%C3%A9_parameters.
Definition: physicshelper.hh:65
static constexpr int worlddim
Dimension of the world space.
Definition: physicshelper.hh:68
static constexpr int mydim
Dimension of the geometry.
Definition: physicshelper.hh:71
Definition: resultevaluators.hh:20
decltype(Dune::Functions::DefaultGlobalBasis(Ikarus::flatPreBasis(std::declval< PreBasis >()))) FlatBasis
The type of the flattened basis.
Definition: utils/basis.hh:36