NiHu  2.0
inverse_mapping.hpp
Go to the documentation of this file.
1 
6 #ifndef INVERSE_MAPPING_HPP_INCLUDED
7 #define INVERSE_MAPPING_HPP_INCLUDED
8 
9 #include <Eigen/Dense>
10 
11 #include "element.hpp"
12 #include "shapeset.hpp"
13 
14 #include <string>
15 
16 namespace NiHu
17 {
22 template <class Elem>
24 
29 template <class LSet, class Scalar>
30 class inverse_mapping<surface_element<LSet, Scalar> >
31 {
33  typedef typename elem_t::xi_t xi_t;
34  typedef typename elem_t::x_t x_t;
35  typedef typename elem_t::domain_t domain_t;
36  static unsigned const xi_dim = domain_t::dimension;
37  static unsigned const N = xi_dim + 1;
38  typedef Eigen::Matrix<Scalar, N, 1> result_t;
39 
40 public:
44  inverse_mapping(elem_t const &elem, bool constrained_in_elem)
45  : m_elem(elem)
46  , m_constrained_in_elem(constrained_in_elem)
47  {
48  }
49 
55  bool eval(x_t const &x0, double tol, unsigned max_iter)
56  {
57  // tolerance in intrinsic coordinates (only for tria and quad elems)
58  // \todo xi_tol only for N = 3 surface elements
59  double xi_tol = tol / std::sqrt(m_elem.get_normal(domain_t::get_center()).norm());
60 
61  // initial guess
62  m_res.setZero();
63 
64  // Newton Raphson derivative matrix
65  Eigen::Matrix<double, N, N> df;
66 
67  xi_t xi_prev = xi_t::Zero();
68 
69  // Newton Raphson iterations
70  for (m_iter = 0; m_iter < max_iter; ++m_iter)
71  {
72  // intrinsic coordinates within the element
73  auto xi = m_res.topRows(xi_dim);
74  double zeta = m_res(xi_dim);
75 
76  // compute physical coordinates of guess
77  auto y = m_elem.get_x(xi);
78  x_t n = m_elem.get_normal(xi);
79 
80  double jac = n.norm();
81  if (jac == 0.0)
82  throw std::runtime_error("Element " + std::to_string(m_elem.get_id()(0)) + " is overdistorted, and inverse mapping cannot be performed for nearly singular integration.");
83  double sqrtjac = std::sqrt(n.norm());
84 
85  n /= sqrtjac;
86 
87  auto x_guess = y + n * zeta;
88 
89  // check if converged
90  auto f = x_guess - x0;
91  m_error = f.norm();
92  if (m_error < tol)
93  return true;
94 
95  // compute derivatives
96  auto dy = m_elem.get_dx(xi);
97  auto ddy = m_elem.get_ddx(xi);
98 
99 
100  if (N == 3)
101  {
102  auto const &dyxi = dy.col(shape_derivative_index::dXI);
103  auto const &dyeta = dy.col(shape_derivative_index::dETA);
104 
105  auto const &ddyxixi = ddy.col(shape_derivative_index::dXIXI);
106  auto const &ddyxieta = ddy.col(shape_derivative_index::dXIETA);
107  auto const &ddyetaeta = ddy.col(shape_derivative_index::dETAETA);
108 
109  x_t dnxi = (ddyxixi.cross(dyeta) + dyxi.cross(ddyxieta)) / sqrtjac;
110  x_t dneta = (ddyxieta.cross(dyeta) + dyxi.cross(ddyetaeta)) / sqrtjac;
111 
112  df.col(0) = dyxi + dnxi * zeta;
113  df.col(1) = dyeta + dneta * zeta;
114  df.col(2) = n;
115  }
116  else
117  throw std::logic_error("Inverse mapping is unimplemented for this element type");
118 
119  m_res = m_res - df.colPivHouseholderQr().solve(f);
120 
121  if (m_constrained_in_elem)
122  {
123  m_res.topRows(xi_dim) = domain_t::constrain_inside(m_res.topRows(xi_dim));
124  xi_t delta = m_res.topRows(xi_dim) - xi_prev;
125  if (delta.norm() < xi_tol)
126  return true;
127  xi_prev = m_res.topRows(xi_dim);
128  }
129  }
130 
131  return false;
132  }
133 
135  result_t const &get_result() const
136  {
137  return m_res;
138  }
139 
141  unsigned get_iter() const
142  {
143  return m_iter;
144  }
145 
147  double get_error() const
148  {
149  return m_error;
150  }
151 
152 private:
153  elem_t m_elem;
154  bool m_constrained_in_elem;
155  result_t m_res;
156  unsigned m_iter;
157  double m_error;
158 };
159 
160 } // end of namespace NiHu
161 
162 #endif // INVERSE_MAPPING_HPP_INCLUDED
NiHu::volume_element
class describing a volume element that has no normal vector
Definition: element.hpp:455
NiHu::inverse_mapping< surface_element< LSet, Scalar > >::get_result
const result_t & get_result() const
get the result of inverse mapping
Definition: inverse_mapping.hpp:135
NiHu::shape_derivative_index::dXIXI
@ dXIXI
index of xi_xi in 2nd derivative matrix
Definition: shapeset.hpp:51
NiHu::surface_element< LSet, Scalar >::x_t
element_traits::location_value_type< Derived, 0 >::type x_t
type of the element's physical location variable
Definition: element.hpp:220
NiHu::inverse_mapping< surface_element< LSet, Scalar > >::eval
bool eval(x_t const &x0, double tol, unsigned max_iter)
compute inverse mapping
Definition: inverse_mapping.hpp:55
NiHu::shape_derivative_index::dETAETA
@ dETAETA
index of eta_eta in 2nd derivative matrix
Definition: shapeset.hpp:54
NiHu::inverse_mapping< surface_element< LSet, Scalar > >::inverse_mapping
inverse_mapping(elem_t const &elem, bool constrained_in_elem)
constructor
Definition: inverse_mapping.hpp:44
NiHu::inverse_mapping< surface_element< LSet, Scalar > >::get_iter
unsigned get_iter() const
get the number of iterations
Definition: inverse_mapping.hpp:141
NiHu::surface_element< LSet, Scalar >::domain_t
typename base_t::domain_t domain_t
the domain type
Definition: element.hpp:569
NiHu::surface_element< LSet, Scalar >::xi_t
domain_t::xi_t xi_t
type of the shape functions' independent variable
Definition: element.hpp:210
NiHu::surface_element
class describing a surface element that provides a normal vector
Definition: element.hpp:451
element.hpp
Declaration of element classes.
NiHu::shape_derivative_index::dXI
@ dXI
index of xi in 1st derivative matrix
Definition: shapeset.hpp:49
NiHu::shape_derivative_index::dXIETA
@ dXIETA
index of xi_eta in 2nd derivative matrix
Definition: shapeset.hpp:52
NiHu::shape_derivative_index::dETA
@ dETA
index of eta in 1st derivative matrix
Definition: shapeset.hpp:50
shapeset.hpp
Definition of shape function sets.
NiHu::inverse_mapping
mapping from physical to intrinsic coordinates
Definition: inverse_mapping.hpp:23
NiHu::inverse_mapping< surface_element< LSet, Scalar > >::get_error
double get_error() const
get the error (absolute in physical coordinates)
Definition: inverse_mapping.hpp:147