66 using Team = Kokkos::TeamPolicy<>::member_type;
78 BoundaryConditions bcs_;
99 int local_subdomains_;
102 int lat_refinement_level_;
123 enum class KernelPath
126 FastDirichletNeumann,
129 KernelPath kernel_path_ = KernelPath::FastDirichletNeumann;
140 void update_kernel_path_flag_host_only()
142 const BoundaryConditionFlag cmb_bc = get_boundary_condition_flag( bcs_, CMB );
143 const BoundaryConditionFlag surface_bc = get_boundary_condition_flag( bcs_, SURFACE );
145 const bool has_freeslip = ( cmb_bc == FREESLIP ) || ( surface_bc == FREESLIP );
148 if ( has_stored_matrices )
149 kernel_path_ = KernelPath::Slow;
150 else if ( has_freeslip )
151 kernel_path_ = KernelPath::FastFreeslip;
153 kernel_path_ = KernelPath::FastDirichletNeumann;
163 BoundaryConditions bcs,
174 , diagonal_( diagonal )
175 , operator_apply_mode_( operator_apply_mode )
176 , operator_communication_mode_( operator_communication_mode )
177 , operator_stored_matrix_mode_( operator_stored_matrix_mode )
178 , recv_buffers_( domain )
179 , comm_plan_( domain )
188 local_subdomains_ = domain_.
subdomains().size();
196 r_tile_block_ = r_tile_ * r_passes_;
198 lat_tiles_ = ( hex_lat_ + lat_tile_ - 1 ) / lat_tile_;
199 r_tiles_ = ( hex_rad_ + r_tile_block_ - 1 ) / r_tile_block_;
201 team_size_ = lat_tile_ * lat_tile_ * r_tile_;
202 blocks_ = local_subdomains_ * lat_tiles_ * lat_tiles_ * r_tiles_;
204 r_min_ = domain_info.
radii()[0];
205 r_max_ = domain_info.
radii()[domain_info.
radii().size() - 1];
208 update_kernel_path_flag_host_only();
210 util::logroot <<
"[EpsilonDivDiv] tile size (x,y,r)=(" << lat_tile_ <<
"," << lat_tile_ <<
"," << r_tile_
211 <<
"), r_passes=" << r_passes_ << std::endl;
212 util::logroot <<
"[EpsilonDivDiv] number of tiles (x,y,r)=(" << lat_tiles_ <<
"," << lat_tiles_ <<
","
213 << r_tiles_ <<
"), team_size=" << team_size_ <<
", blocks=" << blocks_ << std::endl;
214 const char* path_name = ( kernel_path_ == KernelPath::Slow ) ?
"slow" :
215 ( kernel_path_ == KernelPath::FastFreeslip ) ?
"fast-freeslip" :
216 "fast-dirichlet-neumann";
217 util::logroot <<
"[EpsilonDivDiv] kernel path = " << path_name << std::endl;
224 operator_apply_mode_ = operator_apply_mode;
225 operator_communication_mode_ = operator_communication_mode;
236 update_kernel_path_flag_host_only();
244 KOKKOS_INLINE_FUNCTION
246 const int local_subdomain_id,
252 return util::has_flag( mask_( local_subdomain_id, x_cell, y_cell, r_cell ), flag );
260 operator_stored_matrix_mode_ = operator_stored_matrix_mode;
265 domain_, operator_stored_matrix_mode_, level_range, GCAElements );
269 update_kernel_path_flag_host_only();
271 util::logroot <<
"[EpsilonDivDiv] (set_stored_matrix_mode) kernel path = "
272 << (( kernel_path_ == KernelPath::Slow ) ?
"slow" :
273 ( kernel_path_ == KernelPath::FastFreeslip ) ?
"fast-freeslip" :
274 "fast-dirichlet-neumann")
280 KOKKOS_INLINE_FUNCTION
282 const int local_subdomain_id,
290 local_matrix_storage_.
set_matrix( local_subdomain_id, x_cell, y_cell, r_cell, wedge, mat );
293 KOKKOS_INLINE_FUNCTION
295 const int local_subdomain_id,
299 const int wedge )
const
303 if ( !local_matrix_storage_.
has_matrix( local_subdomain_id, x_cell, y_cell, r_cell, wedge ) )
305 Kokkos::abort(
"No matrix found at that spatial index." );
307 return local_matrix_storage_.
get_matrix( local_subdomain_id, x_cell, y_cell, r_cell, wedge );
337 util::Timer timer_kernel(
"epsilon_divdiv_kernel" );
338 Kokkos::TeamPolicy<> policy( blocks_, team_size_ );
341 if ( kernel_path_ != KernelPath::Slow )
343 policy.set_scratch_size( 0, Kokkos::PerTeam(
team_shmem_size( team_size_ ) ) );
347 if ( kernel_path_ == KernelPath::Slow )
349 Kokkos::parallel_for(
350 "epsilon_divdiv_apply_kernel_slow", policy, KOKKOS_CLASS_LAMBDA(
const Team& team ) {
351 this->run_team_slow( team );
354 else if ( kernel_path_ == KernelPath::FastFreeslip )
358 Kokkos::parallel_for(
359 "epsilon_divdiv_apply_kernel_fast_fs_diag",
361 KOKKOS_CLASS_LAMBDA(
const Team& team ) {
362 this->
template run_team_fast_freeslip< true >( team );
367 Kokkos::parallel_for(
368 "epsilon_divdiv_apply_kernel_fast_fs_matvec",
370 KOKKOS_CLASS_LAMBDA(
const Team& team ) {
371 this->
template run_team_fast_freeslip< false >( team );
377 Kokkos::TeamPolicy< Kokkos::LaunchBounds< 128, 5 > > dn_policy( blocks_, team_size_ );
381 Kokkos::parallel_for(
382 "epsilon_divdiv_apply_kernel_fast_dn_diag",
384 KOKKOS_CLASS_LAMBDA(
const Team& team ) {
385 this->
template run_team_fast_dirichlet_neumann< true >( team );
390 Kokkos::parallel_for(
391 "epsilon_divdiv_apply_kernel_fast_dn_matvec",
393 KOKKOS_CLASS_LAMBDA(
const Team& team ) {
394 this->
template run_team_fast_dirichlet_neumann< false >( team );
419 KOKKOS_INLINE_FUNCTION
433 E00 = E11 = E22 = sym01 = sym02 = sym12 = gdd = 0.0;
464 KOKKOS_INLINE_FUNCTION
467 const int nlev = r_tile_ + 1;
468 const int n = lat_tile_ + 1;
469 const int nxy = n * n;
472 const size_t nscalars =
473 size_t( nxy ) * 3 + size_t( nxy ) * 3 + size_t( nxy ) * 3 * nlev + size_t( nxy ) * nlev + size_t( nlev ) + 1;
478 KOKKOS_INLINE_FUNCTION
481 const int nlev = r_tile_block_ + 1;
482 const int n = lat_tile_ + 1;
483 const int nxy = n * n;
486 const size_t nscalars =
487 size_t( nxy ) * 3 + size_t( nxy ) * 3 * nlev + size_t( nxy ) * nlev + size_t( nlev );
499 KOKKOS_INLINE_FUNCTION
500 void decode_team_indices(
502 int& local_subdomain_id,
513 int tmp = team.league_rank();
515 const int r_tile_id = tmp % r_tiles_;
518 const int lat_y_id = tmp % lat_tiles_;
521 const int lat_x_id = tmp % lat_tiles_;
524 local_subdomain_id = tmp;
526 x0 = lat_x_id * lat_tile_;
527 y0 = lat_y_id * lat_tile_;
528 r0 = r_tile_id * r_tile_block_;
530 const int tid = team.team_rank();
532 tx = ( tid / r_tile_ ) % lat_tile_;
533 ty = tid / ( r_tile_ * lat_tile_ );
555 KOKKOS_INLINE_FUNCTION
556 void run_team_slow(
const Team& team )
const
558 int local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell;
559 decode_team_indices( team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell );
564 const bool at_cmb = has_flag( local_subdomain_id, x_cell, y_cell, r_cell, CMB );
565 const bool at_surface = has_flag( local_subdomain_id, x_cell, y_cell, r_cell + 1, SURFACE );
568 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell, at_cmb, at_surface );
577 template <
bool Diagonal >
578 KOKKOS_INLINE_FUNCTION
579 void run_team_fast_dirichlet_neumann(
const Team& team )
const
581 int local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell;
582 decode_team_indices( team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell );
587 operator_fast_dirichlet_neumann_path< Diagonal >(
588 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell );
597 template <
bool Diagonal >
598 KOKKOS_INLINE_FUNCTION
599 void run_team_fast_freeslip(
const Team& team )
const
601 int local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell;
602 decode_team_indices( team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell );
607 const bool at_cmb = has_flag( local_subdomain_id, x_cell, y_cell, r_cell, CMB );
608 const bool at_surface = has_flag( local_subdomain_id, x_cell, y_cell, r_cell + 1, SURFACE );
610 operator_fast_freeslip_path< Diagonal >(
611 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell, at_cmb, at_surface );
615 KOKKOS_INLINE_FUNCTION
616 void operator_slow_path(
618 const int local_subdomain_id,
629 const bool at_surface )
const
639 if ( x_cell >= hex_lat_ || y_cell >= hex_lat_ || r_cell >= hex_rad_ )
646 A[0] = local_matrix_storage_.
get_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 0 );
647 A[1] = local_matrix_storage_.
get_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 1 );
651 if ( local_matrix_storage_.
has_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 0 ) &&
652 local_matrix_storage_.
has_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 1 ) )
654 A[0] = local_matrix_storage_.
get_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 0 );
655 A[1] = local_matrix_storage_.
get_matrix( local_subdomain_id, x_cell, y_cell, r_cell, 1 );
670 for (
int dimj = 0; dimj < 3; dimj++ )
684 dense::Mat< ScalarT, LocalMatrixDim, LocalMatrixDim > boundary_mask;
685 boundary_mask.fill( 1.0 );
687 bool freeslip_reorder =
false;
690 if ( at_cmb || at_surface )
695 if ( bcf == DIRICHLET )
697 for (
int dimi = 0; dimi < 3; ++dimi )
699 for (
int dimj = 0; dimj < 3; ++dimj )
705 if ( ( at_cmb && ( ( dimi == dimj && i != j && ( i < 3 || j < 3 ) ) ||
706 ( dimi != dimj && ( i < 3 || j < 3 ) ) ) ) ||
707 ( at_surface && ( ( dimi == dimj && i != j && ( i >= 3 || j >= 3 ) ) ||
708 ( dimi != dimj && ( i >= 3 || j >= 3 ) ) ) ) )
718 else if ( bcf == FREESLIP )
720 freeslip_reorder =
true;
723 for (
int wedge = 0; wedge < 2; ++wedge )
725 for (
int dimi = 0; dimi < 3; ++dimi )
729 for (
int dimj = 0; dimj < 3; ++dimj )
733 A_tmp[wedge]( node_idxi * 3 + dimi, node_idxj * 3 + dimj ) = A[wedge](
743 constexpr int layer_hex_offset_x[2][3] = { { 0, 1, 0 }, { 1, 0, 1 } };
744 constexpr int layer_hex_offset_y[2][3] = { { 0, 0, 1 }, { 1, 1, 0 } };
746 for (
int wedge = 0; wedge < 2; ++wedge )
750 R[wedge]( i, i ) = 1.0;
753 for (
int boundary_node_idx = 0; boundary_node_idx < 3; boundary_node_idx++ )
757 x_cell + layer_hex_offset_x[wedge][boundary_node_idx],
758 y_cell + layer_hex_offset_y[wedge][boundary_node_idx],
759 r_cell + ( at_cmb ? 0 : 1 ),
765 const int offset_in_R = at_cmb ? 0 : 9;
766 for (
int dimi = 0; dimi < 3; ++dimi )
768 for (
int dimj = 0; dimj < 3; ++dimj )
771 offset_in_R + boundary_node_idx * 3 + dimi,
772 offset_in_R + boundary_node_idx * 3 + dimj ) = R_i( dimi, dimj );
777 A[wedge] = R[wedge] * A_tmp[wedge] * R[wedge].
transposed();
779 auto src_tmp = R[wedge] * src[wedge];
780 for (
int i = 0; i < 18; ++i )
782 src[wedge]( i ) = src_tmp( i );
785 const int node_start = at_surface ? 3 : 0;
786 const int node_end = at_surface ? 6 : 3;
788 for (
int node_idx = node_start; node_idx < node_end; node_idx++ )
790 const int idx = node_idx * 3;
791 for (
int k = 0; k < 18; ++k )
795 boundary_mask( idx, k ) = 0.0;
796 boundary_mask( k, idx ) = 0.0;
816 dst[0] = A[0] * src[0];
817 dst[1] = A[1] * src[1];
819 if ( freeslip_reorder )
823 dst_tmp[1] = R[1].transposed() * dst[1];
825 for (
int i = 0; i < 18; ++i )
827 dst[0]( i ) = dst_tmp[0]( i );
828 dst[1]( i ) = dst_tmp[1]( i );
835 for (
int dimi = 0; dimi < 3; dimi++ )
842 dst_, local_subdomain_id, x_cell, y_cell, r_cell, dimi, dst_d );
847 template <
bool Diagonal >
848 KOKKOS_INLINE_FUNCTION
849 void operator_fast_dirichlet_neumann_path(
851 const int local_subdomain_id,
859 const int y_cell )
const
861 const int nlev = r_tile_block_ + 1;
862 const int nxy = ( lat_tile_ + 1 ) * ( lat_tile_ + 1 );
865 reinterpret_cast< double*
>( team.team_shmem().get_shmem(
team_shmem_size_dn( team.team_size() ) ) );
867 using ScratchCoords =
868 Kokkos::View< double**, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
869 using ScratchSrc = Kokkos::
870 View< double***, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
872 Kokkos::View< double**, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
874 ScratchCoords coords_sh( shmem, nxy, 3 );
877 ScratchSrc src_sh( shmem, nxy, 3, nlev );
878 shmem += nxy * 3 * nlev;
880 ScratchK k_sh( shmem, nxy, nlev );
884 Kokkos::View< double*, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >(
887 auto node_id = [&](
int nx,
int ny ) ->
int {
return nx + ( lat_tile_ + 1 ) * ny; };
889 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, nxy ), [&](
int n ) {
890 const int dxn = n % ( lat_tile_ + 1 );
891 const int dyn = n / ( lat_tile_ + 1 );
892 const int xi = x0 + dxn;
893 const int yi = y0 + dyn;
895 if ( xi <= hex_lat_ && yi <= hex_lat_ )
897 coords_sh( n, 0 ) = grid_( local_subdomain_id, xi, yi, 0 );
898 coords_sh( n, 1 ) = grid_( local_subdomain_id, xi, yi, 1 );
899 coords_sh( n, 2 ) = grid_( local_subdomain_id, xi, yi, 2 );
903 coords_sh( n, 0 ) = coords_sh( n, 1 ) = coords_sh( n, 2 ) = 0.0;
907 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, nlev ), [&](
int lvl ) {
908 const int rr = r0 + lvl;
909 r_sh( lvl ) = ( rr <= hex_rad_ ) ? radii_( local_subdomain_id, rr ) : 0.0;
912 const int total_pairs = nxy * nlev;
913 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, total_pairs ), [&](
int t ) {
914 const int node = t / nlev;
915 const int lvl = t - node * nlev;
917 const int dxn = node % ( lat_tile_ + 1 );
918 const int dyn = node / ( lat_tile_ + 1 );
920 const int xi = x0 + dxn;
921 const int yi = y0 + dyn;
922 const int rr = r0 + lvl;
924 if ( xi <= hex_lat_ && yi <= hex_lat_ && rr <= hex_rad_ )
926 k_sh( node, lvl ) = k_( local_subdomain_id, xi, yi, rr );
927 src_sh( node, 0, lvl ) = src_( local_subdomain_id, xi, yi, rr, 0 );
928 src_sh( node, 1, lvl ) = src_( local_subdomain_id, xi, yi, rr, 1 );
929 src_sh( node, 2, lvl ) = src_( local_subdomain_id, xi, yi, rr, 2 );
933 k_sh( node, lvl ) = 0.0;
934 src_sh( node, 0, lvl ) = src_sh( node, 1, lvl ) = src_sh( node, 2, lvl ) = 0.0;
940 if ( x_cell >= hex_lat_ || y_cell >= hex_lat_ )
943 constexpr double ONE_THIRD = 1.0 / 3.0;
944 constexpr double ONE_SIXTH = 1.0 / 6.0;
946 static constexpr double dN_ref[6][3] = {
947 { -0.5, -0.5, -ONE_SIXTH },
948 { 0.5, 0.0, -ONE_SIXTH },
949 { 0.0, 0.5, -ONE_SIXTH },
950 { -0.5, -0.5, ONE_SIXTH },
951 { 0.5, 0.0, ONE_SIXTH },
952 { 0.0, 0.5, ONE_SIXTH } };
954 static constexpr int WEDGE_NODE_OFF[2][6][3] = {
955 { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 0, 1, 1 } },
956 { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 1, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } } };
958 const int n00 = node_id( tx, ty );
959 const int n01 = node_id( tx, ty + 1 );
960 const int n10 = node_id( tx + 1, ty );
961 const int n11 = node_id( tx + 1, ty + 1 );
965 const int r_cell = r0 + tr;
967 if ( r_cell >= hex_rad_ )
970 const double r_0 = r_sh( lvl0 );
971 const double r_1 = r_sh( lvl0 + 1 );
973 const bool at_cmb =
has_flag( local_subdomain_id, x_cell, y_cell, r_cell, CMB );
974 const bool at_surface =
has_flag( local_subdomain_id, x_cell, y_cell, r_cell + 1, SURFACE );
976 const bool at_boundary = at_cmb || at_surface;
977 bool treat_boundary_dirichlet =
false;
984 const int cmb_shift = ( ( at_boundary && treat_boundary_dirichlet && ( !Diagonal ) && at_cmb ) ? 3 : 0 );
986 ( ( at_boundary && treat_boundary_dirichlet && ( !Diagonal ) && at_surface ) ? 3 : 0 );
988 for (
int w = 0; w < 2; ++w )
990 const int v0 = w == 0 ? n00 : n11;
991 const int v1 = w == 0 ? n10 : n01;
992 const int v2 = w == 0 ? n01 : n10;
996 for (
int node = 0; node < 6; ++node )
998 const int nid = node_id( tx + WEDGE_NODE_OFF[w][node][0], ty + WEDGE_NODE_OFF[w][node][1] );
999 k_sum += k_sh( nid, lvl0 + WEDGE_NODE_OFF[w][node][2] );
1001 const double k_eval = ONE_SIXTH * k_sum;
1008 double gu10 = 0.0, gu11 = 0.0;
1009 double gu20 = 0.0, gu21 = 0.0, gu22 = 0.0;
1012 const double half_dr = 0.5 * ( r_1 - r_0 );
1013 const double r_mid = 0.5 * ( r_0 + r_1 );
1015 const double J_0_0 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v1, 0 ) );
1016 const double J_0_1 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v2, 0 ) );
1017 const double J_0_2 =
1018 half_dr * ( ONE_THIRD * ( coords_sh( v0, 0 ) + coords_sh( v1, 0 ) + coords_sh( v2, 0 ) ) );
1020 const double J_1_0 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v1, 1 ) );
1021 const double J_1_1 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v2, 1 ) );
1022 const double J_1_2 =
1023 half_dr * ( ONE_THIRD * ( coords_sh( v0, 1 ) + coords_sh( v1, 1 ) + coords_sh( v2, 1 ) ) );
1025 const double J_2_0 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v1, 2 ) );
1026 const double J_2_1 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v2, 2 ) );
1027 const double J_2_2 =
1028 half_dr * ( ONE_THIRD * ( coords_sh( v0, 2 ) + coords_sh( v1, 2 ) + coords_sh( v2, 2 ) ) );
1030 const double J_det = J_0_0 * J_1_1 * J_2_2 - J_0_0 * J_1_2 * J_2_1 -
1031 J_0_1 * J_1_0 * J_2_2 + J_0_1 * J_1_2 * J_2_0 +
1032 J_0_2 * J_1_0 * J_2_1 - J_0_2 * J_1_1 * J_2_0;
1034 kwJ =
k_eval * Kokkos::abs( J_det );
1036 const double inv_det = 1.0 /
J_det;
1038 const double i00 = inv_det * ( J_1_1 * J_2_2 - J_1_2 * J_2_1 );
1039 const double i01 = inv_det * ( -J_1_0 * J_2_2 + J_1_2 * J_2_0 );
1040 const double i02 = inv_det * ( J_1_0 * J_2_1 - J_1_1 * J_2_0 );
1041 const double i10 = inv_det * ( -J_0_1 * J_2_2 + J_0_2 * J_2_1 );
1042 const double i11 = inv_det * ( J_0_0 * J_2_2 - J_0_2 * J_2_0 );
1043 const double i12 = inv_det * ( -J_0_0 * J_2_1 + J_0_1 * J_2_0 );
1044 const double i20 = inv_det * ( J_0_1 * J_1_2 - J_0_2 * J_1_1 );
1045 const double i21 = inv_det * ( -J_0_0 * J_1_2 + J_0_2 * J_1_0 );
1046 const double i22 = inv_det * ( J_0_0 * J_1_1 - J_0_1 * J_1_0 );
1053 const double gx = dN_ref[n][0];
1054 const double gy = dN_ref[n][1];
1055 const double gz = dN_ref[n][2];
1056 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1057 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1058 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1060 const int ddx = WEDGE_NODE_OFF[w][n][0];
1061 const int ddy = WEDGE_NODE_OFF[w][n][1];
1062 const int ddr = WEDGE_NODE_OFF[w][n][2];
1063 const int nid = node_id( tx + ddx, ty + ddy );
1064 const int lvl = lvl0 + ddr;
1066 const double s0 = src_sh( nid, 0, lvl );
1067 const double s1 = src_sh( nid, 1, lvl );
1068 const double s2 = src_sh( nid, 2, lvl );
1073 gu10 += 0.5 * (
g1 * s0 + g0 * s1 );
1074 gu20 += 0.5 * (
g2 * s0 + g0 * s2 );
1075 gu21 += 0.5 * (
g2 * s1 +
g1 * s2 );
1084 const double half_dr = 0.5 * ( r_1 - r_0 );
1085 const double r_mid = 0.5 * ( r_0 + r_1 );
1087 const double J_0_0 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v1, 0 ) );
1088 const double J_0_1 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v2, 0 ) );
1089 const double J_0_2 =
1090 half_dr * ( ONE_THIRD * ( coords_sh( v0, 0 ) + coords_sh( v1, 0 ) + coords_sh( v2, 0 ) ) );
1092 const double J_1_0 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v1, 1 ) );
1093 const double J_1_1 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v2, 1 ) );
1094 const double J_1_2 =
1095 half_dr * ( ONE_THIRD * ( coords_sh( v0, 1 ) + coords_sh( v1, 1 ) + coords_sh( v2, 1 ) ) );
1097 const double J_2_0 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v1, 2 ) );
1098 const double J_2_1 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v2, 2 ) );
1099 const double J_2_2 =
1100 half_dr * ( ONE_THIRD * ( coords_sh( v0, 2 ) + coords_sh( v1, 2 ) + coords_sh( v2, 2 ) ) );
1102 const double J_det = J_0_0 * J_1_1 * J_2_2 - J_0_0 * J_1_2 * J_2_1 -
1103 J_0_1 * J_1_0 * J_2_2 + J_0_1 * J_1_2 * J_2_0 +
1104 J_0_2 * J_1_0 * J_2_1 - J_0_2 * J_1_1 * J_2_0;
1106 const double inv_det = 1.0 /
J_det;
1108 const double i00 = inv_det * ( J_1_1 * J_2_2 - J_1_2 * J_2_1 );
1109 const double i01 = inv_det * ( -J_1_0 * J_2_2 + J_1_2 * J_2_0 );
1110 const double i02 = inv_det * ( J_1_0 * J_2_1 - J_1_1 * J_2_0 );
1111 const double i10 = inv_det * ( -J_0_1 * J_2_2 + J_0_2 * J_2_1 );
1112 const double i11 = inv_det * ( J_0_0 * J_2_2 - J_0_2 * J_2_0 );
1113 const double i12 = inv_det * ( -J_0_0 * J_2_1 + J_0_1 * J_2_0 );
1114 const double i20 = inv_det * ( J_0_1 * J_1_2 - J_0_2 * J_1_1 );
1115 const double i21 = inv_det * ( -J_0_0 * J_1_2 + J_0_2 * J_1_0 );
1116 const double i22 = inv_det * ( J_0_0 * J_1_1 - J_0_1 * J_1_0 );
1120 constexpr double NEG_TWO_THIRDS = -0.66666666666666663;
1124 const double gx = dN_ref[n][0];
1125 const double gy = dN_ref[n][1];
1126 const double gz = dN_ref[n][2];
1127 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1128 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1129 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1131 const int ddx = WEDGE_NODE_OFF[w][n][0];
1132 const int ddy = WEDGE_NODE_OFF[w][n][1];
1133 const int ddr = WEDGE_NODE_OFF[w][n][2];
1135 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 0 ),
1136 kwJ * ( 2.0 * ( g0 * gu00 + g1 * gu10 + g2 * gu20 ) +
1137 NEG_TWO_THIRDS * g0 * div_u ) );
1139 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 1 ),
1140 kwJ * ( 2.0 * ( g0 * gu10 + g1 * gu11 + g2 * gu21 ) +
1141 NEG_TWO_THIRDS * g1 * div_u ) );
1143 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 2 ),
1144 kwJ * ( 2.0 * ( g0 * gu20 + g1 * gu21 + g2 * gu22 ) +
1145 NEG_TWO_THIRDS * g2 * div_u ) );
1149 if ( Diagonal || ( treat_boundary_dirichlet && at_boundary ) )
1152 for (
int n = surface_shift; n < 6 -
cmb_shift; ++n )
1154 const double gx = dN_ref[n][0];
1155 const double gy = dN_ref[n][1];
1156 const double gz = dN_ref[n][2];
1157 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1158 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1159 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1160 const double gg = g0 * g0 +
g1 *
g1 +
g2 *
g2;
1162 const int nid = node_id( tx + WEDGE_NODE_OFF[w][n][0], ty + WEDGE_NODE_OFF[w][n][1] );
1163 const int lvl = lvl0 + WEDGE_NODE_OFF[w][n][2];
1165 const double sv0 = src_sh( nid, 0, lvl );
1166 const double sv1 = src_sh( nid, 1, lvl );
1167 const double sv2 = src_sh( nid, 2, lvl );
1169 const int ddx = WEDGE_NODE_OFF[w][n][0];
1170 const int ddy = WEDGE_NODE_OFF[w][n][1];
1171 const int ddr = WEDGE_NODE_OFF[w][n][2];
1173 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 0 ),
1174 kwJ * sv0 * ( gg + ONE_THIRD * g0 * g0 ) );
1176 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 1 ),
1177 kwJ * sv1 * ( gg + ONE_THIRD * g1 * g1 ) );
1179 &dst_( local_subdomain_id, x_cell + ddx, y_cell + ddy, r_cell + ddr, 2 ),
1180 kwJ * sv2 * ( gg + ONE_THIRD * g2 * g2 ) );
1190 KOKKOS_INLINE_FUNCTION
1191 void normalize3(
double& x,
double& y,
double& z )
const
1193 const double n2 = x * x + y * y + z * z;
1196 const double invn = 1.0 / Kokkos::sqrt( n2 );
1203 KOKKOS_INLINE_FUNCTION
1204 void project_tangential_inplace(
1212 const double dot = nx * ux + ny * uy + nz * uz;
1218 template <
bool Diagonal >
1219 KOKKOS_INLINE_FUNCTION
1220 void operator_fast_freeslip_path(
1222 const int local_subdomain_id,
1233 const bool at_surface )
const
1235 const int nlev = r_tile_ + 1;
1236 const int nxy = ( lat_tile_ + 1 ) * ( lat_tile_ + 1 );
1239 reinterpret_cast< double*
>( team.team_shmem().get_shmem(
team_shmem_size( team.team_size() ) ) );
1241 using ScratchCoords =
1242 Kokkos::View< double**, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
1243 using ScratchSrc = Kokkos::
1244 View< double***, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
1246 Kokkos::View< double**, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >;
1248 ScratchCoords coords_sh( shmem, nxy, 3 );
1252 ScratchCoords normals_sh( shmem, nxy, 3 );
1255 ScratchSrc src_sh( shmem, nxy, 3, nlev );
1256 shmem += nxy * 3 * nlev;
1258 ScratchK k_sh( shmem, nxy, nlev );
1259 shmem += nxy * nlev;
1262 Kokkos::View< double*, Kokkos::LayoutRight, typename Team::scratch_memory_space, Kokkos::MemoryUnmanaged >(
1265 auto node_id = [&](
int nx,
int ny ) ->
int {
return nx + ( lat_tile_ + 1 ) * ny; };
1268 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, nxy ), [&](
int n ) {
1269 const int dxn = n % ( lat_tile_ + 1 );
1270 const int dyn = n / ( lat_tile_ + 1 );
1271 const int xi = x0 + dxn;
1272 const int yi = y0 + dyn;
1274 if ( xi <= hex_lat_ && yi <= hex_lat_ )
1276 const double cx = grid_( local_subdomain_id, xi, yi, 0 );
1277 const double cy = grid_( local_subdomain_id, xi, yi, 1 );
1278 const double cz = grid_( local_subdomain_id, xi, yi, 2 );
1279 coords_sh( n, 0 ) = cx;
1280 coords_sh( n, 1 ) = cy;
1281 coords_sh( n, 2 ) = cz;
1283 const double n2 = cx * cx + cy * cy + cz * cz;
1286 const double invn = 1.0 / Kokkos::sqrt( n2 );
1287 normals_sh( n, 0 ) = cx * invn;
1288 normals_sh( n, 1 ) = cy * invn;
1289 normals_sh( n, 2 ) = cz * invn;
1293 normals_sh( n, 0 ) = normals_sh( n, 1 ) = normals_sh( n, 2 ) = 0.0;
1298 coords_sh( n, 0 ) = coords_sh( n, 1 ) = coords_sh( n, 2 ) = 0.0;
1299 normals_sh( n, 0 ) = normals_sh( n, 1 ) = normals_sh( n, 2 ) = 0.0;
1303 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, nlev ), [&](
int lvl ) {
1304 const int rr = r0 + lvl;
1305 r_sh( lvl ) = ( rr <= hex_rad_ ) ? radii_( local_subdomain_id, rr ) : 0.0;
1308 const int total_pairs = nxy * nlev;
1309 Kokkos::parallel_for( Kokkos::TeamThreadRange( team, total_pairs ), [&](
int t ) {
1310 const int node = t / nlev;
1311 const int lvl = t - node * nlev;
1313 const int dxn = node % ( lat_tile_ + 1 );
1314 const int dyn = node / ( lat_tile_ + 1 );
1316 const int xi = x0 + dxn;
1317 const int yi = y0 + dyn;
1318 const int rr = r0 + lvl;
1320 if ( xi <= hex_lat_ && yi <= hex_lat_ && rr <= hex_rad_ )
1322 k_sh( node, lvl ) = k_( local_subdomain_id, xi, yi, rr );
1323 src_sh( node, 0, lvl ) = src_( local_subdomain_id, xi, yi, rr, 0 );
1324 src_sh( node, 1, lvl ) = src_( local_subdomain_id, xi, yi, rr, 1 );
1325 src_sh( node, 2, lvl ) = src_( local_subdomain_id, xi, yi, rr, 2 );
1329 k_sh( node, lvl ) = 0.0;
1330 src_sh( node, 0, lvl ) = src_sh( node, 1, lvl ) = src_sh( node, 2, lvl ) = 0.0;
1334 team.team_barrier();
1336 if ( x_cell >= hex_lat_ || y_cell >= hex_lat_ || r_cell >= hex_rad_ )
1339 const int lvl0 = tr;
1340 const double r_0 = r_sh( lvl0 );
1341 const double r_1 = r_sh( lvl0 + 1 );
1346 const bool cmb_freeslip = at_cmb && ( cmb_bc ==
FREESLIP );
1347 const bool surf_freeslip = at_surface && ( surface_bc ==
FREESLIP );
1348 const bool cmb_dirichlet = at_cmb && ( cmb_bc ==
DIRICHLET );
1349 const bool surface_dirichlet = at_surface && ( surface_bc ==
DIRICHLET );
1351 const int cmb_shift = ( ( cmb_dirichlet && ( !Diagonal ) ) ? 3 : 0 );
1352 const int surface_shift = ( ( surface_dirichlet && ( !Diagonal ) ) ? 3 : 0 );
1354 static constexpr int WEDGE_NODE_OFF[2][6][3] = {
1355 { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 0, 1, 1 } },
1356 { { 1, 1, 0 }, { 0, 1, 0 }, { 1, 0, 0 }, { 1, 1, 1 }, { 0, 1, 1 }, { 1, 0, 1 } } };
1358 static constexpr int WEDGE_TO_UNIQUE[2][6] = {
1359 { 0, 1, 2, 3, 4, 5 },
1360 { 6, 2, 1, 7, 5, 4 }
1363 constexpr double ONE_THIRD = 1.0 / 3.0;
1364 constexpr double ONE_SIXTH = 1.0 / 6.0;
1365 constexpr double NEG_TWO_THIRDS = -0.66666666666666663;
1367 static constexpr double dN_ref[6][3] = {
1368 { -0.5, -0.5, -ONE_SIXTH },
1369 { 0.5, 0.0, -ONE_SIXTH },
1370 { 0.0, 0.5, -ONE_SIXTH },
1371 { -0.5, -0.5, ONE_SIXTH },
1372 { 0.5, 0.0, ONE_SIXTH },
1373 { 0.0, 0.5, ONE_SIXTH } };
1375 const int n00 = node_id( tx, ty );
1376 const int n01 = node_id( tx, ty + 1 );
1377 const int n10 = node_id( tx + 1, ty );
1378 const int n11 = node_id( tx + 1, ty + 1 );
1381 const int corner_node[4] = { n00, n10, n01, n11 };
1383 static constexpr int CMB_CORNER_TO_UNIQUE[4] = { 0, 1, 2, 6 };
1384 static constexpr int SURF_CORNER_TO_UNIQUE[4] = { 3, 4, 5, 7 };
1386 double dst8[3][8] = { { 0.0 } };
1390 double Ann_acc_cmb[4] = {};
1391 double Ann_acc_surf[4] = {};
1393 for (
int w = 0; w < 2; ++w )
1395 const int v0 = w == 0 ? n00 : n11;
1396 const int v1 = w == 0 ? n10 : n01;
1397 const int v2 = w == 0 ? n01 : n10;
1401 for (
int node = 0; node < 6; ++node )
1403 const int ddx = WEDGE_NODE_OFF[w][node][0];
1404 const int ddy = WEDGE_NODE_OFF[w][node][1];
1405 const int ddr = WEDGE_NODE_OFF[w][node][2];
1407 const int nid = node_id( tx + ddx, ty + ddy );
1408 const int lvl = lvl0 + ddr;
1409 k_sum += k_sh( nid, lvl );
1411 const double k_eval = ONE_SIXTH * k_sum;
1414 double i00, i01, i02;
1415 double i10, i11, i12;
1416 double i20, i21, i22;
1419 const double half_dr = 0.5 * ( r_1 - r_0 );
1420 const double r_mid = 0.5 * ( r_0 + r_1 );
1422 const double J_0_0 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v1, 0 ) );
1423 const double J_0_1 = r_mid * ( -coords_sh( v0, 0 ) + coords_sh( v2, 0 ) );
1424 const double J_0_2 = half_dr * ( ONE_THIRD * ( coords_sh( v0, 0 ) + coords_sh( v1, 0 ) + coords_sh( v2, 0 ) ) );
1426 const double J_1_0 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v1, 1 ) );
1427 const double J_1_1 = r_mid * ( -coords_sh( v0, 1 ) + coords_sh( v2, 1 ) );
1428 const double J_1_2 = half_dr * ( ONE_THIRD * ( coords_sh( v0, 1 ) + coords_sh( v1, 1 ) + coords_sh( v2, 1 ) ) );
1430 const double J_2_0 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v1, 2 ) );
1431 const double J_2_1 = r_mid * ( -coords_sh( v0, 2 ) + coords_sh( v2, 2 ) );
1432 const double J_2_2 = half_dr * ( ONE_THIRD * ( coords_sh( v0, 2 ) + coords_sh( v1, 2 ) + coords_sh( v2, 2 ) ) );
1434 const double J_det = J_0_0 * J_1_1 * J_2_2 - J_0_0 * J_1_2 * J_2_1 - J_0_1 * J_1_0 * J_2_2 +
1435 J_0_1 * J_1_2 * J_2_0 + J_0_2 * J_1_0 * J_2_1 - J_0_2 * J_1_1 * J_2_0;
1437 const double invJ = 1.0 /
J_det;
1439 i00 = invJ * ( J_1_1 * J_2_2 - J_1_2 * J_2_1 );
1440 i01 = invJ * ( -J_1_0 * J_2_2 + J_1_2 * J_2_0 );
1441 i02 = invJ * ( J_1_0 * J_2_1 - J_1_1 * J_2_0 );
1443 i10 = invJ * ( -J_0_1 * J_2_2 + J_0_2 * J_2_1 );
1444 i11 = invJ * ( J_0_0 * J_2_2 - J_0_2 * J_2_0 );
1445 i12 = invJ * ( -J_0_0 * J_2_1 + J_0_1 * J_2_0 );
1447 i20 = invJ * ( J_0_1 * J_1_2 - J_0_2 * J_1_1 );
1448 i21 = invJ * ( -J_0_0 * J_1_2 + J_0_2 * J_1_0 );
1449 i22 = invJ * ( J_0_0 * J_1_1 - J_0_1 * J_1_0 );
1451 wJ = Kokkos::abs( J_det );
1454 const double kwJ =
k_eval * wJ;
1457 static constexpr int CMB_NODE_TO_CORNER[2][3] = { { 0, 1, 2 }, { 3, 2, 1 } };
1460 double gu10 = 0.0, gu11 = 0.0;
1461 double gu20 = 0.0, gu21 = 0.0, gu22 = 0.0;
1471 const double gx = dN_ref[n][0];
1472 const double gy = dN_ref[n][1];
1473 const double gz = dN_ref[n][2];
1474 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1475 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1476 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1478 const int nid = node_id( tx + WEDGE_NODE_OFF[w][n][0], ty + WEDGE_NODE_OFF[w][n][1] );
1479 const int lvl = lvl0 + WEDGE_NODE_OFF[w][n][2];
1481 double s0 = src_sh( nid, 0, lvl );
1482 double s1 = src_sh( nid, 1, lvl );
1483 double s2 = src_sh( nid, 2, lvl );
1486 if ( cmb_freeslip && n < 3 )
1488 const double nx = normals_sh( nid, 0 );
1489 const double ny = normals_sh( nid, 1 );
1490 const double nz = normals_sh( nid, 2 );
1491 const double dot = nx * s0 + ny * s1 + nz * s2;
1496 if ( surf_freeslip && n >= 3 )
1498 const double nx = normals_sh( nid, 0 );
1499 const double ny = normals_sh( nid, 1 );
1500 const double nz = normals_sh( nid, 2 );
1501 const double dot = nx * s0 + ny * s1 + nz * s2;
1510 gu10 += 0.5 * (
g1 * s0 + g0 * s1 );
1511 gu20 += 0.5 * (
g2 * s0 + g0 * s2 );
1512 gu21 += 0.5 * (
g2 * s1 +
g1 * s2 );
1521 const double gx = dN_ref[n][0];
1522 const double gy = dN_ref[n][1];
1523 const double gz = dN_ref[n][2];
1524 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1525 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1526 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1528 const int uid = WEDGE_TO_UNIQUE[w][n];
1530 kwJ * ( 2.0 * ( g0 * gu00 +
g1 * gu10 +
g2 * gu20 ) + NEG_TWO_THIRDS * g0 * div_u );
1532 kwJ * ( 2.0 * ( g0 * gu10 +
g1 * gu11 +
g2 * gu21 ) + NEG_TWO_THIRDS * g1 * div_u );
1534 kwJ * ( 2.0 * ( g0 * gu20 +
g1 * gu21 +
g2 * gu22 ) + NEG_TWO_THIRDS * g2 * div_u );
1537 if ( cmb_freeslip && n < 3 )
1539 const int corner = CMB_NODE_TO_CORNER[w][n];
1540 const int cn = corner_node[corner];
1541 const double nxu = normals_sh( cn, 0 );
1542 const double nyu = normals_sh( cn, 1 );
1543 const double nzu = normals_sh( cn, 2 );
1544 const double gg = g0 * g0 +
g1 *
g1 +
g2 *
g2;
1545 const double ng = nxu * g0 + nyu *
g1 + nzu *
g2;
1546 Ann_acc_cmb[corner] += kwJ * ( gg + ONE_THIRD * ng * ng );
1548 if ( surf_freeslip && n >= 3 )
1550 const int corner = CMB_NODE_TO_CORNER[w][n - 3];
1551 const int cn = corner_node[corner];
1552 const double nxu = normals_sh( cn, 0 );
1553 const double nyu = normals_sh( cn, 1 );
1554 const double nzu = normals_sh( cn, 2 );
1555 const double gg = g0 * g0 +
g1 *
g1 +
g2 *
g2;
1556 const double ng = nxu * g0 + nyu *
g1 + nzu *
g2;
1557 Ann_acc_surf[corner] += kwJ * ( gg + ONE_THIRD * ng * ng );
1563 if ( Diagonal || cmb_dirichlet || surface_dirichlet )
1567 for (
int n = surface_shift; n < 6 -
cmb_shift; ++n )
1569 if ( Diagonal && cmb_freeslip && n < 3 )
1571 if ( Diagonal && surf_freeslip && n >= 3 )
1574 const double gx = dN_ref[n][0];
1575 const double gy = dN_ref[n][1];
1576 const double gz = dN_ref[n][2];
1577 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1578 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1579 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1580 const double gg = g0 * g0 +
g1 *
g1 +
g2 *
g2;
1582 const int uid = WEDGE_TO_UNIQUE[w][n];
1583 const int nid = node_id( tx + WEDGE_NODE_OFF[w][n][0], ty + WEDGE_NODE_OFF[w][n][1] );
1584 const int lvl = lvl0 + WEDGE_NODE_OFF[w][n][2];
1585 const double s0 = src_sh( nid, 0, lvl );
1586 const double s1 = src_sh( nid, 1, lvl );
1587 const double s2 = src_sh( nid, 2, lvl );
1589 dst8[0][uid] += kwJ * s0 * ( gg + ONE_THIRD * g0 * g0 );
1590 dst8[1][uid] += kwJ * s1 * ( gg + ONE_THIRD *
g1 *
g1 );
1591 dst8[2][uid] += kwJ * s2 * ( gg + ONE_THIRD *
g2 *
g2 );
1598 static constexpr int FS_CORNER_MAP[2][3] = { { 0, 1, 2 }, { 3, 2, 1 } };
1600 auto apply_rotated_diag =
1601 [&](
const int ni,
const int node_idx,
const int src_lvl ) {
1602 const int corner = FS_CORNER_MAP[w][ni];
1603 const int cn = corner_node[corner];
1604 const double nxu = normals_sh( cn, 0 );
1605 const double nyu = normals_sh( cn, 1 );
1606 const double nzu = normals_sh( cn, 2 );
1607 const int u = WEDGE_TO_UNIQUE[w][node_idx];
1609 const double gx = dN_ref[node_idx][0];
1610 const double gy = dN_ref[node_idx][1];
1611 const double gz = dN_ref[node_idx][2];
1613 const double g0 = i00 * gx + i01 * gy + i02 * gz;
1614 const double g1 = i10 * gx + i11 * gy + i12 * gz;
1615 const double g2 = i20 * gx + i21 * gy + i22 * gz;
1616 const double gg_loc = g0 * g0 +
g1 *
g1 +
g2 *
g2;
1618 dense::Vec< double, 3 > n_vec;
1622 const auto R_rot = trafo_mat_cartesian_to_normal_tangential< double >( n_vec );
1626 const double s0 = src_sh( cn, 0, src_lvl );
1627 const double s1 = src_sh( cn, 1, src_lvl );
1628 const double s2 = src_sh( cn, 2, src_lvl );
1630 const double Rg0 = R_rot( 0, 0 ) * g0 + R_rot( 0, 1 ) *
g1 + R_rot( 0, 2 ) *
g2;
1631 const double Rg1 = R_rot( 1, 0 ) * g0 + R_rot( 1, 1 ) *
g1 + R_rot( 1, 2 ) *
g2;
1632 const double Rg2 = R_rot( 2, 0 ) * g0 + R_rot( 2, 1 ) *
g1 + R_rot( 2, 2 ) *
g2;
1633 const double Rs0 = R_rot( 0, 0 ) * s0 + R_rot( 0, 1 ) * s1 + R_rot( 0, 2 ) * s2;
1634 const double Rs1 = R_rot( 1, 0 ) * s0 + R_rot( 1, 1 ) * s1 + R_rot( 1, 2 ) * s2;
1635 const double Rs2 = R_rot( 2, 0 ) * s0 + R_rot( 2, 1 ) * s1 + R_rot( 2, 2 ) * s2;
1637 const double v0 = kwJ * ( gg_loc + ONE_THIRD * Rg0 * Rg0 ) * Rs0;
1638 const double v1 = kwJ * ( gg_loc + ONE_THIRD * Rg1 * Rg1 ) * Rs1;
1639 const double v2 = kwJ * ( gg_loc + ONE_THIRD * Rg2 * Rg2 ) * Rs2;
1641 dst8[0][u] += R_rot( 0, 0 ) * v0 + R_rot( 1, 0 ) * v1 + R_rot( 2, 0 ) * v2;
1642 dst8[1][u] += R_rot( 0, 1 ) * v0 + R_rot( 1, 1 ) * v1 + R_rot( 2, 1 ) * v2;
1643 dst8[2][u] += R_rot( 0, 2 ) * v0 + R_rot( 1, 2 ) * v1 + R_rot( 2, 2 ) * v2;
1648 for (
int ni = 0; ni < 3; ++ni )
1649 apply_rotated_diag( ni, ni, lvl0 );
1651 if ( surf_freeslip )
1653 for (
int ni = 0; ni < 3; ++ni )
1654 apply_rotated_diag( ni, ni + 3, lvl0 + 1 );
1661 if ( !Diagonal && cmb_freeslip )
1663 for (
int c = 0; c < 4; ++c )
1665 const double nx = normals_sh( corner_node[c], 0 );
1666 const double ny = normals_sh( corner_node[c], 1 );
1667 const double nz = normals_sh( corner_node[c], 2 );
1668 const int u = CMB_CORNER_TO_UNIQUE[c];
1669 const double dot = nx * dst8[0][u] + ny * dst8[1][u] + nz * dst8[2][u];
1670 dst8[0][u] -=
dot * nx;
1671 dst8[1][u] -=
dot * ny;
1672 dst8[2][u] -=
dot * nz;
1675 if ( !Diagonal && surf_freeslip )
1677 for (
int c = 0; c < 4; ++c )
1679 const double nx = normals_sh( corner_node[c], 0 );
1680 const double ny = normals_sh( corner_node[c], 1 );
1681 const double nz = normals_sh( corner_node[c], 2 );
1682 const int u = SURF_CORNER_TO_UNIQUE[c];
1683 const double dot = nx * dst8[0][u] + ny * dst8[1][u] + nz * dst8[2][u];
1684 dst8[0][u] -=
dot * nx;
1685 dst8[1][u] -=
dot * ny;
1686 dst8[2][u] -=
dot * nz;
1692 if ( !Diagonal && cmb_freeslip )
1694 for (
int c = 0; c < 4; ++c )
1696 const int cn = corner_node[c];
1697 const double nx = normals_sh( cn, 0 );
1698 const double ny = normals_sh( cn, 1 );
1699 const double nz = normals_sh( cn, 2 );
1700 const double os0 = src_sh( cn, 0, lvl0 );
1701 const double os1 = src_sh( cn, 1, lvl0 );
1702 const double os2 = src_sh( cn, 2, lvl0 );
1703 const double u_n_val = nx * os0 + ny * os1 + nz * os2;
1704 const double corr = Ann_acc_cmb[c] * u_n_val;
1705 const int u = CMB_CORNER_TO_UNIQUE[c];
1706 dst8[0][u] += corr * nx;
1707 dst8[1][u] += corr * ny;
1708 dst8[2][u] += corr * nz;
1711 if ( !Diagonal && surf_freeslip )
1713 for (
int c = 0; c < 4; ++c )
1715 const int cn = corner_node[c];
1716 const double nx = normals_sh( cn, 0 );
1717 const double ny = normals_sh( cn, 1 );
1718 const double nz = normals_sh( cn, 2 );
1719 const double os0 = src_sh( cn, 0, lvl0 + 1 );
1720 const double os1 = src_sh( cn, 1, lvl0 + 1 );
1721 const double os2 = src_sh( cn, 2, lvl0 + 1 );
1722 const double u_n_val = nx * os0 + ny * os1 + nz * os2;
1723 const double corr = Ann_acc_surf[c] * u_n_val;
1724 const int u = SURF_CORNER_TO_UNIQUE[c];
1725 dst8[0][u] += corr * nx;
1726 dst8[1][u] += corr * ny;
1727 dst8[2][u] += corr * nz;
1733 for (
int dim_add = 0; dim_add < 3; ++dim_add )
1735 Kokkos::atomic_add( &dst_( local_subdomain_id, x_cell, y_cell, r_cell, dim_add ), dst8[dim_add][0] );
1736 Kokkos::atomic_add( &dst_( local_subdomain_id, x_cell + 1, y_cell, r_cell, dim_add ), dst8[dim_add][1] );
1737 Kokkos::atomic_add( &dst_( local_subdomain_id, x_cell, y_cell + 1, r_cell, dim_add ), dst8[dim_add][2] );
1738 Kokkos::atomic_add( &dst_( local_subdomain_id, x_cell, y_cell, r_cell + 1, dim_add ), dst8[dim_add][3] );
1740 &dst_( local_subdomain_id, x_cell + 1, y_cell, r_cell + 1, dim_add ), dst8[dim_add][4] );
1742 &dst_( local_subdomain_id, x_cell, y_cell + 1, r_cell + 1, dim_add ), dst8[dim_add][5] );
1744 &dst_( local_subdomain_id, x_cell + 1, y_cell + 1, r_cell, dim_add ), dst8[dim_add][6] );
1746 &dst_( local_subdomain_id, x_cell + 1, y_cell + 1, r_cell + 1, dim_add ), dst8[dim_add][7] );
1760 KOKKOS_INLINE_FUNCTION
1763 int local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell;
1764 decode_team_indices( team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell );
1766 if ( tr >= r_tile_ )
1769 const bool at_cmb =
has_flag( local_subdomain_id, x_cell, y_cell, r_cell, CMB );
1770 const bool at_surface =
has_flag( local_subdomain_id, x_cell, y_cell, r_cell + 1, SURFACE );
1772 if ( kernel_path_ == KernelPath::Slow )
1775 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell, at_cmb, at_surface );
1777 else if ( kernel_path_ == KernelPath::FastFreeslip )
1780 operator_fast_freeslip_path< true >(
1781 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell, at_cmb, at_surface );
1783 operator_fast_freeslip_path< false >(
1784 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell, r_cell, at_cmb, at_surface );
1789 operator_fast_dirichlet_neumann_path< true >(
1790 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell );
1792 operator_fast_dirichlet_neumann_path< false >(
1793 team, local_subdomain_id, x0, y0, r0, tx, ty, tr, x_cell, y_cell );
1812 const auto det = J.det();
1813 const auto abs_det = Kokkos::abs( det );
1819 k_eval +=
shape( k, quad_point ) * k_local_hex[wedge]( k );
1824 sym_grad_i[k] =
symmetric_grad( J_inv_transposed, quad_point, k, dimi );
1825 sym_grad_j[k] =
symmetric_grad( J_inv_transposed, quad_point, k, dimj );
1828 jdet_keval_quadweight = quad_weight * k_eval * abs_det;
1834 KOKKOS_INLINE_FUNCTION
1836 const int local_subdomain_id,
1840 const int wedge )
const
1845 const ScalarT r_1 = radii_( local_subdomain_id, r_cell );
1846 const ScalarT r_2 = radii_( local_subdomain_id, r_cell + 1 );
1853 for (
int dimi = 0; dimi < 3; ++dimi )
1855 for (
int dimj = 0; dimj < 3; ++dimj )
1857 for (
int q = 0; q < num_quad_points; q++ )
1875 jdet_keval_quadweight );
1882 jdet_keval_quadweight *
1884 2.0 / 3.0 * sym_grad_j[j]( dimj, dimj ) * sym_grad_i[i]( dimi, dimi ) );