8#include <compile_time_options.h>
13#include <deal.II/base/exceptions.h>
14#include <deal.II/base/partitioner.h>
15#include <deal.II/lac/affine_constraints.h>
16#include <deal.II/lac/dynamic_sparsity_pattern.h>
22#ifdef DEBUG_MPI_EXCHANGE
28 template <
typename Number,
32 typename MemorySpace = dealii::MemorySpace::Host,
34 class SparseMatrixView;
54 template <
typename Number,
57 int simd_length = dealii::VectorizedArray<Number>::size()>
59 SparseMatrix<Number, n_comp, warp_size, simd_length>>
62 static_assert(
warp_size % simd_length == 0,
63 "The warp size must be an integer multiple of the SIMD "
120 template <
typename MemorySpace = dealii::MemorySpace::Host>
131 template <
typename MemorySpace = dealii::MemorySpace::Host>
150 template <
typename MemorySpace>
157 template <
typename MemorySpace>
165 template <
typename MemorySpace>
177 template <
typename MemorySpace>
196 using KokkosHost = dealii::MemorySpace::Host::kokkos_space;
197 mutable Kokkos::View<Number *, KokkosHost> data_host_;
199 using KokkosDefault = dealii::MemorySpace::Default::kokkos_space;
200 mutable Kokkos::View<Number *, KokkosDefault> data_default_;
208 mutable Kokkos::View<Number *, KokkosHost> exchange_buffer_host_;
209 mutable Kokkos::View<Number *, KokkosHost> ghost_buffer_host_;
210 mutable Kokkos::View<Number *, KokkosDefault> exchange_buffer_default_;
212 std::vector<MPI_Request> requests_;
218 template <
typename MemorySpace>
219 void allocate_storage()
const;
221 template <
typename To,
typename From>
222 void deep_copy_storage()
const;
224 template <
typename MemorySpace>
225 void deallocate_storage();
231 template <
typename,
int,
int,
int,
typename,
bool>
252 template <
typename Number,
256 typename MemorySpace,
261 static_assert(
warp_size % simd_length == 0,
262 "The warp size must be an integer multiple of the SIMD "
288 template <
bool other_writable>
295 other_writable> &other)
296 requires(!writable && other_writable);
298 template <
typename SparseMatrix>
300 requires(writable != std::is_const_v<SparseMatrix>);
325 template <
typename Number2 = Number>
326 DEAL_II_HOST_DEVICE Number2
327 read_entry(
const unsigned int row,
const unsigned int column_index)
const;
340 template <
typename Number2 = Number,
341 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
342 DEAL_II_HOST_DEVICE Tensor
343 read_tensor(
const unsigned int row,
const unsigned int column_index)
const;
358 template <
typename Number2 = Number>
360 const unsigned int row,
const unsigned int column_index)
const;
373 template <
typename Number2 = Number,
374 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
376 const unsigned int row,
const unsigned int column_index)
const;
391 template <
typename Number2 = Number>
392 DEAL_II_HOST_DEVICE
void
394 const unsigned int row,
395 const unsigned int column_index,
396 const bool do_streaming_store =
false) const
408 template <typename Number2 = Number,
409 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
410 DEAL_II_HOST_DEVICE
void
412 const
unsigned int row,
413 const
unsigned int column_index,
414 const
bool do_streaming_store = false) const
428 template <typename Number2 = Number>
430 const
unsigned int row,
431 const
unsigned int column_index) const
443 template <typename Number2 = Number,
444 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
446 const
unsigned int row,
447 const
unsigned int column_index) const
462 void compress(dealii::VectorOperation::values operation) const
473 std::conditional_t<writable,
SM *, const
SM *> sparse_matrix_;
477 using KokkosSpace = typename MemorySpace::kokkos_space;
478 Kokkos::View<Number *, KokkosSpace> data_;
480 template <typename,
int,
int,
int, typename,
bool>
502 template <typename Number,
508 const FullMatrix &cell_matrix,
509 const std::vector<dealii::types::global_dof_index> &dof_indices_row,
510 const std::vector<dealii::types::global_dof_index> &dof_indices_column,
511 const dealii::AffineConstraints<Number> &affine_constraints,
519 template <typename Number,
526 const FullMatrix &cell_matrix,
527 const std::vector<dealii::types::global_dof_index> &dof_indices,
528 const dealii::AffineConstraints<Number> &affine_constraints,
540 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
545 reinit(sparsity, transfer_policy);
549 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
551 const SparsityPattern<warp_size> &sparsity,
560 this->sparsity_pattern_ = &sparsity;
562 const auto sparsity_view = sparsity.view();
564 using KokkosHost = dealii::MemorySpace::Host::kokkos_space;
565 using Aligned = Kokkos::MemoryTraits<Kokkos::Aligned>;
567 data_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
568 "sparse_matrix_data",
569 sparsity_view.n_nonzero_elements() * n_components);
571 const std::size_t n_indices = sparsity.entries_to_be_sent().size();
573 exchange_buffer_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
574 "sparse_matrix_exchange_buffer", n_components * n_indices);
577 const auto ghost_offset =
578 sparsity_view.template ghost_offset<n_components>();
579 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
581 ghost_buffer_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
582 "sparse_matrix_ghost_buffer", end_offset - ghost_offset);
592 exchange_buffer_default_ = {};
594 this->reset_residency(
true,
597 this->set_transfer_policy(transfer_policy);
601 template <
typename Number,
int n_comp,
int warp_size,
int simd_length>
602 template <
typename MemorySpace>
603 SparseMatrixView<Number, n_comp, warp_size, simd_length, MemorySpace, true>
606 this->
template prepare_write_access<MemorySpace>();
617 template <
typename Number,
int n_comp,
int warp_size,
int simd_length>
618 template <
typename MemorySpace>
619 SparseMatrixView<Number, n_comp, warp_size, simd_length, MemorySpace, false>
622 this->
template prepare_read_access<MemorySpace>();
633 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
634 template <
typename MemorySpace>
636 SparseMatrix<Number, n_components, warp_size, simd_length>::allocate_storage()
639 using HostSpace = dealii::MemorySpace::Host;
640 using Aligned = Kokkos::MemoryTraits<Kokkos::Aligned>;
642 Assert(sparsity_pattern_ !=
nullptr, dealii::ExcNotInitialized());
644 const auto sparsity_view = sparsity_pattern_->view();
651 const std::size_t n_data =
652 sparsity_view.n_nonzero_elements() * n_components;
653 const std::size_t n_exchange =
654 n_components * sparsity_pattern_->entries_to_be_sent().size();
656 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
657 data_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
658 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"sparse_matrix_data"),
662 data_default_ = Kokkos::View<Number *, KokkosDefault>(
663 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"sparse_matrix_data"),
666 exchange_buffer_default_ = Kokkos::View<Number *, KokkosDefault>(
667 Kokkos::view_alloc(Kokkos::WithoutInitializing,
668 "sparse_matrix_exchange_buffer"),
674 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
675 template <
typename To,
typename From>
676 void SparseMatrix<Number, n_components, warp_size, simd_length>::
677 deep_copy_storage()
const
679 using HostSpace = dealii::MemorySpace::Host;
681 if constexpr (std::is_same_v<To, HostSpace>) {
682 Kokkos::deep_copy( data_host_, data_default_);
684 Kokkos::deep_copy( data_default_, data_host_);
689 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
690 template <
typename MemorySpace>
691 void SparseMatrix<Number, n_components, warp_size, simd_length>::
694 using HostSpace = dealii::MemorySpace::Host;
696 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
701 exchange_buffer_default_ = {};
706 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
707 template <
typename MemorySpace>
711 using HostSpace = dealii::MemorySpace::Host;
712 using DefaultSpace = dealii::MemorySpace::Default;
714 Assert(this->
template is_resident<MemorySpace>(),
715 dealii::ExcMessage(
"The chosen memory space is not resident."));
717 AssertThrow((std::is_same_v<MemorySpace, HostSpace>),
718 dealii::ExcNotImplemented());
720 const auto sparsity_view = sparsity_pattern_->view();
722 const auto ghost_offset =
723 sparsity_view.template ghost_offset<n_components>();
724 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
725 std::fill(data_host_.data() + ghost_offset,
726 data_host_.data() + end_offset,
731 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
732 template <
typename MemorySpace>
736 using HostSpace = dealii::MemorySpace::Host;
738 const auto sparsity_view = sparsity_pattern_->template view<MemorySpace>();
740 const auto *entries_to_be_sent =
741 sparsity_pattern_->entries_to_be_sent().template view<MemorySpace>();
742 const std::size_t n_entries_to_be_sent =
743 sparsity_pattern_->entries_to_be_sent().size();
749 constexpr bool on_host =
752 const auto data = [&]() {
753 if constexpr (on_host)
756 return data_default_;
759 const auto exchange_buffer = [&]() {
760 if constexpr (on_host)
761 return exchange_buffer_host_;
763 return exchange_buffer_default_;
766 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
768 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<std::size_t>>;
770 const auto exec = ExecutionSpace{};
772 Kokkos::parallel_for(
773 "sparse_matrix_populate_exchange_buffer",
774 Policy(exec, 0, n_entries_to_be_sent),
775 KOKKOS_LAMBDA(
const std::size_t c) {
776 const auto &[row, column_index] = entries_to_be_sent[c];
777 for (
unsigned int d = 0; d < n_components; ++d) {
778 const auto offset = sparsity_view.template offset<n_components>(
779 row, column_index, d);
780 exchange_buffer(n_components * c + d) = data(offset);
788 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
789 template <
typename MemorySpace>
793 using HostSpace = dealii::MemorySpace::Host;
795 Assert(this->
template is_resident<MemorySpace>(),
796 dealii::ExcMessage(
"The chosen memory space is not resident."));
798 constexpr bool on_host =
801 const auto sparsity_view = sparsity_pattern_->view();
803 const auto &receive_targets = sparsity_pattern_->receive_targets();
804 const auto &send_targets = sparsity_pattern_->send_targets();
806 const unsigned int mpi_tag =
807 dealii::Utilities::MPI::internal::Tags::partitioner_export_start + 0;
809 dealii::Utilities::MPI::internal::Tags::partitioner_export_end,
810 dealii::ExcInternalError());
812 const unsigned int n_requests =
813 receive_targets.size() + send_targets.size();
814 std::vector<MPI_Request> requests(n_requests);
816 const auto ghost_offset =
817 sparsity_view.template ghost_offset<n_components>();
818 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
820 Number *
const receive_pointer =
821 on_host ? data_host_.data() + ghost_offset : ghost_buffer_host_.data();
822 Number *
const send_pointer = exchange_buffer_host_.data();
824 for (
unsigned int p = 0; p < receive_targets.size(); ++p) {
825 const auto receive_offset =
826 n_components * (p == 0 ? 0 : receive_targets[p - 1].second);
827 const auto receive_size =
828 (receive_targets[p].second * n_components - receive_offset);
830#ifdef DEBUG_MPI_EXCHANGE
831 const auto mpi_rank =
832 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
833 std::cout <<
"Rank " << mpi_rank <<
" receive from "
834 << receive_targets[p].first <<
" offset = " << receive_offset
835 <<
" size = " << receive_size << std::endl;
839 MPI_Irecv(receive_pointer + receive_offset,
841 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
842 receive_targets[p].first,
844 sparsity_pattern_->partitioner()->get_mpi_communicator(),
846 AssertThrowMPI(ierr);
849 populate_exchange_buffer_on_memory_space<MemorySpace>();
851 if constexpr (!on_host)
852 Kokkos::deep_copy( exchange_buffer_host_,
853 exchange_buffer_default_);
855 for (
unsigned int p = 0; p < send_targets.size(); ++p) {
856 const auto send_offset =
857 n_components * (p == 0 ? 0 : send_targets[p - 1].second);
858 const auto send_size =
859 (send_targets[p].second * n_components - send_offset);
861#ifdef DEBUG_MPI_EXCHANGE
862 const auto mpi_rank =
863 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
864 std::cout <<
"Rank " << mpi_rank <<
" send to " << send_targets[p].first
865 <<
" offset = " << send_offset <<
" size = " << send_size
870 MPI_Isend(send_pointer + send_offset,
872 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
873 send_targets[p].first,
875 sparsity_pattern_->partitioner()->get_mpi_communicator(),
876 &requests[receive_targets.size() + p]);
877 AssertThrowMPI(ierr);
880#ifdef DEBUG_MPI_EXCHANGE
881 using namespace std::chrono_literals;
882 std::this_thread::sleep_for(200ms);
886 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
887 AssertThrowMPI(ierr);
889 if constexpr (!on_host) {
891 const auto ghost_range =
892 Kokkos::subview(data_default_,
893 Kokkos::make_pair(std::size_t(ghost_offset),
894 std::size_t(end_offset)));
895 Kokkos::deep_copy( ghost_range, ghost_buffer_host_);
900 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
901 template <
typename MemorySpace>
906 AssertThrow(operation == dealii::VectorOperation::add,
907 dealii::ExcNotImplemented());
909 using HostSpace = dealii::MemorySpace::Host;
910 using DefaultSpace = dealii::MemorySpace::Default;
912 AssertThrow((std::is_same_v<MemorySpace, HostSpace>),
913 dealii::ExcNotImplemented());
915 Assert(this->
template is_resident<MemorySpace>(),
916 dealii::ExcMessage(
"The chosen memory space is not resident."));
918 const auto sparsity_view = sparsity_pattern_->view();
920 const auto &receive_targets = sparsity_pattern_->receive_targets();
921 const auto &send_targets = sparsity_pattern_->send_targets();
922 const auto *entries_to_be_sent =
923 sparsity_pattern_->entries_to_be_sent().view();
924 const auto n_entries_to_be_sent =
925 sparsity_pattern_->entries_to_be_sent().size();
927 const unsigned int mpi_tag =
928 dealii::Utilities::MPI::internal::Tags::partitioner_export_start + 0;
930 dealii::Utilities::MPI::internal::Tags::partitioner_export_end,
931 dealii::ExcInternalError());
933 const unsigned int n_requests =
934 receive_targets.size() + send_targets.size();
935 std::vector<MPI_Request> requests(n_requests);
942 for (
unsigned int p = 0; p < send_targets.size(); ++p) {
943 const auto receive_offset =
944 n_components * (p == 0 ? 0 : send_targets[p - 1].second);
945 const auto receive_size =
946 (send_targets[p].second * n_components - receive_offset);
948#ifdef DEBUG_MPI_EXCHANGE
949 const auto mpi_rank =
950 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
951 std::cout <<
"Rank " << mpi_rank <<
" receive from "
952 << send_targets[p].first <<
" offset = " << receive_offset
953 <<
" size = " << receive_size << std::endl;
957 MPI_Irecv(exchange_buffer_host_.data() + receive_offset,
959 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
960 send_targets[p].first,
962 sparsity_pattern_->partitioner()->get_mpi_communicator(),
964 AssertThrowMPI(ierr);
967 const auto ghost_offset =
968 sparsity_view.template ghost_offset<n_components>();
975 for (
unsigned int p = 0; p < receive_targets.size(); ++p) {
976 const auto send_offset =
977 n_components * (p == 0 ? 0 : receive_targets[p - 1].second);
978 const auto send_size =
979 (receive_targets[p].second * n_components - send_offset);
981#ifdef DEBUG_MPI_EXCHANGE
982 const auto mpi_rank =
983 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
984 std::cout <<
"Rank " << mpi_rank <<
" send to "
985 << receive_targets[p].first <<
" offset = " << send_offset
986 <<
" size = " << send_size << std::endl;
990 MPI_Isend(data_host_.data() + ghost_offset + send_offset,
992 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
993 receive_targets[p].first,
995 sparsity_pattern_->partitioner()->get_mpi_communicator(),
996 &requests[send_targets.size() + p]);
997 AssertThrowMPI(ierr);
1000#ifdef DEBUG_MPI_EXCHANGE
1001 using namespace std::chrono_literals;
1002 std::this_thread::sleep_for(200ms);
1006 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1007 AssertThrowMPI(ierr);
1011 for (std::size_t c = 0; c < n_entries_to_be_sent; ++c) {
1012 const auto &[row, column_index] = entries_to_be_sent[c];
1013 for (
unsigned int d = 0; d < n_components; ++d) {
1015 sparsity_view.template offset<n_components>(row, column_index, d);
1016 data_host_(offset) += exchange_buffer_host_(n_components * c + d);
1020 zero_out_ghost_rows_on_memory_space<MemorySpace>();
1024 template <
typename Number,
1028 typename MemorySpace,
1037 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1044 template <
typename Number,
1048 typename MemorySpace,
1057 const SparseMatrix<Number, n_comp, warp_size, simd_length>
1065 template <
typename Number,
1069 typename MemorySpace,
1071 template <
bool other_writable>
1083 other_writable> &other)
1084 requires(!writable && other_writable)
1085 : sparse_matrix_(other.sparse_matrix_)
1086 , sparsity_pattern_(other.sparsity_pattern_)
1087 , data_(other.data_)
1092 template <
typename Number,
1096 typename MemorySpace,
1098 template <
typename SparseMatrix>
1104 writable>
::reinit(SparseMatrix &sparse_matrix)
1105 requires(writable != std::is_const_v<SparseMatrix>)
1107 using HostSpace = dealii::MemorySpace::Host;
1108 using DefaultSpace = dealii::MemorySpace::Default;
1110 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1111 std::is_same_v<MemorySpace, DefaultSpace>,
1112 "Unexpected Kokkos memory space");
1114 sparse_matrix_ = &sparse_matrix;
1121 !std::is_same_v<MemorySpace, HostSpace>) {
1122 data_ = sparse_matrix.data_default_;
1124 data_ = sparse_matrix.data_host_;
1128 sparse_matrix.sparsity_pattern_->template view<MemorySpace>();
1132 template <
typename Number,
1136 typename MemorySpace,
1138 template <
typename Number2>
1139 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number2
1146 const unsigned int column_index)
const
1150 "Attempted to write a scalar value into a tensor-valued matrix entry");
1152 const auto result = read_tensor<Number2>(row, column_index);
1157 template <
typename Number,
1161 typename MemorySpace,
1163 template <
typename Number2,
typename Tensor>
1164 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor
1171 const unsigned int column_index)
const
1173 static_assert(std::is_same_v<Number2, typename Tensor::value_type>,
1176 AssertIndexRange(row, sparsity_pattern_.n_rows());
1177 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1181 using VA = dealii::VectorizedArray<Number, simd_length>;
1182 if constexpr (std::is_same_v<VA, Number2>) {
1188 Assert(row < sparsity_pattern_.n_internal_dofs(),
1190 "Vectorized access only possible in vectorized part"));
1191 Assert(row % simd_length == 0,
1193 "Access only supported for rows at the SIMD granularity"));
1195 const Number *load_pos = data_.data();
1197 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1199 for (
unsigned int d = 0; d < n_comp; ++d)
1200 result[d].load(load_pos + d *
warp_size);
1207 for (
unsigned int d = 0; d < n_comp; ++d) {
1209 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1210 result[d] = data_(offset);
1218 template <
typename Number,
1222 typename MemorySpace,
1224 template <
typename Number2>
1225 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number2
1237 "Attempted to write a scalar value into a tensor-valued matrix entry");
1239 const auto result = read_transposed_tensor<Number2>(row, column_index);
1244 template <
typename Number,
1248 typename MemorySpace,
1250 template <
typename Number2,
typename Tensor>
1251 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor
1261 static_assert(std::is_same_v<Number2, typename Tensor::value_type>,
1264 AssertIndexRange(row, sparsity_pattern_.n_rows());
1265 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1267 dealii::Tensor<1, n_comp, Number2> result;
1269 using VA = dealii::VectorizedArray<Number, simd_length>;
1270 if constexpr (std::is_same_v<VA, Number2> && (n_comp == 1)) {
1276 Assert(row < sparsity_pattern_.n_internal_dofs(),
1278 "Vectorized access only possible in vectorized part"));
1279 Assert(row % simd_length == 0,
1281 "Access only supported for rows at the SIMD granularity"));
1283 const auto offsets =
1284 sparsity_pattern_.template transposed_offset_internal<1>(
1286 result[0].gather(data_.data(), offsets);
1288 }
else if constexpr (std::is_same_v<VA, Number2> && (n_comp != 1)) {
1292 dealii::ExcMessage(
"Vectorized transposed access to multiple "
1293 "components is not implemented."));
1301 for (
unsigned int d = 0; d < n_comp; ++d) {
1303 sparsity_pattern_.template transposed_offset<n_comp>(
1304 row, column_index, d);
1305 result[d] = data_(offset);
1313 template <
typename Number,
1317 typename MemorySpace,
1319 template <
typename Number2>
1320 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1327 const unsigned int row,
1328 const unsigned int column_index,
1329 const bool do_streaming_store)
const
1334 "Attempted to write a scalar value into a tensor-valued matrix entry");
1336 AssertIndexRange(row, sparsity_pattern_.n_rows());
1337 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1339 dealii::Tensor<1, n_comp, Number2> tensor;
1342 write_tensor<Number2>(tensor, row, column_index, do_streaming_store);
1346 template <
typename Number,
1350 typename MemorySpace,
1352 template <
typename Number2,
typename Tensor>
1353 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1360 const unsigned int row,
1361 const unsigned int column_index,
1362 const bool do_streaming_store)
const
1365 AssertIndexRange(row, sparsity_pattern_.n_rows());
1366 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1368 using VA = dealii::VectorizedArray<Number, simd_length>;
1369 if constexpr (std::is_same_v<VA, Number2>) {
1375 Assert(row < sparsity_pattern_.n_internal_dofs(),
1377 "Vectorized access only possible in vectorized part"));
1378 Assert(row % simd_length == 0,
1380 "Access only supported for rows at the SIMD granularity"));
1382 Number *store_pos = data_.data();
1384 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1386 if (do_streaming_store)
1387 for (
unsigned int d = 0; d < n_comp; ++d)
1388 tensor[d].streaming_store(store_pos + d *
warp_size);
1390 for (
unsigned int d = 0; d < n_comp; ++d)
1391 tensor[d].store(store_pos + d *
warp_size);
1398 for (
unsigned int d = 0; d < n_comp; ++d) {
1400 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1401 data_(offset) = tensor[d];
1407 template <
typename Number,
1411 typename MemorySpace,
1413 template <
typename Number2>
1414 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1421 const unsigned int row,
1422 const unsigned int column_index)
const
1427 "Attempted to write a scalar value into a tensor-valued matrix entry");
1429 AssertIndexRange(row, sparsity_pattern_.n_rows());
1430 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1432 dealii::Tensor<1, n_comp, Number2> tensor;
1435 add_tensor<Number2>(tensor, row, column_index);
1439 template <
typename Number,
1443 typename MemorySpace,
1445 template <
typename Number2,
typename Tensor>
1446 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1453 const unsigned int row,
1454 const unsigned int column_index)
const
1457 AssertIndexRange(row, sparsity_pattern_.n_rows());
1458 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1460 using VA = dealii::VectorizedArray<Number, simd_length>;
1461 if constexpr (std::is_same_v<VA, Number2>) {
1467 Assert(row < sparsity_pattern_.n_internal_dofs(),
1469 "Vectorized access only possible in vectorized part"));
1470 Assert(row % simd_length == 0,
1472 "Access only supported for rows at the SIMD granularity"));
1474 Number *store_pos = data_.data();
1476 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1478 for (
unsigned int d = 0; d < n_comp; ++d) {
1479 auto temp = tensor[d];
1490 for (
unsigned int d = 0; d < n_comp; ++d) {
1492 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1493 data_(offset) += tensor[d];
1500 template <
typename Number,
1504 typename MemorySpace,
1514 using HostSpace = dealii::MemorySpace::Host;
1515 using DefaultSpace = dealii::MemorySpace::Default;
1517 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1518 std::is_same_v<MemorySpace, DefaultSpace>,
1519 "Unexpected Kokkos memory space");
1521 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1522 dealii::ExcMessage(
"The chosen memory space is not resident."));
1524 sparse_matrix_->template zero_out_ghost_rows_on_memory_space<MemorySpace>();
1528 template <
typename Number,
1532 typename MemorySpace,
1542 using HostSpace = dealii::MemorySpace::Host;
1543 using DefaultSpace = dealii::MemorySpace::Default;
1545 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1546 std::is_same_v<MemorySpace, DefaultSpace>,
1547 "Unexpected Kokkos memory space");
1549 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1550 dealii::ExcMessage(
"The chosen memory space is not resident."));
1552 sparse_matrix_->template update_ghost_rows_on_memory_space<MemorySpace>();
1556 template <
typename Number,
1560 typename MemorySpace,
1567 writable>
::compress(dealii::VectorOperation::values
1571 using HostSpace = dealii::MemorySpace::Host;
1572 using DefaultSpace = dealii::MemorySpace::Default;
1574 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1575 std::is_same_v<MemorySpace, DefaultSpace>,
1576 "Unexpected Kokkos memory space");
1578 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1579 dealii::ExcMessage(
"The chosen memory space is not resident."));
1581 sparse_matrix_->template compress_on_memory_space<MemorySpace>(operation);
1585 template <
typename Number,
1591 const FM &cell_matrix,
1592 const std::vector<dealii::types::global_dof_index> &dof_indices_row,
1593 const std::vector<dealii::types::global_dof_index> &dof_indices_column,
1594 const dealii::AffineConstraints<Number> &affine_constraints
1596 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1598 constexpr bool is_matrix = std::is_same_v<FM, dealii::FullMatrix<Number>>;
1599 constexpr bool is_array =
1600 std::is_same_v<FM, std::array<dealii::FullMatrix<Number>, n_comp>>;
1601 static_assert((n_comp == 1 && is_matrix) || is_array,
"not implemented");
1603 if constexpr (is_matrix) {
1604 Assert(cell_matrix.m() == dof_indices_row.size(),
1605 dealii::ExcInternalError());
1606 Assert(cell_matrix.n() == dof_indices_column.size(),
1607 dealii::ExcInternalError());
1608 }
else if constexpr (is_array) {
1609 Assert(cell_matrix.size() == n_comp, dealii::ExcInternalError());
1610 for (
unsigned int d = 0; d < n_comp; ++d) {
1611 Assert(cell_matrix[d].m() == dof_indices_row.size(),
1612 dealii::ExcInternalError());
1613 Assert(cell_matrix[d].n() == dof_indices_column.size(),
1614 dealii::ExcInternalError());
1618 const auto sparse_matrix_view = sparse_matrix.view();
1620 const auto &sparsity_pattern = sparse_matrix.sparsity_pattern();
1621 const auto sparsity_pattern_view = sparsity_pattern.view();
1622 const auto &partitioner = sparsity_pattern.partitioner();
1630 const auto insert_entry =
1631 [&](
auto r,
auto c,
auto i,
auto j,
auto c_ij) DEAL_II_ALWAYS_INLINE {
1632 if constexpr (is_matrix) {
1633 const Number &entry = cell_matrix(r, c);
1634 if (entry == Number{})
1636 const auto col_idx = sparsity_pattern_view.column_index(i, j);
1637 sparse_matrix_view.add_entry(c_ij * entry, i, col_idx);
1638 }
else if constexpr (is_array) {
1639 dealii::Tensor<1, n_comp, Number> entry;
1640 for (
unsigned int k = 0; k < n_comp; ++k)
1641 entry[k] = cell_matrix[k](r, c);
1642 if (entry == dealii::Tensor<1, n_comp>{})
1644 const auto col_idx = sparsity_pattern_view.column_index(i, j);
1645 sparse_matrix_view.add_tensor(c_ij * entry, i, col_idx);
1653 const auto iterate_over_row_entries =
1654 [&](
const auto r,
const auto i,
const auto c_i) DEAL_II_ALWAYS_INLINE {
1656 for (
unsigned int c = 0; c < dof_indices_column.size(); ++c) {
1657 const auto j_global = dof_indices_column[c];
1658 if (affine_constraints.is_constrained(j_global)) {
1660 *affine_constraints.get_constraint_entries(j_global);
1661 for (
const auto &[k_global, c_k] : line) {
1662 const auto k = partitioner->global_to_local(k_global);
1663 insert_entry(r, c, i, k, c_i * c_k);
1666 const auto j = partitioner->global_to_local(j_global);
1667 insert_entry(r, c, i, j, c_i);
1673 for (
unsigned int r = 0; r < dof_indices_row.size(); ++r) {
1674 const auto i_global = dof_indices_row[r];
1675 if (affine_constraints.is_constrained(i_global)) {
1676 const auto &line = *affine_constraints.get_constraint_entries(i_global);
1677 for (
const auto &[k_global, c_k] : line) {
1678 const auto k = partitioner->global_to_local(k_global);
1679 iterate_over_row_entries(r, k, c_k);
1682 const auto i = partitioner->global_to_local(i_global);
1683 iterate_over_row_entries(r, i, Number(1.));
1689 template <
typename Number,
1695 const FM &cell_matrix,
1696 const std::vector<dealii::types::global_dof_index> &dof_indices,
1697 const dealii::AffineConstraints<Number> &affine_constraints,
1698 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1700 constexpr bool is_matrix = std::is_same_v<FM, dealii::FullMatrix<Number>>;
1701 constexpr bool is_array =
1702 std::is_same_v<FM, std::array<dealii::FullMatrix<Number>, n_comp>>;
1703 static_assert((n_comp == 1 && is_matrix) || is_array,
"not implemented");
TransferPolicy transfer_policy() const
friend class SparseMatrixView
void zero_out_ghost_rows() const
DEAL_II_HOST_DEVICE Tensor read_transposed_tensor(const unsigned int row, const unsigned int column_index) const
ACCESSOR_READ_ONLY(sparsity_pattern)
DEAL_II_HOST_DEVICE Number2 read_transposed_entry(const unsigned int row, const unsigned int column_index) const
DEAL_II_HOST_DEVICE void write_tensor(const Tensor &tensor, const unsigned int row, const unsigned int column_index, const bool do_streaming_store=false) const
void reinit(SparseMatrix &sparse_matrix)
DEAL_II_HOST_DEVICE void add_tensor(const Tensor &tensor, const unsigned int row, const unsigned int column_index) const
SparseMatrixView(const SparseMatrix< Number, n_comp, warp_size, simd_length > &sparse_matrix)
SparseMatrixView()=default
DEAL_II_HOST_DEVICE void write_entry(const Number2 entry, const unsigned int row, const unsigned int column_index, const bool do_streaming_store=false) const
DEAL_II_HOST_DEVICE SparseMatrixView(const SparseMatrixView< Number, n_comp, warp_size, simd_length, MemorySpace, other_writable > &other)
DEAL_II_HOST_DEVICE Number2 read_entry(const unsigned int row, const unsigned int column_index) const
DEAL_II_HOST_DEVICE void add_entry(const Number2 entry, const unsigned int row, const unsigned int column_index) const
void update_ghost_rows() const
SparseMatrixView(SparseMatrix< Number, n_comp, warp_size, simd_length > &sparse_matrix)
DEAL_II_HOST_DEVICE Tensor read_tensor(const unsigned int row, const unsigned int column_index) const
void compress(dealii::VectorOperation::values operation) const
void populate_exchange_buffer_on_memory_space()
SparseMatrixView< Number, n_comp, warp_size, simd_length, MemorySpace, false > view() const
void compress_on_memory_space(dealii::VectorOperation::values operation)
void update_ghost_rows_on_memory_space()
void zero_out_ghost_rows_on_memory_space()
SparseMatrixView< Number, n_comp, warp_size, simd_length, MemorySpace, true > view()
ACCESSOR_READ_ONLY(sparsity_pattern)
void reinit(const SparsityPattern< warp_size > &sparsity, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers)
SparseMatrix(const SparsityPattern< warp_size > &sparsity, const TransferPolicy transfer_policy=TransferPolicy::explicit_transfers)
constexpr unsigned int warp_size
constexpr bool have_separate_memory_spaces
void distribute_local_to_global(const FullMatrix &cell_matrix, const std::vector< dealii::types::global_dof_index > &dof_indices_row, const std::vector< dealii::types::global_dof_index > &dof_indices_column, const dealii::AffineConstraints< Number > &affine_constraints, SparseMatrix< Number, n_comp, warp_size, simd_length > &sparse_matrix)