FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
alg_dof_parti_system.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include <kernel/adjacency/dynamic_graph.hpp>
9#include <kernel/global/alg_dof_parti.hpp>
10#include <kernel/global/filter.hpp>
11#include <kernel/global/matrix.hpp>
12#include <kernel/lafem/null_matrix.hpp>
13#include <kernel/lafem/sparse_matrix_csr.hpp>
14#include <kernel/lafem/sparse_matrix_bcsr.hpp>
15#include <kernel/lafem/saddle_point_matrix.hpp>
16#include <kernel/lafem/tuple_matrix.hpp>
17#include <kernel/lafem/unit_filter.hpp>
18#include <kernel/lafem/unit_filter_blocked.hpp>
19#include <kernel/lafem/mean_filter.hpp>
20#include <kernel/lafem/mean_filter_blocked.hpp>
21#include <kernel/lafem/none_filter.hpp>
22#include <kernel/lafem/slip_filter.hpp>
23#include <kernel/lafem/filter_chain.hpp>
24#include <kernel/lafem/filter_sequence.hpp>
25#include <kernel/lafem/tuple_filter.hpp>
26#include <kernel/global/mean_filter.hpp>
27#include <kernel/lafem/matrix_mirror.hpp>
28
29#include <algorithm>
30
31namespace FEAT
32{
33 namespace Global
34 {
36 namespace Intern
37 {
39 template<typename Matrix_>
40 class ADPDOMM;
41
43 template<typename Matrix_>
44 class ADPMatAux;
45
47 template<typename Filter_>
48 class ADPFilAux;
49 }
51
131 template<typename LocalMatrix_, typename LocalFilter_, typename Mirror_>
133 {
134 public:
136 typedef typename LocalMatrix_::DataType DataType;
138 typedef typename LocalMatrix_::IndexType IndexType;
139
141 typedef LocalMatrix_ LocalMatrixType;
143 typedef Mirror_ MirrorType;
146
148 typedef typename LocalMatrixType::VectorTypeR LocalVectorType;
149
151 typedef LocalFilter_ LocalFilterType;
152
155
160
163
166
169
173 typedef Intern::ADPDOMM<LocalMatrixType> OwnerMirrorType;
174
175 typedef Intern::ADPMatAux<LocalMatrixType> ADPMatAuxType;
176 typedef Intern::ADPFilAux<LocalFilterType> ADPFilAuxType;
177
178 //protected:
183
185 std::shared_ptr<AlgDofPartiType> _alg_dof_parti;
186
188 std::shared_ptr<Adjacency::Graph> _owned_graph;
189
192
195
197 std::vector<BufferMatrixType> _donee_bufs;
198 std::vector<BufferMatrixType> _owner_bufs;
199
201 std::vector<DoneeMirrorType> _donee_data_mirs;
202 std::vector<OwnerMirrorType> _owner_data_mirs;
203
206
209
210 public:
220 explicit AlgDofPartiSystem(const GlobalMatrixType& matrix, const GlobalFilterType& filter) :
221 _global_matrix(matrix),
222 _global_filter(filter),
224 _owned_graph(),
227 {
228 }
229
242 explicit AlgDofPartiSystem(const GlobalMatrixType& matrix, const GlobalFilterType& filter,
243 std::shared_ptr<AlgDofPartiType> adp) :
244 _global_matrix(matrix),
245 _global_filter(filter),
246 _alg_dof_parti(adp),
247 _owned_graph(),
250 {
251 }
252
257
259 std::size_t bytes() const
260 {
261 std::size_t r = 0u;
262 if(this->_alg_dof_parti)
263 r += this->_alg_dof_parti->bytes();
264 if(this->_owned_graph)
265 r += this->_owned_graph->bytes();
266 for(const auto& x : this->_donee_bufs)
267 r += x.bytes();
268 for(const auto& x : this->_owner_bufs)
269 r += x.bytes();
270 for(const auto& x : this->_donee_data_mirs)
271 r += x.bytes();
272 for(const auto& x : this->_owner_data_mirs)
273 r += x.bytes();
274 r += _owned_data_mir.bytes();
276 return r;
277 }
278
286 std::shared_ptr<AlgDofPartiType> get_alg_dof_parti()
287 {
288 return this->_alg_dof_parti;
289 }
290
293 {
294 return this->_alg_dof_parti->get_num_owned_dofs();
295 }
296
299 {
300 return this->_alg_dof_parti->get_num_global_dofs();
301 }
302
305 {
306 return this->_alg_dof_parti->get_global_dof_offset();
307 }
308
311 {
312 return this->_alg_dof_parti->get_num_owned_dofs();
313 }
314
317 {
318 return this->_alg_dof_parti->get_num_owned_dofs();
319 }
320
323 {
324 return this->_alg_dof_parti->get_num_global_dofs();
325 }
326
329 {
330 return this->_num_owned_non_zeros;
331 }
332
335 {
336 return this->_num_global_non_zeros;
337 }
338
340 const Dist::Comm* get_comm() const
341 {
342 XASSERT(this->_alg_dof_parti != nullptr);
343 return this->_alg_dof_parti->get_comm();
344 }
345
356 template<typename DTV_>
357 void upload_vector(DTV_* val, const LocalVectorType& vector)
358 {
359 XASSERT(this->_alg_dof_parti != nullptr);
360 this->_alg_dof_parti->upload_vector(val, vector);
361 }
362
374 template<typename DTV_>
375 void download_vector(LocalVectorType& vector, const DTV_* val)
376 {
377 XASSERT(this->_alg_dof_parti != nullptr);
378 this->_alg_dof_parti->download_vector(val, vector);
379 }
380
401 template<typename DTX_, typename RPT_, typename CIT_>
402 void apply(DTX_* vec_r, const DTX_* vec_x, const DTX_* val_a, const RPT_* row_ptr, const CIT_* col_idx) const
403 {
404 XASSERTM(!this->_alg_dof_parti->get_all_global_dof_counts().empty(),
405 "You did not ask to assemble the required AlgDofParti allgather data");
406
407 // create and gather full multiplicand vector
408 std::vector<DTX_> vec_full(this->_alg_dof_parti->get_num_global_dofs());
409 this->get_comm()->allgatherv(vec_x,
410 this->_alg_dof_parti->get_num_owned_dofs(),
411 vec_full.data(),
412 this->_alg_dof_parti->get_all_global_dof_counts().data(),
413 this->_alg_dof_parti->get_all_global_dof_offsets().data());
414
415 // apply our owned matrix
416 LAFEM::Arch::Apply::csr_generic(vec_r, DTX_(1), vec_full.data(), DTX_(0), vec_r, val_a, col_idx, row_ptr,
417 this->get_adp_matrix_rows(), this->get_adp_matrix_cols(), this->get_adp_matrix_nzes(), false);
418 }
419
428 {
429 if(this->_alg_dof_parti == nullptr)
430 {
431 this->_alg_dof_parti = std::make_shared<AlgDofPartiType>();
432 this->_alg_dof_parti->assemble_by_gate(*this->_global_matrix.get_row_gate());
433 }
434
435 this->_assemble_buffers();
436 this->_assemble_structure();
438 }
439
464 template<typename RPT_, typename CIT_>
465 void upload_matrix_symbolic(RPT_* row_ptr, CIT_* col_idx, bool keep_graph = false)
466 {
467 XASSERT(row_ptr != nullptr);
468 XASSERT(col_idx != nullptr);
469 XASSERT(this->_owned_graph != nullptr);
470
471 // maximum allowed row-pointer/column index values assuming signed int types
472 static constexpr std::uint64_t max_rpt = 1ull << (8*sizeof(RPT_) - 1);
473 static constexpr std::uint64_t max_cit = 1ull << (8*sizeof(CIT_) - 1);
474
475 // prevent "unused variable" warnings in non-debug builds
476 (void)max_rpt;
477 (void)max_cit;
478
479 const Index* dom_ptr = this->_owned_graph->get_domain_ptr();
480 const Index* img_idx = this->_owned_graph->get_image_idx();
481
482 const Index n = this->_owned_graph->get_num_nodes_domain();
483 FEAT_PRAGMA_OMP(parallel for)
484 for(Index i = 0u; i <= n; ++i)
485 {
486 ASSERTM(std::uint64_t(dom_ptr[i]) < max_rpt, "row-pointer exceeds RPT_ type range!");
487 row_ptr[i] = RPT_(dom_ptr[i]);
488 }
489
490 const Index m = this->_owned_graph->get_num_indices();
491 FEAT_PRAGMA_OMP(parallel for)
492 for(Index j = 0; j < m; ++j)
493 {
494 ASSERTM(std::uint64_t(img_idx[j]) < max_cit, "column-index exceeds CIT_ type range!");
495 col_idx[j] = CIT_(img_idx[j]);
496 }
497
498 // release owned graph
499 if(!keep_graph)
500 this->_owned_graph.reset();
501 }
502
520 template<typename DTA_, typename RPT_, typename CIT_>
521 void upload_matrix_numeric(DTA_* val, const RPT_* row_ptr, const CIT_* col_idx)
522 {
523 this->upload_matrix_numeric(val, row_ptr, col_idx, this->_global_matrix.local());
524 }
525
549 template<typename DTA_, typename RPT_, typename CIT_>
550 void upload_matrix_numeric(DTA_* val, const RPT_* DOXY(row_ptr), const CIT_* DOXY(col_idx), const LocalMatrixType& matrix)
551 {
552 XASSERT(this->_alg_dof_parti != nullptr);
553
554 // get our partitioning
555 const AlgDofPartiType& adp = *this->_alg_dof_parti;
556
557 // get our communicator
558 const Dist::Comm& comm = *this->get_comm();
559
560 // format our internal matrix
561 memset(val, 0, sizeof(DTA_)*this->_num_owned_non_zeros);
562
563 const Index num_neigh_owner = adp.get_num_owner_neighbors();
564 const Index num_neigh_donee = adp.get_num_donee_neighbors();
565
566 Dist::RequestVector recv_reqs(num_neigh_donee);
567 Dist::RequestVector send_reqs(num_neigh_owner);
568
569 std::vector<BufferVectorType> donee_vbufs(num_neigh_donee);
570 std::vector<BufferVectorType> owner_vbufs(num_neigh_owner);
571
572 // create receive buffers and post receives
573 for(Index i(0); i < num_neigh_donee; ++i)
574 {
575 // create buffer
576 BufferVectorType& buf = donee_vbufs.at(i);
577 buf = BufferVectorType(this->_donee_data_mirs.at(i).num_indices());
578
579 // post receive
580 recv_reqs[i] = comm.irecv(buf.elements(), buf.size(), adp.get_donee_rank(i));
581 }
582
583 // post sends
584 for(Index i(0); i < num_neigh_owner; ++i)
585 {
586 // create buffer
587 BufferVectorType& buf = owner_vbufs.at(i);
588 buf = BufferVectorType(this->_owner_data_mirs.at(i).num_indices(), DataType(0));
589
590 // gather from mirror
591 this->_owner_data_mirs.at(i).gather_owner_data(buf, matrix);
592
593 // post send
594 send_reqs[i] = comm.isend(buf.elements(), buf.size(), adp.get_owner_rank(i));
595 }
596
597 // upload our own data
598 this->_owned_data_mir.upload_owned_data(val, matrix);
599
600 // process all pending receives
601 for(std::size_t idx(0u); recv_reqs.wait_any(idx); )
602 {
603 // scatter from buffer
604 this->_scatter_donee_data(val, donee_vbufs.at(idx), this->_donee_data_mirs.at(idx));
605 }
606
607 // wait for all sends to finish
608 send_reqs.wait_all();
609 }
610
613 {
614 upload_filter(this->_global_filter.local());
615 }
616
623 void upload_filter(const LocalFilterType& filter)
624 {
626 ADPFilAuxType::upload_filter(_unit_filter_rows, filter, _alg_dof_parti->get_owned_mirror() ,0u);
627 }
628
635 template<typename DTV_>
636 void filter_vec_def(DTV_* vec_def)
637 {
639 return;
640
641 XASSERT(vec_def != nullptr);
642
643 LAFEM::Arch::UnitFilter::filter_def(vec_def, _unit_filter_rows.get_indices(), _unit_filter_rows.used_elements());
644 }
645
652 template<typename DTV_>
653 void filter_vec_cor(DTV_* vec_cor)
654 {
656 return;
657
658 XASSERT(vec_cor != nullptr);
659
660 // UnitFilter has no filter_cor, because it is identical to filter_def
661 LAFEM::Arch::UnitFilter::filter_def(vec_cor, _unit_filter_rows.get_indices(), _unit_filter_rows.used_elements());
662 }
663
678 template<typename DTA_, typename RPT_, typename CIT_>
679 void filter_matrix(DTA_* val, const RPT_* row_ptr, const CIT_* col_idx)
680 {
682 return;
683
684 XASSERT(val != nullptr);
685 XASSERT(row_ptr != nullptr);
686 XASSERT(col_idx != nullptr);
687
688 const Index row_off = this->get_alg_dof_parti()->get_global_dof_offset();
689 const IndexType* row_idx = this->_unit_filter_rows.get_indices();
690 const Index n = this->_unit_filter_rows.used_elements();
691
692 // process all filtered rows
693 for(Index i = 0; i < n; ++i)
694 {
695 const Index row = row_off + row_idx[i];
696 RPT_ j = row_ptr[row_idx[i]];
697 const RPT_ j_end = row_ptr[row_idx[i]+1];
698 for(; j < j_end; ++j)
699 {
700 val[j] = DTA_(row == Index(col_idx[j]) ? 1 : 0);
701 }
702 }
703 }
704
708
709 protected:
714 const LocalMatrixType& local_matrix,
715 const MirrorType& row_mirror,
716 const IndexVectorType& global_dof_idx,
717 const Index num_global_dofs)
718 {
719 // compute number of rows of matrix buffers
720 Index num_buf_rows = ADPMatAuxType::calc_mat_buf_num_rows(local_matrix, row_mirror);
721
722 // allocate a temporary array
723 std::vector<IndexType> aux_row(std::size_t(num_buf_rows+1u), IndexType(0));
724
725 // count number of non-zeros per row
726 ADPMatAuxType::calc_mat_buf_row_nze(aux_row.data(), local_matrix, row_mirror);
727
728 // build buffer row pointer by exclusive scan
729 feat_omp_ex_scan(std::size_t(num_buf_rows+1u), aux_row.data(), aux_row.data());
730 IndexType num_buf_nze = aux_row.back();
731
732 // allocate buffer
733 BufferMatrixType buffer(num_buf_rows, num_global_dofs, num_buf_nze, 1);
734 IndexType* buf_row_ptr = buffer.row_ptr();
735 IndexType* buf_col_idx = buffer.col_ind();
736
737 // copy buffer row pointer because we need a disposable copy for the next operation
738 for(Index i = 0u; i <= num_buf_rows; ++i)
739 buf_row_ptr[i] = aux_row[i];
740
741 // gather the column indices
742 // we have to use the auxiliary row pointer here because it is overwritten by the following call
743 ADPMatAuxType::gather_mat_buf_col_idx(aux_row.data(), buf_col_idx, local_matrix, row_mirror, global_dof_idx);
744
745 // sort the buffer column indices; this will make things a lot easier and more efficient later on
746 for(Index i = 0u; i < num_buf_rows; ++i)
747 {
748 std::sort(&buf_col_idx[buf_row_ptr[i]], &buf_col_idx[buf_row_ptr[i+1]]);
749 }
750
751 // okay
752 return buffer;
753 }
754
756
761 {
762 // get our partitioning
763 const AlgDofPartiType& adp = *this->_alg_dof_parti;
764
765 // get out communicator
766 const Dist::Comm& comm = *this->get_comm();
767
768 // get number of neighbors and allocate buffer vectors
769 const Index num_neigh_owner = adp.get_num_owner_neighbors();
770 const Index num_neigh_donee = adp.get_num_donee_neighbors();
771 _owner_bufs.resize(num_neigh_owner);
772 _donee_bufs.resize(num_neigh_donee);
773
774 // create the owner buffers by using the auxiliary helper function.
775 for(Index i(0); i < num_neigh_owner; ++i)
776 {
777 // allocate matrix buffer
778 this->_owner_bufs.at(i) = _asm_mat_buf(this->_global_matrix.local(),
780 }
781
782 // We have assembled our owner-neighbor matrix buffers, however, we cannot
783 // assemble the donee-neighbor matrix buffers on our own. Instead, each owner
784 // neighbor has to receive its donee-buffers from its donee-neighbors, because
785 // only the donee knows the matrix layout of those buffers.
786 // Yes, this is brain-twisting, but believe me, it cannot be realized otherwise.
787
788 // Note:
789 // The following code is effectively just copy-&-paste from the SynchMatrix::init()
790 // function, as the same buffer problem also arises when converting global type-0
791 // matrices to local type-1 matrices.
792
793 Dist::RequestVector send_reqs(num_neigh_owner);
794 Dist::RequestVector recv_reqs(num_neigh_donee);
795
796 // receive buffer dimensions vector
797 std::vector<std::array<Index,4>> send_dims(num_neigh_owner);
798 std::vector<std::array<Index,4>> recv_dims(num_neigh_donee);
799
800 // post send-buffer dimension receives
801 for(Index i(0); i < num_neigh_donee; ++i)
802 {
803 recv_reqs[i] = comm.irecv(recv_dims.at(i).data(), std::size_t(4), adp.get_donee_rank(i));
804 }
805
806 // send owner-buffer dimensions
807 for(Index i(0); i < num_neigh_owner; ++i)
808 {
809 const BufferMatrixType& sbuf = this->_owner_bufs.at(i);
810 send_dims.at(i)[0] = Index(sbuf.rows());
811 send_dims.at(i)[1] = Index(sbuf.columns());
812 send_dims.at(i)[2] = Index(sbuf.entries_per_nonzero());
813 send_dims.at(i)[3] = Index(sbuf.used_elements());
814 send_reqs[i] = comm.isend(send_dims.at(i).data(), std::size_t(4), adp.get_owner_rank(i));
815 }
816
817 // wait for all receives to finish
818 recv_reqs.wait_all();
819
820 // allocate donee-buffers
821 for(Index i(0); i < num_neigh_donee; ++i)
822 {
823 // get the receive buffer dimensions
824 Index nrows = recv_dims.at(i)[0];
825 Index ncols = recv_dims.at(i)[1];
826 Index nepnz = recv_dims.at(i)[2];
827 Index nnze = recv_dims.at(i)[3];
828
829 // allocate receive buffer
830 this->_donee_bufs.at(i) = BufferMatrixType(nrows, ncols, nnze, nepnz);
831 }
832
833 // post donee-buffer row-pointer array receives
834 for(Index i(0); i < num_neigh_donee; ++i)
835 {
836 recv_reqs[i] = comm.irecv(this->_donee_bufs.at(i).row_ptr(),
837 this->_donee_bufs.at(i).rows()+std::size_t(1), adp.get_donee_rank(i));
838 }
839
840 // wait for all previous sends to finish
841 send_reqs.wait_all();
842
843 // post owner-buffer row-pointer array sends
844 for(Index i(0); i < num_neigh_owner; ++i)
845 {
846 send_reqs[i] = comm.isend(this->_owner_bufs.at(i).row_ptr(),
847 this->_owner_bufs.at(i).rows()+std::size_t(1), adp.get_owner_rank(i));
848 }
849
850 // wait for all previous receives to finish
851 recv_reqs.wait_all();
852
853 // post donee-buffer column-index array receives
854 for(Index i(0); i < num_neigh_donee; ++i)
855 {
856 recv_reqs[i] = comm.irecv(this->_donee_bufs.at(i).col_ind(),
857 this->_donee_bufs.at(i).used_elements(), adp.get_donee_rank(i));
858 }
859
860 // wait for all previous sends to finish
861 send_reqs.wait_all();
862
863 // post owner-buffer column-index array sends
864 for(Index i(0); i < num_neigh_owner; ++i)
865 {
866 send_reqs[i] = comm.isend(this->_owner_bufs.at(i).col_ind(),
867 this->_owner_bufs.at(i).used_elements(), adp.get_owner_rank(i));
868 }
869
870 // wait for all receives and sends to finish
871 recv_reqs.wait_all();
872 send_reqs.wait_all();
873 }
874
879 {
880 // get our partitioning
881 const AlgDofPartiType& adp = *this->_alg_dof_parti;
882
883 // get our matrix dimensions:
884 // * each row of our matrix corresponds to one owned DOF
885 // * each column corresponds to one global DOF
886 const Index num_rows = adp.get_num_owned_dofs();
887 const Index num_cols = adp.get_num_global_dofs();
888
889 // Unfortunately, assembling the matrix structure is not that easy,
890 // because it is a union of our owned matrix structure and all of
891 // our donee matrix buffers. We don't have a chance to determine how
892 // many duplicate (i,j) pairs we will encounter here, so we use the
893 // DynamicGraph class here to keep things simple.
894
895 // create a dynamic graph for our matrix
896 Adjacency::DynamicGraph dynamic_graph(num_rows, num_cols);
897
898 // gather the owned rows for to obtain the initial structure
899 ADPMatAuxType::gather_owned_struct(dynamic_graph, this->_global_matrix.local(),
901
902 // process all donee-neighbor buffers
903 const Index num_neigh_donee = adp.get_num_donee_neighbors();
904 for(Index ineigh(0); ineigh < num_neigh_donee; ++ineigh)
905 {
906 // get the mirror and the matrix buffer of that donee neighbor
907 // note: the donee mirror indices are owned DOF indices
908 const auto& mir = adp.get_donee_mirror(ineigh);
909 const BufferMatrixType& buf = this->_donee_bufs.at(ineigh);
910 XASSERT(mir.num_indices() == buf.rows());
911 const Index num_idx = mir.num_indices();
912 const IndexType* mir_idx = mir.indices();
913 const IndexType* buf_ptr = buf.row_ptr();
914 const IndexType* buf_idx = buf.col_ind();
915
916 // loop over all matrix buffer rows
917 for(Index i(0); i < num_idx; ++i)
918 {
919 // the owned DOF index of our the buffer matrix row
920 const IndexType row = mir_idx[i];
921
922 // loop over all buffer indices
923 for(IndexType j(buf_ptr[i]); j < buf_ptr[i + 1]; ++j)
924 {
925 // insert entry into our local matrix
926 dynamic_graph.insert(row, buf_idx[j]);
927 }
928 }
929 }
930
931 // store number of non-zero entries
932 this->_num_owned_non_zeros = dynamic_graph.get_num_indices();
933 this->get_comm()->allreduce(&this->_num_owned_non_zeros, &this->_num_global_non_zeros, std::size_t(1), Dist::op_sum);
934
935 // render into a standard graph
936 this->_owned_graph = std::make_shared<Adjacency::Graph>(Adjacency::RenderType::as_is, dynamic_graph);
937 dynamic_graph.clear();
938 }
939
944 DoneeMirrorType& data_mirror,
945 const Adjacency::Graph& owned_graph,
946 const DoneeMirrorType& mirror,
947 const BufferMatrixType& buffer)
948 {
949 const Index buf_rows = buffer.rows();
950 const Index num_idx = buffer.used_elements();
951 const IndexType* row_idx = mirror.indices();
952 const Index* row_ptr = owned_graph.get_domain_ptr();
953 const Index* col_idx = owned_graph.get_image_idx();
954 const IndexType* buf_ptr = buffer.row_ptr();
955 const IndexType* buf_idx = buffer.col_ind();
956
957 // allocate data mirror
958 data_mirror = DoneeMirrorType(owned_graph.get_num_indices(), num_idx);
959 IndexType* dat_idx = data_mirror.indices();
960
961 // loop over all buffer matrix rows
962 for(Index i(0); i < buf_rows; ++i)
963 {
964 IndexType j = buf_ptr[i];
965 const IndexType j_end = buf_ptr[i + 1];
966 Index k = row_ptr[row_idx[i]];
967 const Index k_end = row_ptr[row_idx[i] + 1];
968
969 // loop over local matrix and buffer matrix row in a merge-style fashion
970 while((j < j_end) && (k < k_end))
971 {
972 if(buf_idx[j] < col_idx[k])
973 ++j;
974 else if(buf_idx[j] > col_idx[k])
975 ++k;
976 else
977 {
978 dat_idx[j] = IndexType(k);
979 ++j;
980 ++k;
981 }
982 }
983 }
984 }
985
995 {
996 // get our partitioning
997 const AlgDofPartiType& adp = *this->_alg_dof_parti;
998
999 // assemble donee data mirrors
1000 this->_donee_data_mirs.resize(this->_donee_bufs.size());
1001 for(Index i(0); i < this->_donee_bufs.size(); ++i)
1002 _asm_neighbor_donee_data_mir(this->_donee_data_mirs.at(i), *this->_owned_graph,
1003 adp.get_donee_mirror(i), this->_donee_bufs.at(i));
1004
1005 // assemble owner data mirrors
1006 this->_owner_data_mirs.resize(this->_owner_bufs.size());
1007 for(Index i(0); i < this->_owner_bufs.size(); ++i)
1008 this->_owner_data_mirs.at(i).asm_neighbor_owner_data_mir(this->_global_matrix.local(),
1009 adp.get_owner_mirror(i), this->_owner_bufs.at(i),
1010 adp.get_global_dof_indices(), Index(0));
1011
1012 // assemble our owned data mirror
1013 this->_owned_data_mir.asm_owned_data_mir(this->_global_matrix.local(), *this->_owned_graph,
1015 }
1016
1020 template<typename DTA_>
1021 static void _scatter_donee_data(DTA_* adp_val, const BufferVectorType& buffer,
1022 const DoneeMirrorType& data_mirror)
1023 {
1024 XASSERT(buffer.size() == data_mirror.num_indices());
1025
1026 const DataType* buf_val = buffer.elements();
1027 const IndexType* mir_idx = data_mirror.indices();
1028 const Index n = buffer.size();
1029 for(Index i(0); i < n; ++i)
1030 {
1031 adp_val[mir_idx[i]] += DTA_(buf_val[i]);
1032 }
1033 }
1034 }; // class AlgDofPartiSystem<...>
1035
1041
1043 namespace Intern
1044 {
1045 template<typename DT_, typename IT_>
1046 class ADPDOMM<LAFEM::SparseMatrixCSR<DT_, IT_>>
1047 {
1048 public:
1049 LAFEM::VectorMirror<DT_, IT_> _buf_mir, _loc_mir;
1050
1051 Index num_indices() const
1052 {
1053 return _buf_mir.num_indices();
1054 }
1055
1056 Index buf_size() const
1057 {
1058 return _buf_mir.size();
1059 }
1060
1061 Index loc_size() const
1062 {
1063 return _loc_mir.size();
1064 }
1065
1066 String dump() const
1067 {
1068 String s;
1069 XASSERT(_buf_mir.num_indices() == _loc_mir.num_indices());
1070 const IT_* buf_idx = _buf_mir.indices();
1071 const IT_* loc_idx = _loc_mir.indices();
1072 for(Index i = 0; i < _buf_mir.num_indices(); ++i)
1073 s += " " + stringify(buf_idx[i]) + ":" + stringify(loc_idx[i]);
1074 return "[" + s + "]*" + stringify(_buf_mir.num_indices());
1075 }
1076
1093 Index asm_neighbor_owner_data_mir(
1094 const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix,
1095 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1096 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
1097 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
1098 Index row_offset)
1099 {
1100 // get our mirror and matrix arrays
1101 const IT_* row_idx = row_mirror.indices();
1102 const IT_* row_ptr = local_matrix.row_ptr();
1103 const IT_* col_idx = local_matrix.col_ind();
1104 const IT_* buf_ptr = buffer.row_ptr();
1105 const IT_* buf_idx = buffer.col_ind();
1106 const IT_* glob_dof_idx = global_dof_idx.elements();
1107 const Index row_mir_num_idx = row_mirror.num_indices();
1108
1109 // count the number of non-zeros that this matrix contributes to the buffer
1110 Index data_mir_num_idx = 0u;
1111 for(Index i = 0; i < row_mir_num_idx; ++i)
1112 data_mir_num_idx += row_ptr[row_idx[i]+1u] - row_ptr[row_idx[i]];
1113
1114 XASSERT(data_mir_num_idx <= buffer.used_elements());
1115
1116 // allocate data mirror
1117 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1118 aux_data_mir.reserve(data_mir_num_idx);
1119
1120 // vector for row pointers sorted by global indices
1121 std::vector<IT_> loc_it;
1122 loc_it.reserve(local_matrix.columns());
1123
1124 // declare a lambda that sorts row pointers by global column indices
1125 auto sort_rel_loc = [&glob_dof_idx, &col_idx] (IT_ a, IT_ b)
1126 {
1127 return glob_dof_idx[col_idx[a]] < glob_dof_idx[col_idx[b]];
1128 };
1129
1130 // loop over all buffer matrix rows
1131 for(Index i(0); i < row_mir_num_idx; ++i)
1132 {
1133 // get local matrix row index
1134 IT_ j = buf_ptr[row_offset + i];
1135 const IT_ j_end = buf_ptr[row_offset + i + 1];
1136 const IT_ k_beg = row_ptr[row_idx[i]];
1137 const IT_ k_end = row_ptr[row_idx[i] + 1];
1138 loc_it.clear();
1139 for(IT_ k = k_beg; k < k_end; ++k)
1140 loc_it.push_back(k);
1141 std::sort(loc_it.begin(), loc_it.end(), sort_rel_loc);
1142
1143 auto kit = loc_it.begin();
1144
1145 // loop over local matrix and buffer matrix row in a merge-style fashion
1146 while((j < j_end) && (kit != loc_it.end()))
1147 {
1148 if(buf_idx[j] < glob_dof_idx[col_idx[*kit]])
1149 ++j;
1150 else if(buf_idx[j] > glob_dof_idx[col_idx[*kit]])
1151 ++kit;
1152 else
1153 {
1154 aux_data_mir.push_back(std::make_pair(j, *kit));
1155 ++j;
1156 ++kit;
1157 }
1158 }
1159 }
1160
1161 // create data mirrors
1162 Index num_idx = Index(aux_data_mir.size());
1163 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(buffer.used_elements(), num_idx);
1164 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(
1165 local_matrix.template used_elements<LAFEM::Perspective::pod>(), num_idx);
1166
1167 IT_* bm_idx = this->_buf_mir.indices();
1168 IT_* lm_idx = this->_loc_mir.indices();
1169 for(Index i = 0; i < num_idx; ++i)
1170 {
1171 bm_idx[i] = aux_data_mir[i].first;
1172 lm_idx[i] = aux_data_mir[i].second;
1173 }
1174
1175 return row_mir_num_idx;
1176 }
1177
1191 Index asm_owned_data_mir(
1192 const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix,
1193 const Adjacency::Graph& owned_graph,
1194 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1195 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
1196 Index row_offset)
1197 {
1198 // get matrix arrays
1199 const Index* own_row_ptr = owned_graph.get_domain_ptr();
1200 const Index* own_col_idx = owned_graph.get_image_idx();
1201 const IT_* loc_row_ptr = local_matrix.row_ptr();
1202 const IT_* loc_col_idx = local_matrix.col_ind();
1203
1204 // allocate data mirror
1205 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1206 aux_data_mir.reserve(owned_graph.get_num_indices());
1207
1208 const Index num_owned_dofs = row_mirror.num_indices();
1209 const IT_* loc_dof_idx = row_mirror.indices();
1210 const IT_* glob_dof_idx = global_dof_idx.elements();
1211
1212 //XASSERT(num_owned_dofs == adp_matrix.rows());
1213
1214 // row iterator deque
1215 std::deque<IT_> row_it;
1216
1217 // declare a lambda that sorts row pointers by global column indices
1218 auto sort_rel = [&glob_dof_idx, &loc_col_idx] (IT_ a, IT_ b)
1219 {
1220 return glob_dof_idx[loc_col_idx[a]] < glob_dof_idx[loc_col_idx[b]];
1221 };
1222
1223 // loop over all our owned DOFS
1224 for(Index own_dof(0); own_dof < num_owned_dofs; ++own_dof)
1225 {
1226 const IT_ k_beg = loc_row_ptr[loc_dof_idx[own_dof]];
1227 const IT_ k_end = loc_row_ptr[loc_dof_idx[own_dof] + 1];
1228 row_it.clear();
1229 for(IT_ k = k_beg; k < k_end; ++k)
1230 row_it.push_back(k);
1231 std::sort(row_it.begin(), row_it.end(), sort_rel);
1232
1233 // get the local DOF index for this owned DOF
1234 IT_ j = IT_(own_row_ptr[row_offset + own_dof]);
1235 const IT_ j_end = IT_(own_row_ptr[row_offset + own_dof + 1]);
1236 auto kit = row_it.begin();
1237
1238 // loop over local matrix and owned matrix row in a merge-style fashion
1239 while((j < j_end) && (kit != row_it.end()))
1240 {
1241 if(own_col_idx[j] < glob_dof_idx[loc_col_idx[*kit]])
1242 ++j;
1243 else if(own_col_idx[j] > glob_dof_idx[loc_col_idx[*kit]])
1244 ++kit;
1245 else
1246 {
1247 aux_data_mir.push_back(std::make_pair(j, *kit));
1248 ++j;
1249 ++kit;
1250 }
1251 }
1252 }
1253
1254 // create data mirrors
1255 Index num_idx = Index(aux_data_mir.size());
1256 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(local_matrix.used_elements(), num_idx);
1257 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(local_matrix.used_elements(), num_idx);
1258
1259 IT_* bm_idx = this->_buf_mir.indices();
1260 IT_* lm_idx = this->_loc_mir.indices();
1261 for(Index i = 0; i < num_idx; ++i)
1262 {
1263 bm_idx[i] = aux_data_mir[i].first;
1264 lm_idx[i] = aux_data_mir[i].second;
1265 }
1266
1267 return num_owned_dofs;
1268 }
1269
1270 template<typename DTA_>
1271 void upload_owned_data(DTA_* adp_val, const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix) const
1272 {
1273 const DT_* loc_val = local_matrix.val();
1274 const IT_* adp_idx = _buf_mir.indices();
1275 const IT_* loc_idx = _loc_mir.indices();
1276 XASSERT(_buf_mir.num_indices() == _loc_mir.num_indices());
1277 Index n = _buf_mir.num_indices();
1278 for(Index i = 0; i < n; ++i)
1279 {
1280 ASSERT(loc_idx[i] < local_matrix.used_elements());
1281 adp_val[adp_idx[i]] = DTA_(loc_val[loc_idx[i]]);
1282 }
1283 }
1284
1297 void gather_owner_data(LAFEM::DenseVector<DT_, IT_>& buffer, const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix) const
1298 {
1299 DT_* buf_val = buffer.elements();
1300 const DT_* loc_val = local_matrix.val();
1301 const IT_* buf_idx = this->_buf_mir.indices();
1302 const IT_* loc_idx = this->_loc_mir.indices();
1303 XASSERT(this->_buf_mir.num_indices() == this->_loc_mir.num_indices());
1304 Index n = this->_buf_mir.num_indices();
1305 for(Index i = 0; i < n; ++i)
1306 {
1307 ASSERT(buf_idx[i] < buffer.size());
1308 ASSERT(loc_idx[i] < local_matrix.used_elements());
1309 buf_val[buf_idx[i]] = loc_val[loc_idx[i]];
1310 }
1311 }
1312
1313 }; // class ADPDOMM<LAFEM::SparseMatrixCSR<DT_, IT_>>
1314
1316
1317 template<typename DT_, typename IT_, int bh_, int bw_>
1318 class ADPDOMM<LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>>
1319 {
1320 public:
1321 LAFEM::VectorMirror<DT_, IT_> _buf_mir, _loc_mir;
1322
1323 Index num_indices() const
1324 {
1325 return _buf_mir.num_indices();
1326 }
1327
1328 Index buf_size() const
1329 {
1330 return _buf_mir.size();
1331 }
1332
1333 Index loc_size() const
1334 {
1335 return _loc_mir.size();
1336 }
1337
1338 String dump() const
1339 {
1340 String s;
1341 XASSERT(_buf_mir.num_indices() == _loc_mir.num_indices());
1342 const IT_* buf_idx = _buf_mir.indices();
1343 const IT_* loc_idx = _loc_mir.indices();
1344 for(Index i = 0; i < _buf_mir.num_indices(); ++i)
1345 s += " " + stringify(buf_idx[i]) + ":" + stringify(loc_idx[i]);
1346 return "[" + s + "]*" + stringify(_buf_mir.num_indices());
1347 }
1348
1349 Index asm_neighbor_owner_data_mir(
1350 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix,
1351 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1352 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
1353 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>& global_dof_idx,
1354 Index row_offset)
1355 {
1356 // get our mirror and matrix arrays
1357 const IT_* row_idx = row_mirror.indices();
1358 const IT_* row_ptr = local_matrix.row_ptr();
1359 const IT_* col_idx = local_matrix.col_ind();
1360 const IT_* buf_ptr = buffer.row_ptr();
1361 const IT_* buf_idx = buffer.col_ind();
1362 const auto* glob_dof_idx = global_dof_idx.elements();
1363 const Index row_mir_num_idx = row_mirror.num_indices();
1364
1365 // count the number of non-zeros that this matrix contributes to the buffer
1366 Index data_mir_num_idx = 0u;
1367 for(Index i = 0; i < row_mir_num_idx; ++i)
1368 data_mir_num_idx += row_ptr[row_idx[i]+1u] - row_ptr[row_idx[i]];
1369 data_mir_num_idx *= Index(bh_*bw_);
1370
1371 XASSERT(data_mir_num_idx <= buffer.used_elements());
1372
1373 // allocate data mirror
1374 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1375 aux_data_mir.reserve(data_mir_num_idx);
1376
1377 // vector for row pointers sorted by global indices
1378 std::vector<IT_> loc_it;
1379 loc_it.reserve(local_matrix.columns() * std::size_t(bh_*bw_));
1380
1381 // declare a lambda that sorts row pointers by global column indices
1382 auto sort_rel_loc = [&glob_dof_idx, &col_idx] (IT_ a, IT_ b)
1383 {
1384 return glob_dof_idx[col_idx[a]][0] < glob_dof_idx[col_idx[b]][0];
1385 };
1386
1387 // loop over all buffer matrix rows
1388 for(Index i(0); i < row_mir_num_idx; ++i)
1389 {
1390 const IT_ k_beg = row_ptr[row_idx[i]];
1391 const IT_ k_end = row_ptr[row_idx[i] + 1];
1392 loc_it.clear();
1393 for(IT_ k = k_beg; k < k_end; ++k)
1394 loc_it.push_back(k);
1395 std::sort(loc_it.begin(), loc_it.end(), sort_rel_loc);
1396
1397 // loop over the block height
1398 for(int bi = 0; bi < bh_; ++bi)
1399 {
1400 // get local matrix row index
1401 IT_ j = buf_ptr[row_offset + i*IT_(bh_) + IT_(bi)];
1402 const IT_ j_end = buf_ptr[row_offset + i*IT_(bh_) + IT_(bi) + 1];
1403
1404 auto kit = loc_it.begin();
1405
1406 // loop over local matrix and buffer matrix row in a merge-style fashion
1407 while((j < j_end) && (kit != loc_it.end()))
1408 {
1409 if(buf_idx[j] < glob_dof_idx[col_idx[*kit]][0])
1410 ++j;
1411 else if(buf_idx[j] > glob_dof_idx[col_idx[*kit]][0])
1412 ++kit;
1413 else
1414 {
1415 // global column indices match
1416 for(int bj = 0; bj < bw_; ++bj)
1417 {
1418 aux_data_mir.push_back(std::make_pair(j, (*kit)*IT_(bh_*bw_) + IT_(bi*bw_) + IT_(bj)));
1419 ++j;
1420 }
1421 ++kit;
1422 }
1423 }
1424 }
1425 }
1426
1427 // create data mirrors
1428 Index num_idx = Index(aux_data_mir.size());
1429 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(buffer.used_elements(), num_idx);
1430 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(
1431 local_matrix.template used_elements<LAFEM::Perspective::pod>(), num_idx);
1432
1433 IT_* bm_idx = this->_buf_mir.indices();
1434 IT_* lm_idx = this->_loc_mir.indices();
1435 for(Index i = 0; i < num_idx; ++i)
1436 {
1437 bm_idx[i] = aux_data_mir[i].first;
1438 lm_idx[i] = aux_data_mir[i].second;
1439 }
1440
1441 return row_mir_num_idx * Index(bh_);
1442 }
1443
1444 Index asm_neighbor_owner_data_mir(
1445 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, 1>& local_matrix,
1446 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1447 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
1448 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
1449 Index row_offset)
1450 {
1451 // get our mirror and matrix arrays
1452 const IT_* row_idx = row_mirror.indices();
1453 const IT_* row_ptr = local_matrix.row_ptr();
1454 const IT_* col_idx = local_matrix.col_ind();
1455 const IT_* buf_ptr = buffer.row_ptr();
1456 const IT_* buf_idx = buffer.col_ind();
1457 const IT_* glob_dof_idx = global_dof_idx.elements();
1458 const Index row_mir_num_idx = row_mirror.num_indices();
1459
1460 // count the number of non-zeros that this matrix contributes to the buffer
1461 Index data_mir_num_idx = 0u;
1462 for(Index i = 0; i < row_mir_num_idx; ++i)
1463 data_mir_num_idx += row_ptr[row_idx[i]+1u] - row_ptr[row_idx[i]];
1464 data_mir_num_idx *= Index(bh_);
1465
1466 XASSERT(data_mir_num_idx <= buffer.used_elements());
1467
1468 // allocate data mirror
1469 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1470 aux_data_mir.reserve(data_mir_num_idx);
1471
1472 // vector for row pointers sorted by global indices
1473 std::vector<IT_> loc_it;
1474 loc_it.reserve(local_matrix.columns() * std::size_t(bh_));
1475
1476 // declare a lambda that sorts row pointers by global column indices
1477 auto sort_rel_loc = [&glob_dof_idx, &col_idx] (IT_ a, IT_ b)
1478 {
1479 return glob_dof_idx[col_idx[a]] < glob_dof_idx[col_idx[b]];
1480 };
1481
1482 // loop over all buffer matrix rows
1483 for(Index i(0); i < row_mir_num_idx; ++i)
1484 {
1485 const IT_ k_beg = row_ptr[row_idx[i]];
1486 const IT_ k_end = row_ptr[row_idx[i] + 1];
1487 loc_it.clear();
1488 for(IT_ k = k_beg; k < k_end; ++k)
1489 loc_it.push_back(k);
1490 std::sort(loc_it.begin(), loc_it.end(), sort_rel_loc);
1491
1492 // loop over the block height
1493 for(int bi = 0; bi < bh_; ++bi)
1494 {
1495 // get local matrix row index
1496 IT_ j = buf_ptr[row_offset + i*IT_(bh_) + IT_(bi)];
1497 const IT_ j_end = buf_ptr[row_offset + i*IT_(bh_) + IT_(bi) + 1];
1498 auto kit = loc_it.begin();
1499
1500 // loop over local matrix and buffer matrix row in a merge-style fashion
1501 while((j < j_end) && (kit != loc_it.end()))
1502 {
1503 if(buf_idx[j] < glob_dof_idx[col_idx[*kit]])
1504 ++j;
1505 else if(buf_idx[j] > glob_dof_idx[col_idx[*kit]])
1506 ++kit;
1507 else
1508 {
1509 // global column indices match
1510 aux_data_mir.push_back(std::make_pair(j, (*kit)*IT_(bh_) + IT_(bi)));
1511 ++j;
1512 ++kit;
1513 }
1514 }
1515 }
1516 }
1517
1518 // create data mirrors
1519 Index num_idx = Index(aux_data_mir.size());
1520 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(buffer.used_elements(), num_idx);
1521 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(
1522 local_matrix.template used_elements<LAFEM::Perspective::pod>(), num_idx);
1523
1524 IT_* bm_idx = this->_buf_mir.indices();
1525 IT_* lm_idx = this->_loc_mir.indices();
1526 for(Index i = 0; i < num_idx; ++i)
1527 {
1528 bm_idx[i] = aux_data_mir[i].first;
1529 lm_idx[i] = aux_data_mir[i].second;
1530 }
1531
1532 return row_mir_num_idx * Index(bh_);
1533 }
1534
1535 Index asm_owned_data_mir(
1536 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix,
1537 const Adjacency::Graph& owned_graph,
1538 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1539 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>& global_dof_idx,
1540 Index row_offset)
1541 {
1542 // get matrix arrays
1543 const Index* own_row_ptr = owned_graph.get_domain_ptr();
1544 const Index* own_col_idx = owned_graph.get_image_idx();
1545 const IT_* loc_row_ptr = local_matrix.row_ptr();
1546 const IT_* loc_col_idx = local_matrix.col_ind();
1547
1548 // allocate data mirror
1549 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1550 aux_data_mir.reserve(owned_graph.get_num_indices() * std::size_t(bh_*bw_));
1551
1552 const Index num_owned_dofs = row_mirror.num_indices();
1553 const IT_* loc_dof_idx = row_mirror.indices();
1554 const auto* glob_dof_idx = global_dof_idx.elements();
1555
1556 //XASSERT(num_owned_dofs == adp_matrix.rows());
1557
1558 // row iterator deque
1559 std::deque<IT_> row_it;
1560
1561 // declare a lambda that sorts row pointers by global column indices
1562 auto sort_rel = [&glob_dof_idx, &loc_col_idx] (IT_ a, IT_ b)
1563 {
1564 return glob_dof_idx[loc_col_idx[a]][0] < glob_dof_idx[loc_col_idx[b]][0];
1565 };
1566
1567 // loop over all our owned DOFS
1568 for(Index own_dof(0); own_dof < num_owned_dofs; ++own_dof)
1569 {
1570 const IT_ k_beg = loc_row_ptr[loc_dof_idx[own_dof]];
1571 const IT_ k_end = loc_row_ptr[loc_dof_idx[own_dof] + 1];
1572 row_it.clear();
1573 for(IT_ k = k_beg; k < k_end; ++k)
1574 row_it.push_back(k);
1575 std::sort(row_it.begin(), row_it.end(), sort_rel);
1576
1577 // loop over the block height
1578 for(int bi = 0; bi < bh_; ++bi)
1579 {
1580 IT_ j = IT_(own_row_ptr[row_offset + own_dof*IT_(bh_) + IT_(bi)]);
1581 const IT_ j_end = IT_(own_row_ptr[row_offset + own_dof*IT_(bh_) + IT_(bi) + 1]);
1582 auto kit = row_it.begin();
1583
1584 // loop over local matrix and owned matrix row in a merge-style fashion
1585 while((j < j_end) && (kit != row_it.end()))
1586 {
1587 if(own_col_idx[j] < glob_dof_idx[loc_col_idx[*kit]][0])
1588 ++j;
1589 else if(own_col_idx[j] > glob_dof_idx[loc_col_idx[*kit]][0])
1590 ++kit;
1591 else
1592 {
1593 // global column indices match
1594 for(int bj = 0; bj < bw_; ++bj)
1595 {
1596 aux_data_mir.push_back(std::make_pair(j, (*kit)*IT_(bh_*bw_) + IT_(bi*bw_) + IT_(bj)));
1597 ++j;
1598 }
1599 ++kit;
1600 }
1601 }
1602 }
1603 }
1604
1605 // create data mirrors
1606 Index num_idx = Index(aux_data_mir.size());
1607 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(owned_graph.get_num_indices(), num_idx);
1608 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(
1609 local_matrix.template used_elements<LAFEM::Perspective::pod>(), num_idx);
1610
1611 IT_* bm_idx = this->_buf_mir.indices();
1612 IT_* lm_idx = this->_loc_mir.indices();
1613 for(Index i = 0; i < num_idx; ++i)
1614 {
1615 bm_idx[i] = aux_data_mir[i].first;
1616 lm_idx[i] = aux_data_mir[i].second;
1617 }
1618
1619 return num_owned_dofs * Index(bh_);
1620 }
1621
1622 Index asm_owned_data_mir(
1623 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, 1>& local_matrix,
1624 const Adjacency::Graph& owned_graph,
1625 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1626 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
1627 Index row_offset)
1628 {
1629 // get matrix arrays
1630 const Index* own_row_ptr = owned_graph.get_domain_ptr();
1631 const Index* own_col_idx = owned_graph.get_image_idx();
1632 const IT_* loc_row_ptr = local_matrix.row_ptr();
1633 const IT_* loc_col_idx = local_matrix.col_ind();
1634
1635 // allocate data mirror
1636 std::vector<std::pair<IT_, IT_>> aux_data_mir;
1637 aux_data_mir.reserve(owned_graph.get_num_indices() * std::size_t(bh_));
1638
1639 const Index num_owned_dofs = row_mirror.num_indices();
1640 const IT_* loc_dof_idx = row_mirror.indices();
1641 const IT_* glob_dof_idx = global_dof_idx.elements();
1642
1643 //XASSERT(num_owned_dofs == adp_matrix.rows());
1644
1645 // row iterator deque
1646 std::deque<IT_> row_it;
1647
1648 // declare a lambda that sorts row pointers by global column indices
1649 auto sort_rel = [&glob_dof_idx, &loc_col_idx] (IT_ a, IT_ b)
1650 {
1651 return glob_dof_idx[loc_col_idx[a]] < glob_dof_idx[loc_col_idx[b]];
1652 };
1653
1654 // loop over all our owned DOFS
1655 for(Index own_dof(0); own_dof < num_owned_dofs; ++own_dof)
1656 {
1657 const IT_ k_beg = loc_row_ptr[loc_dof_idx[own_dof]];
1658 const IT_ k_end = loc_row_ptr[loc_dof_idx[own_dof] + 1];
1659 row_it.clear();
1660 for(IT_ k = k_beg; k < k_end; ++k)
1661 row_it.push_back(k);
1662 std::sort(row_it.begin(), row_it.end(), sort_rel);
1663
1664 // loop over the block height
1665 for(int bi = 0; bi < bh_; ++bi)
1666 {
1667 IT_ j = IT_(own_row_ptr[row_offset + own_dof*IT_(bh_) + IT_(bi)]);
1668 const IT_ j_end = IT_(own_row_ptr[row_offset + own_dof*IT_(bh_) + IT_(bi) + 1]);
1669 auto kit = row_it.begin();
1670
1671 // loop over local matrix and owned matrix row in a merge-style fashion
1672 while((j < j_end) && (kit != row_it.end()))
1673 {
1674 if(own_col_idx[j] < glob_dof_idx[loc_col_idx[*kit]])
1675 ++j;
1676 else if(own_col_idx[j] > glob_dof_idx[loc_col_idx[*kit]])
1677 ++kit;
1678 else
1679 {
1680 // global column indices match
1681 aux_data_mir.push_back(std::make_pair(j, (*kit)*IT_(bh_) + IT_(bi)));
1682 ++j;
1683 ++kit;
1684 }
1685 }
1686 }
1687 }
1688
1689 // create data mirrors
1690 Index num_idx = Index(aux_data_mir.size());
1691 this->_buf_mir = LAFEM::VectorMirror<DT_, IT_>(owned_graph.get_num_indices(), num_idx);
1692 this->_loc_mir = LAFEM::VectorMirror<DT_, IT_>(
1693 local_matrix.template used_elements<LAFEM::Perspective::pod>(), num_idx);
1694
1695 IT_* bm_idx = this->_buf_mir.indices();
1696 IT_* lm_idx = this->_loc_mir.indices();
1697 for(Index i = 0; i < num_idx; ++i)
1698 {
1699 bm_idx[i] = aux_data_mir[i].first;
1700 lm_idx[i] = aux_data_mir[i].second;
1701 }
1702
1703 return num_owned_dofs * Index(bh_);
1704 }
1705
1706 template<typename DTA_>
1707 void upload_owned_data(DTA_* adp_val, const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix) const
1708 {
1709 const DT_* loc_val = local_matrix.template val<LAFEM::Perspective::pod>();
1710 const IT_* adp_idx = _buf_mir.indices();
1711 const IT_* loc_idx = _loc_mir.indices();
1712 XASSERT(_buf_mir.num_indices() == _loc_mir.num_indices());
1713 Index n = _buf_mir.num_indices();
1714 for(Index i = 0; i < n; ++i)
1715 {
1716 ASSERT(loc_idx[i] < local_matrix.template used_elements<LAFEM::Perspective::pod>());
1717 adp_val[adp_idx[i]] = DTA_(loc_val[loc_idx[i]]);
1718 }
1719 }
1720
1721 void gather_owner_data(
1722 LAFEM::DenseVector<DT_, IT_>& buffer,
1723 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix) const
1724 {
1725 DT_* buf_val = buffer.elements();
1726 const DT_* loc_val = local_matrix.template val<LAFEM::Perspective::pod>();
1727 const IT_* buf_idx = this->_buf_mir.indices();
1728 const IT_* loc_idx = this->_loc_mir.indices();
1729 XASSERT(this->_buf_mir.num_indices() == this->_loc_mir.num_indices());
1730 Index n = this->_buf_mir.num_indices();
1731 for(Index i = 0; i < n; ++i)
1732 {
1733 ASSERT(buf_idx[i] < buffer.size());
1734 ASSERT(loc_idx[i] < local_matrix.template used_elements<LAFEM::Perspective::pod>());
1735 buf_val[buf_idx[i]] = loc_val[loc_idx[i]];
1736 }
1737 }
1738
1739 }; // class ADPDOMM<LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>>
1740
1742
1743 template<typename DT_, typename IT_, int bh_, int bw_>
1744 class ADPDOMM<LAFEM::NullMatrix<DT_, IT_, bh_, bw_>>
1745 {
1746 public:
1747 Index num_indices() const
1748 {
1749 return Index(0);
1750 }
1751
1752 Index buf_size() const
1753 {
1754 return Index(0);
1755 }
1756
1757 Index loc_size() const
1758 {
1759 return Index(0);
1760 }
1761
1762 String dump() const
1763 {
1764 return "[null]";
1765 }
1766
1767 Index asm_neighbor_owner_data_mir(
1768 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
1769 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1770 const LAFEM::MatrixMirrorBuffer<DT_, IT_>&,
1771 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>&,
1772 Index)
1773 {
1774 return row_mirror.num_indices() * Index(bh_);
1775 }
1776
1777 Index asm_neighbor_owner_data_mir(
1778 const LAFEM::NullMatrix<DT_, IT_, bh_, 1>&,
1779 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1780 const LAFEM::MatrixMirrorBuffer<DT_, IT_>&,
1781 const LAFEM::DenseVector<IT_, IT_>&,
1782 Index)
1783 {
1784 return row_mirror.num_indices() * Index(bh_);
1785 }
1786
1787 Index asm_owned_data_mir(
1788 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
1789 const Adjacency::Graph&,
1790 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1791 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>&,
1792 Index)
1793 {
1794 return row_mirror.num_indices() * Index(bh_);
1795 }
1796
1797 Index asm_owned_data_mir(
1798 const LAFEM::NullMatrix<DT_, IT_, bh_, 1>&,
1799 const Adjacency::Graph&,
1800 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
1801 const LAFEM::DenseVector<IT_, IT_>&,
1802 Index)
1803 {
1804 return row_mirror.num_indices() * Index(bh_);
1805 }
1806
1807 template<typename DTA_>
1808 void upload_owned_data(DTA_*, const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&) const
1809 {
1810 }
1811
1812 void gather_owner_data(
1813 LAFEM::DenseVector<DT_, IT_>&,
1814 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&) const
1815 {
1816 }
1817 }; // class ADPDOMM<LAFEM::NullMatrix<DT_, IT_, bh_, bw_>>
1818
1820
1821 template<typename FirstMatrix_, typename... RestMatrix_>
1822 class ADPDOMM<LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>>
1823 {
1824 public:
1825 typedef typename FirstMatrix_::DataType DT_;
1826 typedef typename FirstMatrix_::IndexType IT_;
1827
1828 ADPDOMM<FirstMatrix_> first;
1829 ADPDOMM<LAFEM::TupleMatrixRow<RestMatrix_...>> rest;
1830
1831 Index num_indices() const
1832 {
1833 return first.num_indices() + rest.num_indices();
1834 }
1835
1836 Index buf_size() const
1837 {
1838 return first.buf_size() + rest.buf_size();
1839 }
1840
1841 Index loc_size() const
1842 {
1843 return first.loc_size() + rest.loc_size();
1844 }
1845
1846 String dump_raw() const
1847 {
1848 return first.dump() + "," + rest.dump_raw();
1849 }
1850
1851 String dump() const
1852 {
1853 return "[" + dump_raw() + "]";
1854 }
1855
1856 template<
1857 typename RowMirror_,
1858 typename FirstIdxVec_, typename... RestIdxVec_>
1859 Index asm_neighbor_owner_data_mir(
1860 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
1861 const RowMirror_& row_mirror,
1862 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
1863 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
1864 Index row_offset)
1865 {
1866 Index n1 = first.asm_neighbor_owner_data_mir(local_matrix.first(), row_mirror, buffer, global_dof_idx.first(), row_offset);
1867 Index n2 = rest.asm_neighbor_owner_data_mir(local_matrix.rest(), row_mirror, buffer, global_dof_idx.rest(), row_offset);
1868 XASSERT(n1 == n2);
1869 return n1;
1870 }
1871
1872 template<
1873 typename RowMirror_,
1874 typename FirstIdxVec_, typename... RestIdxVec_>
1875 Index asm_owned_data_mir(
1876 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
1877 const Adjacency::Graph& owned_graph,
1878 const RowMirror_& row_mirror,
1879 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
1880 Index row_offset)
1881 {
1882 Index n1 = first.asm_owned_data_mir(local_matrix.first(), owned_graph, row_mirror, global_dof_idx.first(), row_offset);
1883 Index n2 = rest.asm_owned_data_mir(local_matrix.rest(), owned_graph, row_mirror, global_dof_idx.rest(), row_offset);
1884 XASSERT(n1 == n2);
1885 return n1;
1886 }
1887
1888 template<typename DTA_>
1889 void upload_owned_data(DTA_* adp_val, const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix) const
1890 {
1891 first.upload_owned_data(adp_val, local_matrix.first());
1892 rest.upload_owned_data(adp_val, local_matrix.rest());
1893 }
1894
1895 void gather_owner_data(
1896 LAFEM::DenseVector<DT_, IT_>& buffer,
1897 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix) const
1898 {
1899 first.gather_owner_data(buffer, local_matrix.first());
1900 rest.gather_owner_data(buffer, local_matrix.rest());
1901 }
1902 }; // class ADPDOMM<LAFEM::TupleMatrixRow<First_, Rest_...>>
1903
1905
1906 template<typename FirstMatrix_>
1907 class ADPDOMM<LAFEM::TupleMatrixRow<FirstMatrix_>>
1908 {
1909 public:
1910 typedef typename FirstMatrix_::DataType DT_;
1911 typedef typename FirstMatrix_::IndexType IT_;
1912
1913 ADPDOMM<FirstMatrix_> first;
1914
1915 Index num_indices() const
1916 {
1917 return first.num_indices();
1918 }
1919
1920 Index buf_size() const
1921 {
1922 return first.buf_size();
1923 }
1924
1925 Index loc_size() const
1926 {
1927 return first.loc_size();
1928 }
1929
1930 String dump_raw() const
1931 {
1932 return first.dump();
1933 }
1934
1935 String dump() const
1936 {
1937 return "[" + dump_raw() + "]";
1938 }
1939
1940 template<
1941 typename RowMirror_,
1942 typename FirstIdxVec_>
1943 Index asm_neighbor_owner_data_mir(
1944 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
1945 const RowMirror_& row_mirror,
1946 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
1947 const LAFEM::TupleVector<FirstIdxVec_>& global_dof_idx,
1948 Index row_offset)
1949 {
1950 return first.asm_neighbor_owner_data_mir(local_matrix.first(), row_mirror, buffer, global_dof_idx.first(), row_offset);
1951 }
1952
1953 template<
1954 typename RowMirror_,
1955 typename FirstIdxVec_>
1956 Index asm_owned_data_mir(
1957 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
1958 const Adjacency::Graph& owned_graph,
1959 const RowMirror_& row_mirror,
1960 const LAFEM::TupleVector<FirstIdxVec_>& global_dof_idx,
1961 Index row_offset)
1962 {
1963 return first.asm_owned_data_mir(local_matrix.first(), owned_graph, row_mirror, global_dof_idx.first(), row_offset);
1964 }
1965
1966 template<typename DTA_>
1967 void upload_owned_data(DTA_* adp_val, const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix) const
1968 {
1969 first.upload_owned_data(adp_val, local_matrix.first());
1970 }
1971
1972 void gather_owner_data(
1973 LAFEM::DenseVector<DT_, IT_>& buffer,
1974 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix) const
1975 {
1976 first.gather_owner_data(buffer, local_matrix.first());
1977 }
1978 }; // class ADPDOMM<LAFEM::TupleMatrixRow<First_>>
1979
1981
1982 template<typename FirstMatRow_, typename... RestMatRow_>
1983 class ADPDOMM<LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>>
1984 {
1985 public:
1986 typedef typename FirstMatRow_::DataType DT_;
1987 typedef typename FirstMatRow_::IndexType IT_;
1988
1989 ADPDOMM<FirstMatRow_> first;
1990 ADPDOMM<LAFEM::TupleMatrix<RestMatRow_...>> rest;
1991
1992 Index num_indices() const
1993 {
1994 return first.num_indices() + rest.num_indices();
1995 }
1996
1997 Index buf_size() const
1998 {
1999 return first.buf_size() + rest.buf_size();
2000 }
2001
2002 Index loc_size() const
2003 {
2004 return first.loc_size() + rest.loc_size();
2005 }
2006
2007 String dump_raw() const
2008 {
2009 return first.dump() + "," + rest.dump_raw();
2010 }
2011
2012 String dump() const
2013 {
2014 return "[" + dump_raw() + "]";
2015 }
2016
2017 template<
2018 typename FirstRowMir_, typename... RestRowMir_,
2019 typename FirstIdxVec_, typename... RestIdxVec_>
2020 Index asm_neighbor_owner_data_mir(
2021 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2022 const LAFEM::TupleMirror<FirstRowMir_, RestRowMir_...>& row_mirror,
2023 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
2024 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
2025 Index row_offset)
2026 {
2027 Index n1 = first.asm_neighbor_owner_data_mir(local_matrix.first(), row_mirror.first(), buffer, global_dof_idx, row_offset);
2028 Index n2 = rest.asm_neighbor_owner_data_mir(local_matrix.rest(), row_mirror.rest(), buffer, global_dof_idx, row_offset + n1);
2029 return n1 + n2;
2030 }
2031
2032 template<
2033 typename FirstRowMir_, typename... RestRowMir_,
2034 typename FirstIdxVec_, typename... RestIdxVec_>
2035 Index asm_owned_data_mir(
2036 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2037 const Adjacency::Graph& owned_graph,
2038 const LAFEM::TupleMirror<FirstRowMir_, RestRowMir_...>& row_mirror,
2039 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
2040 Index row_offset)
2041 {
2042 Index n1 = first.asm_owned_data_mir(local_matrix.first(), owned_graph, row_mirror.first(), global_dof_idx, row_offset);
2043 Index n2 = rest.asm_owned_data_mir(local_matrix.rest(), owned_graph, row_mirror.rest(), global_dof_idx, row_offset + n1);
2044 return n1 + n2;
2045 }
2046
2047 template<typename DTA_>
2048 void upload_owned_data(DTA_* adp_val, const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix) const
2049 {
2050 first.upload_owned_data(adp_val, local_matrix.first());
2051 rest.upload_owned_data(adp_val, local_matrix.rest());
2052 }
2053
2054 void gather_owner_data(
2055 LAFEM::DenseVector<DT_, IT_>& buffer,
2056 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix) const
2057 {
2058 first.gather_owner_data(buffer, local_matrix.first());
2059 rest.gather_owner_data(buffer, local_matrix.rest());
2060 }
2061 }; // class ADPDOMM<LAFEM::TupleMatrix<First_, Rest_...>>
2062
2064
2065 template<typename FirstMatRow_>
2066 class ADPDOMM<LAFEM::TupleMatrix<FirstMatRow_>>
2067 {
2068 public:
2069 typedef typename FirstMatRow_::DataType DT_;
2070 typedef typename FirstMatRow_::IndexType IT_;
2071
2072 ADPDOMM<FirstMatRow_> first;
2073
2074 Index num_indices() const
2075 {
2076 return first.num_indices();
2077 }
2078
2079 Index buf_size() const
2080 {
2081 return first.buf_size();
2082 }
2083
2084 Index loc_size() const
2085 {
2086 return first.loc_size();
2087 }
2088
2089 String dump_raw() const
2090 {
2091 return first.dump();
2092 }
2093
2094 String dump() const
2095 {
2096 return "[" + dump_raw() + "]";
2097 }
2098
2099 template<
2100 typename FirstRowMir_,
2101 typename FirstIdxVec_, typename... RestIdxVec_>
2102 Index asm_neighbor_owner_data_mir(
2103 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2104 const LAFEM::TupleMirror<FirstRowMir_>& row_mirror,
2105 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
2106 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
2107 Index row_offset)
2108 {
2109 return first.asm_neighbor_owner_data_mir(local_matrix.first(), row_mirror.first(), buffer, global_dof_idx, row_offset);
2110 }
2111
2112 template<
2113 typename FirstRowMir_,
2114 typename FirstIdxVec_, typename... RestIdxVec_>
2115 Index asm_owned_data_mir(
2116 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2117 const Adjacency::Graph& owned_graph,
2118 const LAFEM::TupleMirror<FirstRowMir_>& row_mirror,
2119 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
2120 Index row_offset)
2121 {
2122 return first.asm_owned_data_mir(local_matrix.first(), owned_graph, row_mirror.first(), global_dof_idx, row_offset);
2123 }
2124
2125 template<typename DTA_>
2126 void upload_owned_data(DTA_* adp_val, const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix) const
2127 {
2128 first.upload_owned_data(adp_val, local_matrix.first());
2129 }
2130
2131 void gather_owner_data(
2132 LAFEM::DenseVector<DT_, IT_>& buffer,
2133 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix) const
2134 {
2135 first.gather_owner_data(buffer, local_matrix.first());
2136 }
2137 }; // class ADPDOMM<LAFEM::TupleMatrix<First_>>
2138
2140
2141 template<typename MatrixA_, typename MatrixB_, typename MatrixD_>
2142 class ADPDOMM<LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>>
2143 {
2144 public:
2145 typedef typename MatrixA_::DataType DT_;
2146 typedef typename MatrixA_::IndexType IT_;
2147
2148 ADPDOMM<MatrixA_> block_a;
2149 ADPDOMM<MatrixB_> block_b;
2150 ADPDOMM<MatrixD_> block_d;
2151
2152 Index num_indices() const
2153 {
2154 return block_a.num_indices() + block_b.num_indices() + block_d.num_indices();
2155 }
2156
2157 Index buf_size() const
2158 {
2159 return block_a.buf_size() + block_b.buf_size() + block_d.buf_size();
2160 }
2161
2162 Index loc_size() const
2163 {
2164 return block_a.loc_size() + block_b.loc_size() + block_d.loc_size();
2165 }
2166
2167 String dump() const
2168 {
2169 return "[[" + block_a.dump() + "," + block_b.dump() + "],[" + block_d.dump() + ",0]";
2170 }
2171
2172 template<
2173 typename MirrorV_, typename MirrorP_,
2174 typename IdxVecV_, typename IdxVecP_>
2175 Index asm_neighbor_owner_data_mir(
2176 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2177 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror,
2178 const LAFEM::MatrixMirrorBuffer<DT_, IT_>& buffer,
2179 const LAFEM::TupleVector<IdxVecV_, IdxVecP_>& global_dof_idx,
2180 Index row_offset)
2181 {
2182 Index na = block_a.asm_neighbor_owner_data_mir(local_matrix.block_a(), row_mirror.template at<0>(), buffer, global_dof_idx.template at<0>(), row_offset);
2183 Index nb = block_b.asm_neighbor_owner_data_mir(local_matrix.block_b(), row_mirror.template at<0>(), buffer, global_dof_idx.template at<1>(), row_offset);
2184 XASSERT(na == nb);
2185 Index nd = block_d.asm_neighbor_owner_data_mir(local_matrix.block_d(), row_mirror.template at<1>(), buffer, global_dof_idx.template at<0>(), row_offset + na);
2186 return na + nd;
2187 }
2188
2189 template<
2190 typename MirrorV_, typename MirrorP_,
2191 typename IdxVecV_, typename IdxVecP_>
2192 Index asm_owned_data_mir(
2193 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2194 const Adjacency::Graph& owned_graph,
2195 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror,
2196 const LAFEM::TupleVector<IdxVecV_, IdxVecP_>& global_dof_idx,
2197 Index row_offset)
2198 {
2199 Index na = block_a.asm_owned_data_mir(local_matrix.block_a(), owned_graph, row_mirror.template at<0>(), global_dof_idx.template at<0>(), row_offset);
2200 Index nb = block_b.asm_owned_data_mir(local_matrix.block_b(), owned_graph, row_mirror.template at<0>(), global_dof_idx.template at<1>(), row_offset);
2201 XASSERT(na == nb);
2202 Index nd = block_d.asm_owned_data_mir(local_matrix.block_d(), owned_graph, row_mirror.template at<1>(), global_dof_idx.template at<0>(), row_offset + na);
2203 return na + nd;
2204 }
2205
2206 template<typename DTA_>
2207 void upload_owned_data(DTA_* adp_val, const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix) const
2208 {
2209 block_a.upload_owned_data(adp_val, local_matrix.block_a());
2210 block_b.upload_owned_data(adp_val, local_matrix.block_b());
2211 block_d.upload_owned_data(adp_val, local_matrix.block_d());
2212 }
2213
2214 void gather_owner_data(
2215 LAFEM::DenseVector<DT_, IT_>& buffer,
2216 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix) const
2217 {
2218 block_a.gather_owner_data(buffer, local_matrix.block_a());
2219 block_b.gather_owner_data(buffer, local_matrix.block_b());
2220 block_d.gather_owner_data(buffer, local_matrix.block_d());
2221 }
2222 }; // class ADPDOMM<LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>>
2223
2225
2226 template<typename DT_, typename IT_>
2227 class ADPMatAux<LAFEM::SparseMatrixCSR<DT_, IT_>>
2228 {
2229 public:
2230 static Index calc_mat_buf_num_rows(
2231 const LAFEM::SparseMatrixCSR<DT_, IT_>& DOXY(local_matrix),
2232 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2233 {
2234 return row_mirror.num_indices();
2235 }
2236
2237 static Index calc_mat_buf_row_nze(
2238 IT_* buf_row_nze,
2239 const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix,
2240 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2241 {
2242 const Index num_idx = row_mirror.num_indices();
2243 const IT_* mir_idx = row_mirror.indices();
2244 const IT_* row_ptr = local_matrix.row_ptr();
2245
2246 for(Index i(0); i < num_idx; ++i)
2247 {
2248 buf_row_nze[i] += (row_ptr[mir_idx[i]+1] - row_ptr[mir_idx[i]]);
2249 }
2250
2251 return num_idx;
2252 }
2253
2254 static Index gather_mat_buf_col_idx(
2255 IT_* aux_row_ptr,
2256 IT_* buf_col_idx,
2257 const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix,
2258 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2259 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx)
2260 {
2261 const Index num_idx = row_mirror.num_indices();
2262 const IT_* mir_idx = row_mirror.indices();
2263 const IT_* row_ptr = local_matrix.row_ptr();
2264 const IT_* col_idx = local_matrix.col_ind();
2265 const IT_* glob_dof_idx = global_dof_idx.elements();
2266
2267 for(Index i(0); i < num_idx; ++i)
2268 {
2269 // k must be a reference as we need to update the auxiliary row pointer
2270 IT_& k = aux_row_ptr[i];
2271 const IT_ row = mir_idx[i];
2272
2273 // map local DOFs to global DOFs
2274 for(IT_ j(row_ptr[row]); j < row_ptr[row+1]; ++j, ++k)
2275 buf_col_idx[k] = glob_dof_idx[col_idx[j]];
2276 }
2277
2278 return num_idx;
2279 }
2280
2281 static Index gather_owned_struct(
2282 Adjacency::DynamicGraph& graph,
2283 const LAFEM::SparseMatrixCSR<DT_, IT_>& local_matrix,
2284 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2285 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
2286 const Index row_offset)
2287 {
2288 const Index num_rows = row_mirror.num_indices();
2289 const IT_* loc_row_ptr = local_matrix.row_ptr();
2290 const IT_* loc_col_idx = local_matrix.col_ind();
2291 const IT_* row_mir_idx = row_mirror.indices();
2292 const IT_* glob_dof_idx = global_dof_idx.elements();
2293
2294 for(Index i(0); i < num_rows; ++i)
2295 {
2296 const IT_ lrow = row_mir_idx[i];
2297 for(IT_ j(loc_row_ptr[lrow]); j < loc_row_ptr[lrow + 1]; ++j)
2298 {
2299 graph.insert(row_offset + i, Index(glob_dof_idx[loc_col_idx[j]]));
2300 }
2301 }
2302 return num_rows;
2303 }
2304 }; // class ADPMatAux<LAFEM::SparseMatrixCSR<DT_, IT_>>
2305
2307
2308 template<typename DT_, typename IT_, int bh_, int bw_>
2309 class ADPMatAux<LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>>
2310 {
2311 public:
2312 static Index calc_mat_buf_num_rows(
2313 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& DOXY(local_matrix),
2314 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2315 {
2316 return row_mirror.num_indices() * Index(bh_);
2317 }
2318
2319 static Index calc_mat_buf_row_nze(
2320 IT_* buf_row_nze,
2321 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix,
2322 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2323 {
2324 const Index num_idx = row_mirror.num_indices();
2325 const IT_* mir_idx = row_mirror.indices();
2326 const IT_* row_ptr = local_matrix.row_ptr();
2327
2328 for(Index i(0), j(0); i < num_idx; ++i)
2329 {
2330 IT_ nn = IT_(bw_) * (row_ptr[mir_idx[i]+1] - row_ptr[mir_idx[i]]);
2331 for(int k(0); k < bh_; ++k, ++j)
2332 buf_row_nze[j] += nn;
2333 }
2334
2335 return num_idx * Index(bh_);
2336 }
2337
2338 static Index gather_mat_buf_col_idx(
2339 IT_* aux_row_ptr,
2340 IT_* buf_col_idx,
2341 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix,
2342 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2343 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>& global_dof_idx)
2344 {
2345 const Index num_idx = row_mirror.num_indices();
2346 const IT_* mir_idx = row_mirror.indices();
2347 const IT_* row_ptr = local_matrix.row_ptr();
2348 const IT_* col_idx = local_matrix.col_ind();
2349 const auto* glob_dof_idx = global_dof_idx.elements();
2350
2351 for(Index i(0); i < num_idx; ++i)
2352 {
2353 const IT_ row = mir_idx[i];
2354
2355 // loop over the rows of the block
2356 for(int bi(0); bi < bh_; ++bi)
2357 {
2358 // k must be a reference as we need to update the auxiliary row pointer
2359 IT_& k = aux_row_ptr[i*IT_(bh_) + IT_(bi)];
2360
2361 // map local DOFs to global DOFs
2362 for(IT_ j(row_ptr[row]); j < row_ptr[row+1]; ++j)
2363 {
2364 // loop over the columns of this block
2365 for(int bj(0); bj < bw_; ++bj, ++k)
2366 {
2367 buf_col_idx[k] = glob_dof_idx[col_idx[j]][bj];
2368 }
2369 }
2370 }
2371 }
2372
2373 return num_idx * Index(bh_);
2374 }
2375
2376 static Index gather_mat_buf_col_idx(
2377 IT_* aux_row_ptr,
2378 IT_* buf_col_idx,
2379 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, 1>& local_matrix,
2380 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2381 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx)
2382 {
2383 const Index num_idx = row_mirror.num_indices();
2384 const IT_* mir_idx = row_mirror.indices();
2385 const IT_* row_ptr = local_matrix.row_ptr();
2386 const IT_* col_idx = local_matrix.col_ind();
2387 const auto* glob_dof_idx = global_dof_idx.elements();
2388
2389 for(Index i(0); i < num_idx; ++i)
2390 {
2391 const IT_ row = mir_idx[i];
2392
2393 // loop over the rows of the block
2394 for(int bi(0); bi < bh_; ++bi)
2395 {
2396 // k must be a reference as we need to update the auxiliary row pointer
2397 IT_& k = aux_row_ptr[i*IT_(bh_) + IT_(bi)];
2398
2399 // map local DOFs to global DOFs
2400 for(IT_ j(row_ptr[row]); j < row_ptr[row+1]; ++j, ++k)
2401 {
2402 buf_col_idx[k] = glob_dof_idx[col_idx[j]];
2403 }
2404 }
2405 }
2406
2407 return num_idx * Index(bh_);
2408 }
2409
2410 static Index gather_owned_struct(
2411 Adjacency::DynamicGraph& graph,
2412 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>& local_matrix,
2413 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2414 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>& global_dof_idx,
2415 const Index row_offset)
2416 {
2417 const Index num_rows = row_mirror.num_indices();
2418 const IT_* loc_row_ptr = local_matrix.row_ptr();
2419 const IT_* loc_col_idx = local_matrix.col_ind();
2420 const IT_* row_mir_idx = row_mirror.indices();
2421 const auto* glob_dof_idx = global_dof_idx.elements();
2422
2423 for(Index i(0); i < num_rows; ++i)
2424 {
2425 const Index lrow = row_mir_idx[i];
2426 for(IT_ j(loc_row_ptr[lrow]); j < loc_row_ptr[lrow + 1]; ++j)
2427 {
2428 const auto& gci = glob_dof_idx[loc_col_idx[j]];
2429 for(int bi = 0; bi < bh_; ++bi)
2430 {
2431 for(int bj = 0; bj < bw_; ++bj)
2432 {
2433 graph.insert(row_offset + i*Index(bh_) + Index(bi), Index(gci[bj]));
2434 }
2435 }
2436 }
2437 }
2438 return num_rows * Index(bh_);
2439 }
2440
2441 static Index gather_owned_struct(
2442 Adjacency::DynamicGraph& graph,
2443 const LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, 1>& local_matrix,
2444 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2445 const LAFEM::DenseVector<IT_, IT_>& global_dof_idx,
2446 const Index row_offset)
2447 {
2448 const Index num_rows = row_mirror.num_indices();
2449 const IT_* loc_row_ptr = local_matrix.row_ptr();
2450 const IT_* loc_col_idx = local_matrix.col_ind();
2451 const IT_* row_mir_idx = row_mirror.indices();
2452 const IT_* glob_dof_idx = global_dof_idx.elements();
2453
2454 for(Index i(0); i < num_rows; ++i)
2455 {
2456 const Index lrow = row_mir_idx[i];
2457 for(IT_ j(loc_row_ptr[lrow]); j < loc_row_ptr[lrow + 1]; ++j)
2458 {
2459 const IT_ gci = glob_dof_idx[loc_col_idx[j]];
2460 for(int bi = 0; bi < bh_; ++bi)
2461 {
2462 graph.insert(row_offset + i*Index(bh_) + Index(bi), Index(gci));
2463 }
2464 }
2465 }
2466 return num_rows * Index(bh_);
2467 }
2468 }; // class ADPMatAux<LAFEM::SparseMatrixBCSR<DT_, IT_, bh_, bw_>>
2469
2471
2472 template<typename DT_, typename IT_, int bh_, int bw_>
2473 class ADPMatAux<LAFEM::NullMatrix<DT_, IT_, bh_, bw_>>
2474 {
2475 public:
2476 static Index calc_mat_buf_num_rows(
2477 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
2478 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2479 {
2480 return row_mirror.num_indices() * Index(bh_);
2481 }
2482
2483 static Index calc_mat_buf_row_nze(
2484 IT_*,
2485 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
2486 const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2487 {
2488 return row_mirror.num_indices() * Index(bh_);
2489 }
2490
2491 static Index gather_mat_buf_col_idx(
2492 IT_*,
2493 IT_*,
2494 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
2495 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2496 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>&)
2497 {
2498 return row_mirror.num_indices() * Index(bh_);
2499 }
2500
2501 static Index gather_mat_buf_col_idx(
2502 IT_*,
2503 IT_*,
2504 const LAFEM::NullMatrix<DT_, IT_, bh_, 1>&,
2505 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2506 const LAFEM::DenseVector<IT_, IT_>&)
2507 {
2508 return row_mirror.num_indices() * Index(bh_);
2509 }
2510
2511 static Index gather_owned_struct(
2512 Adjacency::DynamicGraph&,
2513 const LAFEM::NullMatrix<DT_, IT_, bh_, bw_>&,
2514 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2515 const LAFEM::DenseVectorBlocked<IT_, IT_, bw_>&,
2516 const Index)
2517 {
2518 return row_mirror.num_indices() * Index(bh_);
2519 }
2520
2521 static Index gather_owned_struct(
2522 Adjacency::DynamicGraph&,
2523 const LAFEM::NullMatrix<DT_, IT_, bh_, 1>&,
2524 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2525 const LAFEM::DenseVector<IT_, IT_>&,
2526 const Index)
2527 {
2528 return row_mirror.num_indices() * Index(bh_);
2529 }
2530 }; // class ADPMatAux<LAFEM::NullMatrix<DT_, IT_, bh_, bw_>>
2531
2533
2534 template<typename FirstMatrix_, typename... RestMatrix_>
2535 class ADPMatAux<LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>>
2536 {
2537 public:
2538 typedef typename FirstMatrix_::IndexType IT_;
2539 typedef ADPMatAux<FirstMatrix_> ADPMatAuxFirst;
2540 typedef ADPMatAux<LAFEM::TupleMatrixRow<RestMatrix_...>> ADPMatAuxRest;
2541
2542 template<typename RowMirror_>
2543 static Index calc_mat_buf_num_rows(
2544 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
2545 const RowMirror_& row_mirror)
2546 {
2547 Index n1 = ADPMatAuxFirst::calc_mat_buf_num_rows(local_matrix.first(), row_mirror);
2548 Index n2 = ADPMatAuxRest::calc_mat_buf_num_rows(local_matrix.rest(), row_mirror);
2549 XASSERT(n1 == n2);
2550 return n1;
2551 }
2552
2553 template<typename RowMirror_>
2554 static Index calc_mat_buf_row_nze(
2555 IT_* buf_row_nze,
2556 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
2557 const RowMirror_& row_mirror)
2558 {
2559 Index n1 = ADPMatAuxFirst::calc_mat_buf_row_nze(buf_row_nze, local_matrix.first(), row_mirror);
2560 Index n2 = ADPMatAuxRest::calc_mat_buf_row_nze(buf_row_nze, local_matrix.rest(), row_mirror);
2561 XASSERT(n1 == n2);
2562 return n1;
2563 }
2564
2565 template<
2566 typename RowMirror_,
2567 typename FirstIdxVec_, typename... RestIdxVec_>
2568 static Index gather_mat_buf_col_idx(
2569 IT_* aux_row_ptr,
2570 IT_* buf_col_idx,
2571 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
2572 const RowMirror_& row_mirror,
2573 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx)
2574 {
2575 Index n1 = ADPMatAuxFirst::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.first(), row_mirror, global_dof_idx.first());
2576 Index n2 = ADPMatAuxRest::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.rest(), row_mirror, global_dof_idx.rest());
2577 XASSERT(n1 == n2);
2578 return n1;
2579 }
2580
2581 template<
2582 typename RowMirror_,
2583 typename FirstIdxVec_, typename... RestIdxVec_>
2584 static Index gather_owned_struct(
2585 Adjacency::DynamicGraph& graph,
2586 const LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>& local_matrix,
2587 const RowMirror_& row_mirror,
2588 const LAFEM::TupleVector<FirstIdxVec_, RestIdxVec_...>& global_dof_idx,
2589 const Index row_offset)
2590 {
2591 Index n1 = ADPMatAuxFirst::gather_owned_struct(graph, local_matrix.first(), row_mirror, global_dof_idx.first(), row_offset);
2592 Index n2 = ADPMatAuxRest::gather_owned_struct(graph, local_matrix.rest(), row_mirror, global_dof_idx.rest(), row_offset);
2593 XASSERT(n1 == n2);
2594 return n1;
2595 }
2596 }; // class ADPMatAux<LAFEM::TupleMatrixRow<FirstMatrix_, RestMatrix_...>>
2597
2599
2600 template<typename FirstMatrix_>
2601 class ADPMatAux<LAFEM::TupleMatrixRow<FirstMatrix_>>
2602 {
2603 public:
2604 typedef typename FirstMatrix_::IndexType IT_;
2605 typedef ADPMatAux<FirstMatrix_> ADPMatAuxFirst;
2606
2607 template<typename RowMirror_>
2608 static Index calc_mat_buf_num_rows(
2609 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
2610 const RowMirror_& row_mirror)
2611 {
2612 return ADPMatAuxFirst::calc_mat_buf_num_rows(local_matrix.first(), row_mirror);
2613 }
2614
2615 template<typename RowMirror_>
2616 static Index calc_mat_buf_row_nze(
2617 IT_* buf_row_nze,
2618 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
2619 const RowMirror_& row_mirror)
2620 {
2621 return ADPMatAuxFirst::calc_mat_buf_row_nze(buf_row_nze, local_matrix.first(), row_mirror);
2622 }
2623
2624 template<
2625 typename RowMirror_,
2626 typename FirstIdxVec_>
2627 static Index gather_mat_buf_col_idx(
2628 IT_* aux_row_ptr,
2629 IT_* buf_col_idx,
2630 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
2631 const RowMirror_& row_mirror,
2632 const LAFEM::TupleVector<FirstIdxVec_>& global_dof_idx)
2633 {
2634 return ADPMatAuxFirst::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.first(), row_mirror, global_dof_idx.first());
2635 }
2636
2637 template<
2638 typename RowMirror_,
2639 typename FirstIdxVec_>
2640 static Index gather_owned_struct(
2641 Adjacency::DynamicGraph& graph,
2642 const LAFEM::TupleMatrixRow<FirstMatrix_>& local_matrix,
2643 const RowMirror_& row_mirror,
2644 const LAFEM::TupleVector<FirstIdxVec_>& global_dof_idx,
2645 const Index row_offset)
2646 {
2647 return ADPMatAuxFirst::gather_owned_struct(graph, local_matrix.first(), row_mirror, global_dof_idx.first(), row_offset);
2648 }
2649 }; // class ADPMatAux<LAFEM::TupleMatrixRow<FirstMatrix_>>
2650
2652
2653 template<typename FirstMatRow_, typename... RestMatRow_>
2654 class ADPMatAux<LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>>
2655 {
2656 public:
2657 typedef typename FirstMatRow_::IndexType IT_;
2658 typedef ADPMatAux<FirstMatRow_> ADPMatAuxFirst;
2659 typedef ADPMatAux<LAFEM::TupleMatrix<RestMatRow_...>> ADPMatAuxRest;
2660
2661 template<typename FirstMirror_, typename... RestMirror_>
2662 static Index calc_mat_buf_num_rows(
2663 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2664 const LAFEM::TupleMirror<FirstMirror_, RestMirror_...>& row_mirror)
2665 {
2666 Index n1 = ADPMatAuxFirst::calc_mat_buf_num_rows(local_matrix.first(), row_mirror.first());
2667 Index n2 = ADPMatAuxRest::calc_mat_buf_num_rows(local_matrix.rest(), row_mirror.rest());
2668 return n1 + n2;
2669 }
2670
2671 template<typename FirstMirror_, typename... RestMirror_>
2672 static Index calc_mat_buf_row_nze(
2673 IT_* buf_row_nze,
2674 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2675 const LAFEM::TupleMirror<FirstMirror_, RestMirror_...>& row_mirror)
2676 {
2677 Index n1 = ADPMatAuxFirst::calc_mat_buf_row_nze(buf_row_nze, local_matrix.first(), row_mirror.first());
2678 Index n2 = ADPMatAuxRest::calc_mat_buf_row_nze(&buf_row_nze[n1], local_matrix.rest(), row_mirror.rest());
2679 return n1 + n2;
2680 }
2681
2682 template<
2683 typename FirstMirror_, typename... RestMirror_,
2684 typename IndexVector_>
2685 static Index gather_mat_buf_col_idx(
2686 IT_* aux_row_ptr,
2687 IT_* buf_col_idx,
2688 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2689 const LAFEM::TupleMirror<FirstMirror_, RestMirror_...>& row_mirror,
2690 const IndexVector_& global_dof_idx)
2691 {
2692 Index n1 = ADPMatAuxFirst::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.first(), row_mirror.first(), global_dof_idx);
2693 Index n2 = ADPMatAuxRest::gather_mat_buf_col_idx(&aux_row_ptr[n1], buf_col_idx, local_matrix.rest(), row_mirror.rest(), global_dof_idx);
2694 return n1 + n2;
2695 }
2696
2697 template<
2698 typename FirstMirror_, typename... RestMirror_,
2699 typename IndexVector_>
2700 static Index gather_owned_struct(
2701 Adjacency::DynamicGraph& graph,
2702 const LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>& local_matrix,
2703 const LAFEM::TupleMirror<FirstMirror_, RestMirror_...>& row_mirror,
2704 const IndexVector_& global_dof_idx,
2705 const Index row_offset)
2706 {
2707 Index n1 = ADPMatAuxFirst::gather_owned_struct(graph, local_matrix.first(), row_mirror.first(), global_dof_idx, row_offset);
2708 Index n2 = ADPMatAuxRest::gather_owned_struct(graph, local_matrix.rest(), row_mirror.rest(), global_dof_idx, row_offset + n1);
2709 return n1 + n2;
2710 }
2711 }; // class ADPMatAux<LAFEM::TupleMatrix<FirstMatRow_, RestMatRow_...>>
2712
2714
2715 template<typename FirstMatRow_>
2716 class ADPMatAux<LAFEM::TupleMatrix<FirstMatRow_>>
2717 {
2718 public:
2719 typedef typename FirstMatRow_::IndexType IT_;
2720 typedef ADPMatAux<FirstMatRow_> ADPMatAuxFirst;
2721
2722 template<typename FirstMirror_>
2723 static Index calc_mat_buf_num_rows(
2724 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2725 const LAFEM::TupleMirror<FirstMirror_>& row_mirror)
2726 {
2727 return ADPMatAuxFirst::calc_mat_buf_num_rows(local_matrix.first(), row_mirror.first());
2728 }
2729
2730 template<typename FirstMirror_>
2731 static Index calc_mat_buf_row_nze(
2732 IT_* buf_row_nze,
2733 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2734 const LAFEM::TupleMirror<FirstMirror_>& row_mirror)
2735 {
2736 return ADPMatAuxFirst::calc_mat_buf_row_nze(buf_row_nze, local_matrix.first(), row_mirror.first());
2737 }
2738
2739 template<
2740 typename FirstMirror_,
2741 typename IndexVector_>
2742 static Index gather_mat_buf_col_idx(
2743 IT_* aux_row_ptr,
2744 IT_* buf_col_idx,
2745 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2746 const LAFEM::TupleMirror<FirstMirror_>& row_mirror,
2747 const IndexVector_& global_dof_idx)
2748 {
2749 return ADPMatAuxFirst::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.first(), row_mirror.first(), global_dof_idx);
2750 }
2751
2752 template<
2753 typename FirstMirror_,
2754 typename IndexVector_>
2755 static Index gather_owned_struct(
2756 Adjacency::DynamicGraph& graph,
2757 const LAFEM::TupleMatrix<FirstMatRow_>& local_matrix,
2758 const LAFEM::TupleMirror<FirstMirror_>& row_mirror,
2759 const IndexVector_& global_dof_idx,
2760 const Index row_offset)
2761 {
2762 return ADPMatAuxFirst::gather_owned_struct(graph, local_matrix.first(), row_mirror.first(), global_dof_idx, row_offset);
2763 }
2764 }; // class ADPMatAux<LAFEM::TupleMatrix<FirstMatRow_>>
2765
2767
2768 template<typename MatrixA_, typename MatrixB_, typename MatrixD_>
2769 class ADPMatAux<LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>>
2770 {
2771 public:
2772 typedef typename MatrixA_::IndexType IT_;
2773 typedef ADPMatAux<MatrixA_> ADPMatAuxA;
2774 typedef ADPMatAux<MatrixB_> ADPMatAuxB;
2775 typedef ADPMatAux<MatrixD_> ADPMatAuxD;
2776
2777 template<typename MirrorV_, typename MirrorP_>
2778 static Index calc_mat_buf_num_rows(
2779 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2780 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror)
2781 {
2782 Index n1 = ADPMatAuxB::calc_mat_buf_num_rows(local_matrix.block_b(), row_mirror.template at<0>());
2783 Index n2 = ADPMatAuxD::calc_mat_buf_num_rows(local_matrix.block_d(), row_mirror.template at<1>());
2784 return n1 + n2;
2785 }
2786
2787 template<typename MirrorV_, typename MirrorP_>
2788 static Index calc_mat_buf_row_nze(
2789 IT_* buf_row_nze,
2790 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2791 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror)
2792 {
2793 Index na = ADPMatAuxA::calc_mat_buf_row_nze(buf_row_nze, local_matrix.block_a(), row_mirror.template at<0>());
2794 Index nb = ADPMatAuxB::calc_mat_buf_row_nze(buf_row_nze, local_matrix.block_b(), row_mirror.template at<0>());
2795 XASSERT(na == nb);
2796 Index nd = ADPMatAuxD::calc_mat_buf_row_nze(&buf_row_nze[na], local_matrix.block_d(), row_mirror.template at<1>());
2797
2798 // \todo invent main diagonal for pressure block
2799 //for(Index i = 0u; i < nd; ++i)
2800 //++buf_row_nze[na + i];
2801
2802 return na + nd;
2803 }
2804
2805 template<
2806 typename MirrorV_, typename MirrorP_,
2807 typename IdxVecV_, typename IdxVecP_>
2808 static Index gather_mat_buf_col_idx(
2809 IT_* aux_row_ptr,
2810 IT_* buf_col_idx,
2811 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2812 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror,
2813 const LAFEM::TupleVector<IdxVecV_, IdxVecP_>& global_dof_idx)
2814 {
2815 Index na = ADPMatAuxA::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.block_a(), row_mirror.template at<0>(), global_dof_idx.template at<0>());
2816 Index nb = ADPMatAuxB::gather_mat_buf_col_idx(aux_row_ptr, buf_col_idx, local_matrix.block_b(), row_mirror.template at<0>(), global_dof_idx.template at<1>());
2817 XASSERT(na == nb);
2818 Index nd = ADPMatAuxD::gather_mat_buf_col_idx(&aux_row_ptr[na], buf_col_idx, local_matrix.block_d(), row_mirror.template at<1>(), global_dof_idx.template at<0>());
2819
2820 // \todo invent main diagonal for pressure block
2821 //const auto* p_dof_idx = global_dof_idx.template at<1>().elements();
2822 //for(Index i = 0u; i < nd; ++i)
2823 //buf_col_idx[aux_row_ptr[na + i]] = p_dof_idx[i];
2824
2825 return na + nd;
2826 }
2827
2828 template<
2829 typename MirrorV_, typename MirrorP_,
2830 typename IdxVecV_, typename IdxVecP_>
2831 static Index gather_owned_struct(
2832 Adjacency::DynamicGraph& graph,
2833 const LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>& local_matrix,
2834 const LAFEM::TupleMirror<MirrorV_, MirrorP_>& row_mirror,
2835 const LAFEM::TupleVector<IdxVecV_, IdxVecP_>& global_dof_idx,
2836 const Index row_offset)
2837 {
2838 Index na = ADPMatAuxA::gather_owned_struct(graph, local_matrix.block_a(), row_mirror.template at<0>(), global_dof_idx.template at<0>(), row_offset);
2839 Index nb = ADPMatAuxB::gather_owned_struct(graph, local_matrix.block_b(), row_mirror.template at<0>(), global_dof_idx.template at<1>(), row_offset);
2840 XASSERT(na == nb);
2841 Index nd = ADPMatAuxD::gather_owned_struct(graph, local_matrix.block_d(), row_mirror.template at<1>(), global_dof_idx.template at<0>(), row_offset + na);
2842
2843 // invent main diagonal for pressure block
2844 {
2845 const auto* p_dof_idx = global_dof_idx.template at<1>().elements();
2846 for(Index i = 0u; i < nd; ++i)
2847 graph.insert(na + i, p_dof_idx[i]);
2848 }
2849
2850 return na + nd;
2851 }
2852 }; // class ADPMatAux<LAFEM::SaddlePointMatrix<MatrixA_, MatrixB_, MatrixD_>>
2853
2857
2858 template<typename DT_, typename IT_>
2859 class ADPFilAux<LAFEM::NoneFilter<DT_, IT_>>
2860 {
2861 public:
2862 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2863 {
2864 return row_mirror.num_indices();
2865 }
2866
2867 static Index upload_filter(
2868 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
2869 const LAFEM::NoneFilter<DT_, IT_>& DOXY(filter),
2870 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2871 Index DOXY(row_offset))
2872 {
2873 // nothing to do here
2874 return row_count(row_mirror);
2875 }
2876 }; // class ADPFilAux<LAFEM::NoneFilter<DT_, IT_>>
2877
2879
2880 template<typename DT_, typename IT_, int bs_>
2881 class ADPFilAux<LAFEM::NoneFilterBlocked<DT_, IT_, bs_>>
2882 {
2883 public:
2884 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2885 {
2886 return row_mirror.num_indices() * Index(bs_);
2887 }
2888
2889 static Index upload_filter(
2890 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
2891 const LAFEM::NoneFilterBlocked<DT_, IT_, bs_>& DOXY(filter),
2892 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2893 Index DOXY(row_offset))
2894 {
2895 // nothing to do here
2896 return row_count(row_mirror);
2897 }
2898 }; // class ADPFilAux<LAFEM::NoneFilterBlocked<DT_, IT_, bs_>>
2899
2901
2902 template<typename DT_, typename IT_>
2903 class ADPFilAux<LAFEM::UnitFilter<DT_, IT_>>
2904 {
2905 public:
2906 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2907 {
2908 return row_mirror.num_indices();
2909 }
2910
2911 static Index upload_filter(
2912 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
2913 const LAFEM::UnitFilter<DT_, IT_>& filter,
2914 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2915 Index row_offset)
2916 {
2917 if(filter.used_elements() <= Index(0))
2918 return row_count(row_mirror);
2919
2920 const IT_* fil_idx = filter.get_indices();
2921 const IT_* mir_idx = row_mirror.indices();
2922 const Index num_fil = filter.used_elements();
2923 const Index num_mir = row_mirror.num_indices();
2924
2925 Index i = 0u, j = 0u;
2926 while((i < num_fil) && (j < num_mir))
2927 {
2928 if(fil_idx[i] < Index(mir_idx[j]))
2929 ++i;
2930 else if(fil_idx[i] > Index(mir_idx[j]))
2931 ++j;
2932 else
2933 {
2934 unit_rows.add(IT_(row_offset + j), DT_(0));
2935 ++i;
2936 ++j;
2937 }
2938 }
2939
2940 return row_count(row_mirror);
2941 }
2942 }; // class ADPFilAux<LAFEM::UnitFilter<DT_, IT_>>
2943
2945
2946 template<typename DT_, typename IT_, int bs_>
2947 class ADPFilAux<LAFEM::UnitFilterBlocked<DT_, IT_, bs_>>
2948 {
2949 public:
2950 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
2951 {
2952 return row_mirror.num_indices() * Index(bs_);
2953 }
2954
2955 static Index upload_filter(
2956 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
2957 const LAFEM::UnitFilterBlocked<DT_, IT_, bs_>& filter,
2958 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
2959 Index row_offset)
2960 {
2961 if(filter.used_elements() <= Index(0))
2962 return row_count(row_mirror);
2963
2964 const bool ignore_nans = filter.get_ignore_nans();
2965 const auto* fil_val = filter.get_values();
2966 const IT_* fil_idx = filter.get_indices();
2967 const IT_* mir_idx = row_mirror.indices();
2968 const Index num_fil = filter.used_elements();
2969 const Index num_mir = row_mirror.num_indices();
2970
2971 Index i = 0u, j = 0u;
2972 while((i < num_fil) && (j < num_mir))
2973 {
2974 if(fil_idx[i] < Index(mir_idx[j]))
2975 ++i;
2976 else if(fil_idx[i] > Index(mir_idx[j]))
2977 ++j;
2978 else
2979 {
2980 // process the entire block
2981 for(int k = 0; k < bs_; ++k)
2982 {
2983 if(!ignore_nans || !Math::isnan(fil_val[i][k]))
2984 unit_rows.add(IT_(row_offset + j*Index(bs_) + Index(k)), DT_(0));
2985 }
2986 ++i;
2987 }
2988 }
2989
2990 return row_count(row_mirror);
2991 }
2992 }; // class ADPFilAux<LAFEM::UnitFilterBlocked<DT_, IT_, bs_>>
2993
2995
2996 template<typename DT_, typename IT_>
2997 class ADPFilAux<LAFEM::MeanFilter<DT_, IT_>>
2998 {
2999 public:
3000 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3001 {
3002 return row_mirror.num_indices();
3003 }
3004
3005 static Index upload_filter(
3006 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
3007 const LAFEM::MeanFilter<DT_, IT_>& filter,
3008 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
3009 Index DOXY(row_offset))
3010 {
3011 XASSERTM(filter.empty(), "AlgDofParti does not support LAFEM::MeanFilter yet!");
3012 return row_count(row_mirror);
3013 }
3014 }; // class ADPFilAux<LAFEM::MeanFilter<DT_, IT_>>
3015
3017
3018 template<typename DT_, typename IT_, int bs_>
3019 class ADPFilAux<LAFEM::MeanFilterBlocked<DT_, IT_, bs_>>
3020 {
3021 public:
3022 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3023 {
3024 return row_mirror.num_indices() * Index(bs_);
3025 }
3026
3027 static Index upload_filter(
3028 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
3029 const LAFEM::MeanFilterBlocked<DT_, IT_, bs_>& filter,
3030 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
3031 Index DOXY(row_offset))
3032 {
3033 XASSERTM(filter.empty(), "AlgDofParti does not support LAFEM::MeanFilterBlocked yet!");
3034 return row_count(row_mirror);
3035 }
3036 }; // class ADPFilAux<LAFEM::MeanFilterBlocked<DT_, IT_, bs_>>
3037
3039
3040 template<typename DT_, typename IT_>
3041 class ADPFilAux<Global::MeanFilter<DT_, IT_>>
3042 {
3043 public:
3044 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3045 {
3046 return row_mirror.num_indices();
3047 }
3048
3049 static Index upload_filter(
3050 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
3051 const Global::MeanFilter<DT_, IT_>& filter,
3052 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
3053 Index DOXY(row_offset))
3054 {
3055 XASSERTM(filter.empty(), "AlgDofParti does not support Global::MeanFilter yet!");
3056 return row_count(row_mirror);
3057 }
3058 }; // class ADPFilAux<Global::MeanFilter<DT_, IT_>>
3059
3061
3062 template<typename DT_, typename IT_, int bs_>
3063 class ADPFilAux<LAFEM::SlipFilter<DT_, IT_, bs_>>
3064 {
3065 public:
3066 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3067 {
3068 return row_mirror.num_indices() * Index(bs_);
3069 }
3070
3071 static Index upload_filter(
3072 LAFEM::UnitFilter<DT_, IT_>& DOXY(unit_rows),
3073 const LAFEM::SlipFilter<DT_, IT_, bs_>& filter,
3074 const LAFEM::VectorMirror<DT_, IT_>& row_mirror,
3075 Index DOXY(row_offset))
3076 {
3077 XASSERTM(filter.empty(), "AlgDofParti does not support LAFEM::SlipFilter yet!");
3078 return row_count(row_mirror);
3079 }
3080 }; // class ADPFilAux<LAFEM::SlipFilter<DT_, IT_, bs_>>
3081
3083
3084 template<typename FirstFilter_, typename... RestFilter_>
3085 class ADPFilAux<LAFEM::FilterChain<FirstFilter_, RestFilter_...>>
3086 {
3087 public:
3088 typedef typename FirstFilter_::DataType DT_;
3089 typedef typename FirstFilter_::IndexType IT_;
3090 typedef ADPFilAux<FirstFilter_> ADPFilAuxFirst;
3091 typedef ADPFilAux<LAFEM::FilterChain<RestFilter_...>> ADPFilAuxRest;
3092
3093 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3094 {
3095 Index n1 = ADPFilAuxFirst::row_count(row_mirror);
3096 Index n2 = ADPFilAuxRest::row_count(row_mirror);
3097 XASSERT(n1 == n2);
3098 return n1;
3099 }
3100
3101 template<typename RowMirror_>
3102 static Index upload_filter(
3103 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
3104 const LAFEM::FilterChain<FirstFilter_, RestFilter_...>& filter,
3105 const RowMirror_& row_mirror,
3106 Index row_offset)
3107 {
3108 Index n1 = ADPFilAuxFirst::upload_filter(unit_rows, filter.first(), row_mirror, row_offset);
3109 Index n2 = ADPFilAuxRest::upload_filter(unit_rows, filter.rest(), row_mirror, row_offset);
3110 XASSERT(n1 == n2);
3111 return n1;
3112 }
3113 }; // class ADPFilAux<LAFEM::FilterChain<FirstFilter_, RestFilter_...>>
3114
3116
3117 template<typename FirstFilter_>
3118 class ADPFilAux<LAFEM::FilterChain<FirstFilter_>>
3119 {
3120 public:
3121 typedef typename FirstFilter_::DataType DT_;
3122 typedef typename FirstFilter_::IndexType IT_;
3123 typedef ADPFilAux<FirstFilter_> ADPFilAuxFirst;
3124
3125 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3126 {
3127 return ADPFilAuxFirst::row_count(row_mirror);
3128 }
3129
3130 template<typename RowMirror_>
3131 static Index upload_filter(
3132 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
3133 const LAFEM::FilterChain<FirstFilter_>& filter,
3134 const RowMirror_& row_mirror,
3135 Index row_offset)
3136 {
3137 return ADPFilAuxFirst::upload_filter(unit_rows, filter.first(), row_mirror, row_offset);
3138 }
3139 }; // class ADPFilAux<LAFEM::FilterChain<FirstFilter_>>
3140
3142
3143 template<typename SubFilter_>
3144 class ADPFilAux<LAFEM::FilterSequence<SubFilter_>>
3145 {
3146 public:
3147 typedef typename SubFilter_::DataType DT_;
3148 typedef typename SubFilter_::IndexType IT_;
3149 typedef ADPFilAux<SubFilter_> ADPFilAuxSub;
3150
3151 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3152 {
3153 return ADPFilAuxSub::row_count(row_mirror);
3154 }
3155
3156 template<typename RowMirror_>
3157 static Index upload_filter(
3158 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
3159 const LAFEM::FilterSequence<SubFilter_>& filter,
3160 const RowMirror_& row_mirror,
3161 Index row_offset)
3162 {
3163 for(const auto& x : filter)
3164 {
3165 ADPFilAuxSub::upload_filter(unit_rows, x.second, row_mirror, row_offset);
3166 }
3167 return row_count(row_mirror);
3168 }
3169 }; // class ADPFilAux<LAFEM::FilterSequence<SubFilter_>>
3170
3172
3173 template<typename FirstFilter_, typename... RestFilter_>
3174 class ADPFilAux<LAFEM::TupleFilter<FirstFilter_, RestFilter_...>>
3175 {
3176 public:
3177 typedef typename FirstFilter_::DataType DT_;
3178 typedef typename FirstFilter_::IndexType IT_;
3179 typedef ADPFilAux<FirstFilter_> ADPFilAuxFirst;
3180 typedef ADPFilAux<LAFEM::TupleFilter<RestFilter_...>> ADPFilAuxRest;
3181
3182 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3183 {
3184 Index n1 = ADPFilAuxFirst::row_count(row_mirror);
3185 Index n2 = ADPFilAuxRest::row_count(row_mirror);
3186 return n1 + n2;
3187 }
3188
3189 template<typename FirstMirror_, typename... RestMirror_>
3190 static Index upload_filter(
3191 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
3192 const LAFEM::TupleFilter<FirstFilter_, RestFilter_...>& filter,
3193 const LAFEM::TupleMirror<FirstMirror_, RestMirror_...>& row_mirror,
3194 Index row_offset)
3195 {
3196 Index n1 = ADPFilAuxFirst::upload_filter(unit_rows, filter.first(), row_mirror.first(), row_offset);
3197 Index n2 = ADPFilAuxRest::upload_filter(unit_rows, filter.rest(), row_mirror.rest(), row_offset + n1);
3198 return n1 + n2;
3199 }
3200 }; // class ADPFilAux<LAFEM::TupleFilter<FirstFilter_, RestFilter_...>>
3201
3203
3204 template<typename FirstFilter_>
3205 class ADPFilAux<LAFEM::TupleFilter<FirstFilter_>>
3206 {
3207 public:
3208 typedef typename FirstFilter_::DataType DT_;
3209 typedef typename FirstFilter_::IndexType IT_;
3210 typedef ADPFilAux<FirstFilter_> ADPFilAuxFirst;
3211
3212 static Index row_count(const LAFEM::VectorMirror<DT_, IT_>& row_mirror)
3213 {
3214 return ADPFilAuxFirst::row_count(row_mirror);
3215 }
3216
3217 template<typename FirstMirror_>
3218 static Index upload_filter(
3219 LAFEM::UnitFilter<DT_, IT_>& unit_rows,
3220 const LAFEM::TupleFilter<FirstFilter_>& filter,
3221 const LAFEM::TupleMirror<FirstMirror_>& row_mirror,
3222 Index row_offset)
3223 {
3224 return ADPFilAuxFirst::upload_filter(unit_rows, filter.first(), row_mirror.first(), row_offset);
3225 }
3226 }; // class ADPFilAux<LAFEM::TupleFilter<FirstFilter_, RestFilter_...>>
3227 } // namespace Intern
3229 } // namespace Global
3230} // namespace FEAT
#define ASSERT(expr)
Debug-Assertion macro definition.
Definition: assertion.hpp:229
#define ASSERTM(expr, msg)
Debug-Assertion macro definition with custom message.
Definition: assertion.hpp:230
#define XASSERT(expr)
Assertion macro definition.
Definition: assertion.hpp:262
#define XASSERTM(expr, msg)
Assertion macro definition with custom message.
Definition: assertion.hpp:263
Dynamic Adjacency Graph implementation.
void clear()
Clears the graph.
bool insert(Index domain_node, Index image_node)
Inserts a new adjacency entry to the graph.
Index get_num_indices() const
Returns the total number of indices.
Adjacency Graph implementation.
Definition: graph.hpp:34
Index * get_domain_ptr()
Returns the domain pointer array.
Definition: graph.hpp:359
Index * get_image_idx()
Returns the image node index array.
Definition: graph.hpp:374
Index get_num_indices() const
Returns the total number indices.
Definition: graph.hpp:390
Communicator class.
Definition: dist.hpp:1349
void allreduce(const void *sendbuf, void *recvbuf, std::size_t count, const Datatype &datatype, const Operation &op) const
Blocking All-Reduce.
Definition: dist.cpp:655
Request irecv(void *buffer, std::size_t count, const Datatype &datatype, int source, int tag=0) const
Nonblocking Receive.
Definition: dist.cpp:716
Request isend(const void *buffer, std::size_t count, const Datatype &datatype, int dest, int tag=0) const
Nonblocking Send.
Definition: dist.cpp:704
void allgatherv(const void *sendbuf, std::size_t sendcount, const Datatype &sendtype, void *recvbuf, const int *recvcounts, const int *displs, const Datatype &recvtype) const
Blocking gather-to-all.
Definition: dist.cpp:607
Communication Request vector class.
Definition: dist.hpp:640
bool wait_any(std::size_t &idx, Status &status)
Blocks until one of the active requests has been fulfilled.
Definition: dist.cpp:329
void wait_all()
Blocks until all active requests are fulfilled.
Definition: dist.cpp:324
Algebraic DOF Partitioning implementation.
int get_donee_rank(Index i) const
Returns an donee neighbor rank.
const OwnedMirrorType & get_owned_mirror() const
Returns the Mirror of the owned DOFs.
const OwnerMirrorType & get_owner_mirror(Index i) const
Returns an owner neighbor mirror.
LocalVectorType::template ContainerTypeByDI< IndexType, IndexType > IndexVectorType
the index vector type, this one is required for internal computations
const IndexVectorType & get_global_dof_indices() const
Returns the global-dof-indices array.
int get_owner_rank(Index i) const
Returns an owner neighbor rank.
Index get_num_owner_neighbors() const
Index get_num_donee_neighbors() const
const DoneeMirrorType & get_donee_mirror(Index i) const
Returns a donee neighbor mirror.
Index get_num_global_dofs() const
Index get_num_owned_dofs() const
Algebraic DOF partitioning linear system conversion class.
Index _num_owned_non_zeros
number of non-zero entries owned by this process
void filter_vec_cor(DTV_ *vec_cor)
Applies the ADP filter onto an ADP correction vector.
void filter_vec_def(DTV_ *vec_def)
Applies the ADP filter onto an ADP defect vector.
std::shared_ptr< Adjacency::Graph > _owned_graph
adjacency graph containing the owned matrix structure
void upload_matrix_numeric(DTA_ *val, const RPT_ *row_ptr, const CIT_ *col_idx)
Uploads the data value array of the ADP CSR system matrix.
AlgDofPartiSystem(const GlobalMatrixType &matrix, const GlobalFilterType &filter)
Constructor.
LocalMatrix_ LocalMatrixType
the local matrix type
LAFEM::MatrixMirrorBuffer< DataType, IndexType > BufferMatrixType
the buffer matrix type used for communication
const GlobalFilterType & _global_filter
the global filter that we want to convert
LAFEM::VectorMirror< DataType, IndexType > DoneeMirrorType
donee neighbor mirror type
LAFEM::DenseVector< DataType, IndexType > BufferVectorType
the buffer vector type used for communication
LAFEM::SparseMatrixCSR< DataType, IndexType > OwnedMatrixType
the matrix type used for the internal storage of our owned matrix rows
void upload_filter(const LocalFilterType &filter)
Uploads the values of the given filter to the ADP system.
std::shared_ptr< AlgDofPartiType > _alg_dof_parti
the algebraic dof-partitioning
Global::AlgDofParti< LocalVectorType, MirrorType > AlgDofPartiType
the algebraic DOF partitioning
void upload_vector(DTV_ *val, const LocalVectorType &vector)
Uploads the ADP vector values to the given array.
Mirror_ MirrorType
the vector mirror type
AlgDofPartiSystem & operator=(const AlgDofPartiSystem &)=delete
no copy, no problems
void init_symbolic()
Performs the symbolic initialization.
void apply(DTX_ *vec_r, const DTX_ *vec_x, const DTX_ *val_a, const RPT_ *row_ptr, const CIT_ *col_idx) const
Performs a global matrix-vector product with this matrix.
static void _asm_neighbor_donee_data_mir(DoneeMirrorType &data_mirror, const Adjacency::Graph &owned_graph, const DoneeMirrorType &mirror, const BufferMatrixType &buffer)
Auxiliary function: assembles a data-mirror for a donee-neighbor.
const GlobalMatrixType & _global_matrix
the global matrix that we want to convert
void _assemble_data_mirrors()
Assembles the data-mirrors for all owner- and donee-neighbors.
const Dist::Comm * get_comm() const
void download_vector(LocalVectorType &vector, const DTV_ *val)
Downloads the ADP vector values from the given array.
LocalMatrixType::VectorTypeR LocalVectorType
the local vector type
static BufferMatrixType _asm_mat_buf(const LocalMatrixType &local_matrix, const MirrorType &row_mirror, const IndexVectorType &global_dof_idx, const Index num_global_dofs)
Assembles a matrix buffer for a given row mirror.
Global::Filter< LocalFilterType, MirrorType > GlobalFilterType
the global filter type
std::shared_ptr< AlgDofPartiType > get_alg_dof_parti()
Returns the algebraic dof partitioning that is used internally.
std::vector< DoneeMirrorType > _donee_data_mirs
the data array mirrors for our donee and owner neighbors
LocalMatrix_::DataType DataType
our data type
void _assemble_buffers()
Assembles the owner and donee matrix buffers.
void _assemble_structure()
Assembles the matrix structure of the algebraic-DOF-partitioned matrix.
LAFEM::UnitFilter< DataType, IndexType > _unit_filter_rows
indices of all unit-filtered matrix rows; we store this as a mirror
LocalMatrix_::IndexType IndexType
our index type
void filter_matrix(DTA_ *val, const RPT_ *row_ptr, const CIT_ *col_idx)
Applies the ADP filter onto an ADP matrix.
OwnerMirrorType _owned_data_mir
the data array mirror for this process
LocalFilter_ LocalFilterType
the local filter type
Index _num_global_non_zeros
number of non-zero entries in total
AlgDofPartiType::IndexVectorType IndexVectorType
auxiliary index vector type
static void _scatter_donee_data(DTA_ *adp_val, const BufferVectorType &buffer, const DoneeMirrorType &data_mirror)
Scatters the values of a donee-neighbor buffer-vector into a local matrix.
AlgDofPartiSystem(const AlgDofPartiSystem &)=delete
no copy, no problems
std::vector< BufferMatrixType > _donee_bufs
the matrix buffers for our donee and owner neighbors; both buffers use global DOF indices
void upload_matrix_numeric(DTA_ *val, const RPT_ *row_ptr, const CIT_ *col_idx, const LocalMatrixType &matrix)
Copies the matrix entry values from the input matrix into this algebraic-dof-partitioned matrix.
void upload_matrix_symbolic(RPT_ *row_ptr, CIT_ *col_idx, bool keep_graph=false)
Uploads the row-pointer and column-index arrays of the ADP CSR system matrix.
void upload_filter()
Uploads the values of the system filter to the ADP system.
Intern::ADPDOMM< LocalMatrixType > OwnerMirrorType
owner neighbor mirror type
AlgDofPartiSystem(const GlobalMatrixType &matrix, const GlobalFilterType &filter, std::shared_ptr< AlgDofPartiType > adp)
Constructor.
Global::Matrix< LocalMatrixType, MirrorType, MirrorType > GlobalMatrixType
the global matrix type
Global Filter wrapper class template.
Definition: filter.hpp:21
Global Matrix wrapper class template.
Definition: matrix.hpp:40
const GateRowType * get_row_gate() const
Returns a const pointer to the internal row gate of the matrix.
Definition: matrix.hpp:154
LocalMatrix_ & local()
Returns a reference to the internal local LAFEM matrix object.
Definition: matrix.hpp:126
Index size() const
Returns the containers size.
Definition: container.hpp:1136
Dense data vector class template.
DT_ * elements()
Get a pointer to the data array.
Matrix Mirror Buffer class template.
Index columns() const
Retrieve matrix column count.
IT_ * row_ptr()
Retrieve row start index array.
IT_ * col_ind()
Retrieve column indices array.
Index entries_per_nonzero() const
Retrieve entries per non zero element count.
Index used_elements() const
Retrieve non zero element count.
Index rows() const
Retrieve matrix row count.
CSR based sparse matrix.
Unit Filter class template.
Definition: unit_filter.hpp:29
Index used_elements() const
std::size_t bytes() const
Returns the total amount of bytes allocated.
Handles vector prolongation, restriction and serialization.
IT_ * indices()
Get a pointer to the non zero indices array.
Index num_indices() const
Returns the number of indices in the mirror.
@ as_is
Render-As-Is mode.
const Operation op_sum(MPI_SUM)
Operation wrapper for MPI_SUM.
Definition: dist.hpp:271
@ rest
restriction (multigrid)
FEAT namespace.
Definition: adjactor.hpp:12
void feat_omp_ex_scan(std::size_t n, const T_ x[], T_ y[])
Computes an OpenMP-parallel exclusive scan a.k.a. a prefix sum of an array, i.e.
Definition: omp_util.hpp:153
String stringify(const T_ &item)
Converts an item into a String.
Definition: string.hpp:993
std::uint64_t Index
Index data type.