Loading...
Searching...
No Matches
epsilon.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "../../quadrature/quadrature.hpp"
5#include "dense/vec.hpp"
9#include "linalg/operator.hpp"
10#include "linalg/vector.hpp"
11#include "linalg/vector_q1.hpp"
12#include "util/timer.hpp"
13
15
16template < typename ScalarT, int VecDim = 3 >
18{
19 public:
22 using ScalarType = ScalarT;
23
24 private:
26
30
31 bool treat_boundary_;
32 bool diagonal_;
33
34 linalg::OperatorApplyMode operator_apply_mode_;
35 linalg::OperatorCommunicationMode operator_communication_mode_;
36
39
42
43 public:
49 bool treat_boundary,
50 bool diagonal,
52 linalg::OperatorCommunicationMode operator_communication_mode =
54 : domain_( domain )
55 , grid_( grid )
56 , radii_( radii )
57 , k_( k )
58 , treat_boundary_( treat_boundary )
59 , diagonal_( diagonal )
60 , operator_apply_mode_( operator_apply_mode )
61 , operator_communication_mode_( operator_communication_mode )
62 // TODO: we can reuse the send and recv buffers and pass in from the outside somehow
63 , send_buffers_( domain )
64 , recv_buffers_( domain )
65 {}
66
68
70 const linalg::OperatorApplyMode operator_apply_mode,
71 const linalg::OperatorCommunicationMode operator_communication_mode )
72 {
73 operator_apply_mode_ = operator_apply_mode;
74 operator_communication_mode_ = operator_communication_mode;
75 }
76
77 void apply_impl( const SrcVectorType& src, DstVectorType& dst )
78 {
79 util::Timer timer_apply( "vector_laplace_apply" );
80
81 if ( operator_apply_mode_ == linalg::OperatorApplyMode::Replace )
82 {
83 assign( dst, 0 );
84 }
85
86 src_ = src.grid_data();
87 dst_ = dst.grid_data();
88
89 if ( src_.extent( 0 ) != dst_.extent( 0 ) || src_.extent( 1 ) != dst_.extent( 1 ) ||
90 src_.extent( 2 ) != dst_.extent( 2 ) || src_.extent( 3 ) != dst_.extent( 3 ) )
91 {
92 throw std::runtime_error( "VectorLaplace: src/dst mismatch" );
93 }
94
95 if ( src_.extent( 1 ) != grid_.extent( 1 ) || src_.extent( 2 ) != grid_.extent( 2 ) )
96 {
97 throw std::runtime_error( "VectorLaplace: src/dst mismatch" );
98 }
99
100 util::Timer timer_kernel( "vector_laplace_kernel" );
101 Kokkos::parallel_for( "matvec", grid::shell::local_domain_md_range_policy_cells( domain_ ), *this );
102 Kokkos::fence();
103 timer_kernel.stop();
104
105 if ( operator_communication_mode_ == linalg::OperatorCommunicationMode::CommunicateAdditively )
106 {
107 util::Timer timer_comm( "vector_laplace_comm" );
108
110 domain_, dst_, send_buffers_, recv_buffers_ );
112 }
113 }
114
115 KOKKOS_INLINE_FUNCTION void
116 operator()( const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell ) const
117 {
118 // Gather surface points for each wedge.
120 wedge_surface_physical_coords( wedge_phy_surf, grid_, local_subdomain_id, x_cell, y_cell );
121
122 // Gather wedge radii.
123 const ScalarT r_1 = radii_( local_subdomain_id, r_cell );
124 const ScalarT r_2 = radii_( local_subdomain_id, r_cell + 1 );
125
126 // Quadrature points.
127 constexpr auto num_quad_points = quadrature::quad_felippa_3x2_num_quad_points;
128
129 dense::Vec< ScalarT, 3 > quad_points[num_quad_points];
130 ScalarT quad_weights[num_quad_points];
131
134
136 extract_local_wedge_scalar_coefficients( k_local_hex, local_subdomain_id, x_cell, y_cell, r_cell, k_ );
137
138 // FE dimensions: velocity coupling components of epsilon operator
139
140 for ( int dimi = 0; dimi < 3; ++dimi )
141 {
142 for ( int dimj = 0; dimj < 3; ++dimj )
143 {
144 if ( diagonal_ and dimi != dimj )
145 continue;
146
147 ScalarType src_local_hex[8] = { { 0 } };
148 ScalarType dst_local_hex[8] = { { 0 } };
149
150 constexpr int hex_offset_x[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
151 constexpr int hex_offset_y[8] = { 0, 0, 1, 1, 0, 0, 1, 1 };
152 constexpr int hex_offset_r[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
153 for ( int i = 0; i < 8; i++ )
154 {
155 src_local_hex[i] = src_(
156 local_subdomain_id,
157 x_cell + hex_offset_x[i],
158 y_cell + hex_offset_y[i],
159 r_cell + hex_offset_r[i],
160 dimi );
161 }
162
163 // spatial dimensions: quadrature points and wedge
164 for ( int q = 0; q < num_quad_points; q++ )
165 {
166 const auto quad_weight = quad_weights[q];
167
168 for ( int wedge = 0; wedge < num_wedges_per_hex_cell; wedge++ )
169 {
171 jac( wedge_phy_surf[wedge], r_1, r_2, quad_points[q] );
172 const auto det = J.det();
173 const auto abs_det = Kokkos::abs( det );
174 const dense::Mat< ScalarT, VecDim, VecDim > J_inv_transposed = J.inv_transposed( det );
175 ScalarType k_eval = 0.0;
176 for ( int k = 0; k < num_nodes_per_wedge; k++ )
177 {
178 k_eval += shape( k, quad_points[q] ) * k_local_hex[wedge]( k );
179 }
180
183 for ( int k = 0; k < num_nodes_per_wedge; k++ )
184 {
187 grad_shape( k, quad_points[q] ), dimi );
188 sym_grad_i[k] = ( grad_i + grad_i.transposed() ) * 0.5;
189
192 grad_shape( k, quad_points[q] ), dimj );
193 sym_grad_j[k] = ( grad_j + grad_j.transposed() ) * 0.5;
194 }
195
196 if ( diagonal_ )
197 {
198 diagonal(
199 src_local_hex,
200 dst_local_hex,
201 k_eval,
202 wedge,
203 quad_weight,
204 abs_det,
205 sym_grad_i,
206 sym_grad_j,
207 dimi,
208 dimj );
209 }
210 else if ( treat_boundary_ && r_cell == 0 )
211 {
212 // Bottom boundary dirichlet
214 src_local_hex,
215 dst_local_hex,
216 k_eval,
217 wedge,
218 quad_weight,
219 abs_det,
220 sym_grad_i,
221 sym_grad_j,
222 dimi,
223 dimj );
224 }
225 else if ( treat_boundary_ && r_cell + 1 == radii_.extent( 1 ) - 1 )
226 {
227 // Top boundary dirichlet
229 src_local_hex,
230 dst_local_hex,
231 k_eval,
232 wedge,
233 quad_weight,
234 abs_det,
235 sym_grad_i,
236 sym_grad_j,
237 dimi,
238 dimj );
239 }
240 else
241 {
242 neumann(
243 src_local_hex,
244 dst_local_hex,
245 k_eval,
246 wedge,
247 quad_weight,
248 abs_det,
249 sym_grad_i,
250 sym_grad_j,
251 dimi,
252 dimj );
253 }
254 }
255 }
256
257 for ( int i = 0; i < 8; i++ )
258 {
259 constexpr int hex_offset_x[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
260 constexpr int hex_offset_y[8] = { 0, 0, 1, 1, 0, 0, 1, 1 };
261 constexpr int hex_offset_r[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
262
263 Kokkos::atomic_add(
264 &dst_(
265 local_subdomain_id,
266 x_cell + hex_offset_x[i],
267 y_cell + hex_offset_y[i],
268 r_cell + hex_offset_r[i],
269 dimj ),
270 dst_local_hex[i] );
271 }
272 }
273 }
274 }
275
276 KOKKOS_INLINE_FUNCTION void neumann(
277 ScalarType src_local_hex[8],
278 ScalarType dst_local_hex[8],
279 const ScalarType k_eval,
280 const int wedge,
281 const ScalarType quad_weight,
282 const ScalarType abs_det,
285 const int dimi,
286 const int dimj ) const
287 {
288 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
289 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
290 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
291
292 // 3. Compute ∇u at this quadrature point.
294
295 grad_u.fill( 0.0 );
296 for ( int j = 0; j < num_nodes_per_wedge; j++ )
297 {
298 grad_u = grad_u + sym_grad_i[j] *
299 src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]];
300 }
301
302 // 4. Add the test function contributions.
303 for ( int i = 0; i < num_nodes_per_wedge; i++ )
304 {
305 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
306 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u ) * abs_det;
307 }
308 }
309
310 KOKKOS_INLINE_FUNCTION void dirichlet_cmb(
311 ScalarType src_local_hex[8],
312 ScalarType dst_local_hex[8],
313 const ScalarType k_eval,
314 const int wedge,
315 const ScalarType quad_weight,
316 const ScalarType abs_det,
319 const int dimi,
320 const int dimj ) const
321 {
322 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
323 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
324 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
325
326 // 3. Compute ∇u at this quadrature point.
328 grad_u.fill( 0.0 );
329 for ( int j = 3; j < num_nodes_per_wedge; j++ )
330 {
331 grad_u = grad_u + sym_grad_i[j] *
332 src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]];
333 }
334
335 // 4. Add the test function contributions.
336 for ( int i = 3; i < num_nodes_per_wedge; i++ )
337 {
338 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
339 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u ) * abs_det;
340 }
341
342 // Diagonal for top part
343 if ( dimi == dimj )
344 {
345 for ( int i = 0; i < 3; i++ )
346 {
347 const auto grad_u_diag =
348 sym_grad_i[i] * src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]];
349
350 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
351 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u_diag ) * abs_det;
352 }
353 }
354 }
355
356 KOKKOS_INLINE_FUNCTION void dirichlet_surface(
357 ScalarType src_local_hex[8],
358 ScalarType dst_local_hex[8],
359 const ScalarType k_eval,
360 const int wedge,
361 const ScalarType quad_weight,
362 const ScalarType abs_det,
365 const int dimi,
366 const int dimj ) const
367 {
368 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
369 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
370 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
371
372 // 3. Compute ∇u at this quadrature point.
374
375 grad_u.fill( 0.0 );
376 for ( int j = 0; j < 3; j++ )
377 {
378 grad_u = grad_u + sym_grad_i[j] *
379 src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]];
380 }
381
382 // 4. Add the test function contributions.
383 for ( int i = 0; i < 3; i++ )
384 {
385 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
386 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u ) * abs_det;
387 }
388
389 // Diagonal for top part
390 if ( dimi == dimj )
391 {
392 for ( int i = 3; i < num_nodes_per_wedge; i++ )
393 {
394 const auto grad_u_diag =
395 sym_grad_i[i] * src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]];
396
397 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
398 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u_diag ) * abs_det;
399 }
400 }
401 }
402
403 KOKKOS_INLINE_FUNCTION void diagonal(
404 ScalarType src_local_hex[8],
405 ScalarType dst_local_hex[8],
406 const ScalarType k_eval,
407 const int wedge,
408 const ScalarType quad_weight,
409 const ScalarType abs_det,
412 const int dimi,
413 const int dimj ) const
414 {
415 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
416 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
417 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
418
419 // 3. Compute ∇u at this quadrature point.
420 for ( int i = 0; i < num_nodes_per_wedge; i++ )
421 {
422 const auto grad_u_diag =
423 sym_grad_i[i] * src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]];
424
425 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]] +=
426 2 * quad_weight * k_eval * ( sym_grad_j[i] ).double_contract( grad_u_diag ) * abs_det;
427 }
428 }
429};
430
433
434} // namespace terra::fe::wedge::operators::shell
Send and receive buffers for all process-local subdomain boundaries.
Definition communication.hpp:56
void apply_impl(const SrcVectorType &src, DstVectorType &dst)
Definition epsilon.hpp:77
void diagonal(ScalarType src_local_hex[8], ScalarType dst_local_hex[8], const ScalarType k_eval, const int wedge, const ScalarType quad_weight, const ScalarType abs_det, dense::Mat< ScalarType, 3, 3 > *sym_grad_i, dense::Mat< ScalarType, 3, 3 > *sym_grad_j, const int dimi, const int dimj) const
Definition epsilon.hpp:403
void operator()(const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell) const
Definition epsilon.hpp:116
void set_operator_apply_and_communication_modes(const linalg::OperatorApplyMode operator_apply_mode, const linalg::OperatorCommunicationMode operator_communication_mode)
Definition epsilon.hpp:69
void dirichlet_cmb(ScalarType src_local_hex[8], ScalarType dst_local_hex[8], const ScalarType k_eval, const int wedge, const ScalarType quad_weight, const ScalarType abs_det, dense::Mat< ScalarType, 3, 3 > *sym_grad_i, dense::Mat< ScalarType, 3, 3 > *sym_grad_j, const int dimi, const int dimj) const
Definition epsilon.hpp:310
const grid::Grid4DDataScalar< ScalarType > & k_grid_data()
Definition epsilon.hpp:67
ScalarT ScalarType
Definition epsilon.hpp:22
void neumann(ScalarType src_local_hex[8], ScalarType dst_local_hex[8], const ScalarType k_eval, const int wedge, const ScalarType quad_weight, const ScalarType abs_det, dense::Mat< ScalarType, 3, 3 > *sym_grad_i, dense::Mat< ScalarType, 3, 3 > *sym_grad_j, const int dimi, const int dimj) const
Definition epsilon.hpp:276
Epsilon(const grid::shell::DistributedDomain &domain, const grid::Grid3DDataVec< ScalarT, 3 > &grid, const grid::Grid2DDataScalar< ScalarT > &radii, const grid::Grid4DDataScalar< ScalarT > &k, bool treat_boundary, bool diagonal, linalg::OperatorApplyMode operator_apply_mode=linalg::OperatorApplyMode::Replace, linalg::OperatorCommunicationMode operator_communication_mode=linalg::OperatorCommunicationMode::CommunicateAdditively)
Definition epsilon.hpp:44
void dirichlet_surface(ScalarType src_local_hex[8], ScalarType dst_local_hex[8], const ScalarType k_eval, const int wedge, const ScalarType quad_weight, const ScalarType abs_det, dense::Mat< ScalarType, 3, 3 > *sym_grad_i, dense::Mat< ScalarType, 3, 3 > *sym_grad_j, const int dimi, const int dimj) const
Definition epsilon.hpp:356
Parallel data structure organizing the thick spherical shell metadata for distributed (MPI parallel) ...
Definition spherical_shell.hpp:2498
Static assertion: VectorQ1Scalar satisfies VectorLike concept.
Definition vector_q1.hpp:162
const grid::Grid4DDataVec< ScalarType, VecDim > & grid_data() const
Get const reference to grid data.
Definition vector_q1.hpp:280
Timer supporting RAII scope or manual stop.
Definition timer.hpp:270
void stop()
Stop the timer and record elapsed time.
Definition timer.hpp:289
Concept for types that behave like linear operators.
Definition operator.hpp:57
void unpack_and_reduce_local_subdomain_boundaries(const grid::shell::DistributedDomain &domain, const GridDataType &data, SubdomainNeighborhoodSendRecvBuffer< typename GridDataType::value_type, grid::grid_data_vec_dim< GridDataType >() > &boundary_recv_buffers, CommunicationReduction reduction=CommunicationReduction::SUM)
Unpacks and reduces local subdomain boundaries.
Definition communication.hpp:672
void pack_send_and_recv_local_subdomain_boundaries(const grid::shell::DistributedDomain &domain, const GridDataType &data, SubdomainNeighborhoodSendRecvBuffer< typename GridDataType::value_type, grid::grid_data_vec_dim< GridDataType >() > &boundary_send_buffers, SubdomainNeighborhoodSendRecvBuffer< typename GridDataType::value_type, grid::grid_data_vec_dim< GridDataType >() > &boundary_recv_buffers)
Packs, sends and recvs local subdomain boundaries using two sets of buffers.
Definition communication.hpp:242
Definition boundary_mass.hpp:14
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_scalar_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 grid::Grid4DDataScalar< T > &global_coefficients)
Extracts the local vector coefficients for the two wedges of a hex cell from the global coefficient v...
Definition kernel_helpers.hpp:306
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:643
Kokkos::MDRangePolicy< Kokkos::Rank< 4 > > local_domain_md_range_policy_cells(const DistributedDomain &distributed_domain)
Definition spherical_shell.hpp:2668
Kokkos::View< ScalarType ***[VecDim], Layout > Grid3DDataVec
Definition grid_types.hpp:40
Kokkos::View< ScalarType ****[VecDim], Layout > Grid4DDataVec
Definition grid_types.hpp:43
Kokkos::View< ScalarType ****, Layout > Grid4DDataScalar
Definition grid_types.hpp:25
Kokkos::View< ScalarType **, Layout > Grid2DDataScalar
Definition grid_types.hpp:19
OperatorApplyMode
Modes for applying an operator to a vector.
Definition operator.hpp:30
@ Replace
Overwrite the destination vector.
OperatorCommunicationMode
Modes for communication during operator application.
Definition operator.hpp:40
@ CommunicateAdditively
Communicate and add results.
Definition mat.hpp:10
constexpr Mat< T, Cols, Rows > transposed() const
Definition mat.hpp:187
static constexpr Mat from_single_col_vec(const Vec< T, Cols > &col, const int d)
Definition mat.hpp:66