Loading...
Searching...
No Matches
local_basis_trafo_normal_tangential.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "terra/dense/mat.hpp"
5#include "terra/dense/vec.hpp"
8
10
11/// \brief Constructs a robust orthonormal transformation matrix
12/// from Cartesian to (normal–tangential–tangential) coordinates.
13///
14/// Given a surface normal \p n, this function returns the 3×3 matrix
15/// \f$ R \f$ whose rows form a right-handed orthonormal basis
16/// \f$ \{ \hat{n}, \mathbf{t}_1, \mathbf{t}_2 \} \f$ such that:
17/// \f[
18/// \mathbf{v}_{\text{local}} = R \, \mathbf{v}_{\text{cartesian}},
19/// \qquad
20/// \mathbf{v}_{\text{cartesian}} = R^{\mathsf{T}} \, \mathbf{v}_{\text{local}} .
21/// \f]
22///
23/// The basis vectors are constructed as:
24/// - \f$ \hat{n} = \frac{\mathbf{n}}{||\mathbf{n}||} \f$
25/// - \f$ \mathbf{t}_1 = \mathrm{normalize}(\mathbf{r} \times \hat{n}) \f$,
26/// where \f$ \mathbf{r} \f$ is the coordinate axis least aligned with \f$ \hat{n} \f$
27/// - \f$ \mathbf{t}_2 = \hat{n} \times \mathbf{t}_1 \f$
28///
29/// This ensures numerical stability even when \f$ \hat{n} \f$ is nearly axis-aligned.
30///
31/// \tparam ScalarType Floating-point scalar type (e.g. float, double).
32/// \param n_input Surface normal vector at the point of interest (not required to be unit length).
33/// \return 3×3 transformation matrix \f$ R \f$ with rows \f$ [\,\hat{n}^\mathrm{T},\, \mathbf{t}_1^\mathrm{T},\, \mathbf{t}_2^\mathrm{T}\,] \f$.
34template < std::floating_point ScalarType >
35KOKKOS_INLINE_FUNCTION dense::Mat< ScalarType, 3, 3 >
37{
38 using Vec3 = dense::Vec< ScalarType, 3 >;
40
41 // 1. normalize normal
42 const Vec3 n = n_input.normalized();
43 const ScalarType nx = Kokkos::fabs( n( 0 ) );
44 const ScalarType ny = Kokkos::fabs( n( 1 ) );
45 const ScalarType nz = Kokkos::fabs( n( 2 ) );
46
47 // 2. choose reference axis least aligned with n
48 Vec3 ref;
49 if ( nx <= ny && nx <= nz )
50 {
51 ref = { ScalarType( 1 ), ScalarType( 0 ), ScalarType( 0 ) };
52 }
53 else if ( ny <= nx && ny <= nz )
54 {
55 ref = { ScalarType( 0 ), ScalarType( 1 ), ScalarType( 0 ) };
56 }
57 else
58 {
59 ref = { ScalarType( 0 ), ScalarType( 0 ), ScalarType( 1 ) };
60 }
61
62 // 3. construct tangents
63 Vec3 t1 = ref.cross( n ).normalized();
64 const ScalarType eps = std::is_same_v< ScalarType, double > ? 1e-15 : 1e-6;
65 if ( t1.norm() < eps )
66 {
67 t1 = Vec3{ n( 1 ), -n( 0 ), ScalarType( 0 ) }.normalized();
68 }
69
70 const Vec3 t2 = n.cross( t1 ).normalized();
71
72 // 4. assemble transformation matrix (rows = n, t1, t2)
73 Mat3 R = Mat3::from_row_vecs( n, t1, t2 );
74
75 return R;
76}
77
78/// \brief Constructs the inverse transformation matrix from (normal–tangential–tangential) to Cartesian coordinates.
79///
80/// This function returns the transpose of the orthonormal transformation matrix
81/// \f$ R \f$ produced by \ref trafo_mat_cartesian_to_normal_tangential, since
82/// for an orthonormal basis \f$ R^{-1} = R^{\mathsf{T}} \f$.
83///
84/// Hence, for any vector \f$ \mathbf{v} \f$:
85/// \f[
86/// \mathbf{v}_{\text{local}} = R \, \mathbf{v}_{\text{cartesian}}, \qquad
87/// \mathbf{v}_{\text{cartesian}} = R^{\mathsf{T}} \, \mathbf{v}_{\text{local}} .
88/// \f]
89///
90/// \tparam ScalarType Floating-point scalar type (e.g. float, double).
91/// \param n_input Surface normal vector at the point of interest (not required to be unit length).
92/// \return The 3×3 inverse transformation matrix \f$ R^{\mathsf{T}} \f$
93/// that maps local (n, t₁, t₂) coordinates back to Cartesian space.
94template < std::floating_point ScalarType >
95KOKKOS_INLINE_FUNCTION dense::Mat< ScalarType, 3, 3 >
97{
98 return trafo_mat_cartesian_to_normal_tangential< ScalarType >( n_input ).transposed();
99}
100
101template < std::floating_point ScalarType, std::floating_point ScalarTypeGrid, util::FlagLike FlagType >
103 VectorQ1Vec< ScalarType, 3 >& vec_cartesian,
106 const FlagType& flag )
107{
108 auto data = vec_cartesian.grid_data();
109 auto mask = vec_cartesian.mask_data();
110
111 Kokkos::parallel_for(
112 "cartesian_to_normal_tangential_in_place",
113 Kokkos::MDRangePolicy(
114 { 0, 0, 0, 0 }, { data.extent( 0 ), data.extent( 1 ), data.extent( 2 ), data.extent( 3 ) } ),
115 KOKKOS_LAMBDA( int local_subdomain, int i, int j, int k ) {
116 if ( !util::has_flag( mask_data( local_subdomain, i, j, k ), flag ) )
117 {
118 return;
119 }
120
121 dense::Vec< ScalarType, 3 > vec_local_cart{};
122 for ( int d = 0; d < 3; ++d )
123 {
124 vec_local_cart( d ) = data( local_subdomain, i, j, k, d );
125 }
126
128 //int sign = flag == grid::shell::ShellBoundaryFlag::CMB ? -1 : 1;
129 for ( int d = 0; d < 3; ++d )
130 {
131 normal( d ) = coords_shell( local_subdomain, i, j, d );
132 }
133
134 const auto R = trafo_mat_cartesian_to_normal_tangential( normal );
135 const auto vec_local_normal_tangential = R * vec_local_cart;
136
137 for ( int d = 0; d < 3; ++d )
138 {
139 data( local_subdomain, i, j, k, d ) = vec_local_normal_tangential( d );
140 }
141 } );
142 Kokkos::fence();
143}
144
145template < std::floating_point ScalarType, std::floating_point ScalarTypeGrid, util::FlagLike FlagType >
147 VectorQ1Vec< ScalarType, 3 >& vec_normal_tangential,
150 const FlagType& flag )
151{
152 auto data = vec_normal_tangential.grid_data();
153 auto mask = vec_normal_tangential.mask_data();
154
155 Kokkos::parallel_for(
156 "cartesian_to_normal_tangential_in_place",
157 Kokkos::MDRangePolicy(
158 { 0, 0, 0, 0 }, { data.extent( 0 ), data.extent( 1 ), data.extent( 2 ), data.extent( 3 ) } ),
159 KOKKOS_LAMBDA( int local_subdomain, int i, int j, int k ) {
160 if ( !util::has_flag( mask_data( local_subdomain, i, j, k ), flag ) )
161 {
162 return;
163 }
164
165 dense::Vec< ScalarType, 3 > vec_local_normal_tangential{};
166 for ( int d = 0; d < 3; ++d )
167 {
168 vec_local_normal_tangential( d ) = data( local_subdomain, i, j, k, d );
169 }
170
172 for ( int d = 0; d < 3; ++d )
173 {
174 normal( d ) = coords_shell( local_subdomain, i, j, d );
175 }
176
177 const auto Rt = trafo_mat_normal_tangential_to_cartesian_trafo( normal );
178 const auto vec_local_cart = Rt * vec_local_normal_tangential;
179
180 for ( int d = 0; d < 3; ++d )
181 {
182 data( local_subdomain, i, j, k, d ) = vec_local_cart( d );
183 }
184 } );
185 Kokkos::fence();
186}
187
188} // namespace terra::linalg::trafo
const grid::Grid4DDataScalar< grid::NodeOwnershipFlag > & mask_data() const
Get const reference to mask data.
Definition vector_q1.hpp:285
const grid::Grid4DDataVec< ScalarType, VecDim > & grid_data() const
Get const reference to grid data.
Definition vector_q1.hpp:280
Kokkos::View< ScalarType ***[VecDim], Layout > Grid3DDataVec
Definition grid_types.hpp:40
Kokkos::View< ScalarType ****, Layout > Grid4DDataScalar
Definition grid_types.hpp:25
Definition local_basis_trafo_normal_tangential.hpp:9
void cartesian_to_normal_tangential_in_place(VectorQ1Vec< ScalarType, 3 > &vec_cartesian, const grid::Grid3DDataVec< ScalarTypeGrid, 3 > &coords_shell, const grid::Grid4DDataScalar< FlagType > mask_data, const FlagType &flag)
Definition local_basis_trafo_normal_tangential.hpp:102
dense::Mat< ScalarType, 3, 3 > trafo_mat_normal_tangential_to_cartesian_trafo(const dense::Vec< ScalarType, 3 > &n_input)
Constructs the inverse transformation matrix from (normal–tangential–tangential) to Cartesian coordin...
Definition local_basis_trafo_normal_tangential.hpp:96
void normal_tangential_to_cartesian_in_place(VectorQ1Vec< ScalarType, 3 > &vec_normal_tangential, const grid::Grid3DDataVec< ScalarTypeGrid, 3 > &coords_shell, const grid::Grid4DDataScalar< FlagType > mask_data, const FlagType &flag)
Definition local_basis_trafo_normal_tangential.hpp:146
dense::Mat< ScalarType, 3, 3 > trafo_mat_cartesian_to_normal_tangential(const dense::Vec< ScalarType, 3 > &n_input)
Constructs a robust orthonormal transformation matrix from Cartesian to (normal–tangential–tangential...
Definition local_basis_trafo_normal_tangential.hpp:36
constexpr bool has_flag(E mask_value, E flag) noexcept
Checks if a bitmask value contains a specific flag.
Definition bit_masking.hpp:43
Definition mat.hpp:10
constexpr Mat< T, Cols, Rows > transposed() const
Definition mat.hpp:187
Vec normalized() const
Return a normalized copy of the vector.
Definition vec.hpp:102