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_;
216 template <
typename MemorySpace>
217 void allocate_storage()
const;
219 template <
typename To,
typename From>
220 void deep_copy_storage()
const;
222 template <
typename MemorySpace>
223 void deallocate_storage();
229 template <
typename,
int,
int,
int,
typename,
bool>
250 template <
typename Number,
254 typename MemorySpace,
259 static_assert(
warp_size % simd_length == 0,
260 "The warp size must be an integer multiple of the SIMD "
286 template <
bool other_writable>
293 other_writable> &other)
294 requires(!writable && other_writable);
296 template <
typename SparseMatrix>
298 requires(writable != std::is_const_v<SparseMatrix>);
323 template <
typename Number2 = Number>
324 DEAL_II_HOST_DEVICE Number2
325 read_entry(
const unsigned int row,
const unsigned int column_index)
const;
338 template <
typename Number2 = Number,
339 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
340 DEAL_II_HOST_DEVICE Tensor
341 read_tensor(
const unsigned int row,
const unsigned int column_index)
const;
356 template <
typename Number2 = Number>
358 const unsigned int row,
const unsigned int column_index)
const;
371 template <
typename Number2 = Number,
372 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
374 const unsigned int row,
const unsigned int column_index)
const;
389 template <
typename Number2 = Number>
390 DEAL_II_HOST_DEVICE
void
392 const unsigned int row,
393 const unsigned int column_index,
394 const bool do_streaming_store =
false) const
406 template <typename Number2 = Number,
407 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
408 DEAL_II_HOST_DEVICE
void
410 const
unsigned int row,
411 const
unsigned int column_index,
412 const
bool do_streaming_store = false) const
426 template <typename Number2 = Number>
428 const
unsigned int row,
429 const
unsigned int column_index) const
441 template <typename Number2 = Number,
442 typename Tensor = dealii::Tensor<1, n_comp, Number2>>
444 const
unsigned int row,
445 const
unsigned int column_index) const
460 void compress(dealii::VectorOperation::values operation) const
471 std::conditional_t<writable,
SM *, const
SM *> sparse_matrix_;
475 using KokkosSpace = typename MemorySpace::kokkos_space;
476 Kokkos::View<Number *, KokkosSpace> data_;
478 template <typename,
int,
int,
int, typename,
bool>
500 template <typename Number,
506 const FullMatrix &cell_matrix,
507 const std::vector<dealii::types::global_dof_index> &dof_indices_row,
508 const std::vector<dealii::types::global_dof_index> &dof_indices_column,
509 const dealii::AffineConstraints<Number> &affine_constraints,
517 template <typename Number,
524 const FullMatrix &cell_matrix,
525 const std::vector<dealii::types::global_dof_index> &dof_indices,
526 const dealii::AffineConstraints<Number> &affine_constraints,
538 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
543 reinit(sparsity, transfer_policy);
547 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
549 const SparsityPattern<warp_size> &sparsity,
558 this->sparsity_pattern_ = &sparsity;
560 const auto sparsity_view = sparsity.view();
562 using KokkosHost = dealii::MemorySpace::Host::kokkos_space;
563 using Aligned = Kokkos::MemoryTraits<Kokkos::Aligned>;
565 data_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
566 "sparse_matrix_data",
567 sparsity_view.n_nonzero_elements() * n_components);
569 const std::size_t n_indices = sparsity.entries_to_be_sent().size();
571 exchange_buffer_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
572 "sparse_matrix_exchange_buffer", n_components * n_indices);
575 const auto ghost_offset =
576 sparsity_view.template ghost_offset<n_components>();
577 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
579 ghost_buffer_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
580 "sparse_matrix_ghost_buffer", end_offset - ghost_offset);
590 exchange_buffer_default_ = {};
592 this->reset_residency(
true,
595 this->set_transfer_policy(transfer_policy);
599 template <
typename Number,
int n_comp,
int warp_size,
int simd_length>
600 template <
typename MemorySpace>
601 SparseMatrixView<Number, n_comp, warp_size, simd_length, MemorySpace, true>
604 this->
template prepare_write_access<MemorySpace>();
615 template <
typename Number,
int n_comp,
int warp_size,
int simd_length>
616 template <
typename MemorySpace>
617 SparseMatrixView<Number, n_comp, warp_size, simd_length, MemorySpace, false>
620 this->
template prepare_read_access<MemorySpace>();
631 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
632 template <
typename MemorySpace>
634 SparseMatrix<Number, n_components, warp_size, simd_length>::allocate_storage()
637 using HostSpace = dealii::MemorySpace::Host;
638 using Aligned = Kokkos::MemoryTraits<Kokkos::Aligned>;
640 Assert(sparsity_pattern_ !=
nullptr, dealii::ExcNotInitialized());
642 const auto sparsity_view = sparsity_pattern_->view();
649 const std::size_t n_data =
650 sparsity_view.n_nonzero_elements() * n_components;
651 const std::size_t n_exchange =
652 n_components * sparsity_pattern_->entries_to_be_sent().size();
654 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
655 data_host_ = Kokkos::View<Number *, KokkosHost, Aligned>(
656 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"sparse_matrix_data"),
660 data_default_ = Kokkos::View<Number *, KokkosDefault>(
661 Kokkos::view_alloc(Kokkos::WithoutInitializing,
"sparse_matrix_data"),
664 exchange_buffer_default_ = Kokkos::View<Number *, KokkosDefault>(
665 Kokkos::view_alloc(Kokkos::WithoutInitializing,
666 "sparse_matrix_exchange_buffer"),
672 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
673 template <
typename To,
typename From>
674 void SparseMatrix<Number, n_components, warp_size, simd_length>::
675 deep_copy_storage()
const
677 using HostSpace = dealii::MemorySpace::Host;
679 if constexpr (std::is_same_v<To, HostSpace>) {
680 Kokkos::deep_copy( data_host_, data_default_);
682 Kokkos::deep_copy( data_default_, data_host_);
687 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
688 template <
typename MemorySpace>
689 void SparseMatrix<Number, n_components, warp_size, simd_length>::
692 using HostSpace = dealii::MemorySpace::Host;
694 if constexpr (std::is_same_v<MemorySpace, HostSpace>) {
699 exchange_buffer_default_ = {};
704 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
705 template <
typename MemorySpace>
709 using HostSpace = dealii::MemorySpace::Host;
710 using DefaultSpace = dealii::MemorySpace::Default;
712 Assert(this->
template is_resident<MemorySpace>(),
713 dealii::ExcMessage(
"The chosen memory space is not resident."));
715 AssertThrow((std::is_same_v<MemorySpace, HostSpace>),
716 dealii::ExcNotImplemented());
718 const auto sparsity_view = sparsity_pattern_->view();
720 const auto ghost_offset =
721 sparsity_view.template ghost_offset<n_components>();
722 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
723 std::fill(data_host_.data() + ghost_offset,
724 data_host_.data() + end_offset,
729 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
730 template <
typename MemorySpace>
734 using HostSpace = dealii::MemorySpace::Host;
736 const auto sparsity_view = sparsity_pattern_->template view<MemorySpace>();
738 const auto *entries_to_be_sent =
739 sparsity_pattern_->entries_to_be_sent().template view<MemorySpace>();
740 const std::size_t n_entries_to_be_sent =
741 sparsity_pattern_->entries_to_be_sent().size();
747 constexpr bool on_host =
750 const auto data = [&]() {
751 if constexpr (on_host)
754 return data_default_;
757 const auto exchange_buffer = [&]() {
758 if constexpr (on_host)
759 return exchange_buffer_host_;
761 return exchange_buffer_default_;
764 using ExecutionSpace =
typename MemorySpace::kokkos_space::execution_space;
766 Kokkos::RangePolicy<ExecutionSpace, Kokkos::IndexType<std::size_t>>;
768 const auto exec = ExecutionSpace{};
770 Kokkos::parallel_for(
771 "sparse_matrix_populate_exchange_buffer",
772 Policy(exec, 0, n_entries_to_be_sent),
773 KOKKOS_LAMBDA(
const std::size_t c) {
774 const auto &[row, column_index] = entries_to_be_sent[c];
775 for (
unsigned int d = 0; d < n_components; ++d) {
776 const auto offset = sparsity_view.template offset<n_components>(
777 row, column_index, d);
778 exchange_buffer(n_components * c + d) = data(offset);
786 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
787 template <
typename MemorySpace>
791 using HostSpace = dealii::MemorySpace::Host;
793 Assert(this->
template is_resident<MemorySpace>(),
794 dealii::ExcMessage(
"The chosen memory space is not resident."));
796 constexpr bool on_host =
799 const auto sparsity_view = sparsity_pattern_->view();
801 const auto &receive_targets = sparsity_pattern_->receive_targets();
802 const auto &send_targets = sparsity_pattern_->send_targets();
804 const unsigned int mpi_tag =
805 dealii::Utilities::MPI::internal::Tags::partitioner_export_start + 0;
807 dealii::Utilities::MPI::internal::Tags::partitioner_export_end,
808 dealii::ExcInternalError());
810 const unsigned int n_requests =
811 receive_targets.size() + send_targets.size();
812 std::vector<MPI_Request> requests(n_requests);
814 const auto ghost_offset =
815 sparsity_view.template ghost_offset<n_components>();
816 const auto end_offset = sparsity_view.n_nonzero_elements() * n_components;
818 Number *
const receive_pointer =
819 on_host ? data_host_.data() + ghost_offset : ghost_buffer_host_.data();
820 Number *
const send_pointer = exchange_buffer_host_.data();
822 for (
unsigned int p = 0; p < receive_targets.size(); ++p) {
823 const auto receive_offset =
824 n_components * (p == 0 ? 0 : receive_targets[p - 1].second);
825 const auto receive_size =
826 (receive_targets[p].second * n_components - receive_offset);
828#ifdef DEBUG_MPI_EXCHANGE
829 const auto mpi_rank =
830 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
831 std::cout <<
"Rank " << mpi_rank <<
" receive from "
832 << receive_targets[p].first <<
" offset = " << receive_offset
833 <<
" size = " << receive_size << std::endl;
837 MPI_Irecv(receive_pointer + receive_offset,
839 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
840 receive_targets[p].first,
842 sparsity_pattern_->partitioner()->get_mpi_communicator(),
844 AssertThrowMPI(ierr);
847 populate_exchange_buffer_on_memory_space<MemorySpace>();
849 if constexpr (!on_host)
850 Kokkos::deep_copy( exchange_buffer_host_,
851 exchange_buffer_default_);
853 for (
unsigned int p = 0; p < send_targets.size(); ++p) {
854 const auto send_offset =
855 n_components * (p == 0 ? 0 : send_targets[p - 1].second);
856 const auto send_size =
857 (send_targets[p].second * n_components - send_offset);
859#ifdef DEBUG_MPI_EXCHANGE
860 const auto mpi_rank =
861 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
862 std::cout <<
"Rank " << mpi_rank <<
" send to " << send_targets[p].first
863 <<
" offset = " << send_offset <<
" size = " << send_size
868 MPI_Isend(send_pointer + send_offset,
870 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
871 send_targets[p].first,
873 sparsity_pattern_->partitioner()->get_mpi_communicator(),
874 &requests[receive_targets.size() + p]);
875 AssertThrowMPI(ierr);
878#ifdef DEBUG_MPI_EXCHANGE
879 using namespace std::chrono_literals;
880 std::this_thread::sleep_for(200ms);
884 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
885 AssertThrowMPI(ierr);
887 if constexpr (!on_host) {
889 const auto ghost_range =
890 Kokkos::subview(data_default_,
891 Kokkos::make_pair(std::size_t(ghost_offset),
892 std::size_t(end_offset)));
893 Kokkos::deep_copy( ghost_range, ghost_buffer_host_);
898 template <
typename Number,
int n_components,
int warp_size,
int simd_length>
899 template <
typename MemorySpace>
904 AssertThrow(operation == dealii::VectorOperation::add,
905 dealii::ExcNotImplemented());
907 using HostSpace = dealii::MemorySpace::Host;
908 using DefaultSpace = dealii::MemorySpace::Default;
910 AssertThrow((std::is_same_v<MemorySpace, HostSpace>),
911 dealii::ExcNotImplemented());
913 Assert(this->
template is_resident<MemorySpace>(),
914 dealii::ExcMessage(
"The chosen memory space is not resident."));
916 const auto sparsity_view = sparsity_pattern_->view();
918 const auto &receive_targets = sparsity_pattern_->receive_targets();
919 const auto &send_targets = sparsity_pattern_->send_targets();
920 const auto *entries_to_be_sent =
921 sparsity_pattern_->entries_to_be_sent().view();
922 const auto n_entries_to_be_sent =
923 sparsity_pattern_->entries_to_be_sent().size();
925 const unsigned int mpi_tag =
926 dealii::Utilities::MPI::internal::Tags::partitioner_export_start + 0;
928 dealii::Utilities::MPI::internal::Tags::partitioner_export_end,
929 dealii::ExcInternalError());
931 const unsigned int n_requests =
932 receive_targets.size() + send_targets.size();
933 std::vector<MPI_Request> requests(n_requests);
940 for (
unsigned int p = 0; p < send_targets.size(); ++p) {
941 const auto receive_offset =
942 n_components * (p == 0 ? 0 : send_targets[p - 1].second);
943 const auto receive_size =
944 (send_targets[p].second * n_components - receive_offset);
946#ifdef DEBUG_MPI_EXCHANGE
947 const auto mpi_rank =
948 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
949 std::cout <<
"Rank " << mpi_rank <<
" receive from "
950 << send_targets[p].first <<
" offset = " << receive_offset
951 <<
" size = " << receive_size << std::endl;
955 MPI_Irecv(exchange_buffer_host_.data() + receive_offset,
957 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
958 send_targets[p].first,
960 sparsity_pattern_->partitioner()->get_mpi_communicator(),
962 AssertThrowMPI(ierr);
965 const auto ghost_offset =
966 sparsity_view.template ghost_offset<n_components>();
973 for (
unsigned int p = 0; p < receive_targets.size(); ++p) {
974 const auto send_offset =
975 n_components * (p == 0 ? 0 : receive_targets[p - 1].second);
976 const auto send_size =
977 (receive_targets[p].second * n_components - send_offset);
979#ifdef DEBUG_MPI_EXCHANGE
980 const auto mpi_rank =
981 dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD);
982 std::cout <<
"Rank " << mpi_rank <<
" send to "
983 << receive_targets[p].first <<
" offset = " << send_offset
984 <<
" size = " << send_size << std::endl;
988 MPI_Isend(data_host_.data() + ghost_offset + send_offset,
990 dealii::Utilities::MPI::mpi_type_id_for_type<Number>,
991 receive_targets[p].first,
993 sparsity_pattern_->partitioner()->get_mpi_communicator(),
994 &requests[send_targets.size() + p]);
995 AssertThrowMPI(ierr);
998#ifdef DEBUG_MPI_EXCHANGE
999 using namespace std::chrono_literals;
1000 std::this_thread::sleep_for(200ms);
1004 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
1005 AssertThrowMPI(ierr);
1009 for (std::size_t c = 0; c < n_entries_to_be_sent; ++c) {
1010 const auto &[row, column_index] = entries_to_be_sent[c];
1011 for (
unsigned int d = 0; d < n_components; ++d) {
1013 sparsity_view.template offset<n_components>(row, column_index, d);
1014 data_host_(offset) += exchange_buffer_host_(n_components * c + d);
1018 zero_out_ghost_rows_on_memory_space<MemorySpace>();
1022 template <
typename Number,
1026 typename MemorySpace,
1035 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1042 template <
typename Number,
1046 typename MemorySpace,
1055 const SparseMatrix<Number, n_comp, warp_size, simd_length>
1063 template <
typename Number,
1067 typename MemorySpace,
1069 template <
bool other_writable>
1081 other_writable> &other)
1082 requires(!writable && other_writable)
1083 : sparse_matrix_(other.sparse_matrix_)
1084 , sparsity_pattern_(other.sparsity_pattern_)
1085 , data_(other.data_)
1090 template <
typename Number,
1094 typename MemorySpace,
1096 template <
typename SparseMatrix>
1102 writable>
::reinit(SparseMatrix &sparse_matrix)
1103 requires(writable != std::is_const_v<SparseMatrix>)
1105 using HostSpace = dealii::MemorySpace::Host;
1106 using DefaultSpace = dealii::MemorySpace::Default;
1108 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1109 std::is_same_v<MemorySpace, DefaultSpace>,
1110 "Unexpected Kokkos memory space");
1112 sparse_matrix_ = &sparse_matrix;
1119 !std::is_same_v<MemorySpace, HostSpace>) {
1120 data_ = sparse_matrix.data_default_;
1122 data_ = sparse_matrix.data_host_;
1126 sparse_matrix.sparsity_pattern_->template view<MemorySpace>();
1130 template <
typename Number,
1134 typename MemorySpace,
1136 template <
typename Number2>
1137 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number2
1144 const unsigned int column_index)
const
1148 "Attempted to write a scalar value into a tensor-valued matrix entry");
1150 const auto result = read_tensor<Number2>(row, column_index);
1155 template <
typename Number,
1159 typename MemorySpace,
1161 template <
typename Number2,
typename Tensor>
1162 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor
1169 const unsigned int column_index)
const
1171 static_assert(std::is_same_v<Number2, typename Tensor::value_type>,
1174 AssertIndexRange(row, sparsity_pattern_.n_rows());
1175 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1179 using VA = dealii::VectorizedArray<Number, simd_length>;
1180 if constexpr (std::is_same_v<VA, Number2>) {
1186 Assert(row < sparsity_pattern_.n_internal_dofs(),
1188 "Vectorized access only possible in vectorized part"));
1189 Assert(row % simd_length == 0,
1191 "Access only supported for rows at the SIMD granularity"));
1193 const Number *load_pos = data_.data();
1195 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1197 for (
unsigned int d = 0; d < n_comp; ++d)
1198 result[d].load(load_pos + d *
warp_size);
1205 for (
unsigned int d = 0; d < n_comp; ++d) {
1207 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1208 result[d] = data_(offset);
1216 template <
typename Number,
1220 typename MemorySpace,
1222 template <
typename Number2>
1223 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Number2
1235 "Attempted to write a scalar value into a tensor-valued matrix entry");
1237 const auto result = read_transposed_tensor<Number2>(row, column_index);
1242 template <
typename Number,
1246 typename MemorySpace,
1248 template <
typename Number2,
typename Tensor>
1249 DEAL_II_HOST_DEVICE_ALWAYS_INLINE Tensor
1259 static_assert(std::is_same_v<Number2, typename Tensor::value_type>,
1262 AssertIndexRange(row, sparsity_pattern_.n_rows());
1263 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1265 dealii::Tensor<1, n_comp, Number2> result;
1267 using VA = dealii::VectorizedArray<Number, simd_length>;
1268 if constexpr (std::is_same_v<VA, Number2> && (n_comp == 1)) {
1274 Assert(row < sparsity_pattern_.n_internal_dofs(),
1276 "Vectorized access only possible in vectorized part"));
1277 Assert(row % simd_length == 0,
1279 "Access only supported for rows at the SIMD granularity"));
1281 const auto offsets =
1282 sparsity_pattern_.template transposed_offset_internal<1>(
1284 result[0].gather(data_.data(), offsets);
1286 }
else if constexpr (std::is_same_v<VA, Number2> && (n_comp != 1)) {
1290 dealii::ExcMessage(
"Vectorized transposed access to multiple "
1291 "components is not implemented."));
1299 for (
unsigned int d = 0; d < n_comp; ++d) {
1301 sparsity_pattern_.template transposed_offset<n_comp>(
1302 row, column_index, d);
1303 result[d] = data_(offset);
1311 template <
typename Number,
1315 typename MemorySpace,
1317 template <
typename Number2>
1318 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1325 const unsigned int row,
1326 const unsigned int column_index,
1327 const bool do_streaming_store)
const
1332 "Attempted to write a scalar value into a tensor-valued matrix entry");
1334 AssertIndexRange(row, sparsity_pattern_.n_rows());
1335 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1337 dealii::Tensor<1, n_comp, Number2> tensor;
1340 write_tensor<Number2>(tensor, row, column_index, do_streaming_store);
1344 template <
typename Number,
1348 typename MemorySpace,
1350 template <
typename Number2,
typename Tensor>
1351 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1358 const unsigned int row,
1359 const unsigned int column_index,
1360 const bool do_streaming_store)
const
1363 AssertIndexRange(row, sparsity_pattern_.n_rows());
1364 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1366 using VA = dealii::VectorizedArray<Number, simd_length>;
1367 if constexpr (std::is_same_v<VA, Number2>) {
1373 Assert(row < sparsity_pattern_.n_internal_dofs(),
1375 "Vectorized access only possible in vectorized part"));
1376 Assert(row % simd_length == 0,
1378 "Access only supported for rows at the SIMD granularity"));
1380 Number *store_pos = data_.data();
1382 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1384 if (do_streaming_store)
1385 for (
unsigned int d = 0; d < n_comp; ++d)
1386 tensor[d].streaming_store(store_pos + d *
warp_size);
1388 for (
unsigned int d = 0; d < n_comp; ++d)
1389 tensor[d].store(store_pos + d *
warp_size);
1396 for (
unsigned int d = 0; d < n_comp; ++d) {
1398 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1399 data_(offset) = tensor[d];
1405 template <
typename Number,
1409 typename MemorySpace,
1411 template <
typename Number2>
1412 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1419 const unsigned int row,
1420 const unsigned int column_index)
const
1425 "Attempted to write a scalar value into a tensor-valued matrix entry");
1427 AssertIndexRange(row, sparsity_pattern_.n_rows());
1428 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1430 dealii::Tensor<1, n_comp, Number2> tensor;
1433 add_tensor<Number2>(tensor, row, column_index);
1437 template <
typename Number,
1441 typename MemorySpace,
1443 template <
typename Number2,
typename Tensor>
1444 DEAL_II_HOST_DEVICE_ALWAYS_INLINE
void
1451 const unsigned int row,
1452 const unsigned int column_index)
const
1455 AssertIndexRange(row, sparsity_pattern_.n_rows());
1456 AssertIndexRange(column_index, sparsity_pattern_.row_length(row));
1458 using VA = dealii::VectorizedArray<Number, simd_length>;
1459 if constexpr (std::is_same_v<VA, Number2>) {
1465 Assert(row < sparsity_pattern_.n_internal_dofs(),
1467 "Vectorized access only possible in vectorized part"));
1468 Assert(row % simd_length == 0,
1470 "Access only supported for rows at the SIMD granularity"));
1472 Number *store_pos = data_.data();
1474 sparsity_pattern_.template offset_internal<n_comp>(row, column_index);
1476 for (
unsigned int d = 0; d < n_comp; ++d) {
1477 auto temp = tensor[d];
1488 for (
unsigned int d = 0; d < n_comp; ++d) {
1490 sparsity_pattern_.template offset<n_comp>(row, column_index, d);
1491 data_(offset) += tensor[d];
1498 template <
typename Number,
1502 typename MemorySpace,
1512 using HostSpace = dealii::MemorySpace::Host;
1513 using DefaultSpace = dealii::MemorySpace::Default;
1515 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1516 std::is_same_v<MemorySpace, DefaultSpace>,
1517 "Unexpected Kokkos memory space");
1519 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1520 dealii::ExcMessage(
"The chosen memory space is not resident."));
1522 sparse_matrix_->template zero_out_ghost_rows_on_memory_space<MemorySpace>();
1526 template <
typename Number,
1530 typename MemorySpace,
1540 using HostSpace = dealii::MemorySpace::Host;
1541 using DefaultSpace = dealii::MemorySpace::Default;
1543 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1544 std::is_same_v<MemorySpace, DefaultSpace>,
1545 "Unexpected Kokkos memory space");
1547 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1548 dealii::ExcMessage(
"The chosen memory space is not resident."));
1550 sparse_matrix_->template update_ghost_rows_on_memory_space<MemorySpace>();
1554 template <
typename Number,
1558 typename MemorySpace,
1565 writable>
::compress(dealii::VectorOperation::values
1569 using HostSpace = dealii::MemorySpace::Host;
1570 using DefaultSpace = dealii::MemorySpace::Default;
1572 static_assert(std::is_same_v<MemorySpace, HostSpace> ||
1573 std::is_same_v<MemorySpace, DefaultSpace>,
1574 "Unexpected Kokkos memory space");
1576 Assert(sparse_matrix_->template is_resident<MemorySpace>(),
1577 dealii::ExcMessage(
"The chosen memory space is not resident."));
1579 sparse_matrix_->template compress_on_memory_space<MemorySpace>(operation);
1583 template <
typename Number,
1589 const FM &cell_matrix,
1590 const std::vector<dealii::types::global_dof_index> &dof_indices_row,
1591 const std::vector<dealii::types::global_dof_index> &dof_indices_column,
1592 const dealii::AffineConstraints<Number> &affine_constraints
1594 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1596 constexpr bool is_matrix = std::is_same_v<FM, dealii::FullMatrix<Number>>;
1597 constexpr bool is_array =
1598 std::is_same_v<FM, std::array<dealii::FullMatrix<Number>, n_comp>>;
1599 static_assert((n_comp == 1 && is_matrix) || is_array,
"not implemented");
1601 if constexpr (is_matrix) {
1602 Assert(cell_matrix.m() == dof_indices_row.size(),
1603 dealii::ExcInternalError());
1604 Assert(cell_matrix.n() == dof_indices_column.size(),
1605 dealii::ExcInternalError());
1606 }
else if constexpr (is_array) {
1607 Assert(cell_matrix.size() == n_comp, dealii::ExcInternalError());
1608 for (
unsigned int d = 0; d < n_comp; ++d) {
1609 Assert(cell_matrix[d].m() == dof_indices_row.size(),
1610 dealii::ExcInternalError());
1611 Assert(cell_matrix[d].n() == dof_indices_column.size(),
1612 dealii::ExcInternalError());
1616 const auto sparse_matrix_view = sparse_matrix.view();
1618 const auto &sparsity_pattern = sparse_matrix.sparsity_pattern();
1619 const auto sparsity_pattern_view = sparsity_pattern.view();
1620 const auto &partitioner = sparsity_pattern.partitioner();
1628 const auto insert_entry =
1629 [&](
auto r,
auto c,
auto i,
auto j,
auto c_ij) DEAL_II_ALWAYS_INLINE {
1630 if constexpr (is_matrix) {
1631 const Number &entry = cell_matrix(r, c);
1632 if (entry == Number{})
1634 const auto col_idx = sparsity_pattern_view.column_index(i, j);
1635 sparse_matrix_view.add_entry(c_ij * entry, i, col_idx);
1636 }
else if constexpr (is_array) {
1637 dealii::Tensor<1, n_comp, Number> entry;
1638 for (
unsigned int k = 0; k < n_comp; ++k)
1639 entry[k] = cell_matrix[k](r, c);
1640 if (entry == dealii::Tensor<1, n_comp>{})
1642 const auto col_idx = sparsity_pattern_view.column_index(i, j);
1643 sparse_matrix_view.add_tensor(c_ij * entry, i, col_idx);
1651 const auto iterate_over_row_entries =
1652 [&](
const auto r,
const auto i,
const auto c_i) DEAL_II_ALWAYS_INLINE {
1654 for (
unsigned int c = 0; c < dof_indices_column.size(); ++c) {
1655 const auto j_global = dof_indices_column[c];
1656 if (affine_constraints.is_constrained(j_global)) {
1658 *affine_constraints.get_constraint_entries(j_global);
1659 for (
const auto &[k_global, c_k] : line) {
1660 const auto k = partitioner->global_to_local(k_global);
1661 insert_entry(r, c, i, k, c_i * c_k);
1664 const auto j = partitioner->global_to_local(j_global);
1665 insert_entry(r, c, i, j, c_i);
1671 for (
unsigned int r = 0; r < dof_indices_row.size(); ++r) {
1672 const auto i_global = dof_indices_row[r];
1673 if (affine_constraints.is_constrained(i_global)) {
1674 const auto &line = *affine_constraints.get_constraint_entries(i_global);
1675 for (
const auto &[k_global, c_k] : line) {
1676 const auto k = partitioner->global_to_local(k_global);
1677 iterate_over_row_entries(r, k, c_k);
1680 const auto i = partitioner->global_to_local(i_global);
1681 iterate_over_row_entries(r, i, Number(1.));
1687 template <
typename Number,
1693 const FM &cell_matrix,
1694 const std::vector<dealii::types::global_dof_index> &dof_indices,
1695 const dealii::AffineConstraints<Number> &affine_constraints,
1696 SparseMatrix<Number, n_comp, warp_size, simd_length> &sparse_matrix)
1698 constexpr bool is_matrix = std::is_same_v<FM, dealii::FullMatrix<Number>>;
1699 constexpr bool is_array =
1700 std::is_same_v<FM, std::array<dealii::FullMatrix<Number>, n_comp>>;
1701 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)