Caribou
Element.h
1 #pragma once
2 
3 #include <Caribou/config.h>
4 #include <Caribou/traits.h>
5 #include <Caribou/macros.h>
6 #include <Eigen/Dense>
7 #include <vector>
8 
9 #include <iostream>
10 
11 namespace caribou::geometry {
12 
13 template<typename T>
14 struct traits;
15 
21 template<class T, class Enable = void>
22 struct element_has_boundaries : std::false_type {};
23 
24 template< class T>
25 constexpr bool element_has_boundaries_v = element_has_boundaries<T>::value;
26 
27 template<typename Derived, typename ScalarType = FLOATING_POINT_TYPE>
28 struct Element {
29  // Types
30  using Scalar = ScalarType;
31 
32  template <INTEGER_TYPE Dim>
33  using Vector = Eigen::Matrix<Scalar, Dim, 1>;
34 
35  template <INTEGER_TYPE Rows, INTEGER_TYPE Cols, int Options = Eigen::ColMajor>
36  using Matrix = Eigen::Matrix<Scalar, Rows, Cols, Options>;
37 
38  template <INTEGER_TYPE Rows, INTEGER_TYPE Cols, int Options = Eigen::ColMajor>
39  using MatrixI = Eigen::Matrix<Scalar, Rows, Cols, Options>;
40 
41  static constexpr auto CanonicalDimension = traits<Derived>::CanonicalDimension;
42  static constexpr auto Dimension = traits<Derived>::Dimension;
43  static constexpr auto NumberOfNodesAtCompileTime = traits<Derived>::NumberOfNodesAtCompileTime;
44  static constexpr auto NumberOfGaussNodesAtCompileTime = traits<Derived>::NumberOfGaussNodesAtCompileTime;
45  using LocalCoordinates = Vector<CanonicalDimension>;
46  using WorldCoordinates = Vector<Dimension>;
47 
48  struct GaussNode {
49  LocalCoordinates position;
50  Scalar weight;
51  };
52 
53 
54  // Functions
56  [[nodiscard]]
57  inline auto number_of_nodes() const -> UNSIGNED_INTEGER_TYPE {return self().get_number_of_nodes();}
58 
60  [[nodiscard]]
61  inline auto number_of_gauss_nodes() const -> UNSIGNED_INTEGER_TYPE {return self().get_number_of_gauss_nodes();}
62 
64  inline auto node(const UNSIGNED_INTEGER_TYPE & index) const {return self().get_node(index);};
65 
67  inline auto nodes() const {return self().get_nodes();};
68 
70  inline auto gauss_node(const UNSIGNED_INTEGER_TYPE & index) const -> const GaussNode & {return self().gauss_nodes()[index];};
71 
73  inline auto gauss_nodes() const -> const std::vector<GaussNode> & {return self().get_gauss_nodes();};
74 
76  inline auto number_of_boundary_elements() const {
77  if constexpr (element_has_boundaries_v<Derived>) {
78  return self().get_number_of_boundary_elements();
79  } else {
80  return 0;
81  }
82  }
83 
100  inline auto boundary_elements_node_indices() const -> const auto & {
101  static_assert(element_has_boundaries_v<Derived>, "This element type has no boundary elements defined.");
102  return self().get_boundary_elements_nodes();
103  }
104 
118  inline auto boundary_element(const UNSIGNED_INTEGER_TYPE & boundary_id) const {
119  static_assert(element_has_boundaries_v<Derived>, "This element type has no boundary elements defined.");
120  using BoundaryElement = typename traits<Derived>::BoundaryElementType;
121  const auto & node_indices = boundary_elements_node_indices()[boundary_id];
122  Matrix<BoundaryElement::NumberOfNodesAtCompileTime, Dimension> nodes;
123  for (Eigen::Index boundary_node_id = 0; boundary_node_id < nodes.rows(); ++boundary_node_id) {
124  nodes.row(boundary_node_id) = self().node(node_indices[boundary_node_id]);
125  }
126  return BoundaryElement(nodes);
127  }
128 
139  inline auto L(const LocalCoordinates & xi) const -> Vector<NumberOfNodesAtCompileTime> {return self().get_L(xi);};
140 
151  inline auto dL(const LocalCoordinates & xi) const -> Matrix<NumberOfNodesAtCompileTime, CanonicalDimension> {return self().get_dL(xi);};
152 
154  inline auto center() const -> WorldCoordinates {return self().get_center();}
155 
157  inline auto world_coordinates(const LocalCoordinates & coordinates) const -> WorldCoordinates {
158  return WorldCoordinates(self().interpolate(coordinates, self().nodes()));
159  }
160 
169  inline auto local_coordinates(const WorldCoordinates & coordinates) const -> LocalCoordinates {
170  return local_coordinates(coordinates, LocalCoordinates::Constant(0), 1e-5, 5);
171  }
172 
223  inline auto local_coordinates(
224  const WorldCoordinates & coordinates,
225  const LocalCoordinates & starting_point,
226  const FLOATING_POINT_TYPE & residual_tolerance,
227  const UNSIGNED_INTEGER_TYPE & maximum_number_of_iterations) const -> LocalCoordinates {
228 
229  using namespace Eigen;
230 
231  LocalCoordinates xi = starting_point;
232  UNSIGNED_INTEGER_TYPE iteration = 0;
233  FLOATING_POINT_TYPE squared_threshold = residual_tolerance*residual_tolerance;
234 
235  // Initial residual
236  WorldCoordinates residual = coordinates - world_coordinates(xi);
237  FLOATING_POINT_TYPE r_norm_2 = residual.squaredNorm();
238  FLOATING_POINT_TYPE r0_norm_2 = r_norm_2;
239 
240  if (r_norm_2 < squared_threshold) {
241  // The initial guess is good enough
242  return xi;
243  }
244 
245  // Start the iterations
246  do {
247  Matrix<Dimension, CanonicalDimension> J = jacobian(xi);
248 
249  LocalCoordinates dxi;
250  if constexpr (Dimension == CanonicalDimension) {
251  dxi.noalias() = J.inverse() * residual;
252  } else {
253  dxi.noalias() = (J.transpose()*J).inverse() * (J.transpose()*residual);
254  }
255 
256  xi.noalias() = (xi + dxi).eval();
257  residual.noalias() = coordinates - world_coordinates(xi);
258  r_norm_2 = residual.squaredNorm();
259 
260  ++iteration;
261  }
262  while (iteration < maximum_number_of_iterations and r_norm_2 >= r0_norm_2*squared_threshold);
263 
264  return xi;
265  }
266 
272  inline auto contains_local(const LocalCoordinates & xi, const FLOATING_POINT_TYPE & eps = 1e-10) const -> bool {
273  return self().get_contains_local(xi, eps);
274  }
275 
284  template <typename MatrixType>
285  inline auto interpolate (const LocalCoordinates & coordinates,
286  const Eigen::MatrixBase<MatrixType> & values) const {
287  static_assert(Eigen::MatrixBase<MatrixType>::RowsAtCompileTime == NumberOfNodesAtCompileTime,
288  "The matrix containing the values at each nodes must have one node-value per row.");
289  constexpr auto NbCols = Eigen::MatrixBase<MatrixType>::ColsAtCompileTime;
290  using MatrixScalar = typename Eigen::MatrixBase<MatrixType>::Scalar;
291  const auto result = ((values.array().colwise() * self().L(coordinates).array().template cast<typename Eigen::MatrixBase<MatrixType>::Scalar>()).matrix().colwise().sum().transpose()).eval();
292  if constexpr (NbCols == 1) {
293  return static_cast<MatrixScalar>(result[0]);
294  } else {
295  return result.template cast<MatrixScalar>();
296  }
297  }
298 
377  inline auto jacobian (const LocalCoordinates & coordinates) const -> Matrix<Dimension, CanonicalDimension>
378  {
379  const auto shape_derivatives = self().dL(coordinates);
380  return self().nodes().transpose() * shape_derivatives;
381  }
382 private:
383  auto self() -> Derived& { return *static_cast<Derived*>(this); }
384  auto self() const -> const Derived& { return *static_cast<const Derived*>(this); }
385 };
386 
387 
388 template <class T>
389 using element_boundary_type_t = typename traits<T>::BoundaryElementType;
390 
391 template<class T>
392 struct element_has_boundaries<T, CLASS_REQUIRES(
393  caribou::internal::is_detected_v<element_boundary_type_t, T>
394 )> : std::true_type {};
395 
396 
397 } /// namespace caribou::geometry
caribou::geometry::Element::L
auto L(const LocalCoordinates &xi) const -> Vector< NumberOfNodesAtCompileTime >
Get the Lagrange polynomial values evaluated at local coordinates xi w.r.t each element's interpolati...
Definition: Element.h:139
caribou::geometry::Element::number_of_gauss_nodes
auto number_of_gauss_nodes() const -> UNSIGNED_INTEGER_TYPE
Get the number of gauss nodes in the element.
Definition: Element.h:61
caribou::geometry::Element::boundary_elements_node_indices
auto boundary_elements_node_indices() const -> const auto &
Get the list of node indices of the boundary elements.
Definition: Element.h:100
caribou::geometry::Element::world_coordinates
auto world_coordinates(const LocalCoordinates &coordinates) const -> WorldCoordinates
Get the world coordinates of a point from its local coordinates.
Definition: Element.h:157
caribou::geometry::Element
Definition: Element.h:28
caribou::geometry::Element::gauss_node
auto gauss_node(const UNSIGNED_INTEGER_TYPE &index) const -> const GaussNode &
Get the gauss node at given index.
Definition: Element.h:70
caribou::geometry::Element::gauss_nodes
auto gauss_nodes() const -> const std::vector< GaussNode > &
Get the set of gauss nodes.
Definition: Element.h:73
caribou::geometry::Element::dL
auto dL(const LocalCoordinates &xi) const -> Matrix< NumberOfNodesAtCompileTime, CanonicalDimension >
Get the Lagrange polynomial derivatives w.r.t the local frame {dL/du} evaluated at local coordinates ...
Definition: Element.h:151
caribou::geometry::Element::number_of_boundary_elements
auto number_of_boundary_elements() const
Get the number of boundary elements (ex.
Definition: Element.h:76
caribou::geometry::Element::nodes
auto nodes() const
Get the set of nodes.
Definition: Element.h:67
caribou::geometry::traits
Definition: Element.h:14
caribou::geometry::Element::local_coordinates
auto local_coordinates(const WorldCoordinates &coordinates, const LocalCoordinates &starting_point, const FLOATING_POINT_TYPE &residual_tolerance, const UNSIGNED_INTEGER_TYPE &maximum_number_of_iterations) const -> LocalCoordinates
Get the local coordinates of a point from its world coordinates by doing a set of Newton-Raphson iter...
Definition: Element.h:223
caribou::geometry::element_has_boundaries
Test whether or not the Element type T has boundary elements.
Definition: Element.h:22
caribou::geometry::Element::local_coordinates
auto local_coordinates(const WorldCoordinates &coordinates) const -> LocalCoordinates
Get the local coordinates of a point from its world coordinates by doing a set of Newton-Raphson iter...
Definition: Element.h:169
caribou::geometry::Element::node
auto node(const UNSIGNED_INTEGER_TYPE &index) const
Get the Node at given index.
Definition: Element.h:64
caribou::geometry::Element::interpolate
auto interpolate(const LocalCoordinates &coordinates, const Eigen::MatrixBase< MatrixType > &values) const
Interpolate a value at local coordinates from the given interpolation node values.
Definition: Element.h:285
caribou::geometry::Element::boundary_element
auto boundary_element(const UNSIGNED_INTEGER_TYPE &boundary_id) const
Construct and return the given boundary element.
Definition: Element.h:118
caribou::geometry::Element::contains_local
auto contains_local(const LocalCoordinates &xi, const FLOATING_POINT_TYPE &eps=1e-10) const -> bool
Return true if the element contains the point located at the given local coordinates.
Definition: Element.h:272
caribou::geometry::Element::number_of_nodes
auto number_of_nodes() const -> UNSIGNED_INTEGER_TYPE
Get the number of nodes in the element.
Definition: Element.h:57
caribou::geometry::Element::jacobian
auto jacobian(const LocalCoordinates &coordinates) const -> Matrix< Dimension, CanonicalDimension >
Compute the Jacobian matrix of the transformation T(xi)-> x evaluated at local coordinates xi.
Definition: Element.h:377
caribou::geometry::Element::center
auto center() const -> WorldCoordinates
Get the position at the center of the element.
Definition: Element.h:154
caribou::geometry::Element::GaussNode
Definition: Element.h:48