Loading...
Searching...
No Matches
geometry_helper.hpp
Go to the documentation of this file.
1
2#pragma once
3
4/// @file geometry_helper.hpp
5/// @brief Shared FV hex cell geometry: face-normal surface integrals, velocity fluxes, cell volume.
6///
7/// Used by both fct_advection.hpp (advection only) and advection_diffusion.hpp (advection + diffusion).
8/// Cell centers must have been initialised via fv::hex::initialize_cell_centers so that ghost layers
9/// hold valid neighbour values — required for the outward-normal sign check.
10
15#include "grid/grid_types.hpp"
16
18
19/// @brief Stateless geometry helper for a single FV hex cell.
20///
21/// Computes:
22/// - `beta[6]` : velocity flux ∫ u·n dS through each of the 6 faces (positive = outward).
23/// - `M_ii` : cell volume.
24/// - `S_f[6]` : area-weighted outward normal vector for each face (∫ n dS).
25///
26/// Neighbour ordering (faces 0..5):
27/// face 0: x-1 face 1: x+1
28/// face 2: y-1 face 3: y+1
29/// face 4: r-1 face 5: r+1
30template < typename ScalarT >
32{
34
35 static constexpr int num_neighbors = 6;
36
37 KOKKOS_INLINE_FUNCTION static constexpr int cell_offset_x( int n )
38 {
39 constexpr int v[num_neighbors] = { -1, 1, 0, 0, 0, 0 };
40 return v[n];
41 }
42 KOKKOS_INLINE_FUNCTION static constexpr int cell_offset_y( int n )
43 {
44 constexpr int v[num_neighbors] = { 0, 0, -1, 1, 0, 0 };
45 return v[n];
46 }
47 KOKKOS_INLINE_FUNCTION static constexpr int cell_offset_r( int n )
48 {
49 constexpr int v[num_neighbors] = { 0, 0, 0, 0, -1, 1 };
50 return v[n];
51 }
52
53 enum class WedgeContribution : int
54 {
55 NONE = 0,
56 TRIANGLE = 1,
57 QUAD = 2
58 };
59 enum class CrossProductType : int
60 {
61 XI_ETA = 0,
62 XI_ZETA = 1,
63 ETA_ZETA = 2
64 };
65
66 KOKKOS_INLINE_FUNCTION
67 static constexpr WedgeContribution contribution( const int hex_direction, const int wedge_id )
68 {
69 if ( wedge_id == 0 )
70 {
71 switch ( hex_direction )
72 {
73 case 0:
75 case 2:
77 case 4:
79 case 5:
81 default:
83 }
84 }
85 else
86 {
87 switch ( hex_direction )
88 {
89 case 1:
91 case 3:
93 case 4:
95 case 5:
97 default:
99 }
100 }
101 }
102
103 KOKKOS_INLINE_FUNCTION
104 static constexpr void map_face(
105 const int hex_direction,
106 const int wedge_id,
107 const double s,
108 const double t,
109 double& xi,
110 double& eta,
111 double& zeta,
112 CrossProductType& cross_product_type )
113 {
114 if ( wedge_id == 0 )
115 {
116 switch ( hex_direction )
117 {
118 case 0:
119 xi = 0;
120 eta = s;
121 zeta = t;
122 cross_product_type = CrossProductType::ETA_ZETA;
123 break;
124 case 2:
125 xi = s;
126 eta = 0;
127 zeta = t;
128 cross_product_type = CrossProductType::XI_ZETA;
129 break;
130 case 4:
131 xi = s;
132 eta = t;
133 zeta = -1.0;
134 cross_product_type = CrossProductType::XI_ETA;
135 break;
136 case 5:
137 xi = s;
138 eta = t;
139 zeta = 1.0;
140 cross_product_type = CrossProductType::XI_ETA;
141 break;
142 default:
143 xi = eta = zeta = 0;
144 cross_product_type = CrossProductType::XI_ETA;
145 break;
146 }
147 }
148 else
149 {
150 switch ( hex_direction )
151 {
152 case 1:
153 xi = 0;
154 eta = s;
155 zeta = t;
156 cross_product_type = CrossProductType::ETA_ZETA;
157 break;
158 case 3:
159 xi = s;
160 eta = 0;
161 zeta = t;
162 cross_product_type = CrossProductType::XI_ZETA;
163 break;
164 case 4:
165 xi = s;
166 eta = t;
167 zeta = -1.0;
168 cross_product_type = CrossProductType::XI_ETA;
169 break;
170 case 5:
171 xi = s;
172 eta = t;
173 zeta = 1.0;
174 cross_product_type = CrossProductType::XI_ETA;
175 break;
176 default:
177 xi = eta = zeta = 0;
178 cross_product_type = CrossProductType::XI_ETA;
179 break;
180 }
181 }
182 }
183
184 /// @brief Compute beta[6], M_ii, and S_f[6] for the cell at (x_cell, y_cell, r_cell).
185 ///
186 /// @param beta [out] Velocity flux ∫ u·n dS per face; positive = flow out of cell.
187 /// @param M_ii [out] Cell volume.
188 /// @param S_f [out] Area-weighted outward normal ∫ n dS per face.
189 /// All three are needed by advection-diffusion; only beta and M_ii by pure advection.
190 KOKKOS_INLINE_FUNCTION
191 static void compute_geometry(
194 const grid::Grid4DDataVec< ScalarT, 3 >& cell_centers,
195 const grid::Grid4DDataVec< ScalarT, 3 >& vel_grid,
196 const int local_subdomain_id,
197 const int x_cell,
198 const int y_cell,
199 const int r_cell,
200 ScalarT ( &beta )[num_neighbors],
201 ScalarT& M_ii,
202 Vec3 ( &S_f )[num_neighbors] )
203 {
204 constexpr int cell_offset_x[num_neighbors] = { -1, 1, 0, 0, 0, 0 };
205 constexpr int cell_offset_y[num_neighbors] = { 0, 0, -1, 1, 0, 0 };
206 constexpr int cell_offset_r[num_neighbors] = { 0, 0, 0, 0, -1, 1 };
207
208 // Surface coords for both wedges.
211 fe::wedge::wedge_surface_physical_coords( wedge_phy_surf, grid, local_subdomain_id, x_cell - 1, y_cell - 1 );
212
213 const ScalarT r_1 = radii( local_subdomain_id, r_cell - 1 );
214 const ScalarT r_2 = radii( local_subdomain_id, r_cell );
215
216 // Velocity coefficients (3 components × 2 wedges × 6 nodes).
218 for ( int d = 0; d < 3; d++ )
220 vel_coeffs[d], local_subdomain_id, x_cell - 1, y_cell - 1, r_cell - 1, d, vel_grid );
221
222 // Quadrature for face integrals.
223 constexpr auto num_quad_points_tri = fe::triangle::quadrature::quad_triangle_3_num_quad_points;
224 dense::Vec< ScalarT, 2 > quad_points_tri[num_quad_points_tri];
225 ScalarT quad_weights_tri[num_quad_points_tri];
228
229 constexpr auto num_quad_points_line = 2;
230 ScalarT quad_points_line[num_quad_points_line] = { -1.0 / Kokkos::sqrt( 3 ), 1.0 / Kokkos::sqrt( 3 ) };
231 ScalarT quad_weights_line[num_quad_points_line] = { 1.0, 1.0 };
232
233 // Cell center.
234 const Vec3 cell_center{
235 cell_centers( local_subdomain_id, x_cell, y_cell, r_cell, 0 ),
236 cell_centers( local_subdomain_id, x_cell, y_cell, r_cell, 1 ),
237 cell_centers( local_subdomain_id, x_cell, y_cell, r_cell, 2 ) };
238
239 // Initialise outputs.
240 for ( int n = 0; n < num_neighbors; ++n )
241 {
242 beta[n] = ScalarT( 0 );
243 S_f[n] = {};
244 }
245 M_ii = ScalarT( 0 );
246
247 // Face integrals.
248 for ( int neighbor = 0; neighbor < num_neighbors; ++neighbor )
249 {
250 for ( int wedge = 0; wedge < fe::wedge::num_wedges_per_hex_cell; ++wedge )
251 {
252 const auto contr = contribution( neighbor, wedge );
253 if ( contr == WedgeContribution::NONE )
254 continue;
255
256 if ( contr == WedgeContribution::TRIANGLE )
257 {
258 for ( int q = 0; q < num_quad_points_tri; ++q )
259 {
260 const auto s = quad_points_tri[q]( 0 );
261 const auto t = quad_points_tri[q]( 1 );
262
263 ScalarT xi = 0, eta = 0, zeta = 0;
265 map_face( neighbor, wedge, s, t, xi, eta, zeta, cpt );
266
267 Vec3 dx_dxi{}, dx_deta{}, dx_dzeta{}, u{};
268 for ( int i = 0; i < fe::wedge::num_nodes_per_wedge; ++i )
269 {
270 const auto shape_i = fe::wedge::shape( i, xi, eta, zeta );
271 const auto grad_i = fe::wedge::grad_shape( i, xi, eta, zeta );
272 const Vec3 x_i = wedge_phy_surf[wedge][i % 3] * ( i < 3 ? r_1 : r_2 );
273 const Vec3 u_i{
274 vel_coeffs[0][wedge]( i ), vel_coeffs[1][wedge]( i ), vel_coeffs[2][wedge]( i ) };
275 dx_dxi = dx_dxi + grad_i( 0 ) * x_i;
276 dx_deta = dx_deta + grad_i( 1 ) * x_i;
277 dx_dzeta = dx_dzeta + grad_i( 2 ) * x_i;
278 u = u + shape_i * u_i;
279 }
280
281 const Vec3 n = dx_dxi.cross( dx_deta ); // cpt must be XI_ETA here
282 beta[neighbor] += quad_weights_tri[q] * u.dot( n );
283 S_f[neighbor] = S_f[neighbor] + quad_weights_tri[q] * n;
284 }
285 }
286 else // QUAD
287 {
288 for ( int q_a = 0; q_a < num_quad_points_line; ++q_a )
289 {
290 for ( int q_b = 0; q_b < num_quad_points_line; ++q_b )
291 {
292 // map_face maps (s, t) as:
293 // s → lateral reference coordinate (xi or eta) ∈ [0,1]
294 // t → zeta (radial direction) ∈ [-1,1]
295 //
296 // The lateral coordinate lives on the standard triangle, so its
297 // valid range is [0,1], not [-1,1]. Remap the Gauss point from
298 // [-1,1] to [0,1] and include the Jacobian factor 1/2.
299 //
300 // t maps to zeta in all four QUAD cases (directions 0,1,2,3) —
301 // confirmed in map_face above. The radial reference coordinate
302 // already spans [-1,1], so t needs no remapping.
303 const auto s = ScalarT( 0.5 ) * ( quad_points_line[q_a] + ScalarT( 1 ) );
304 const auto t = quad_points_line[q_b];
305 const auto w = ScalarT( 0.5 ) * quad_weights_line[q_a] * quad_weights_line[q_b];
306
307 ScalarT xi = 0, eta = 0, zeta = 0;
309 map_face( neighbor, wedge, s, t, xi, eta, zeta, cpt );
310
311 Vec3 dx_dxi{}, dx_deta{}, dx_dzeta{}, u{};
312 for ( int i = 0; i < fe::wedge::num_nodes_per_wedge; ++i )
313 {
314 const auto shape_i = fe::wedge::shape( i, xi, eta, zeta );
315 const auto grad_i = fe::wedge::grad_shape( i, xi, eta, zeta );
316 const Vec3 x_i = wedge_phy_surf[wedge][i % 3] * ( i < 3 ? r_1 : r_2 );
317 const Vec3 u_i{
318 vel_coeffs[0][wedge]( i ), vel_coeffs[1][wedge]( i ), vel_coeffs[2][wedge]( i ) };
319 dx_dxi = dx_dxi + grad_i( 0 ) * x_i;
320 dx_deta = dx_deta + grad_i( 1 ) * x_i;
321 dx_dzeta = dx_dzeta + grad_i( 2 ) * x_i;
322 u = u + shape_i * u_i;
323 }
324
325 Vec3 n{};
326 if ( cpt == CrossProductType::XI_ZETA )
327 n = dx_dxi.cross( dx_dzeta );
328 else
329 n = dx_deta.cross( dx_dzeta );
330
331 beta[neighbor] += w * u.dot( n );
332 S_f[neighbor] = S_f[neighbor] + w * n;
333 }
334 }
335 }
336 }
337
338 // Ensure S_f[neighbor] points outward from cell i toward cell j.
339 // Neighbour cell centre is available in ghost layers after initialize_cell_centers;
340 // on curved domains this is the symmetric, correct reference direction.
341 const int nx = x_cell + cell_offset_x[ neighbor ];
342 const int ny = y_cell + cell_offset_y[ neighbor ];
343 const int nr = r_cell + cell_offset_r[ neighbor ];
344 const Vec3 neighbor_center{
345 cell_centers( local_subdomain_id, nx, ny, nr, 0 ),
346 cell_centers( local_subdomain_id, nx, ny, nr, 1 ),
347 cell_centers( local_subdomain_id, nx, ny, nr, 2 ) };
348
349 if ( S_f[neighbor].dot( neighbor_center - cell_center ) < 0 )
350 {
351 S_f[neighbor] = S_f[neighbor] * ScalarT( -1 );
352 beta[neighbor] *= ScalarT( -1 );
353 }
354 }
355
356 // Cell volume = mass matrix diagonal entry.
357 constexpr auto num_quad_points_vol = fe::wedge::quadrature::quad_felippa_3x2_num_quad_points;
358 dense::Vec< ScalarT, 3 > quad_points_vol[num_quad_points_vol];
359 ScalarT quad_weights_vol[num_quad_points_vol];
362
363 for ( int wedge = 0; wedge < fe::wedge::num_wedges_per_hex_cell; ++wedge )
364 for ( int q = 0; q < num_quad_points_vol; ++q )
365 {
366 const auto J = fe::wedge::jac( wedge_phy_surf[wedge], r_1, r_2, quad_points_vol[q] );
367 const auto abs_det = Kokkos::abs( J.det() );
368 M_ii += abs_det * quad_weights_vol[q];
369 }
370 }
371
372}; // struct GeometryHelper
373
374} // namespace terra::fv::hex::operators::detail
constexpr int quad_triangle_3_num_quad_points
Definition triangle/quadrature/quadrature.hpp:8
constexpr void quad_triangle_3_quad_points(dense::Vec< T, 2 >(&quad_points)[quad_triangle_3_num_quad_points])
Definition triangle/quadrature/quadrature.hpp:12
constexpr void quad_triangle_3_quad_weights(T(&quad_weights)[quad_triangle_3_num_quad_points])
Definition triangle/quadrature/quadrature.hpp:21
constexpr void quad_felippa_3x2_quad_weights(T(&quad_weights)[quad_felippa_3x2_num_quad_points])
Definition wedge/quadrature/quadrature.hpp:93
constexpr int quad_felippa_3x2_num_quad_points
Definition wedge/quadrature/quadrature.hpp:66
constexpr void quad_felippa_3x2_quad_points(dense::Vec< T, 3 >(&quad_points)[quad_felippa_3x2_num_quad_points])
Definition wedge/quadrature/quadrature.hpp:70
constexpr int num_nodes_per_wedge_surface
Definition kernel_helpers.hpp:6
void wedge_surface_physical_coords(dense::Vec< T, 3 >(&wedge_surf_phy_coords)[num_wedges_per_hex_cell][num_nodes_per_wedge_surface], const grid::Grid3DDataVec< T, 3 > &lateral_grid, const int local_subdomain_id, const int x_cell, const int y_cell)
Extracts the (unit sphere) surface vertex coords of the two wedges of a hex cell.
Definition kernel_helpers.hpp:26
constexpr int num_wedges_per_hex_cell
Definition kernel_helpers.hpp:5
void extract_local_wedge_vector_coefficients(dense::Vec< T, 6 >(&local_coefficients)[2], const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell, const int d, const grid::Grid4DDataVec< T, VecDim > &global_coefficients)
Extracts the local vector coefficients for the two wedges of a hex cell from the global coefficient v...
Definition kernel_helpers.hpp:356
constexpr int num_nodes_per_wedge
Definition kernel_helpers.hpp:7
constexpr dense::Vec< T, 3 > grad_shape(const int node_idx, const T xi, const T eta, const T zeta)
Gradient of the full shape function:
Definition integrands.hpp:228
constexpr T shape(const int node_idx, const T xi, const T eta, const T zeta)
(Tensor-product) Shape function.
Definition integrands.hpp:146
constexpr dense::Mat< T, 3, 3 > jac(const dense::Vec< T, 3 > &p1_phy, const dense::Vec< T, 3 > &p2_phy, const dense::Vec< T, 3 > &p3_phy, const T r_1, const T r_2, const T xi, const T eta, const T zeta)
Definition integrands.hpp:657
Definition geometry_helper.hpp:17
Kokkos::View< ScalarType ***[VecDim], Layout > Grid3DDataVec
Definition grid_types.hpp:42
Kokkos::View< ScalarType **, Layout > Grid2DDataScalar
Definition grid_types.hpp:21
constexpr Vec cross(const Vec &other) const
Definition vec.hpp:48
T dot(const Vec &other) const
Definition vec.hpp:39
Stateless geometry helper for a single FV hex cell.
Definition geometry_helper.hpp:32
static constexpr WedgeContribution contribution(const int hex_direction, const int wedge_id)
Definition geometry_helper.hpp:67
static constexpr int cell_offset_y(int n)
Definition geometry_helper.hpp:42
WedgeContribution
Definition geometry_helper.hpp:54
static constexpr int cell_offset_r(int n)
Definition geometry_helper.hpp:47
static constexpr int cell_offset_x(int n)
Definition geometry_helper.hpp:37
static constexpr int num_neighbors
Definition geometry_helper.hpp:35
CrossProductType
Definition geometry_helper.hpp:60
static void compute_geometry(const grid::Grid3DDataVec< ScalarT, 3 > &grid, const grid::Grid2DDataScalar< ScalarT > &radii, const grid::Grid4DDataVec< ScalarT, 3 > &cell_centers, const grid::Grid4DDataVec< ScalarT, 3 > &vel_grid, const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell, ScalarT(&beta)[num_neighbors], ScalarT &M_ii, Vec3(&S_f)[num_neighbors])
Compute beta[6], M_ii, and S_f[6] for the cell at (x_cell, y_cell, r_cell).
Definition geometry_helper.hpp:191
static constexpr void map_face(const int hex_direction, const int wedge_id, const double s, const double t, double &xi, double &eta, double &zeta, CrossProductType &cross_product_type)
Definition geometry_helper.hpp:104