Loading...
Searching...
No Matches
vector_laplace.hpp
Go to the documentation of this file.
1
2#pragma once
3
4#include "../../quadrature/quadrature.hpp"
6#include "dense/vec.hpp"
10#include "linalg/operator.hpp"
13#include "linalg/vector.hpp"
14#include "linalg/vector_q1.hpp"
15#include "util/timer.hpp"
16
17
19
20
30
31template < typename ScalarT, int VecDim = 3 >
33{
34 public:
37 using ScalarType = ScalarT;
38
39 private:
41
45
46 BoundaryConditions bcs_;
47 bool diagonal_;
48
49 linalg::OperatorApplyMode operator_apply_mode_;
50 linalg::OperatorCommunicationMode operator_communication_mode_;
51
54
57
58 public:
64 BoundaryConditions bcs,
65 bool diagonal,
67 linalg::OperatorCommunicationMode operator_communication_mode =
69 : domain_( domain )
70 , grid_( grid )
71 , radii_( radii )
72 , boundary_mask_data_( boundary_mask_data )
73 , diagonal_( diagonal )
74 , operator_apply_mode_( operator_apply_mode )
75 , operator_communication_mode_( operator_communication_mode )
76 // TODO: we can reuse the send and recv buffers and pass in from the outside somehow
77 , send_buffers_( domain )
78 , recv_buffers_( domain )
79 {
80 bcs_[0] = bcs[0];
81 bcs_[1] = bcs[1];
82 }
83
85 const linalg::OperatorApplyMode operator_apply_mode,
86 const linalg::OperatorCommunicationMode operator_communication_mode )
87 {
88 operator_apply_mode_ = operator_apply_mode;
89 operator_communication_mode_ = operator_communication_mode;
90 }
91
92 void apply_impl( const SrcVectorType& src, DstVectorType& dst )
93 {
94 util::Timer timer_apply( "vector_laplace_apply" );
95
96 if ( operator_apply_mode_ == linalg::OperatorApplyMode::Replace )
97 {
98 assign( dst, 0 );
99 }
100
101 src_ = src.grid_data();
102 dst_ = dst.grid_data();
103
104 if ( src_.extent( 0 ) != dst_.extent( 0 ) || src_.extent( 1 ) != dst_.extent( 1 ) ||
105 src_.extent( 2 ) != dst_.extent( 2 ) || src_.extent( 3 ) != dst_.extent( 3 ) )
106 {
107 throw std::runtime_error( "VectorLaplace: src/dst mismatch" );
108 }
109
110 if ( src_.extent( 1 ) != grid_.extent( 1 ) || src_.extent( 2 ) != grid_.extent( 2 ) )
111 {
112 throw std::runtime_error( "VectorLaplace: src/dst mismatch" );
113 }
114
115 util::Timer timer_kernel( "vector_laplace_kernel" );
116 Kokkos::parallel_for( "matvec", grid::shell::local_domain_md_range_policy_cells( domain_ ), *this );
117 Kokkos::fence();
118 timer_kernel.stop();
119
120 if ( operator_communication_mode_ == linalg::OperatorCommunicationMode::CommunicateAdditively )
121 {
122 util::Timer timer_comm( "vector_laplace_comm" );
123
125 domain_, dst_, send_buffers_, recv_buffers_ );
127 }
128 }
129
130 KOKKOS_INLINE_FUNCTION void
131 operator()( const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell ) const
132 {
133 // Gather surface points for each wedge.
135 wedge_surface_physical_coords( wedge_phy_surf, grid_, local_subdomain_id, x_cell, y_cell );
136
137 // Gather wedge radii.
138 const ScalarT r_1 = radii_( local_subdomain_id, r_cell );
139 const ScalarT r_2 = radii_( local_subdomain_id, r_cell + 1 );
140
141 // Quadrature points.
142 constexpr auto num_quad_points = quadrature::quad_felippa_3x2_num_quad_points;
143
144 dense::Vec< ScalarT, 3 > quad_points[num_quad_points];
145 ScalarT quad_weights[num_quad_points];
146
149
150 // Compute the local element matrix.
151
152 ScalarType src_local_hex[8][VecDim] = { { 0 } };
153 ScalarType dst_local_hex[8][VecDim] = { { 0 } };
154
155 for ( int i = 0; i < 8; i++ )
156 {
157 for ( int d = 0; d < VecDim; d++ )
158 {
159 constexpr int hex_offset_x[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
160 constexpr int hex_offset_y[8] = { 0, 0, 1, 1, 0, 0, 1, 1 };
161 constexpr int hex_offset_r[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
162
163 src_local_hex[i][d] = src_(
164 local_subdomain_id,
165 x_cell + hex_offset_x[i],
166 y_cell + hex_offset_y[i],
167 r_cell + hex_offset_r[i],
168 d );
169 }
170 }
171
172 for ( int wedge = 0; wedge < num_wedges_per_hex_cell; wedge++ )
173 {
174 for ( int q = 0; q < num_quad_points; q++ )
175 {
176 const auto quad_point = quad_points[q];
177 const auto quad_weight = quad_weights[q];
178
179 // 1. Compute Jacobian and inverse at this quadrature point.
180
181 const auto J = jac( wedge_phy_surf[wedge], r_1, r_2, quad_points[q] );
182 const auto det = J.det();
183 const auto abs_det = Kokkos::abs( det );
184 const auto J_inv_transposed = J.inv_transposed( det );
185
186 // 2. Compute physical gradients for all nodes at this quadrature point.
188 for ( int k = 0; k < num_nodes_per_wedge; k++ )
189 {
190 grad_phy[k] = J_inv_transposed * grad_shape( k, quad_point );
191 }
192
193 ShellBoundaryFlag sbf = util::has_flag(
194 boundary_mask_data_( local_subdomain_id, x_cell, y_cell, r_cell ),
196 CMB :
197 SURFACE;
198 BoundaryConditionFlag bcf = get_boundary_condition_flag( bcs_, sbf );
199
200 if ( diagonal_ )
201 {
202 diagonal( src_local_hex, dst_local_hex, wedge, quad_weight, abs_det, grad_phy );
203 }
204 else if ( sbf == CMB && bcf == DIRICHLET )
205 {
206 // Bottom boundary dirichlet
207 dirichlet_bot( src_local_hex, dst_local_hex, wedge, quad_weight, abs_det, grad_phy );
208 }
209 else if ( sbf == SURFACE && bcf == DIRICHLET )
210 {
211 // Top boundary dirichlet
212 dirichlet_top( src_local_hex, dst_local_hex, wedge, quad_weight, abs_det, grad_phy );
213 }
214 else if ( bcf == NEUMANN )
215 {
216 neumann( src_local_hex, dst_local_hex, wedge, quad_weight, abs_det, grad_phy );
217 }
218 else
219 {
220 Kokkos::abort( "Unexpected." );
221 }
222 }
223 }
224
225 for ( int i = 0; i < 8; i++ )
226 {
227 for ( int d = 0; d < VecDim; d++ )
228 {
229 constexpr int hex_offset_x[8] = { 0, 1, 0, 1, 0, 1, 0, 1 };
230 constexpr int hex_offset_y[8] = { 0, 0, 1, 1, 0, 0, 1, 1 };
231 constexpr int hex_offset_r[8] = { 0, 0, 0, 0, 1, 1, 1, 1 };
232
233 Kokkos::atomic_add(
234 &dst_(
235 local_subdomain_id,
236 x_cell + hex_offset_x[i],
237 y_cell + hex_offset_y[i],
238 r_cell + hex_offset_r[i],
239 d ),
240 dst_local_hex[i][d] );
241 }
242 }
243 }
244
245 KOKKOS_INLINE_FUNCTION void neumann(
246 ScalarType src_local_hex[8][VecDim],
247 ScalarType dst_local_hex[8][VecDim],
248 const int wedge,
249 const ScalarType quad_weight,
250 const ScalarType abs_det,
251 const dense::Vec< ScalarType, 3 >* grad_phy ) const
252 {
253 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
254 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
255 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
256
257 // 3. Compute ∇u at this quadrature point.
258 dense::Vec< ScalarType, 3 > grad_u[VecDim];
259 for ( int d = 0; d < VecDim; d++ )
260 {
261 grad_u[d].fill( 0.0 );
262 }
263
264 for ( int j = 0; j < num_nodes_per_wedge; j++ )
265 {
266 for ( int d = 0; d < VecDim; d++ )
267 {
268 grad_u[d] =
269 grad_u[d] + src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]][d] *
270 grad_phy[j];
271 }
272 }
273
274 // 4. Add the test function contributions.
275 for ( int i = 0; i < num_nodes_per_wedge; i++ )
276 {
277 for ( int d = 0; d < VecDim; d++ )
278 {
279 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
280 quad_weight * grad_phy[i].dot( grad_u[d] ) * abs_det;
281 }
282 }
283 }
284
285 KOKKOS_INLINE_FUNCTION void dirichlet_bot(
286 ScalarType src_local_hex[8][VecDim],
287 ScalarType dst_local_hex[8][VecDim],
288 const int wedge,
289 const ScalarType quad_weight,
290 const ScalarType abs_det,
291 const dense::Vec< ScalarType, 3 >* grad_phy ) const
292 {
293 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
294 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
295 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
296
297 // 3. Compute ∇u at this quadrature point.
298 dense::Vec< ScalarType, 3 > grad_u[VecDim];
299 for ( int d = 0; d < VecDim; d++ )
300 {
301 grad_u[d].fill( 0.0 );
302 }
303
304 for ( int j = 3; j < num_nodes_per_wedge; j++ )
305 {
306 for ( int d = 0; d < VecDim; d++ )
307 {
308 grad_u[d] =
309 grad_u[d] + src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]][d] *
310 grad_phy[j];
311 }
312 }
313
314 // 4. Add the test function contributions.
315 for ( int i = 3; i < num_nodes_per_wedge; i++ )
316 {
317 for ( int d = 0; d < VecDim; d++ )
318 {
319 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
320 quad_weight * grad_phy[i].dot( grad_u[d] ) * abs_det;
321 }
322 }
323
324 // Diagonal for top part
325 for ( int i = 0; i < 3; i++ )
326 {
327 for ( int d = 0; d < VecDim; d++ )
328 {
329 const auto grad_u_diag =
330 src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] *
331 grad_phy[i];
332
333 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
334 quad_weight * grad_phy[i].dot( grad_u_diag ) * abs_det;
335 }
336 }
337 }
338
339 KOKKOS_INLINE_FUNCTION void dirichlet_top(
340 ScalarType src_local_hex[8][VecDim],
341 ScalarType dst_local_hex[8][VecDim],
342 const int wedge,
343 const ScalarType quad_weight,
344 const ScalarType abs_det,
345 const dense::Vec< ScalarType, 3 >* grad_phy ) const
346 {
347 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
348 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
349 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
350
351 // 3. Compute ∇u at this quadrature point.
352 dense::Vec< ScalarType, 3 > grad_u[VecDim];
353 for ( int d = 0; d < VecDim; d++ )
354 {
355 grad_u[d].fill( 0.0 );
356 }
357
358 for ( int j = 0; j < 3; j++ )
359 {
360 for ( int d = 0; d < VecDim; d++ )
361 {
362 grad_u[d] =
363 grad_u[d] + src_local_hex[4 * offset_r[wedge][j] + 2 * offset_y[wedge][j] + offset_x[wedge][j]][d] *
364 grad_phy[j];
365 }
366 }
367
368 // 4. Add the test function contributions.
369 for ( int i = 0; i < 3; i++ )
370 {
371 for ( int d = 0; d < VecDim; d++ )
372 {
373 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
374 quad_weight * grad_phy[i].dot( grad_u[d] ) * abs_det;
375 }
376 }
377
378 // Diagonal for top part
379 for ( int i = 3; i < num_nodes_per_wedge; i++ )
380 {
381 for ( int d = 0; d < VecDim; d++ )
382 {
383 const auto grad_u_diag =
384 src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] *
385 grad_phy[i];
386
387 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
388 quad_weight * grad_phy[i].dot( grad_u_diag ) * abs_det;
389 }
390 }
391 }
392
393 KOKKOS_INLINE_FUNCTION void diagonal(
394 ScalarType src_local_hex[8][VecDim],
395 ScalarType dst_local_hex[8][VecDim],
396 const int wedge,
397 const ScalarType quad_weight,
398 const ScalarType abs_det,
399 const dense::Vec< ScalarType, 3 >* grad_phy ) const
400 {
401 constexpr int offset_x[2][6] = { { 0, 1, 0, 0, 1, 0 }, { 1, 0, 1, 1, 0, 1 } };
402 constexpr int offset_y[2][6] = { { 0, 0, 1, 0, 0, 1 }, { 1, 1, 0, 1, 1, 0 } };
403 constexpr int offset_r[2][6] = { { 0, 0, 0, 1, 1, 1 }, { 0, 0, 0, 1, 1, 1 } };
404
405 // 3. Compute ∇u at this quadrature point.
406 // 4. Add the test function contributions.
407 for ( int i = 0; i < num_nodes_per_wedge; i++ )
408 {
409 for ( int d = 0; d < VecDim; d++ )
410 {
411 const auto grad_u =
412 src_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] *
413 grad_phy[i];
414
415 dst_local_hex[4 * offset_r[wedge][i] + 2 * offset_y[wedge][i] + offset_x[wedge][i]][d] +=
416 quad_weight * grad_phy[i].dot( grad_u ) * abs_det;
417 }
418 }
419 }
420};
421
424
425} // namespace terra::fe::wedge::operators::shell
Send and receive buffers for all process-local subdomain boundaries.
Definition communication.hpp:56
VectorLaplace(const grid::shell::DistributedDomain &domain, const grid::Grid3DDataVec< ScalarT, 3 > &grid, const grid::Grid2DDataScalar< ScalarT > &radii, const grid::Grid4DDataScalar< grid::shell::ShellBoundaryFlag > &boundary_mask_data, BoundaryConditions bcs, bool diagonal, linalg::OperatorApplyMode operator_apply_mode=linalg::OperatorApplyMode::Replace, linalg::OperatorCommunicationMode operator_communication_mode=linalg::OperatorCommunicationMode::CommunicateAdditively)
Definition vector_laplace.hpp:59
void neumann(ScalarType src_local_hex[8][VecDim], ScalarType dst_local_hex[8][VecDim], const int wedge, const ScalarType quad_weight, const ScalarType abs_det, const dense::Vec< ScalarType, 3 > *grad_phy) const
Definition vector_laplace.hpp:245
void operator()(const int local_subdomain_id, const int x_cell, const int y_cell, const int r_cell) const
Definition vector_laplace.hpp:131
void dirichlet_bot(ScalarType src_local_hex[8][VecDim], ScalarType dst_local_hex[8][VecDim], const int wedge, const ScalarType quad_weight, const ScalarType abs_det, const dense::Vec< ScalarType, 3 > *grad_phy) const
Definition vector_laplace.hpp:285
void apply_impl(const SrcVectorType &src, DstVectorType &dst)
Definition vector_laplace.hpp:92
void set_operator_apply_and_communication_modes(const linalg::OperatorApplyMode operator_apply_mode, const linalg::OperatorCommunicationMode operator_communication_mode)
Definition vector_laplace.hpp:84
void diagonal(ScalarType src_local_hex[8][VecDim], ScalarType dst_local_hex[8][VecDim], const int wedge, const ScalarType quad_weight, const ScalarType abs_det, const dense::Vec< ScalarType, 3 > *grad_phy) const
Definition vector_laplace.hpp:393
void dirichlet_top(ScalarType src_local_hex[8][VecDim], ScalarType dst_local_hex[8][VecDim], const int wedge, const ScalarType quad_weight, const ScalarType abs_det, const dense::Vec< ScalarType, 3 > *grad_phy) const
Definition vector_laplace.hpp:339
ScalarT ScalarType
Definition vector_laplace.hpp:37
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
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 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
BoundaryConditionMapping[2] BoundaryConditions
Definition shell/bit_masks.hpp:37
ShellBoundaryFlag
FlagLike that indicates boundary types for the thick spherical shell.
Definition shell/bit_masks.hpp:12
Kokkos::MDRangePolicy< Kokkos::Rank< 4 > > local_domain_md_range_policy_cells(const DistributedDomain &distributed_domain)
Definition spherical_shell.hpp:2668
BoundaryConditionFlag
FlagLike that indicates the type of boundary condition
Definition shell/bit_masks.hpp:25
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.
constexpr bool has_flag(E mask_value, E flag) noexcept
Checks if a bitmask value contains a specific flag.
Definition bit_masking.hpp:43
T dot(const Vec &other) const
Definition vec.hpp:39