49 return ::MatSetValues(
51 S, row_ind.size(), &*row_ind.begin(), col_ind.size(), &*col_ind.begin(),
52 &*
m.data().begin(), iora
72 boost::shared_ptr<std::vector<unsigned char>> marker_ptr,
79 boost::shared_ptr<std::vector<unsigned char>>
markerPtr;
87template <
typename OP_SCHUR_ASSEMBLE_BASE>
105 std::vector<std::string> fields_name,
106 std::vector<boost::shared_ptr<Range>> field_ents,
110 bool sym_schur,
bool symm_op);
113 template <
typename I>
161struct SchurElemMats :
public boost::enable_shared_from_this<SchurElemMats> {
187 template <
typename OP_SCHUR_ASSEMBLE_BASE>
202 member<SchurElemMats, const UId, &SchurElemMats::uidRow>,
203 member<SchurElemMats, const UId, &SchurElemMats::uidCol>
212 static boost::ptr_vector<MatrixDouble>
locMats;
278 inline void setStorage(
size_t shift,
int leading_dim,
int element) {
357 inline int mLd(
int a,
int b)
const {
return sLd(b,
a); }
420 "A00 factorisation failed and block matrix data is corrupted, "
421 "call MatZeroEntries and assemble again");
431 "A00 element matrices are factorised in place, call "
432 "MatZeroEntries before assembling or modifying block matrix");
438 for (
auto &e :
elems) {
439 e.factorised =
false;
443 std::vector<double>().swap(d);
461 auto it = std::lower_bound(
463 [](
const Indexes &
a,
const std::pair<UId, UId> &p) {
464 if (a.getRowUId() != p.first)
465 return a.getRowUId() < p.first;
466 return a.getColUId() < p.second;
468 if (it !=
blockIndex.end() && it->getRowUId() == row &&
469 it->getColUId() == col)
480 return a.getRowUId() < b;
495 auto lo = std::lower_bound(
497 [
this](
int i,
const UId &
c) { return blockIndex[i].getColUId() < c; });
498 auto hi = std::upper_bound(
500 [
this](
const UId &
c,
int i) { return c < blockIndex[i].getColUId(); });
501 return std::make_pair(lo, hi);
574 : iDX(idx), uidRow(uid_row), uidCol(uid_col) {}
588 auto get_row_indices = [&]() ->
const VectorInt & {
590 if (
auto stored_data_ptr =
592 return stored_data_ptr->entityIndices;
598 const auto &row_ind = get_row_indices();
601 const auto nb_rows = row_ind.size();
602 const auto nb_cols = col_ind.size();
605 if (mat.size1() != nb_rows) {
607 "Wrong mat size %zu != %zu", mat.size1(), nb_rows);
609 if (mat.size2() != nb_cols) {
611 "Wrong mat size %zu != %zu", mat.size2(), nb_cols);
616 auto get_uid = [](
auto &data) {
617 if (data.getFieldEntities().size() == 1) {
619 return data.getFieldEntities()[0]->getLocalUniqueId();
628 auto &uid0 = data.getFieldEntities()[0]->getLocalUniqueId();
634 for (
auto i = 1;
i < data.getFieldEntities().
size(); ++
i) {
641 data.getFieldEntities()[
i]->getLocalUniqueId())
655 auto uid_row = get_uid(row_data);
656 auto uid_col = get_uid(col_data);
660 .find(boost::make_tuple(uid_row, uid_col));
692 auto asmb = [&](
auto &sm) {
693 sm.resize(nb_rows, nb_cols,
false);
697 asmb((*p.first)->getMat());
699 auto add_indices = [](
auto &storage,
auto &ind) {
700 storage.resize(ind.size(),
false);
701 noalias(storage) = ind;
704 add_indices((*p.first)->getRowInd(), row_ind);
705 add_indices((*p.first)->getColInd(), col_ind);
710 auto asmb = [&](
auto &sm) {
714 if (sm.size1() != nb_rows) {
716 "Wrong mat or storage size %zu != %zu", sm.size1(), nb_rows);
718 if (sm.size2() != nb_cols) {
720 "Wrong mat or storage size %zu != %zu", sm.size2(), nb_cols);
733 "Assembly type not implemented");
738 CHKERR asmb((*it)->getMat());
758 MOFEM_LOG(
"SELF", Sev::noisy) <<
"Schur assemble begin";
767 boost::shared_ptr<std::vector<unsigned char>> marker_ptr,
double diag_val)
777 auto prb_ptr = fe_ptr->problemPtr;
780 auto find_loc_dof_index = [&](
auto glob) {
781 auto it = dof.find(glob);
782 if (it != dof.end()) {
783 return (*it)->getPetscLocalDofIdx();
785 MOFEM_LOG(
"SELF", Sev::error) <<
"Global dof " << glob;
788 "Global dof index not found in local numered dofs storage");
794 auto zero_ind = [&](
auto &ind) {
795 for (
auto i = 0;
i < ind.size(); ++
i) {
797 if ((*
markerPtr)[find_loc_dof_index(ind[
i])]) {
804 zero_ind(s->getRowInd());
805 zero_ind(s->getColInd());
811template <
typename OP_SCHUR_ASSEMBLE_BASE>
813 std::vector<std::string> fields_name,
814 std::vector<boost::shared_ptr<Range>> field_ents,
817 :
OP(
NOSPACE,
OP::OPSPACE, symm_op), fieldsName(fields_name),
818 fieldEnts(field_ents), schurAO(schur_ao), schurMat(schur_mat),
819 symSchur(sym_schur) {}
821template <
typename OP_SCHUR_ASSEMBLE_BASE>
834 MOFEM_LOG(
"SELF", Sev::noisy) <<
"Schur assemble begin -> end";
837 auto get_a00_uids = [&]() {
838 auto get_field_bit = [&](
auto &
name) {
839 return OP::getPtrFE()->mField.get_field_bit_number(
name);
842 std::vector<std::pair<UId, UId>> a00_uids;
843 a00_uids.reserve(fieldsName.size());
844 for (
auto ss = 0; ss != fieldsName.size(); ++ss) {
845 auto field_bit = get_field_bit(fieldsName[ss]);
846 auto row_ents = fieldEnts[ss];
848 for (
auto p = row_ents->pair_begin(); p != row_ents->pair_end(); ++p) {
853 a00_uids.push_back(std::make_pair(lo_uid, hi_uid));
857 field_bit, get_id_for_min_type<MBVERTEX>());
859 field_bit, get_id_for_max_type<MBENTITYSET>());
860 a00_uids.push_back(std::make_pair(lo_uid, hi_uid));
867 auto get_field_name = [&](
auto uid) {
871 auto list_storage = [&](
auto &storage) {
874 for (
auto &p : storage) {
876 <<
"List schur storage: " <<
i <<
" " << p->iDX <<
": "
877 << get_field_name(p->uidRow) <<
" " << get_field_name(p->uidCol)
878 <<
" : " << p->getMat().size1() <<
" " << p->getMat().size2();
885 auto assemble_dense_blocks = [&]() {
886 using matrix_range = ublas::matrix_range<MatrixDouble>;
887 using range = ublas::range;
891 auto assemble_schur = [
this](
auto &
m,
auto &uid_row,
auto &uid_col,
892 auto *row_ind_ptr,
auto *col_ind_ptr) {
897 if (
auto ierr = this->assembleSchurMat(
899 schurMat, uid_row, *row_ind_ptr, uid_col, *col_ind_ptr,
m,
904 auto field_ents = OP::getPtrFE()->mField.get_field_ents();
905 auto row_ent_it = field_ents->find(uid_row);
906 auto col_ent_it = field_ents->find(uid_col);
908 if (row_ent_it != field_ents->end())
910 <<
"Assemble row entity: " << (*row_ent_it)->getName() <<
" "
911 << (*col_ent_it)->getEntTypeName() <<
" side "
912 << (*row_ent_it)->getSideNumber();
913 if (col_ent_it != field_ents->end())
915 <<
"Assemble col entity: " << (*col_ent_it)->getName() <<
" "
916 << (*col_ent_it)->getEntTypeName() <<
" side "
917 << (*col_ent_it)->getSideNumber();
926 auto a00_uids = get_a00_uids();
928 auto get_block_indexing = [&](
auto &a00_uids) {
930 std::vector<const SchurElemMats *> block_list;
931 block_list.reserve(storage.size());
932 for (
auto &rp_uid : a00_uids) {
933 auto [rlo_uid, rhi_uid] = rp_uid;
934 for (
auto &cp_uid : a00_uids) {
935 auto [clo_uid, chi_uid] = cp_uid;
938 storage.template get<SchurElemMats::uid_mi_tag>().lower_bound(
939 boost::make_tuple(rlo_uid, clo_uid));
941 storage.template get<SchurElemMats::uid_mi_tag>().upper_bound(
942 boost::make_tuple(rhi_uid, chi_uid));
944 for (; it != hi_it; ++it) {
945 if ((*it)->uidRow >= rlo_uid && (*it)->uidRow < rhi_uid &&
946 (*it)->uidCol >= clo_uid && (*it)->uidCol < chi_uid) {
947 block_list.push_back(*it);
954 std::map<UId, std::pair<size_t, const VectorInt *>>
956 for (
auto d : block_list) {
957 if (block_indexing.find(d->uidRow) == block_indexing.end()) {
958 block_indexing[d->uidRow] =
959 std::make_pair(d->getRowInd().size(), &(d->getRowInd()));
964 int mat_block_size = 0;
965 for (
auto &p_uid : a00_uids) {
966 auto [lo_uid, hi_uid] = p_uid;
967 auto lo = block_indexing.lower_bound(lo_uid);
968 auto up = block_indexing.upper_bound(hi_uid);
969 for (; lo != up; ++lo) {
970 lo->second.first = mat_block_size;
971 mat_block_size += lo->second.second->size();
975 return std::make_tuple(block_list, block_indexing, mat_block_size);
978 auto get_schur_block_list = [&](
auto &block_indexing) {
979 std::vector<const SchurElemMats *> block_list;
980 block_list.reserve(storage.size());
981 for (
auto &s : storage) {
982 if (block_indexing.find(s->uidRow) == block_indexing.end() &&
983 block_indexing.find(s->uidCol) == block_indexing.end()) {
984 block_list.push_back(s);
990 auto bi = get_block_indexing(a00_uids);
991 auto &[block_list, block_indexing, block_mat_size] = bi;
993 if (block_mat_size == 0) {
996 for (
auto &s : storage) {
997 CHKERR AOApplicationToPetsc(schurAO, s->getRowInd().size(),
998 &*s->getRowInd().begin());
999 CHKERR AOApplicationToPetsc(schurAO, s->getColInd().size(),
1000 &*s->getColInd().begin());
1004 for (
auto &s : storage) {
1005 auto &
m = s->getMat();
1006 CHKERR assemble_schur(
m, s->uidRow, s->uidCol, &(s->getRowInd()),
1012 blockMat.resize(block_mat_size, block_mat_size,
false);
1015 auto get_range = [](
auto &bi) {
1016 return range(bi.first, bi.first + bi.second->size());
1019 for (
auto &s : block_list) {
1020 auto &
m = s->getMat();
1022 if (block_indexing.find(s->uidRow) == block_indexing.end())
1024 if (block_indexing.find(s->uidCol) == block_indexing.end())
1028 auto &rbi = block_indexing.at(s->uidRow);
1029 auto &cbi = block_indexing.at(s->uidCol);
1031 auto sub_mat = matrix_range(blockMat, get_range(rbi), get_range(cbi));
1035 auto get_zeroed_indices = [&](
auto extractor_uid,
auto extractor_ind) {
1036 auto &[block_list, block_indexing, block_mat_size] = bi;
1037 std::vector<int> zeroed_indices;
1038 zeroed_indices.reserve(block_mat_size);
1039 for (
auto &s : block_list) {
1040 auto &bi = block_indexing.at(extractor_uid(s));
1041 auto &ind = extractor_ind(s);
1042 for (
auto it = ind.begin(); it != ind.end(); ++it) {
1044 auto idx = bi.first + std::distance(ind.begin(), it);
1045 zeroed_indices.push_back(idx);
1049 std::sort(zeroed_indices.begin(), zeroed_indices.end());
1050 auto it = std::unique(zeroed_indices.begin(), zeroed_indices.end());
1051 zeroed_indices.resize(std::distance(zeroed_indices.begin(), it));
1052 return zeroed_indices;
1054 auto zero_rows = get_zeroed_indices(
1055 [](
auto &s) {
return s->uidRow; },
1056 [](
auto &s) ->
VectorInt & {
return s->getRowInd(); });
1057 auto zero_cols = get_zeroed_indices(
1058 [](
auto &s) {
return s->uidCol; },
1059 [](
auto &s) ->
VectorInt & {
return s->getColInd(); });
1061 for (
auto i : zero_rows) {
1062 for (
auto j = 0;
j != blockMat.size2(); ++
j) {
1066 for (
auto j : zero_cols) {
1067 for (
auto i = 0;
i != blockMat.size1(); ++
i) {
1071 for (
auto i : zero_rows) {
1075 CHKERR I::invertMat(blockMat, invMat);
1078 for (
auto &s : block_list) {
1079 auto it = storage.template get<SchurElemMats::uid_mi_tag>().find(
1080 boost::make_tuple(s->uidRow, s->uidCol));
1081 storage.template get<SchurElemMats::uid_mi_tag>().erase(it);
1086 for (
auto &s : storage) {
1087 if (block_indexing.find(s->uidRow) == block_indexing.end()) {
1088 CHKERR AOApplicationToPetsc(schurAO, s->getRowInd().size(),
1089 &*s->getRowInd().begin());
1091 if (block_indexing.find(s->uidCol) == block_indexing.end()) {
1092 CHKERR AOApplicationToPetsc(schurAO, s->getColInd().size(),
1093 &*s->getColInd().begin());
1098 auto schur_block_list = get_schur_block_list(block_indexing);
1099 for (
auto &s : schur_block_list) {
1100 auto &
m = s->getMat();
1101 CHKERR assemble_schur(
m, s->uidRow, s->uidCol, &(s->getRowInd()),
1104 for (
auto &s : schur_block_list) {
1105 auto it = storage.template get<SchurElemMats::uid_mi_tag>().find(
1106 boost::make_tuple(s->uidRow, s->uidCol));
1107 storage.template get<SchurElemMats::uid_mi_tag>().erase(it);
1109 schur_block_list.clear();
1113 auto rp_uid_it = a00_uids.begin(); rp_uid_it != a00_uids.end();
1117 auto [rlo_uid, rhi_uid] = *rp_uid_it;
1118 for (
auto rm = block_indexing.lower_bound(rlo_uid);
1119 rm != block_indexing.upper_bound(rhi_uid); ++rm) {
1120 auto &rbi = rm->second;
1123 storage.template get<SchurElemMats::col_mi_tag>().lower_bound(
1126 storage.template get<SchurElemMats::col_mi_tag>().upper_bound(
1131 auto cp_uid_it = (symSchur) ? rp_uid_it : a00_uids.begin();
1132 cp_uid_it != a00_uids.end(); ++cp_uid_it
1135 auto [clo_uid, chi_uid] = *cp_uid_it;
1136 for (
auto cm = block_indexing.lower_bound(clo_uid);
1137 cm != block_indexing.upper_bound(chi_uid); ++cm) {
1138 auto &cbi = cm->second;
1141 storage.template get<SchurElemMats::uid_mi_tag>().lower_bound(
1142 boost::make_tuple(cm->first, 0));
1144 storage.template get<SchurElemMats::uid_mi_tag>().upper_bound(
1149 matrix_range(invMat, get_range(rbi), get_range(cbi));
1150 bM.resize(sub_inv_mat.size1(), sub_inv_mat.size2());
1151 noalias(bM) = sub_inv_mat;
1153 for (
auto a_lo = a_lo_tmp; a_lo != a_hi; ++a_lo) {
1155 if (block_indexing.find((*a_lo)->uidRow) != block_indexing.end())
1157 "Wrong a_lo->uidRow");
1160 auto &
a = (*a_lo)->getMat();
1161 abM.resize(
a.size1(), bM.size2(),
false);
1163 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
1165 a.size1(), bM.size2(),
a.size2(), 1.,
1167 &*
a.data().begin(),
a.size2(),
1169 &*bM.data().begin(), bM.size2(), 0.,
1171 &*abM.data().begin(), abM.size2());
1173 for (
auto c_lo = c_lo_tmp; c_lo != c_hi; ++c_lo) {
1175 if (block_indexing.find((*c_lo)->uidCol) !=
1176 block_indexing.end())
1178 "Wrong a_lo->uidRow");
1181 auto &
c = (*c_lo)->getMat();
1183 abcM.resize(abM.size1(),
c.size2(),
false);
1186 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
1187 abM.size1(),
c.size2(), abM.size2(), -1.,
1189 &*abM.data().begin(), abM.size2(),
1191 &*
c.data().begin(),
c.size2(), 0.,
1193 &*abcM.data().begin(), abcM.size2());
1195 CHKERR assemble_schur(abcM, (*a_lo)->uidRow, (*c_lo)->uidCol,
1196 &((*a_lo)->getRowInd()),
1197 &((*c_lo)->getColInd()));
1199 if (symSchur && rp_uid_it != cp_uid_it) {
1201 CHKERR assemble_schur(abcM, (*c_lo)->uidCol, (*a_lo)->uidRow,
1202 &((*c_lo)->getColInd()),
1203 &((*a_lo)->getRowInd()));
1216 CHKERR assemble_dense_blocks();
1220 MOFEM_LOG(
"SELF", Sev::noisy) <<
"Schur assemble done";
1235 const auto nb =
m.size1();
1237 if (nb !=
m.size2()) {
1239 "It should be square matrix %zu != %zu", nb,
m.size2());
1243 inv.resize(nb, nb,
false);
1245 m.resize(2 * nb, 2 * nb,
false);
1252 info =
lapack_dgetrf(nb, nb, &*inv.data().begin(), nb, &*ipiv.begin());
1255 "lapack error info = %d", info);
1256 info =
lapack_dgetri(nb, &*inv.data().begin(), nb, &*ipiv.begin(),
1257 &*
m.data().begin(),
m.data().size());
1260 "lapack error info = %d", info);
1271 const auto nb =
m.size1();
1273 if (nb !=
m.size2()) {
1275 "It should be square matrix %zu != %zu", nb,
m.size2());
1279 inv.resize(nb, nb,
false);
1285 info =
lapack_dgetrf(nb, nb, &*inv.data().begin(), nb, &*ipiv.begin());
1288 "lapack error info = %d", info);
1289 info =
lapack_dgetri(nb, &*inv.data().begin(), nb, &*ipiv.begin(),
1290 &*
m.data().begin(),
m.data().size());
1293 "lapack error info = %d", info);
1302 return doWorkImpl<SchurDSYSV>(side,
type, data);
1308 return doWorkImpl<SchurDGESV>(side,
type, data);
1324 for (
int k = 0;
k !=
n; ++
k) {
1325 const int p = ipiv[
k] - 1;
1327 std::swap(
t[
k],
t[p]);
1329 cblas_dtrmv(CblasColMajor, CblasLower, CblasTrans, CblasUnit,
n, lu,
n,
t,
1331 cblas_dtrmv(CblasColMajor, CblasUpper, CblasTrans, CblasNonUnit,
n, lu,
n,
1334 cblas_dtrmv(CblasColMajor, CblasUpper, CblasNoTrans, CblasNonUnit,
n, lu,
n,
1336 cblas_dtrmv(CblasColMajor, CblasLower, CblasNoTrans, CblasUnit,
n, lu,
n,
t,
1338 for (
int k =
n - 1;
k >= 0; --
k) {
1339 const int p = ipiv[
k] - 1;
1341 std::swap(
t[
k],
t[p]);
1347static inline void copy_block(
double *dst,
int ld_dst,
int ridx,
int cidx,
1348 const double *src,
int ld_src,
int nb_rows,
1350 for (
int i = 0;
i != nb_rows; ++
i)
1351 cblas_dcopy(nb_cols, src +
static_cast<size_t>(
i) * ld_src, 1,
1352 dst +
static_cast<size_t>(ridx +
i) * ld_dst + cidx, 1);
1356 return std::all_of(ptr, ptr +
size, [](
double v) {
return v == 0.; });
1369 for (
int j = 0;
j !=
n; ++
j) {
1371 const double s = cblas_dasum(
m,
a +
static_cast<size_t>(
j) * ld, 1);
1372 if (!std::isfinite(s))
1373 return std::numeric_limits<double>::infinity();
1380static inline void add_gemv(
bool trans_a,
int m,
int kk,
const double *
a,
1381 int lda,
const double *x,
double *y) {
1384 cblas_dgemv(CblasColMajor, trans_a ? CblasTrans : CblasNoTrans,
1385 trans_a ? kk :
m, trans_a ?
m : kk, 1.,
a, lda, x, 1, 1., y, 1);
1389static inline void sub_gemm(
bool trans_a,
int m,
int kk,
int nrhs,
1390 const double *
a,
int lda,
const double *b,
int ldb,
1391 double *
c,
int ldc) {
1392 if (!
m || !kk || !nrhs)
1395 cblas_dgemv(CblasColMajor, trans_a ? CblasTrans : CblasNoTrans,
1396 trans_a ? kk :
m, trans_a ?
m : kk, -1.,
a, lda, b, 1, 1.,
c,
1399 cblas_dgemm(CblasColMajor, trans_a ? CblasTrans : CblasNoTrans,
1400 CblasNoTrans,
m, nrhs, kk, -1.,
a, lda, b, ldb, 1.,
c, ldc);
1415 double coupling,
double u,
double rcond_min,
1416 std::vector<double> &
work,
1417 std::vector<__CLPK_integer> &iwork,
1418 double *rcond_out =
nullptr,
1419 double *anorm_out =
nullptr) {
1426 if (anorm == 0 || !std::isfinite(anorm))
1435 dgecon_(&norm, &nn, d, &lda, &an, &rcond,
work.data(), iwork.data(), &info);
1438 if (info != 0 || !std::isfinite(rcond))
1440 if (rcond < rcond_min)
1442 if (u > 0 && rcond * anorm < u * coupling)
1451 std::vector<int> off(p.
nbNodes);
1453 for (
int r = 0; r != p.
nbNodes; ++r) {
1463 for (
int r = 0; r != p.
nbNodes; ++r)
1480 for (
int r = 0; r !=
k; ++r)
1481 for (
int c = 0;
c !=
k; ++
c)
1499 const std::vector<int> &
order) {
1501 std::vector<char> pm(
k *
k, 0);
1502 for (
int r = 0; r !=
k; ++r)
1503 for (
int c = 0;
c !=
k; ++
c)
1505 std::vector<char> done(
k, 0);
1506 for (
auto e :
order) {
1508 for (
int i = 0;
i !=
k; ++
i)
1509 if (!done[
i] && pm[
i *
k + e])
1510 for (
int j = 0;
j !=
k; ++
j)
1511 if (!done[
j] && pm[e *
k +
j])
1530 std::vector<char> in_core(
k, 1);
1531 for (
auto e :
order)
1535 for (
int i = 0;
i !=
k; ++
i)
1537 p.
core.push_back(
i);
1540 std::vector<int> pos(
k);
1542 for (
auto e : p.
order) {
1548 for (
auto c : p.
core) {
1556 std::vector<std::array<int, 4>> slots;
1557 for (
int r = 0; r !=
k; ++r)
1558 for (
int c = 0;
c !=
k; ++
c)
1559 if (!(in_core[r] && in_core[
c]) && pm[
c *
k + r])
1560 slots.push_back({std::min(pos[r], pos[
c]), pos[r], pos[
c], r *
k +
c});
1561 std::sort(slots.begin(), slots.end());
1563 p.slotShift.assign(
k *
k, -1);
1564 p.slotLd.assign(
k *
k, 0);
1566 for (
auto &s : slots) {
1567 const int r = s[3] /
k,
c = s[3] %
k;
1568 p.slotShift[s[3]] = shift;
1569 p.slotLd[s[3]] = p.nodeSize[
c];
1570 shift +=
static_cast<size_t>(p.nodeSize[r]) * p.nodeSize[
c];
1572 p.coreShift = shift;
1573 for (
auto r : p.core)
1574 for (auto
c : p.core) {
1575 p.slotShift[
r *
k +
c] =
1577 static_cast<size_t>(p.nodeOffset[
r] - p.coreOffset) * p.coreSize +
1578 (p.nodeOffset[
c] - p.coreOffset);
1579 p.slotLd[
r *
k +
c] = p.coreSize;
1581 p.elemSize = p.coreShift +
static_cast<size_t>(p.coreSize) * p.coreSize;
1589 std::vector<char> rem(
k, 1);
1590 std::vector<int>
order;
1593 double best_fill = 0;
1594 for (
int e = 0; e !=
k; ++e) {
1595 if (!rem[e] || !pm[e *
k + e])
1598 for (
int i = 0;
i !=
k; ++
i)
1599 if (rem[
i] &&
i != e && pm[
i *
k + e])
1600 for (
int j = 0;
j !=
k; ++
j)
1601 if (rem[
j] &&
j != e && pm[e *
k +
j] && !pm[
i *
k +
j])
1603 if (best < 0 || fill < best_fill) {
1610 for (
int i = 0;
i !=
k; ++
i)
1611 if (rem[
i] &&
i != best && pm[
i *
k + best])
1612 for (
int j = 0;
j !=
k; ++
j)
1613 if (rem[
j] &&
j != best && pm[best *
k +
j])
1616 order.push_back(best);
1633 double u,
double rcond_min) {
1638 auto mb = [&](
int a,
int b) {
1639 return w +
static_cast<size_t>(off[b]) *
n + off[
a];
1642 std::vector<char> rem(
k, 1);
1643 std::vector<int>
order;
1644 std::vector<double> tmp,
work;
1645 std::vector<__CLPK_integer> piv, iwork;
1649 double best_fill = 0;
1650 for (
int e = 0; e !=
k; ++e) {
1651 if (!rem[e] || !pm[e *
k + e])
1653 const int ne = ns[e];
1654 double coupling = 0;
1655 for (
int j = 0;
j !=
k; ++
j) {
1656 if (!rem[
j] ||
j == e)
1659 coupling = std::max(coupling,
norm1_block(ne, ns[
j], mb(e,
j),
n));
1661 coupling = std::max(coupling,
norm1_block(ns[
j], ne, mb(
j, e),
n));
1663 tmp.resize(
static_cast<size_t>(ne) * ne);
1664 for (
int c = 0;
c != ne; ++
c)
1665 cblas_dcopy(ne, mb(e, e) +
static_cast<size_t>(
c) *
n, 1,
1666 tmp.data() +
static_cast<size_t>(
c) * ne, 1);
1668 double rcond, anorm;
1669 const bool admissible =
1671 rcond_min,
work, iwork, &rcond, &anorm);
1673 <<
"A00 analysis step " <<
order.size() <<
" node " << p.
nodeName[e]
1674 <<
"(" << ne <<
") rcond " << rcond <<
" smin " << rcond * anorm
1675 <<
" norm " << anorm <<
" coupling " << coupling
1676 << (admissible ?
" admissible" :
" rejected");
1680 for (
int i = 0;
i !=
k; ++
i)
1681 if (rem[
i] &&
i != e && pm[
i *
k + e])
1682 for (
int j = 0;
j !=
k; ++
j)
1683 if (rem[
j] &&
j != e && pm[e *
k +
j] && !pm[
i *
k +
j])
1684 fill +=
static_cast<double>(ns[
i]) * ns[
j];
1685 if (best < 0 || fill < best_fill) {
1693 const int e = best, ne = ns[e];
1696 for (
int j = 0;
j !=
k; ++
j)
1697 if (rem[
j] &&
j != e && pm[e *
k +
j])
1699 for (
int i = 0;
i !=
k; ++
i)
1700 if (rem[
i] &&
i != e && pm[
i *
k + e])
1701 for (
int j = 0;
j !=
k; ++
j)
1702 if (rem[
j] &&
j != e && pm[e *
k +
j]) {
1703 cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, ns[
i], ns[
j],
1704 ne, -1., mb(
i, e),
n, mb(e,
j),
n, 1., mb(
i,
j),
n);
1716 for (
int r = 0; r != from.
nbNodes; ++r)
1727 const int n = p.
size;
1728 for (
int r = 0; r != p.
nbNodes; ++r)
1738 const double *x,
double *y,
bool trans) {
1739 for (
int r = 0; r != p.
nbNodes; ++r)
1743 const double *
a = buf + p.
sShift(r,
c);
1745 cblas_dgemv(CblasRowMajor, CblasNoTrans, nr, nc, 1.,
a, p.
sLd(r,
c),
1748 cblas_dgemv(CblasRowMajor, CblasTrans, nr, nc, 1.,
a, p.
sLd(r,
c),
1766 std::vector<double> &
work,
1767 std::vector<__CLPK_integer> &iwork) {
1768 const int m = p.
order.size();
1769 std::vector<int> seq(p.
order);
1770 seq.insert(seq.end(), p.
core.begin(), p.
core.end());
1773 for (
int t = 0;
t !=
m; ++
t) {
1774 const int e = seq[
t], ne = ns[e];
1775 double *d = buf + p.
mShift(e, e);
1776 const int ldd = p.
mLd(e, e);
1778 double coupling = 0;
1779 for (
int q =
t + 1; u > 0 && q < static_cast<int>(seq.size()); ++
q) {
1780 const int j = seq[
q];
1791 rcond_min,
work, iwork))
1794 for (
int q =
t + 1; q < static_cast<int>(seq.size()); ++
q) {
1795 const int j = seq[
q];
1800 for (
int qi =
t + 1; qi < static_cast<int>(seq.size()); ++qi) {
1801 const int i = seq[qi];
1804 for (
int qj =
t + 1; qj < static_cast<int>(seq.size()); ++qj) {
1805 const int j = seq[qj];
1808 cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans, ns[
i], ns[
j], ne,
1836 int nrhs,
bool trans,
1837 const std::vector<char> *nz_in) {
1840 std::vector<int> seq(p.
order);
1841 seq.insert(seq.end(), p.
core.begin(), p.
core.end());
1844 std::vector<char> nz = nz_in ? *nz_in : std::vector<char>(
k, 1);
1845 auto blk = [&](
int a,
int b) {
return buf + p.
mShift(
a, b); };
1846 auto rr = [&](
int a) {
return r + off[
a]; };
1847 auto lu = [&](
int e) {
return const_cast<double *
>(blk(e, e)); };
1848 auto pv = [&](
int e) {
return const_cast<__CLPK_integer *
>(piv + off[e]); };
1849 auto core_solve = [&](
char t) {
1854 for (
auto c : p.
core)
1864 "error lapack dgetrs info = %d",
static_cast<int>(info));
1865 for (
auto c : p.
core)
1869 auto diag_solve = [&](
int e,
char t) {
1877 "error lapack dgetrs info = %d",
static_cast<int>(info));
1883 for (
int t = 0;
t !=
static_cast<int>(seq.size()); ++
t) {
1884 const int e = seq[
t];
1885 for (
int q = 0;
q != std::min(
t,
m); ++
q) {
1886 const int j = seq[
q];
1887 if (nz[
j] && p.
mShift(
j, e) >= 0) {
1888 sub_gemm(
true, ns[e], ns[
j], nrhs, blk(
j, e), p.
mLd(
j, e), rr(
j), ldr,
1896 for (
int t =
m - 1;
t >= 0; --
t) {
1897 const int e = seq[
t];
1898 for (
int q =
t + 1;
q !=
static_cast<int>(seq.size()); ++
q) {
1899 const int i = seq[
q];
1900 if (nz[
i] && p.
mShift(
i, e) >= 0) {
1901 sub_gemm(
true, ns[e], ns[
i], nrhs, blk(
i, e), p.
mLd(
i, e), rr(
i), ldr,
1906 CHKERR diag_solve(e,
'T');
1910 for (
int t = 0;
t !=
static_cast<int>(seq.size()); ++
t) {
1911 const int e = seq[
t];
1912 for (
int q = 0;
q != std::min(
t,
m); ++
q) {
1913 const int i = seq[
q];
1914 if (nz[
i] && p.
mShift(e,
i) >= 0) {
1921 CHKERR diag_solve(e,
'N');
1925 for (
int t =
m - 1;
t >= 0; --
t) {
1926 const int e = seq[
t];
1927 for (
int q =
t + 1;
q !=
static_cast<int>(seq.size()); ++
q) {
1928 const int j = seq[
q];
1929 if (nz[
j] && p.
mShift(e,
j) >= 0) {
1949 const int m = p.
order.size();
1950 std::vector<int> seq(p.
order);
1951 seq.insert(seq.end(), p.
core.begin(), p.
core.end());
1952 const int nseq = seq.size();
1955 auto blk = [&](
int a,
int b) {
return buf + p.
mShift(
a, b); };
1956 auto vv = [&](
int a) {
return v + off[
a]; };
1960 for (
int t = 0;
t !=
m; ++
t) {
1961 const int e = seq[
t];
1963 for (
int q =
t + 1;
q != nseq; ++
q) {
1964 const int i = seq[
q];
1972 for (
int t = nseq - 1;
t >= 0; --
t) {
1973 const int e = seq[
t];
1974 for (
int q = 0;
q != std::min(
t,
m); ++
q) {
1975 const int j = seq[
q];
1982 for (
int t = 0;
t !=
m; ++
t) {
1983 const int e = seq[
t];
1984 for (
int q =
t + 1;
q != nseq; ++
q) {
1985 const int j = seq[
q];
1993 for (
int t = nseq - 1;
t >= 0; --
t) {
1994 const int e = seq[
t];
1997 for (
int q = 0;
q != std::min(
t,
m); ++
q) {
1998 const int i = seq[
q];
2011 return 1. + 0.5 * std::sin(1. +
i);
2024 std::vector<double> &x,
2025 std::vector<double> &r,
2026 std::vector<double> &rs) {
2027 const int n = p.
size;
2032 for (
int i = 0;
i !=
n; ++
i) {
2035 b_norm = std::max(b_norm, std::abs(x[
i]));
2037 constexpr double inf = std::numeric_limits<double>::infinity();
2038 if (
elem_solve(p, lu, piv, x.data(),
n, 1,
false,
nullptr))
2042 for (
int i = 0;
i !=
n; ++
i)
2043 if (!std::isfinite(x[
i]))
2050 const double *blk = orig + p.
sShift(
a,
c);
2055 double r_norm = 0, x_norm = 0, a_norm = 0;
2056 for (
int i = 0;
i !=
n; ++
i) {
2057 if (!std::isfinite(r[
i]) || !std::isfinite(rs[
i]))
2059 r_norm = std::max(r_norm, std::abs(r[
i]));
2060 x_norm = std::max(x_norm, std::abs(x[
i]));
2061 a_norm = std::max(a_norm, rs[
i]);
2063 const double den = a_norm * x_norm + b_norm;
2064 if (!std::isfinite(den) || !(den > 0))
2066 const double be = r_norm / den;
2067 return std::isfinite(be) ? be : inf;
2072 return std::isfinite(be_dense)
2094 double u,
double rcond_min,
double be_tol,
2095 double &be_block,
double &be_dense) {
2096 const int n = nl.
size;
2097 std::vector<double> x, r, rs, f,
work;
2098 std::vector<__CLPK_integer> piv(
n), iwork;
2103 std::vector<double> dense(dl.
elemSize, 0.);
2106 be_dense = std::numeric_limits<double>::infinity();
2111 be_block = std::numeric_limits<double>::infinity();
2121 const std::vector<int> &nodes) {
2123 for (
auto r : nodes) {
2128 return s.empty() ? std::string(
"none") : s;
2141 const int k = p.nbNodes;
2142 std::vector<double> scratch;
2143 for (
int ei = 0; ei !=
static_cast<int>(s.
elems.size()); ++ei) {
2144 auto &e = s.
elems[ei];
2145 if (e.pattern != pi)
2147 auto relayout_buf = [&](std::vector<double> &buf) {
2148 scratch.assign(buf.begin(), buf.end());
2150 buf.reserve(
static_cast<size_t>(nl.
size) * nl.
size);
2152 std::fill(buf.begin(), buf.end(), 0.);
2158 for (
int r = 0; r !=
k; ++r)
2159 for (
int c = 0;
c !=
k; ++
c)
2160 if (p.isListed(r,
c)) {
2165 for (
int r = 0; r !=
k; ++r)
2189 "A00 element matrices are already factorised in other storage");
2191 const bool in_prec = where == BlockStorage::FACTOR_IN_PRECONDITIONER;
2194 "No preconditioner blocks");
2200 auto get_matrix = [&](
int ei, std::vector<double> &out) {
2203 cblas_daxpy(out.size(), 1., storage.
elemPrec[ei].data(), 1, out.data(),
2207 std::vector<double> mat, w;
2208 for (
int pi = 0; pi !=
static_cast<int>(storage.
patterns.size()); ++pi) {
2210 if (p.state != BlockPattern::LISTED)
2215 for (
int pass = 0; pass != 2 && probe < 0; ++pass)
2216 for (
int ei = 0; ei !=
static_cast<int>(storage.
elems.size()); ++ei) {
2217 auto &e = storage.
elems[ei];
2218 if (e.pattern != pi || !e.local || (pass == 0 && !e.owned))
2220 get_matrix(ei, mat);
2229 const int n = p.size;
2230 w.assign(
static_cast<size_t>(
n) *
n, 0.);
2235 double be_block = 0, be_dense = 0;
2236 bool verified =
true;
2237 if (nl.
state == BlockPattern::BLOCK) {
2238 std::vector<double> probe_mat(nl.
elemSize, 0.);
2242 nl.
beRef = be_dense;
2245 <<
"A00 pattern " << pi <<
": block elimination rejected on probe "
2246 <<
"(backward error " << be_block <<
", dense " << be_dense
2247 <<
"), element matrices are dense";
2253 <<
"A00 pattern " << pi <<
" (" << p.nbElems
2256 <<
"; doubles per element: listed " <<
listed_size(p) <<
", layout "
2257 << nl.
elemSize <<
", dense " <<
static_cast<size_t>(
n) *
n
2258 <<
"; probe backward error " << be_block <<
" (dense " << be_dense
2270 std::vector<double> scratch,
work, be_x, be_r, be_rs;
2271 std::vector<__CLPK_integer> iwork;
2272 for (
int ei = 0; ei !=
static_cast<int>(storage.
elems.size()); ++ei) {
2273 auto &e = storage.
elems[ei];
2274 e.factorised =
false;
2276 std::vector<double>().swap(storage.
elemDense[ei]);
2277 if (!e.size || !e.local)
2279 auto &p = storage.
patterns[e.pattern];
2282 cblas_daxpy(buf.size(), 1., storage.
elemData[ei].data(), 1, buf.data(),
2289 "A00 element matrix is zero (not assembled or singular)");
2292 if (p.state == BlockPattern::LISTED)
2294 "A00 pattern not analysed");
2296 auto piv = storage.
pivots.data() + e.pivShift;
2297 if (p.state == BlockPattern::BLOCK)
2298 scratch.assign(buf.begin(), buf.end());
2300 if (!ret && p.state == BlockPattern::BLOCK) {
2304 p.beMax = std::max(p.beMax, be);
2309 if (p.state != BlockPattern::BLOCK)
2311 "error lapack dgetrf, A00 element matrix is singular");
2314 dense.assign(
static_cast<size_t>(e.size) * e.size, 0.);
2316 if (
lapack_dgetrf(e.size, e.size, dense.data(), e.size, piv) != 0)
2318 "error lapack dgetrf, A00 element matrix is singular");
2322 e.factorised =
true;
2324 for (
int pi = 0; pi !=
static_cast<int>(storage.
patterns.size()); ++pi) {
2330 <<
"A00 pattern " << pi <<
": " << p.nbFallback <<
" of " << p.nbElems
2331 <<
" elements failed block pivot or backward error test and are "
2335 for (
int pi = 0; pi !=
static_cast<int>(storage.
patterns.size()); ++pi) {
2337 if (p.state == BlockPattern::BLOCK) {
2339 <<
"A00 pattern " << pi <<
": largest backward error " << p.beMax
2340 <<
" (dense on probe " << p.beRef <<
"), dense fallback "
2351 auto &fe_order = storage.
feOrder;
2352 fe_order.resize(index.size());
2353 std::iota(fe_order.begin(), fe_order.end(), 0);
2354 std::sort(fe_order.begin(), fe_order.end(), [&index](
int a,
int b) {
2355 if (index[a].getFEUId() != index[b].getFEUId())
2356 return index[a].getFEUId() < index[b].getFEUId();
2359 auto &col_order = storage.
colOrder;
2360 col_order.resize(index.size());
2361 std::iota(col_order.begin(), col_order.end(), 0);
2362 std::sort(col_order.begin(), col_order.end(), [&index](
int a,
int b) {
2363 if (index[a].getColUId() != index[b].getColUId())
2364 return index[a].getColUId() < index[b].getColUId();
2372 for (
auto &d : s.
storage->blockIndex) {
2373 if (d.getElem() == -1)
2374 s.
blocks.push_back({d.getMatShift(), d.getLd(), d.getRow(), d.getCol(),
2375 d.getNbRows(), d.getNbCols(), d.getLocRow(),
2378 s.blocks.shrink_to_fit();
2379 s.hasElems = !s.storage->elems.empty();
2380 s.numbering = BlockStructure::PARENT;
2389template <
typename FUN>
2392 double *data = storage.data.data();
2393 for (
auto &b : ctx.
blocks)
2394 fun(data + b.shift, b.ld, b.row, b.col, b.nbRows, b.nbCols, b.locRow,
2397 for (
int ei = 0; ei !=
static_cast<int>(storage.elems.size()); ++ei) {
2398 auto &e = storage.elems[ei];
2399 auto &p = storage.patterns[e.pattern];
2400 double *buf = storage.elemData[ei].data();
2401 for (
int r = 0; r != p.nbNodes; ++r) {
2402 auto &re = storage.elemEntities[e.entBegin + r];
2403 for (
int c = 0;
c != p.nbNodes; ++
c) {
2404 if (!p.isListed(r,
c))
2406 auto &ce = storage.elemEntities[e.entBegin +
c];
2407 fun(buf + p.sShift(r,
c), p.sLd(r,
c), ctx.
globIdx(re),
2422 auto cmp_uid_lo = [](
const boost::weak_ptr<FieldEntity> &
a,
const UId &b) {
2423 if (
auto a_ptr =
a.lock()) {
2424 if (a_ptr->getLocalUniqueId() < b)
2433 auto cmp_uid_hi = [](
const UId &b,
const boost::weak_ptr<FieldEntity> &
a) {
2434 if (
auto a_ptr =
a.lock()) {
2435 if (b < a_ptr->getLocalUniqueId())
2445 auto get_uid_pair = [](
const auto &field_id) {
2446 auto lo_uid = FieldEntity::getLocalUniqueIdCalculate(
2447 field_id, get_id_for_min_type<MBVERTEX>());
2448 auto hi_uid = FieldEntity::getLocalUniqueIdCalculate(
2449 field_id, get_id_for_max_type<MBENTITYSET>());
2450 return std::make_pair(lo_uid, hi_uid);
2454 auto get_it_pair = [cmp_uid_lo, cmp_uid_hi](
auto &&field_ents,
auto &&p_uid) {
2455 auto lo = std::lower_bound(field_ents.begin(), field_ents.end(),
2456 p_uid.first, cmp_uid_lo);
2457 auto hi = std::upper_bound(field_ents.begin(), field_ents.end(),
2458 p_uid.second, cmp_uid_hi);
2459 return std::make_pair(lo, hi);
2464 auto row_extractor = [](
auto &e) {
return e->entityCacheRowDofs; };
2465 auto col_extractor = [](
auto &e) {
return e->entityCacheColDofs; };
2467 auto extract_data = [](
auto &&its,
auto extractor) {
2468 std::vector<std::tuple<UId, int, int, int>> data;
2469 data.reserve(std::distance(its.first, its.second));
2471 for (; its.first != its.second; ++its.first) {
2472 if (
auto e = its.first->lock()) {
2473 if (
auto cache = extractor(e).lock()) {
2475 for (
auto dof = cache->loHi[0]; dof != cache->loHi[1]; ++dof) {
2476 if ((*dof)->getPetscGlobalDofIdx() != -1)
2479 auto uid = e->getLocalUniqueId();
2482 auto glob = (*cache->loHi[0])->getPetscGlobalDofIdx();
2483 auto loc = (*cache->loHi[0])->getPetscLocalDofIdx();
2484 while (glob == -1 && cache->loHi[0] != cache->loHi[1]) {
2486 glob = (*cache->loHi[0])->getPetscGlobalDofIdx();
2487 loc = (*cache->loHi[0])->getPetscLocalDofIdx();
2489 data.emplace_back(uid, glob, nb_dofs, loc);
2493 for (
auto lo = cache->loHi[0]; lo != cache->loHi[1]; ++lo) {
2494 auto glob = (*lo)->getPetscGlobalDofIdx();
2497 "Wrong global index");
2503 data.emplace_back(uid, -1, 0, -1);
2511 auto data_ptr = boost::make_shared<BlockStructure>();
2512 auto storage = boost::make_shared<BlockStorage>();
2513 data_ptr->storage = storage;
2514 auto &index = storage->blockIndex;
2518 auto fe_method = boost::shared_ptr<MoFEM::FEMethod>(
new MoFEM::FEMethod());
2522 size_t nb_pairs = 0;
2523 for (
auto count_only : {
true,
false}) {
2526 index.reserve(nb_pairs);
2528 for (
auto &d : schur_fe_op_vec) {
2531 auto get_bit_numbers = [&d](
auto op) {
2532 std::vector<FieldBitNumber> bit_numbers(d.second.size());
2533 std::transform(d.second.begin(), d.second.end(), bit_numbers.begin(),
2539 auto row_bit_numbers = get_bit_numbers(
2540 [&](
auto &p) {
return m_field_ptr->get_field_bit_number(p.first); });
2542 auto col_bit_numbers = get_bit_numbers(
2543 [&](
auto &p) {
return m_field_ptr->get_field_bit_number(p.second); });
2545 fe_method->preProcessHook = []() {
return 0; };
2546 fe_method->postProcessHook = []() {
return 0; };
2547 fe_method->operatorHook = [&]() {
2550 auto fe_uid = fe_method->numeredEntFiniteElementPtr->getLocalUniqueId();
2552 for (
auto f = 0; f != row_bit_numbers.size(); ++f) {
2555 extract_data(get_it_pair(fe_method->getRowFieldEnts(),
2556 get_uid_pair(row_bit_numbers[f])),
2559 extract_data(get_it_pair(fe_method->getColFieldEnts(),
2560 get_uid_pair(col_bit_numbers[f])),
2563 for (
auto &r : row_data) {
2564 auto [r_uid, r_glob, r_nb_dofs, r_loc] = r;
2567 for (
auto &
c : col_data) {
2568 auto [c_uid, c_glob, c_nb_dofs, c_loc] =
c;
2574 index.emplace_back(r_uid, c_uid, fe_uid, r_glob, c_glob,
2575 r_nb_dofs, c_nb_dofs, r_loc, c_loc);
2584 m_field_ptr->get_comm_size());
2589 std::stable_sort(index.begin(), index.end(), BlockStorage::lessRowCol);
2590 index.erase(std::unique(index.begin(), index.end(),
2591 [](
auto &
a,
auto &b) {
2592 return a.getRowUId() == b.getRowUId() &&
2593 a.getColUId() == b.getColUId();
2596 index.shrink_to_fit();
2599 size_t mem_size = 0;
2600 for (
auto &
v : index) {
2601 v.setStorage(mem_size,
v.getNbCols(), -1);
2602 mem_size +=
static_cast<size_t>(
v.getNbRows()) *
v.getNbCols();
2605 if (mem_size > storage->data.max_size())
2607 storage->dataSize = mem_size;
2614 CHKERR VecSetDM(ghost_x, PETSC_NULLPTR);
2615 CHKERR VecSetDM(ghost_y, PETSC_NULLPTR);
2617 data_ptr->ghostX = ghost_x;
2618 data_ptr->ghostY = ghost_y;
2621 CHKERR PetscObjectGetComm((PetscObject)dm, &
comm);
2622 std::array<size_t, 2> loc_stats = {index.size(), mem_size *
sizeof(
double)};
2623 std::array<size_t, 2> sum_stats, max_stats;
2624 MPI_Allreduce(loc_stats.data(), sum_stats.data(), 2, MPIU_SIZE_T, MPI_SUM,
2626 MPI_Allreduce(loc_stats.data(), max_stats.data(), 2, MPIU_SIZE_T, MPI_MAX,
2628 constexpr double mb = 1024. * 1024.;
2630 <<
"Blocks " << sum_stats[0] <<
" (max per process " << max_stats[0]
2631 <<
"), data " << sum_stats[1] / mb <<
" MB (max per process "
2632 << max_stats[1] / mb <<
" MB), index "
2649 InsertMode iora,
bool trans) {
2652 CHKERR MatShellGetContext(mat, (
void **)&ctx);
2653 auto &storage = *ctx->
storage;
2654 storage.ensureAllocated();
2656 PetscLogEventBegin(SchurEvents::MOFEM_EVENT_BlockStructureMult, 0, 0, 0, 0);
2659 CHKERR VecGetLocalSize(x, &x_loc_size);
2661 Vec ghost_x = ctx->
ghostX;
2662 Vec ghost_y = ctx->
ghostY;
2664 std::swap(ghost_x, ghost_y);
2666 CHKERR storage.checkNotFailed();
2668 if (with_p && !storage.hasPreconditioner)
2670 "No preconditioner blocks");
2672 ctx->
hasElems && storage.isFactorised() &&
2673 (storage.factorStorage == BlockStorage::FACTOR_IN_DATA || with_p);
2675 storage.factorStorage == BlockStorage::FACTOR_IN_PRECONDITIONER
2679 CHKERR VecCopy(x, ghost_x);
2682 CHKERR VecGhostGetLocalForm(ghost_y, &loc_ghost_y);
2683 CHKERR VecSet(loc_ghost_y, 0.);
2684 CHKERR VecGhostRestoreLocalForm(ghost_y, &loc_ghost_y);
2687 std::vector<double> xe, ye;
2689 xe.resize(storage.maxElemSize);
2690 ye.resize(storage.maxElemSize);
2693 auto mult_pass = [&](
bool ghost_pass) {
2696 const double *x_array;
2698 CHKERR VecGhostGetLocalForm(ghost_x, &loc_ghost_x);
2699 CHKERR VecGetArrayRead(loc_ghost_x, &x_array);
2703 CHKERR VecGhostGetLocalForm(ghost_y, &loc_ghost_y);
2704 CHKERR VecGetArray(loc_ghost_y, &y_array);
2706 const double *data = storage.data.data();
2707 const auto cblas_trans = trans ? CblasTrans : CblasNoTrans;
2709 for (
auto &b : ctx->
blocks) {
2710 const int x_loc = trans ? b.locRow : b.locCol;
2711 const int y_loc = trans ? b.locCol : b.locRow;
2713 if (x_loc < 0 || y_loc < 0)
2715 if ((x_loc >= x_loc_size) != ghost_pass)
2717 cblas_dgemv(CblasRowMajor, cblas_trans, b.nbRows, b.nbCols, 1.0,
2718 data + b.shift, b.ld, x_array + x_loc, 1, 1.0,
2719 y_array + y_loc, 1);
2723 for (
int ei = 0; ei !=
static_cast<int>(storage.elems.size()); ++ei) {
2724 auto &e = storage.elems[ei];
2725 const int n = e.size;
2730 if (use_lu && !e.factorised)
2732 auto ent_begin = storage.elemEntities.data() + e.entBegin;
2733 auto ent_end = storage.elemEntities.data() + e.entEnd;
2737 bool any_ghost =
false;
2738 bool available =
true;
2739 for (
auto ent = ent_begin; ent != ent_end; ++ent) {
2742 const int loc = ctx->
locIdx(*ent);
2745 else if (loc >= x_loc_size)
2748 if (!available || any_ghost != ghost_pass)
2751 for (
auto ent = ent_begin; ent != ent_end; ++ent)
2753 cblas_dcopy(ent->nb, x_array + ctx->
locIdx(*ent), 1,
2754 xe.data() + ent->offset, 1);
2756 auto &p = storage.patterns[e.pattern];
2757 auto piv = storage.pivots.data() + e.pivShift;
2767 std::fill(ye.begin(), ye.begin() +
n, 0.);
2776 for (
auto ent = ent_begin; ent != ent_end; ++ent)
2778 cblas_daxpy(ent->nb, 1.0, y_e + ent->offset, 1,
2779 y_array + ctx->
locIdx(*ent), 1);
2783 CHKERR VecRestoreArrayRead(loc_ghost_x, &x_array);
2784 CHKERR VecRestoreArray(loc_ghost_y, &y_array);
2785 CHKERR VecGhostRestoreLocalForm(ghost_x, &loc_ghost_x);
2786 CHKERR VecGhostRestoreLocalForm(ghost_y, &loc_ghost_y);
2790 CHKERR VecGhostUpdateBegin(ghost_x, INSERT_VALUES, SCATTER_FORWARD);
2792 CHKERR VecGhostUpdateEnd(ghost_x, INSERT_VALUES, SCATTER_FORWARD);
2795 CHKERR VecGhostUpdateBegin(ghost_y, ADD_VALUES, SCATTER_REVERSE);
2796 CHKERR VecGhostUpdateEnd(ghost_y, ADD_VALUES, SCATTER_REVERSE);
2800 CHKERR VecCopy(ghost_y, y);
2803 CHKERR VecAXPY(y, 1., ghost_y);
2809 PetscLogEventEnd(SchurEvents::MOFEM_EVENT_BlockStructureMult, 0, 0, 0, 0);
2821 InsertMode iora,
bool trans) {
2824 CHKERR MatShellGetContext(mat, (
void **)&ctx);
2825 auto &storage = *ctx->
storage;
2826 storage.ensureAllocated();
2828 PetscLogEventBegin(SchurEvents::MOFEM_EVENT_BlockStructureSolve, 0, 0, 0, 0);
2830 if (ctx->
numbering != BlockStructure::BLOCK)
2832 "Solve is implemented only for A00 block of nested Schur matrix, "
2833 "see createSchurNestedMatrixStruture");
2835 CHKERR storage.checkNotFailed();
2837 if (with_p && !storage.hasPreconditioner)
2839 "No preconditioner blocks");
2844 }
else if (!storage.hasPreconditioner) {
2851 auto &lu_bufs = with_p ? storage.elemPrec : storage.elemData;
2854 CHKERR VecGetLocalSize(x, &nb_local);
2856 if (iora == INSERT_VALUES)
2857 CHKERR VecZeroEntries(x);
2860 CHKERR VecGetArray(x, &x_array);
2861 const double *f_array;
2862 CHKERR VecGetArrayRead(f, &f_array);
2864 std::vector<double>
t(storage.maxElemSize);
2865 std::vector<double> scratch;
2866 std::vector<__CLPK_integer> scratch_piv;
2868 scratch.resize(
static_cast<size_t>(storage.maxElemSize) *
2869 storage.maxElemSize);
2870 scratch_piv.resize(storage.maxElemSize);
2873 const char lapack_trans = trans ?
'N' :
'T';
2875 for (
int ei = 0; ei !=
static_cast<int>(storage.elems.size()); ++ei) {
2876 auto &e = storage.elems[ei];
2877 const int n = e.size;
2880 if (use_lu && !e.factorised)
2882 auto ent_begin = storage.elemEntities.data() + e.entBegin;
2883 auto ent_end = storage.elemEntities.data() + e.entEnd;
2887 for (
auto ent = ent_begin; ent != ent_end; ++ent) {
2888 if (ent->nb && (ent->locBlock < 0 || ent->locBlock >= nb_local)) {
2896 for (
auto ent = ent_begin; ent != ent_end; ++ent)
2898 cblas_dcopy(ent->nb, f_array + ent->locBlock, 1,
t.data() + ent->offset,
2901 auto &p = storage.patterns[e.pattern];
2902 auto piv = storage.pivots.data() + e.pivShift;
2906 info =
lapack_dgetrs(lapack_trans,
n, 1, storage.elemDense[ei].data(),
2907 n, piv,
t.data(),
n);
2912 std::fill(scratch.begin(), scratch.begin() +
static_cast<size_t>(
n) *
n,
2918 scratch_piv.data(),
t.data(),
n);
2922 "error lapack solve info = %d",
static_cast<int>(info));
2924 for (
auto ent = ent_begin; ent != ent_end; ++ent)
2926 cblas_daxpy(ent->nb, 1.0,
t.data() + ent->offset, 1,
2927 x_array + ent->locBlock, 1);
2930 CHKERR VecRestoreArray(x, &x_array);
2931 CHKERR VecRestoreArrayRead(f, &f_array);
2933 PetscLogEventEnd(SchurEvents::MOFEM_EVENT_BlockStructureSolve, 0, 0, 0, 0);
2938static PetscErrorCode
mult(Mat mat, Vec x, Vec y) {
2951static PetscErrorCode
solve(Mat mat, Vec x, Vec y) {
2965 const PetscInt
rows[], PetscScalar diag,
2970 CHKERR MatShellGetContext(
A, (
void **)&ctx);
2971 auto &storage = *ctx->
storage;
2972 CHKERR storage.modified();
2973 storage.ensureAllocated();
2975 PetscLogEventBegin(SchurEvents::MOFEM_EVENT_zeroRowsAndCols, 0, 0, 0, 0);
2979 std::vector<int> zero_idx;
2989 CHKERR ISGetSize(is_local, &is_nb_rows);
2991 CHKERR ISGetIndices(is_local, &ptr);
2992 zero_idx.assign(ptr, ptr + is_nb_rows);
2993 CHKERR ISRestoreIndices(is_local, &ptr);
2998 std::sort(zero_idx.begin(), zero_idx.end());
2999 zero_idx.erase(std::unique(zero_idx.begin(), zero_idx.end()), zero_idx.end());
3002 CHKERR MatGetLocalSize(
A, &loc_m, &loc_n);
3004 for_each_block(*ctx, [&](
double *ptr,
int ld,
int row,
int col,
int nb_rows,
3005 int nb_cols,
int loc_row,
int loc_col) {
3006 if (!nb_rows || !nb_cols)
3009 auto lo = std::lower_bound(zero_idx.begin(), zero_idx.end(), row);
3010 for (; lo != zero_idx.end() && *lo < row + nb_rows; ++lo) {
3011 auto *row_ptr = ptr +
static_cast<size_t>(*lo - row) * ld;
3012 std::fill(row_ptr, row_ptr + nb_cols, 0.);
3015 const bool diag_block = row == col && loc_row >= 0 && loc_row < loc_m &&
3016 loc_col >= 0 && loc_col < loc_n;
3017 lo = std::lower_bound(zero_idx.begin(), zero_idx.end(), col);
3018 for (; lo != zero_idx.end() && *lo < col + nb_cols; ++lo) {
3019 const int c = *lo - col;
3020 for (
int i = 0;
i != nb_rows; ++
i)
3021 ptr[
static_cast<size_t>(
i) * ld +
c] = 0.;
3022 if (diag_block &&
c < nb_rows)
3023 ptr[
static_cast<size_t>(
c) * ld +
c] = diag;
3027 PetscLogEventEnd(SchurEvents::MOFEM_EVENT_zeroRowsAndCols, 0, 0, 0, 0);
3035 CHKERR MatShellGetContext(
m, (
void **)&ctx);
3036 auto &storage = *ctx->
storage;
3037 storage.ensureAllocated();
3038 std::fill(storage.data.begin(), storage.data.end(), 0.);
3039 for (
auto &buf : storage.elemData)
3040 std::fill(buf.begin(), buf.end(), 0.);
3041 for (
auto &buf : storage.elemPrec)
3042 std::fill(buf.begin(), buf.end(), 0.);
3043 storage.resetFactors();
3049 CHKERR MatShellSetManageScalingShifts(mat_raw);
3050 CHKERR MatShellSetOperation(mat_raw, MATOP_MULT, (
void (*)(
void))
mult);
3051 CHKERR MatShellSetOperation(mat_raw, MATOP_MULT_ADD,
3053 CHKERR MatShellSetOperation(mat_raw, MATOP_MULT_TRANSPOSE,
3055 CHKERR MatShellSetOperation(mat_raw, MATOP_MULT_TRANSPOSE_ADD,
3057 CHKERR MatShellSetOperation(mat_raw, MATOP_SOLVE, (
void (*)(
void))
solve);
3058 CHKERR MatShellSetOperation(mat_raw, MATOP_SOLVE_ADD,
3060 CHKERR MatShellSetOperation(mat_raw, MATOP_SOLVE_TRANSPOSE,
3062 CHKERR MatShellSetOperation(mat_raw, MATOP_SOLVE_TRANSPOSE_ADD,
3064 CHKERR MatShellSetOperation(mat_raw, MATOP_ZERO_ENTRIES,
3066 CHKERR MatShellSetOperation(mat_raw, MATOP_ZERO_ROWS_COLUMNS,
3073 boost::shared_ptr<BlockStructure> data) {
3076 auto nb_local = problem_ptr->nbLocDofsRow;
3077 auto nb_global = problem_ptr->nbDofsRow;
3080 if (nb_local != problem_ptr->nbLocDofsCol) {
3082 <<
"Wrong size " << nb_local <<
" != " << problem_ptr->nbLocDofsCol;
3084 "nb. cols is inconsistent with nb. rows");
3086 if (nb_global != problem_ptr->nbDofsCol) {
3088 <<
"Wrong size " << nb_global <<
" != " << problem_ptr->nbDofsCol;
3090 "nb. cols is inconsistent with nb. rows");
3095 CHKERR PetscObjectGetComm((PetscObject)dm, &
comm);
3098 CHKERR MatCreateShell(
comm, nb_local, nb_local, nb_global, nb_global,
3099 (
void *)data.get(), &mat_raw);
3108 std::vector<std::string> fields_name,
3109 std::vector<boost::shared_ptr<Range>> field_ents,
3113 CHKERR MatShellGetContext(
B, (
void **)&ctx);
3114 auto &storage = *ctx->
storage;
3115 auto &index = storage.blockIndex;
3116 storage.ensureAllocated();
3118 PetscLogEventBegin(SchurEvents::MOFEM_EVENT_AssembleSchurMat, 0, 0, 0, 0);
3123 CHKERR storage.checkNotFailed();
3126 if (with_p && !storage.hasPreconditioner)
3128 "No preconditioner blocks");
3130 if (fields_name.size() != field_ents.size()) {
3132 "fields_name.size() != field_ents.size()");
3135 std::vector<std::pair<UId, UId>> a00_fields_uids;
3136 a00_fields_uids.reserve(fields_name.size());
3137 auto it_field_ents = field_ents.begin();
3138 for (
auto &f : fields_name) {
3140 if (*it_field_ents) {
3141 for (
auto p = (*it_field_ents)->pair_begin();
3142 p != (*it_field_ents)->pair_end(); ++p) {
3143 a00_fields_uids.emplace_back(
3144 DofEntity::getLoFieldEntityUId(bn, p->first),
3145 DofEntity::getHiFieldEntityUId(bn, p->second));
3148 a00_fields_uids.emplace_back(FieldEntity::getLoBitNumberUId(bn),
3149 FieldEntity::getHiBitNumberUId(bn));
3154 auto is_a00 = [&](
const UId &uid) {
3155 for (
auto &uid_pair : a00_fields_uids) {
3156 if (uid >= uid_pair.first && uid < uid_pair.second)
3163 std::vector<const Idx *> a00_blocks, a01_blocks, a10_blocks, a11_blocks;
3169 std::map<UId, LocIdx> a00_indexing, a11_indexing;
3170 std::vector<UId> col_uids;
3171 std::vector<double> a00_mat, a01t_mat, a10_mat, s_mat, tmp_block;
3172 std::vector<__CLPK_integer> ipiv;
3173 std::vector<int> glob_idx, row_glob_idx, col_glob_idx;
3174 std::vector<char> nz;
3177 auto set_values_block = [&](
const Idx *b) {
3180 const int nb_cols = b->getNbCols();
3181 row_glob_idx.resize(nb_rows);
3182 col_glob_idx.resize(nb_cols);
3183 std::iota(row_glob_idx.begin(), row_glob_idx.end(), b->getRow());
3184 std::iota(col_glob_idx.begin(), col_glob_idx.end(), b->getCol());
3185 CHKERR AOApplicationToPetsc(ao, nb_rows, row_glob_idx.data());
3186 CHKERR AOApplicationToPetsc(ao, nb_cols, col_glob_idx.data());
3187 const double *ptr = storage.blockPtr(*b);
3188 if (b->getLd() != nb_cols) {
3189 tmp_block.resize(
static_cast<size_t>(nb_rows) * nb_cols);
3190 copy_block(tmp_block.data(), nb_cols, 0, 0, ptr, b->getLd(), nb_rows,
3192 ptr = tmp_block.data();
3195 col_glob_idx.data(), ptr, ADD_VALUES);
3200 auto set_local_indices = [](
auto &indexing,
auto &row_blocks,
3203 for (
auto b : row_blocks)
3204 indexing.emplace(b->getRowUId(), LocIdx{0, b->getNbRows(), b->getRow()});
3205 for (
auto b : col_blocks)
3206 indexing.emplace(b->getColUId(), LocIdx{0, b->getNbCols(), b->getCol()});
3208 for (
auto &p : indexing) {
3209 p.second.index =
size;
3210 size += p.second.size;
3215 const auto &fe_order = storage.feOrder;
3219 auto classify_fe = [&](
size_t &p) {
3224 const auto fe_uid = index[fe_order[p]].getFEUId();
3225 for (; p != fe_order.size() && index[fe_order[p]].getFEUId() == fe_uid;
3227 auto b = &index[fe_order[p]];
3228 const bool r00 = is_a00(b->getRowUId());
3229 const bool c00 = is_a00(b->getColUId());
3231 a00_blocks.push_back(b);
3233 a01_blocks.push_back(b);
3235 a10_blocks.push_back(b);
3237 a11_blocks.push_back(b);
3244 auto element_of = [&]() {
3245 const int elem = a00_blocks.front()->getElem();
3248 auto &p = storage.patterns[storage.elems[elem].pattern];
3249 if (
static_cast<int>(a00_blocks.size()) != p.nbListed)
3251 for (
auto b : a00_blocks)
3252 if (b->getElem() != elem)
3261 bool all_consistent = storage.nested;
3262 for (
size_t p = 0; all_consistent && p != fe_order.size();) {
3266 for (
auto blocks : {&a01_blocks, &a10_blocks, &a11_blocks})
3267 for (
auto b : *blocks)
3268 if (b->getElem() >= 0)
3269 all_consistent =
false;
3270 if (!a00_blocks.empty() && element_of() < 0)
3271 all_consistent =
false;
3274 enum Mode { SCRATCH, DATA_FACTORS, PRECONDITIONER_FACTORS } mode = SCRATCH;
3276 if (!all_consistent)
3278 "Schur complement with preconditioner blocks requires eliminated "
3279 "fields equal to A00 of nested matrix");
3281 mode = PRECONDITIONER_FACTORS;
3282 }
else if (storage.nested && !storage.hasPreconditioner) {
3283 if (all_consistent) {
3285 mode = DATA_FACTORS;
3286 }
else if (storage.isFactorised()) {
3288 "A00 is factorised in place, eliminated fields have to be equal "
3289 "to A00 of nested matrix");
3293 for (
size_t p = 0; p != fe_order.size();) {
3295 const auto fe_uid = classify_fe(p);
3297 for (
auto b : a11_blocks)
3298 CHKERR set_values_block(b);
3300 if (a00_blocks.empty())
3305 for (
size_t i = 0;
i != a00_blocks.size(); ++
i) {
3306 const auto r_uid = a00_blocks[
i]->getRowUId();
3307 if (
i && a00_blocks[
i - 1]->getRowUId() == r_uid)
3309 auto range = storage.rowRange(r_uid);
3310 for (
auto it = range.first; it != range.second; ++it) {
3311 if (it->getFEUId() != fe_uid && !is_a00(it->getColUId()))
3312 a01_blocks.push_back(&*it);
3316 for (
auto b : a00_blocks)
3317 col_uids.push_back(b->getColUId());
3318 std::sort(col_uids.begin(), col_uids.end());
3319 col_uids.erase(std::unique(col_uids.begin(), col_uids.end()),
3321 for (
auto &c_uid : col_uids) {
3322 auto range = storage.colRange(c_uid);
3323 for (
auto it = range.first; it != range.second; ++it) {
3324 auto &b = index[*it];
3325 if (b.getFEUId() != fe_uid && !is_a00(b.getRowUId()))
3326 a10_blocks.push_back(&b);
3330 const int a11_size =
3331 set_local_indices(a11_indexing, a10_blocks, a01_blocks);
3337 auto gather_a01t = [&](
int a00_size) {
3338 a01t_mat.assign(
static_cast<size_t>(a11_size) * a00_size, 0.);
3339 for (
auto b : a01_blocks) {
3340 const auto &ri = a00_indexing.at(b->getRowUId());
3341 const auto &ci = a11_indexing.at(b->getColUId());
3342 const double *ptr = storage.blockPtr(*b);
3343 const int ld = b->getLd();
3344 for (
int i = 0;
i != b->getNbRows(); ++
i)
3345 for (
int j = 0;
j != b->getNbCols(); ++
j)
3346 a01t_mat[
static_cast<size_t>(ci.index +
j) * a00_size + ri.index +
3347 i] = ptr[
static_cast<size_t>(
i) * ld +
j];
3352 if (mode != SCRATCH) {
3353 const int elem = element_of();
3356 "Inconsistent A00 element");
3357 auto &e = storage.elems[elem];
3361 auto &pat = storage.patterns[e.pattern];
3363 a00_indexing.clear();
3364 for (
int r = e.entBegin; r != e.entEnd; ++r) {
3365 auto &ent = storage.elemEntities[r];
3366 a00_indexing.emplace(ent.uid,
3367 LocIdx{ent.offset, ent.nb, ent.globParent});
3370 gather_a01t(a00_size);
3371 auto piv = storage.pivots.data() + e.pivShift;
3374 storage.elemDense[elem].data(), a00_size, piv,
3375 a01t_mat.data(), a00_size);
3378 "error lapack dgetrs info = %d",
static_cast<int>(info));
3381 nz.assign(pat.nbNodes, 0);
3382 for (
auto b : a01_blocks)
3383 for (
int r = 0; r != pat.nbNodes; ++r)
3384 if (storage.elemEntities[e.entBegin + r].uid == b->getRowUId())
3386 auto &buf = mode == DATA_FACTORS ? storage.elemData[elem]
3387 : storage.elemPrec[elem];
3389 a11_size,
false, &nz);
3392 a00_size = set_local_indices(a00_indexing, a00_blocks, a00_blocks);
3393 const int elem = a00_blocks.front()->getElem();
3394 if (elem >= 0 && !storage.elems[elem].local)
3396 a00_mat.assign(
static_cast<size_t>(a00_size) * a00_size, 0.);
3397 for (
auto b : a00_blocks) {
3398 const auto &ri = a00_indexing.at(b->getRowUId());
3399 const auto &ci = a00_indexing.at(b->getColUId());
3400 copy_block(a00_mat.data(), a00_size, ri.index, ci.index,
3401 storage.blockPtr(*b), b->getLd(), b->getNbRows(),
3405 if (elem >= 0 && !storage.elems[elem].owned &&
3408 ipiv.resize(a00_size);
3409 auto info =
lapack_dgetrf(a00_size, a00_size, a00_mat.data(), a00_size,
3413 "error lapack dgetrf info = %d",
static_cast<int>(info));
3414 gather_a01t(a00_size);
3415 info =
lapack_dgetrs(
'T', a00_size, a11_size, a00_mat.data(), a00_size,
3416 ipiv.data(), a01t_mat.data(), a00_size);
3419 "error lapack dgetrs info = %d",
static_cast<int>(info));
3422 a10_mat.assign(
static_cast<size_t>(a11_size) * a00_size, 0.);
3423 for (
auto b : a10_blocks) {
3424 const auto &ri = a11_indexing.at(b->getRowUId());
3425 const auto &ci = a00_indexing.at(b->getColUId());
3426 copy_block(a10_mat.data(), a00_size, ri.index, ci.index,
3427 storage.blockPtr(*b), b->getLd(), b->getNbRows(),
3432 s_mat.resize(
static_cast<size_t>(a11_size) * a11_size);
3433 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasTrans, a11_size, a11_size,
3434 a00_size, -1., a10_mat.data(), a00_size, a01t_mat.data(),
3435 a00_size, 0., s_mat.data(), a11_size);
3437 glob_idx.resize(a11_size);
3438 for (
auto &pi : a11_indexing) {
3439 auto &[idx,
size, glob] = pi.second;
3440 std::iota(glob_idx.begin() + idx, glob_idx.begin() + idx +
size, glob);
3442 CHKERR AOApplicationToPetsc(ao, a11_size, glob_idx.data());
3444 s_mat.data(), ADD_VALUES);
3447 PetscLogEventEnd(SchurEvents::MOFEM_EVENT_AssembleSchurMat, 0, 0, 0, 0);
3454 CHKERR MatShellGetContext(
B, (
void **)&ctx);
3455 ctx->
storage->ensureAllocated();
3456 return boost::shared_ptr<std::vector<double>>(ctx->
storage,
3460boost::shared_ptr<std::vector<double>>
3463 return boost::make_shared<std::vector<double>>();
3469 InsertMode iora,
bool is_preconditioner) {
3480 PetscLogEventBegin(SchurEvents::MOFEM_EVENT_BlockStructureSetValues, 0, 0, 0,
3493 auto &storage = *ctx->
storage;
3494 CHKERR storage.modified();
3495 storage.ensureAllocated();
3497 auto get_row_data = [&]() -> std::pair<bool, VectorInt> {
3499 if (
auto stored_data_ptr =
3501 MOFEM_LOG(
"SELF", Sev::warning) <<
"Can lead to unhandled behaviour";
3502 return std::make_pair(
true, stored_data_ptr->entityIndices);
3505 return std::make_pair(
false, row_data.
getIndices());
3508 auto row_indices = get_row_data();
3509 const auto &row_ind = row_indices.second;
3512 std::vector<int> ent_row_indices;
3513 std::vector<int> ent_col_indices;
3515 auto get_ent_indices = [](
auto &cache,
auto &ind) {
3517 ind.reserve(std::distance(cache->loHi[0], cache->loHi[1]));
3518 for (
auto e = cache->loHi[0]; e != cache->loHi[1]; ++e) {
3519 auto glob = (*e)->getPetscGlobalDofIdx();
3521 ind.push_back(glob);
3526 auto r_cache = rent->entityCacheRowDofs.lock();
3529 get_ent_indices(r_cache, ent_row_indices);
3530 if (ent_row_indices.empty())
3532 const auto &row_uid = rent->getLocalUniqueId();
3535 auto c_cache = cent->entityCacheColDofs.lock();
3538 get_ent_indices(c_cache, ent_col_indices);
3539 if (ent_col_indices.empty())
3541 const auto &col_uid = cent->getLocalUniqueId();
3543 auto idx = storage.find(row_uid, col_uid);
3547 <<
"missing block: row " << row_data.
getFieldDofs()[0]->getName()
3550 "Block not allocated");
3552 if (is_preconditioner && idx->getElem() == -1)
3554 "Preconditioner blocks are allocated only for A00 element "
3557 const int nb_rows = idx->getNbRows();
3558 const int nb_cols = idx->getNbCols();
3559 const int ld = idx->getLd();
3560 double *s_mat = storage.blockPtr(*idx, is_preconditioner);
3562 if (mat.size1() == ent_row_indices.size() &&
3563 mat.size2() == ent_col_indices.size()) {
3565 const double *
m = mat.data().data();
3566 if (ld == nb_cols) {
3567 if (iora == ADD_VALUES)
3568 cblas_daxpy(nb_rows * nb_cols, 1.0,
m, 1, s_mat, 1);
3570 cblas_dcopy(nb_rows * nb_cols,
m, 1, s_mat, 1);
3572 for (
int i = 0;
i != nb_rows; ++
i) {
3573 if (iora == ADD_VALUES)
3574 cblas_daxpy(nb_cols, 1.0,
m +
static_cast<size_t>(
i) * nb_cols, 1,
3575 s_mat +
static_cast<size_t>(
i) * ld, 1);
3577 cblas_dcopy(nb_cols,
m +
static_cast<size_t>(
i) * nb_cols, 1,
3578 s_mat +
static_cast<size_t>(
i) * ld, 1);
3584 auto ri = row_ind.begin();
3585 auto rie = row_ind.end();
3588 for (
auto re : ent_row_indices) {
3589 ri = std::find(ri, rie, re);
3592 auto ci = col_ind.begin();
3593 auto cie = col_ind.end();
3596 for (
auto ce : ent_col_indices) {
3597 ci = std::find(ci, cie, ce);
3599 auto &
m = s_mat[
static_cast<size_t>(row) * ld + col];
3600 if (iora == ADD_VALUES) {
3601 m += mat(std::distance(row_ind.begin(), ri),
3602 std::distance(col_ind.begin(), ci));
3604 m = mat(std::distance(row_ind.begin(), ri),
3605 std::distance(col_ind.begin(), ci));
3619 PetscLogEventEnd(SchurEvents::MOFEM_EVENT_BlockStructureSetValues, 0, 0, 0,
3631 PetscBool is_mat_shell = PETSC_FALSE;
3632 PetscObjectTypeCompare((PetscObject)
M, MATSHELL, &is_mat_shell);
3635 CHKERR MatShellGetContext(
M, (
void **)&ctx);
3639 CHKERR MatSetValues<AssemblyTypeSelector<PETSC>>(
M, row_data, col_data, mat,
3650 PetscBool is_mat_shell = PETSC_FALSE;
3651 PetscObjectTypeCompare((PetscObject)
M, MATSHELL, &is_mat_shell);
3654 CHKERR MatShellGetContext(
M, (
void **)&ctx);
3655 if (!ctx->
storage->hasPreconditioner)
3657 "No preconditioner blocks");
3661 CHKERR MatSetValues<AssemblyTypeSelector<PETSC>>(
M, row_data, col_data, mat,
3670 boost::shared_ptr<BlockStructure> block_mat_data_ptr,
3672 std::vector<std::string> fields_names,
3673 std::vector<boost::shared_ptr<Range>>
3675 bool add_preconditioner_block) {
3677 if (!block_mat_data_ptr) {
3681 if (fields_names.size() != field_ents.size())
3683 "fields_names.size() != field_ents.size()");
3685 auto &storage = *block_mat_data_ptr->storage;
3686 auto &index = storage.blockIndex;
3687 const int nb_blocks = index.size();
3689 if (storage.isFactorised())
3691 "Block matrix is factorised in place");
3696 "Nested Schur structure already created for this block "
3697 "matrix, create new one with createBlockMatStructure");
3700 PetscBool dense = PETSC_FALSE;
3703 storage.optDense = dense == PETSC_TRUE;
3704 CHKERR ::PetscOptionsGetReal(PETSC_NULLPTR,
"",
3705 "-schur_a00_pivot_threshold",
3706 &storage.optPivotThreshold, PETSC_NULLPTR);
3707 CHKERR ::PetscOptionsGetReal(PETSC_NULLPTR,
"",
"-schur_a00_rcond_min",
3708 &storage.optRcondMin, PETSC_NULLPTR);
3709 CHKERR ::PetscOptionsGetReal(PETSC_NULLPTR,
"",
"-schur_a00_backward_error",
3710 &storage.optBackwardError, PETSC_NULLPTR);
3713 int nb_local_parent;
3714 CHKERR VecGetLocalSize(block_mat_data_ptr->ghostX, &nb_local_parent);
3716 auto [schur_dm, block_dm] = dms;
3725 CHKERR VecSetDM(schur_vec_x, PETSC_NULLPTR);
3726 CHKERR VecSetDM(block_vec_x, PETSC_NULLPTR);
3727 CHKERR VecSetDM(schur_vec_y, PETSC_NULLPTR);
3728 CHKERR VecSetDM(block_vec_y, PETSC_NULLPTR);
3730 auto find_field_ent = [&](
auto uid,
auto prb,
auto rc) {
3731 boost::shared_ptr<NumeredDofEntity_multiIndex> dofs;
3735 dofs = prb->getNumeredRowDofsPtr();
3738 dofs = prb->getNumeredColDofsPtr();
3747 return boost::shared_ptr<NumeredDofEntity>();
3753 return boost::shared_ptr<NumeredDofEntity>();
3763 SubIdx schurRow, schurCol, blockRow, blockCol;
3765 std::vector<SubIdxs> sub(nb_blocks);
3766 auto get_sub = [&](
auto uid,
auto prb,
auto rc) {
3768 if (
auto dof = find_field_ent(uid, prb, rc)) {
3769 s.glob = dof->getPetscGlobalDofIdx();
3770 s.loc = dof->getPetscLocalDofIdx();
3774 for (
int i = 0;
i != nb_blocks; ++
i) {
3776 sub[
i].schurRow = get_sub(d.getRowUId(), schur_prb,
ROW);
3777 sub[
i].schurCol = get_sub(d.getColUId(), schur_prb,
COL);
3778 sub[
i].blockRow = get_sub(d.getRowUId(), block_prb,
ROW);
3779 sub[
i].blockCol = get_sub(d.getColUId(), block_prb,
COL);
3784 std::vector<std::pair<size_t, int>> old_layout(nb_blocks);
3785 for (
int i = 0;
i != nb_blocks; ++
i) {
3786 old_layout[
i] = std::make_pair(index[
i].getMatShift(), index[
i].getLd());
3787 index[
i].setStorage(0, index[
i].getNbCols(), -1);
3790 std::vector<int> a00;
3791 for (
int i = 0;
i != nb_blocks; ++
i) {
3792 if (sub[
i].blockRow.glob != -1 && sub[
i].blockCol.glob != -1)
3795 std::sort(a00.begin(), a00.end(), [&index](
int a,
int b) {
3796 if (index[a].getFEUId() != index[b].getFEUId())
3797 return index[a].getFEUId() < index[b].getFEUId();
3801 storage.patterns.clear();
3802 storage.elems.clear();
3803 storage.elemEntities.clear();
3804 storage.maxElemSize = 0;
3806 std::map<std::vector<long>,
int> pattern_map;
3807 std::vector<BlockStorage::ElemEntity> ents;
3808 std::vector<long>
key;
3810 for (
size_t p = 0; p != a00.size();) {
3811 const auto fe_uid = index[a00[p]].getFEUId();
3812 const size_t p_begin = p;
3814 for (; p != a00.size() && index[a00[p]].getFEUId() == fe_uid; ++p) {
3815 const auto i = a00[p];
3817 ents.push_back({d.getRowUId(), d.getNbRows(), 0, d.getLocRow(),
3818 d.getRow(), sub[
i].blockRow.loc, sub[
i].blockRow.glob});
3819 ents.push_back({d.getColUId(), d.getNbCols(), 0, d.getLocCol(),
3820 d.getCol(), sub[
i].blockCol.loc, sub[
i].blockCol.glob});
3822 std::sort(ents.begin(), ents.end(),
3823 [](
auto &
a,
auto &b) { return a.uid < b.uid; });
3824 ents.erase(std::unique(ents.begin(), ents.end(),
3825 [](
auto &
a,
auto &b) { return a.uid == b.uid; }),
3827 const int k = ents.size();
3828 auto node_of = [&](
const UId &uid) {
3829 return static_cast<int>(
3830 std::lower_bound(ents.begin(), ents.end(), uid,
3831 [](
auto &e,
auto &u) { return e.uid < u; }) -
3836 std::vector<char> listed(
k *
k, 0);
3837 for (
size_t q = p_begin;
q != p; ++
q) {
3838 auto &d = index[a00[
q]];
3839 listed[node_of(d.getRowUId()) *
k + node_of(d.getColUId())] = 1;
3844 for (
auto &e : ents) {
3845 key.push_back(FieldEntity::getFieldBitNumberFromUniqueId(e.uid));
3848 key.push_back(e.nb);
3851 key.insert(
key.end(), listed.begin(), listed.end());
3852 auto pit = pattern_map.find(
key);
3853 if (pit == pattern_map.end()) {
3858 pat.
nbListed = std::count(listed.begin(), listed.end(), 1);
3859 for (
auto &e : ents) {
3863 FieldEntity::getFieldBitNumberFromUniqueId(e.uid))));
3865 if (storage.optDense)
3869 pit = pattern_map.emplace(
key, storage.patterns.size()).first;
3870 storage.patterns.push_back(pat);
3872 const int pi = pit->second;
3873 auto &pat = storage.patterns[pi];
3876 const int elem_idx = storage.elems.size();
3877 const int ent_begin = storage.elemEntities.size();
3878 for (
int r = 0; r !=
k; ++r)
3879 ents[r].offset = pat.nodeOffset[r];
3880 storage.elems.push_back({pi,
n, ent_begin, ent_begin +
k, nb_pivots});
3881 storage.elemEntities.insert(storage.elemEntities.end(), ents.begin(),
3883 for (
size_t q = p_begin;
q != p; ++
q) {
3884 auto &d = index[a00[
q]];
3885 const int r = node_of(d.getRowUId()),
c = node_of(d.getColUId());
3886 d.setStorage(pat.sShift(r,
c), pat.sLd(r,
c), elem_idx);
3890 storage.maxElemSize = std::max(storage.maxElemSize,
n);
3892 auto &elem = storage.elems.back();
3895 for (
auto &e : ents) {
3898 if (e.locParent < 0)
3900 if (e.locParent < 0 || e.locParent >= nb_local_parent)
3908 std::vector<UId> uids;
3909 uids.reserve(storage.elemEntities.size());
3910 for (
auto &e : storage.elemEntities)
3911 uids.push_back(e.uid);
3912 std::sort(uids.begin(), uids.end());
3913 if (std::adjacent_find(uids.begin(), uids.end()) != uids.end())
3915 "Entity of A00 field is shared by more than one "
3916 "element, eliminated fields have to be element local "
3917 "(L2, broken spaces, or interior DOFs)");
3921 size_t mem_size = 0;
3922 for (
auto &d : index) {
3923 if (d.getElem() == -1) {
3924 d.setStorage(mem_size, d.getNbCols(), -1);
3925 mem_size +=
static_cast<size_t>(d.getNbRows()) * d.getNbCols();
3929 const int nb_elems = storage.elems.size();
3930 storage.hasPreconditioner = add_preconditioner_block;
3931 storage.elemData.assign(nb_elems, std::vector<double>());
3932 storage.elemPrec.assign(add_preconditioner_block ? nb_elems : 0,
3933 std::vector<double>());
3934 storage.elemDense.assign(nb_elems, std::vector<double>());
3935 storage.maxElemBuffer = 0;
3936 for (
int ei = 0; ei != nb_elems; ++ei) {
3937 const auto sz = storage.patterns[storage.elems[ei].pattern].elemSize;
3940 const auto n = storage.elems[ei].size;
3941 storage.elemData[ei].reserve(
static_cast<size_t>(
n) *
n);
3942 storage.elemData[ei].assign(sz, 0.);
3943 if (add_preconditioner_block) {
3944 storage.elemPrec[ei].reserve(
static_cast<size_t>(
n) *
n);
3945 storage.elemPrec[ei].assign(sz, 0.);
3947 storage.maxElemBuffer = std::max(storage.maxElemBuffer, sz);
3952 auto &data = storage.data;
3953 const bool has_values =
3954 std::any_of(data.begin(), data.end(), [](
double v) { return v != 0.; });
3956 std::vector<double> new_data(mem_size, 0.);
3957 for (
int i = 0;
i != nb_blocks; ++
i) {
3959 auto [old_shift, old_ld] = old_layout[
i];
3960 double *dst = d.getElem() >= 0
3961 ? storage.elemData[d.getElem()].data() + d.getMatShift()
3962 : new_data.data() + d.getMatShift();
3963 copy_block(dst, d.getLd(), 0, 0, data.data() + old_shift, old_ld,
3964 d.getNbRows(), d.getNbCols());
3966 data.swap(new_data);
3968 std::vector<double>().swap(data);
3970 storage.dataSize = mem_size;
3971 storage.ensureAllocated();
3972 storage.pivots.assign(nb_pivots, 0);
3973 storage.factorStorage = BlockStorage::FACTOR_NONE;
3978 std::array<boost::shared_ptr<BlockStructure>, 4> data_ptrs;
3979 for (
auto r = 0; r != 4; ++r) {
3980 data_ptrs[r] = boost::make_shared<BlockStructure>();
3981 data_ptrs[r]->storage = block_mat_data_ptr->storage;
3983 data_ptrs[3]->hasElems = !storage.elems.empty();
3984 data_ptrs[3]->numbering = BlockStructure::BLOCK;
3986 for (
int i = 0;
i != nb_blocks; ++
i) {
3989 auto add = [&](
auto &
m,
const SubIdx &r,
const SubIdx &
c) {
3990 m->blocks.push_back({d.getMatShift(), d.getLd(), r.glob,
c.glob,
3991 d.getNbRows(), d.getNbCols(), r.loc,
c.loc});
3993 if (s.schurRow.glob != -1 && s.schurCol.glob != -1)
3994 add(data_ptrs[0], s.schurRow, s.schurCol);
3995 if (s.schurRow.glob != -1 && s.blockCol.glob != -1)
3996 add(data_ptrs[1], s.schurRow, s.blockCol);
3997 if (s.blockRow.glob != -1 && s.schurCol.glob != -1)
3998 add(data_ptrs[2], s.blockRow, s.schurCol);
4000 if (s.blockRow.glob != -1 && s.blockCol.glob != -1 && d.getElem() == -1)
4003 for (
auto r = 0; r != 3; ++r)
4004 data_ptrs[r]->blocks.shrink_to_fit();
4006 data_ptrs[0]->ghostX = schur_vec_x;
4007 data_ptrs[0]->ghostY = schur_vec_y;
4008 data_ptrs[1]->ghostX = block_vec_x;
4009 data_ptrs[1]->ghostY = schur_vec_y;
4010 data_ptrs[2]->ghostX = schur_vec_x;
4011 data_ptrs[2]->ghostY = block_vec_y;
4012 data_ptrs[3]->ghostX = block_vec_x;
4013 data_ptrs[3]->ghostY = block_vec_y;
4015 if (add_preconditioner_block) {
4016 data_ptrs[3]->multiplyByPreconditioner =
true;
4017 block_mat_data_ptr->multiplyByPreconditioner =
false;
4021 CHKERR PetscObjectGetComm((PetscObject)schur_dm, &
comm);
4023 auto create_shell_mat = [&](
auto nb_r_loc,
auto nb_c_loc,
auto nb_r_glob,
4024 auto nb_c_glob,
auto data_ptr) {
4026 CHKERR MatCreateShell(
comm, nb_r_loc, nb_c_loc, nb_r_glob, nb_c_glob,
4027 (
void *)data_ptr.get(), &mat_raw);
4032 auto schur_nb_global = schur_prb->getNbDofsRow();
4033 auto block_nb_global = block_prb->getNbDofsRow();
4034 auto schur_nb_local = schur_prb->getNbLocalDofsRow();
4035 auto block_nb_local = block_prb->getNbLocalDofsRow();
4037 std::array<SmartPetscObj<Mat>, 4> mats_array;
4039 create_shell_mat(schur_nb_local, schur_nb_local, schur_nb_global,
4040 schur_nb_global, data_ptrs[0]);
4042 create_shell_mat(schur_nb_local, block_nb_local, schur_nb_global,
4043 block_nb_global, data_ptrs[1]);
4045 create_shell_mat(block_nb_local, schur_nb_local, block_nb_global,
4046 schur_nb_global, data_ptrs[2]);
4048 create_shell_mat(block_nb_local, block_nb_local, block_nb_global,
4049 block_nb_global, data_ptrs[3]);
4052 <<
"(0, 0) " << schur_nb_local <<
" " << schur_nb_global <<
" "
4053 << data_ptrs[0]->blocks.size();
4055 <<
"(0, 1) " << schur_nb_local <<
" " << block_nb_local <<
" "
4056 << schur_nb_global <<
" " << block_nb_global <<
" "
4057 << data_ptrs[1]->blocks.size();
4059 <<
"(1, 0) " << block_nb_local <<
" " << schur_nb_local <<
" "
4060 << block_nb_global <<
" " << schur_nb_global <<
" "
4061 << data_ptrs[2]->blocks.size();
4063 <<
"(1, 1) " << block_nb_local <<
" " << block_nb_global <<
" "
4064 << storage.elems.size() <<
" elements (" << a00.size() <<
" blocks, "
4065 << storage.patterns.size() <<
" patterns) max size "
4066 << storage.maxElemSize;
4073 size_t listed_d = 0, dense_d = 0, struct_d = 0, buffers_d = 0;
4074 for (
auto &pat : storage.patterns) {
4078 dense_d += pat.nbElems *
static_cast<size_t>(pat.size) * pat.size;
4079 struct_d += pat.nbElems * est.elemSize;
4080 buffers_d += pat.nbElems * pat.elemSize;
4082 <<
"A00 pattern (" << pat.nbElems <<
" elements): "
4085 std::vector<int> all(pat.nbNodes);
4086 std::iota(all.begin(), all.end(), 0);
4089 <<
"; listed pairs " << pat.nbListed <<
" of "
4090 << pat.nbNodes * pat.nbNodes <<
"; doubles per element: listed "
4092 <<
static_cast<size_t>(pat.size) * pat.size
4093 <<
", structural estimate " << est.elemSize <<
" (eliminated "
4098 size_t ghost_elems = 0, ghost_elems_data = 0, ghost_blocks_data = 0;
4099 for (
int ei = 0; ei != nb_elems; ++ei) {
4100 auto &e = storage.elems[ei];
4101 bool all_ghost =
true;
4102 for (
int k = e.entBegin;
k != e.entEnd; ++
k)
4103 if (storage.elemEntities[
k].locParent < nb_local_parent)
4107 ghost_elems_data += storage.elemData[ei].size();
4110 for (
auto &d : index)
4111 if (d.getElem() == -1 && d.getLocRow() >= nb_local_parent &&
4112 d.getLocCol() >= nb_local_parent)
4113 ghost_blocks_data +=
static_cast<size_t>(d.getNbRows()) * d.getNbCols();
4115 constexpr size_t dsz =
sizeof(
double);
4116 std::array<size_t, 10> loc_stats = {
4117 storage.elems.size(),
4123 (add_preconditioner_block ? buffers_d : 0) * dsz,
4125 ghost_elems_data * dsz,
4126 ghost_blocks_data * dsz};
4127 std::array<size_t, 10> sum_stats, max_stats;
4128 MPI_Allreduce(loc_stats.data(), sum_stats.data(), 10, MPIU_SIZE_T, MPI_SUM,
4130 MPI_Allreduce(loc_stats.data(), max_stats.data(), 10, MPIU_SIZE_T, MPI_MAX,
4132 constexpr double mb = 1024. * 1024.;
4134 <<
"A00 elements " << sum_stats[0] <<
" (max per process "
4135 << max_stats[0] <<
"), element buffers " << sum_stats[1] / mb
4136 <<
" MB (max per process " << max_stats[1] / mb
4137 <<
" MB); listed blocks " << sum_stats[2] / mb
4138 <<
" MB, dense element matrices would be " << sum_stats[3] / mb
4139 <<
" MB, structural estimate of block elimination " << sum_stats[4] / mb
4140 <<
" MB; other blocks data " << sum_stats[5] / mb
4141 <<
" MB (max per process " << max_stats[5] / mb
4142 <<
" MB); preconditioner blocks " << sum_stats[6] / mb <<
" MB";
4144 <<
"Not owned (ghost) elements " << sum_stats[7] <<
" data "
4145 << sum_stats[8] / mb <<
" MB, not owned other blocks data "
4146 << sum_stats[9] / mb <<
" MB";
4149 auto schur_is = schur_prb->getSubData()->getSmartRowIs();
4150 auto block_is = block_prb->getSubData()->getSmartRowIs();
4152 storage.nested =
true;
4154 return boost::make_shared<NestSchurData>(
4156 mats_array, data_ptrs, block_mat_data_ptr,
4157 std::make_pair(schur_is, block_is)
4162std::pair<SmartPetscObj<Mat>, boost::shared_ptr<NestSchurData>>
4165 if (!schur_net_data_ptr)
4168 auto [mat_arrays, data_ptrs, block_mat_data_ptr, iss] = *schur_net_data_ptr;
4169 auto [schur_is, block_is] = iss;
4171 std::array<IS, 2> is_a = {schur_is, block_is};
4172 std::array<Mat, 4> mats_a = {
4174 mat_arrays[0], mat_arrays[1], mat_arrays[2], mat_arrays[3]
4179 CHKERR PetscObjectGetComm((PetscObject)mat_arrays[0], &
comm);
4184 comm, 2, is_a.data(), 2, is_a.data(), mats_a.data(), &mat_raw
4195OpSchurAssembleBase *
4197 std::vector<boost::shared_ptr<Range>> field_ents,
4199 bool sym_schur,
bool symm_op) {
4202 schur, sym_schur, symm_op);
4205 schur, sym_schur, symm_op);
4209 boost::shared_ptr<std::vector<unsigned char>> marker_ptr,
double diag_val) {
4213OpSchurAssembleBase *
4215 std::vector<boost::shared_ptr<Range>> field_ents,
4218 std::vector<bool> sym_schur,
bool symm_op,
4219 boost::shared_ptr<BlockStructure> diag_blocks) {
4221 fields_name, field_ents, sequence_of_aos.back(), sequence_of_mats.back(),
4222 sym_schur.back(), symm_op);
4225OpSchurAssembleBase *
4227 std::vector<boost::shared_ptr<Range>> field_ents,
4230 std::vector<bool> sym_schur,
4231 std::vector<double> diag_eps,
bool symm_op,
4232 boost::shared_ptr<BlockStructure> diag_blocks) {
4234 fields_name, field_ents, sequence_of_aos.back(), sequence_of_mats.back(),
4235 sym_schur.back(), symm_op);
4241 auto apply = [](PC pc, Vec f, Vec x) {
4244 CHKERR PCGetOperators(pc, &
A, &P);
4245 CHKERR MatSolve(P, f, x);
4249 auto apply_transpose = [](PC pc, Vec f, Vec x) {
4252 CHKERR PCGetOperators(pc, &
A, &P);
4253 CHKERR MatSolveTranspose(P, f, x);
4257 CHKERR PCSetType(pc, PCSHELL);
4258 CHKERR PCShellSetApply(pc, apply);
4259 CHKERR PCShellSetApplyTranspose(pc, apply_transpose);
4260 CHKERR PCShellSetName(pc,
"MoFEMSchurBlockPC");
4272 return SchurElemMats::MatSetValues(
M, row_data, col_data, mat, iora);
4279 return MatSetValues<AssemblyTypeSelector<PETSC>>(
M, row_data, col_data, mat,
4284SchurBackendMatSetValuesPtr::MatSetValuesPtr
4285 SchurBackendMatSetValuesPtr::matSetValuesPtr = schur_mat_set_values_wrap;
4294 CHKERR assembleStorage(row_data, col_data, mat, iora);
4295 CHKERR SchurBackendMatSetValuesPtr::matSetValuesPtr(
M, row_data, col_data,
4307 return MatSetValues<SchurElemMats>(
M, row_data, col_data, mat, iora);
4328 SchurBackendMatSetValuesPtr::matSetValuesBlockPtr =
4332SchurElemMatsBlock::MatSetValues(Mat
M,
4337 CHKERR assembleStorage(row_data, col_data, mat, iora);
4338 CHKERR SchurBackendMatSetValuesPtr::matSetValuesBlockPtr(
M, row_data,
4339 col_data, mat, iora);
4345MatSetValues<SchurElemMatsBlock>(Mat
M,
4349 return SchurElemMatsBlock::MatSetValues(
M, row_data, col_data, mat, iora);
4361 SchurBackendMatSetValuesPtr::matSetValuesPreconditionedBlockPtr =
4369 CHKERR assembleStorage(row_data, col_data, mat, iora);
4370 CHKERR SchurBackendMatSetValuesPtr::matSetValuesPreconditionedBlockPtr(
4371 M, row_data, col_data, mat, iora);
4380 return SchurElemMatsPreconditionedBlock::MatSetValues(
M, row_data, col_data,
4387 if (block_mat_data->multiplyByPreconditioner) {
4388 block_mat_data->multiplyByPreconditioner =
false;
4390 if (!block_mat_data->storage->hasPreconditioner) {
4392 "preconditioner blocks not set");
4394 block_mat_data->multiplyByPreconditioner =
true;
4401 std::string filename) {
4405 moab::Interface &moab = core;
4407 ReadUtilIface *iface;
4408 CHKERR moab.query_interface(iface);
4412 [&](
double *,
int,
int,
int,
int,
int,
int,
int) { ++
size; });
4414 EntityHandle starting_vertex;
4415 vector<double *> arrays_coord;
4416 CHKERR iface->get_node_coords(3, 4 *
size, 0, starting_vertex, arrays_coord);
4417 EntityHandle starting_handle;
4418 EntityHandle *array;
4419 CHKERR iface->get_element_connect(
size, 4, MBQUAD, 0, starting_handle, array);
4421 double def_val_nrm2 = 0;
4423 CHKERR moab.tag_get_handle(
"nrm2", 1, MB_TYPE_DOUBLE, th_nrm2,
4424 MB_TAG_CREAT | MB_TAG_DENSE, &def_val_nrm2);
4426 int def_val_mat_shift = 0;
4428 CHKERR moab.tag_get_handle(
"mat_shift", 1, MB_TYPE_INTEGER, th_mat_shift,
4429 MB_TAG_CREAT | MB_TAG_DENSE, &def_val_mat_shift);
4431 block_mat_data->storage->ensureAllocated();
4434 for_each_block(*block_mat_data, [&](
double *ptr,
int ld,
int row,
int col,
4435 int nb_rows,
int nb_cols,
int,
int) {
4437 arrays_coord[0][4 *
i + 0] = row;
4438 arrays_coord[1][4 *
i + 0] = col;
4439 arrays_coord[2][4 *
i + 0] = 0;
4442 arrays_coord[0][4 *
i + 1] = row + nb_rows;
4443 arrays_coord[1][4 *
i + 1] = col;
4444 arrays_coord[2][4 *
i + 1] = 0;
4447 arrays_coord[0][4 *
i + 2] = row + nb_rows;
4448 arrays_coord[1][4 *
i + 2] = col + nb_cols;
4449 arrays_coord[2][4 *
i + 2] = 0;
4452 arrays_coord[0][4 *
i + 3] = row;
4453 arrays_coord[1][4 *
i + 3] = col + nb_cols;
4454 arrays_coord[2][4 *
i + 3] = 0;
4457 array[4 *
i + 0] = starting_vertex + 4 *
i + 0;
4458 array[4 *
i + 1] = starting_vertex + 4 *
i + 1;
4459 array[4 *
i + 2] = starting_vertex + 4 *
i + 2;
4460 array[4 *
i + 3] = starting_vertex + 4 *
i + 3;
4463 for (
int r = 0; r != nb_rows; ++r) {
4465 cblas_dnrm2(nb_cols, ptr +
static_cast<size_t>(r) * ld, 1);
4466 nrm2 += row_nrm2 * row_nrm2;
4468 nrm2 = std::sqrt(nrm2);
4470 EntityHandle ele = starting_handle +
i;
4471 CHKERR moab.tag_set_data(th_nrm2, &ele, 1, &nrm2);
4472 CHKERR moab.tag_set_data(th_mat_shift, &ele, 1, &mat_shift);
4477 CHKERR iface->update_adjacencies(starting_handle,
size, 4, array);
4478 CHKERR moab.write_file(filename.c_str(),
"VTK",
"");
#define MOFEM_LOG_SEVERITY_SYNC(comm, severity)
Synchronise "SYNC" on curtain severity level.
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
SmartPetscObj< Vec > work
#define MAX_DOFS_ON_ENTITY
Maximal number of DOFs on entity.
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define BITFIELDID_SIZE
max number of fields
@ MOFEM_OPERATION_UNSUCCESSFUL
@ MOFEM_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#define MoFEMFunctionBeginHot
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
PetscErrorCode DMoFEMLoopFiniteElementsUpAndLowRank(DM dm, const char fe_name[], MoFEM::FEMethod *method, int low_rank, int up_rank, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
FTensor::Index< 'i', SPACE_DIM > i
const double c
speed of light (cm/ns)
const double v
phase velocity of light in medium (cm/ns)
const double n
refractive index of diffusive medium
static __CLPK_integer lapack_dgetrf(__CLPK_integer m, __CLPK_integer n, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv)
static __CLPK_integer lapack_dgetri(__CLPK_integer n, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv, __CLPK_doublereal *work, __CLPK_integer lwork)
static __CLPK_integer lapack_dgetrs(char trans, __CLPK_integer n, __CLPK_integer nrhs, __CLPK_doublereal *a, __CLPK_integer lda, __CLPK_integer *ipiv, __CLPK_doublereal *b, __CLPK_integer ldb)
FTensor::Index< 'j', 3 > j
FTensor::Index< 'k', 3 > k
static MoFEMErrorCodeGeneric< PetscErrorCode > ierr
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
UBlasMatrix< double > MatrixDouble
UBlasVector< int > VectorInt
implementation of Data Operators for Forces and Sources
auto type_from_handle(const EntityHandle h)
get type from entity handle
MoFEMErrorCode schur_mat_set_values_wrap(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)
static void add_gemv(bool trans_a, int m, int kk, const double *a, int lda, const double *x, double *y)
y += op(A) x, op(A) is m x kk, A is column-major
MoFEMErrorCode shell_block_mat_asmb_wrap_impl(BlockStructure *ctx, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora, bool is_preconditioner)
static void elem_mult_listed(const BlockPattern &p, const double *buf, const double *x, double *y, bool trans)
y += A x (trans false) or y += A^T x (trans true) from listed blocks
static PetscErrorCode solve_add(Mat mat, Vec x, Vec y)
OpSchurAssembleBase * createOpSchurAssembleEnd(std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > ao, SmartPetscObj< Mat > schur, bool sym_schur, bool symm_op)
Construct a new Op Schur Assemble End object.
static MoFEMErrorCode mult_block_structure(Mat mat, Vec x, Vec y, InsertMode iora, bool trans)
Matrix-vector product of block matrix.
static bool verify_probe(const BlockPattern &nl, const std::vector< double > &mat, double u, double rcond_min, double be_tol, double &be_block, double &be_dense)
Verify block layout on probe element.
auto isAllGather(IS is)
IS All gather.
static void apply_lu_factors(int n, const double *lu, const __CLPK_integer *ipiv, double *t, bool trans)
Apply in place LU factors of element matrix.
MoFEMErrorCode schurSwitchPreconditioner(boost::shared_ptr< BlockStructure > block_mat_data)
Switch preconditioner.
static void for_each_block(const BlockStructure &ctx, FUN &&fun)
Iterate all blocks of matrix, including listed blocks of A00 elements.
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
constexpr bool debug_schur
static PetscErrorCode solve_transpose_add(Mat mat, Vec x, Vec y)
static int elem_factorise(const BlockPattern &p, double *buf, __CLPK_integer *piv, double u, double rcond_min, std::vector< double > &work, std::vector< __CLPK_integer > &iwork)
Factorise element buffer in place.
auto id_from_handle(const EntityHandle h)
static void elem_gather_dense(const BlockPattern &p, const double *buf, double *dense)
dense element matrix (row-major A, size x size) from listed blocks
static size_t listed_size(const BlockPattern &p)
doubles in listed blocks of one element
std::pair< SmartPetscObj< Mat >, boost::shared_ptr< BlockStructure > > SchurShellMatData
static std::vector< int > analyse_pattern(const BlockPattern &p, double *w, double u, double rcond_min)
Decide elimination order on probe element.
std::pair< SmartPetscObj< Mat >, boost::shared_ptr< NestSchurData > > createSchurNestedMatrix(boost::shared_ptr< NestSchurData > schur_net_data_ptr)
Create a Mat Diag Blocks object.
static PetscErrorCode mult_transpose_add(Mat mat, Vec x, Vec y)
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
MoFEMErrorCode shell_block_mat_asmb_wrap(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)
static double accepted_backward_error(double be_dense, double be_tol)
backward error accepted for block factors, given dense backward error
static void sub_gemm(bool trans_a, int m, int kk, int nrhs, const double *a, int lda, const double *b, int ldb, double *c, int ldc)
C -= op(A) B, op(A) is m x kk, A, B and C are column-major.
static MoFEMErrorCode factorise_elems(BlockStorage &storage, BlockStorage::FactorStorage where)
Factorise A00 elements in place.
static bool is_zero_matrix(const double *ptr, size_t size)
auto createISGeneral(MPI_Comm comm, PetscInt n, const PetscInt idx[], PetscCopyMode mode)
Creates a data structure for an index set containing a list of integers.
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
static std::vector< char > symbolic_elimination(const BlockPattern &p, const std::vector< int > &order)
Blocks of M = A^T present after eliminating nodes in given order.
static void copy_block(double *dst, int ld_dst, int ridx, int cidx, const double *src, int ld_src, int nb_rows, int nb_cols)
copy row-major block into row-major matrix at (ridx, cidx)
static bool factorise_pivot_block(int n, double *d, int ld, __CLPK_integer *piv, double coupling, double u, double rcond_min, std::vector< double > &work, std::vector< __CLPK_integer > &iwork, double *rcond_out=nullptr, double *anorm_out=nullptr)
Factorise diagonal block in place and test it as block pivot.
void dgecon_(char *norm, __CLPK_integer *n, __CLPK_doublereal *a, __CLPK_integer *lda, __CLPK_doublereal *anorm, __CLPK_doublereal *rcond, __CLPK_doublereal *work, __CLPK_integer *iwork, __CLPK_integer *info)
static PetscErrorCode solve(Mat mat, Vec x, Vec y)
static MoFEMErrorCode elem_solve(const BlockPattern &p, const double *buf, const __CLPK_integer *piv, double *r, int ldr, int nrhs, bool trans, const std::vector< char > *nz_in)
Solve with factorised element buffer.
boost::shared_ptr< std::vector< double > > getBlockMatPrconditionerStorageMat(Mat B)
Get preconditioner blocks storage.
static MoFEMErrorCode solve_block_structure(Mat mat, Vec f, Vec x, InsertMode iora, bool trans)
Solve with A00, i.e. x = A00^{-1} f, element by element.
static double elem_backward_error(const BlockPattern &p, const double *orig, const double *lu, const __CLPK_integer *piv, std::vector< double > &x, std::vector< double > &r, std::vector< double > &rs)
Normwise backward error of solve with factors of element.
static bool backward_error_accepted(double be, double be_dense, double be_tol)
true if backward error is finite and not larger than accepted
static std::string describe_nodes(const BlockPattern &p, const std::vector< int > &nodes)
static void make_block_layout(BlockPattern &p, const std::vector< int > &order)
Layout for block elimination of nodes in order, followed by dense core of remaining nodes.
static PetscErrorCode zero_rows_columns(Mat A, PetscInt N, const PetscInt rows[], PetscScalar diag, Vec x, Vec b)
static std::vector< int > natural_offsets(const BlockPattern &p)
offsets of nodes in element vector in order of nodes
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create block matrix structure.
boost::shared_ptr< NestSchurData > createSchurNestedMatrixStruture(std::pair< SmartPetscObj< DM >, SmartPetscObj< DM > > dms, boost::shared_ptr< BlockStructure > block_mat_data_ptr, std::vector< std::string > fields_names, std::vector< boost::shared_ptr< Range > > field_ents, bool add_preconditioner_block)
Create structure of nested matrix [A11 A10; A01 A00].
static PetscErrorCode mult_add(Mat mat, Vec x, Vec y)
MoFEMErrorCode MatSetValues(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const double *ptr, InsertMode iora)
Assemble PETSc matrix.
static void set_block_orders(BlockStorage &storage)
set orders of blocks by finite element and by column entity
static PetscErrorCode mult_transpose(Mat mat, Vec x, Vec y)
auto field_bit_from_bit_number(const int bit_number)
get field bit id from bit number
OpSchurAssembleBase * createOpSchurZeroRowsAndCols(boost::shared_ptr< std::vector< unsigned char > > marker_ptr, double diag_val)
Create a Op Schur Zero Rows And Cols object.
static PetscErrorCode mat_zero(Mat m)
MoFEMErrorCode schurSaveBlockMesh(boost::shared_ptr< BlockStructure > block_mat_data, std::string filename)
Save block matrix as a mesh.
auto getInterfacePtr(DM dm)
Get the Interface Ptr object.
static PetscErrorCode mult(Mat mat, Vec x, Vec y)
static PetscErrorCode solve_transpose(Mat mat, Vec x, Vec y)
static double norm1_block(int m, int n, const double *a, int ld)
1-norm of column-major m x n block, infinity if block is not finite
static double backward_error_rhs(int i)
right-hand side used to measure backward error
static void copy_listed(const BlockPattern &from, const double *src, const BlockPattern &to, double *dst)
copy listed blocks of element buffer from one layout to another
static void elem_mult_factors(const BlockPattern &p, const double *buf, const __CLPK_integer *piv, double *v, bool trans)
Product with factorised element buffer, in place.
static void set_parent_blocks(BlockStructure &s)
set blocks of block matrix (parent numbering)
static void make_listed_layout(BlockPattern &p)
layout with listed blocks only
constexpr double backward_error_factor
factor of dense backward error accepted for block factors
std::vector< std::pair< std::string, std::vector< SchurFieldPair > > > SchurFEOpsFEandFields
static MoFEMErrorCode setSchurBlockMatOps(Mat mat_raw)
MoFEMErrorCode shell_block_preconditioner_mat_asmb_wrap(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)
auto getProblemPtr(DM dm)
get problem pointer from DM
static void relayout_pattern(BlockStorage &s, int pi, BlockPattern nl)
Relayout element buffers of pattern pi, element by element, in place.
static std::vector< int > structural_order(const BlockPattern &p)
elimination order by structure only (minimal fill, diagonal present)
SchurShellMatData createBlockMat(DM dm, boost::shared_ptr< BlockStructure > data)
Create a Schur Mat object.
MoFEMErrorCode assembleBlockMatSchur(MoFEM::Interface &m_field, Mat B, Mat S, std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > ao)
Assemble Schur complement S = A11 - A10 A00^{-1} A01 from block matrix.
OpSchurAssembleBase * createOpSchurAssembleBegin()
auto ent_form_type_and_id(const EntityType type, const EntityID id)
get entity handle from type and id
boost::shared_ptr< std::vector< double > > getBlockMatStorageMat(Mat B)
Get block values storage.
constexpr double t
plate stiffness
FTensor::Index< 'm', 3 > m
DOFs on one entity (node) of A00 element.
int globParent
global index in block matrix numbering
int offset
offset in element vector (layout of pattern)
int locParent
local index in block matrix numbering
int locBlock
local index in A00 sub-problem numbering
int globBlock
global index in A00 sub-problem numbering
bool local
all entities have local index on this process
int entBegin
first entity in elemEntities
bool owned
all entities are owned by this process
int pivShift
shift in pivots
int entEnd
one past last entity in elemEntities
int pattern
index of pattern
bool factorised
factors are stored for this element
bool dense
factors are in elemDense (pivot test failed)
Indexes(UId uid_row, UId uid_col, UId uid_fe, int row, int col, int nb_rows, int nb_cols, int loc_row, int loc_col)
size_t mat_shift
shift in data, or in element buffer if elem >= 0
void setStorage(size_t shift, int leading_dim, int element)
size_t getMatShift() const
int ld
leading dimension of block in storage
int elem
index of A00 element, -1 if none
Block pattern of A00 element and layout of element buffer.
long mShift(int a, int b) const
shift of block (a, b) of M = A^T, column-major
int coreOffset
offset of core DOFs in element vector
long sShift(int r, int c) const
int size
DOFs per element.
std::vector< int > nodeSize
double beRef
backward error of dense solve on probe
std::vector< std::string > nodeName
int coreSize
DOFs in dense core.
std::vector< char > listed
nbNodes x nbNodes, slot (r, c) is listed
int nbFallback
elements factorised dense in last factorisation
int mLd(int a, int b) const
leading dimension of block (a, b) of M = A^T
@ LISTED
listed blocks only, not analysed
@ DENSE
dense element matrix (core contains all nodes)
@ BLOCK
block elimination of order nodes, then dense core
size_t coreShift
shift of dense core in element buffer
size_t elemSize
doubles in element buffer
int sLd(int r, int c) const
std::vector< int > order
nodes eliminated block by block
bool isListed(int r, int c) const
std::vector< long > slotShift
nbNodes x nbNodes, -1 if not stored
double beMax
largest backward error in last factorisation
std::vector< int > core
nodes of dense core
std::vector< int > nodeOffset
offset of node DOFs in element vector
std::vector< int > slotLd
bool operator()(const UId &a, const Indexes &b) const
bool operator()(const Indexes &a, const UId &b) const
Storage of block matrix, shared by block matrix and its nested (Schur) sub-matrices.
bool hasPreconditioner
preconditioner blocks are enabled
MoFEMErrorCode modified() const
Call before modification of data, fails if factors are stored in place.
size_t maxElemBuffer
maximal size of element buffer
double optRcondMin
-schur_a00_rcond_min
auto rowRange(const UId &row) const
range of blocks with given row entity uid
bool isFactorised() const
double * blockPtr(const Indexes &b, bool prec=false)
values of block, preconditioner buffer if prec is true
std::vector< ElemEntity > elemEntities
std::vector< int > feOrder
blocks sorted by (fe uid, row uid, col uid)
std::vector< int > colOrder
blocks sorted by (col uid, row uid)
std::vector< Elem > elems
bool optDense
-schur_a00_dense
FactorStorage factorStorage
std::vector< double > data
blocks not in A00, allocated on first use
std::vector< std::vector< double > > elemPrec
preconditioner buffers
std::vector< std::vector< double > > elemDense
dense factors (fallback)
double optBackwardError
-schur_a00_backward_error
std::vector< std::vector< double > > elemData
A00 element buffers.
MoFEMErrorCode checkNotFailed() const
Fails if factorisation failed, storage has to be zeroed.
std::vector< Indexes > blockIndex
blocks sorted by (row uid, col uid)
double optPivotThreshold
-schur_a00_pivot_threshold
size_t dataSize
required size of data
@ FACTOR_IN_PRECONDITIONER
@ FACTOR_FAILED
factorisation failed, data is corrupted
int maxElemSize
maximal DOFs of element
static bool lessRowCol(const Indexes &a, const Indexes &b)
const Indexes * find(const UId &row, const UId &col) const
find block by row and column entity uid, return nullptr if not found
Indexes * findMutable(const UId &row, const UId &col)
std::vector< Pattern > patterns
std::vector< __CLPK_integer > pivots
bool nested
nested Schur structure has been created
auto colRange(const UId &col) const
range (in colOrder) of blocks with given column entity uid
block in numbering of this matrix (blocks not stored in element buffers)
Context of block matrix shell.
std::vector< Block > blocks
Numbering
numbering of A00 element matrix entities used by this matrix
bool multiplyByPreconditioner
boost::shared_ptr< BlockStorage > storage
int locIdx(const BlockStorage::ElemEntity &e) const
SmartPetscObj< Vec > ghostX
SmartPetscObj< Vec > ghostY
int globIdx(const BlockStorage::ElemEntity &e) const
bool hasElems
A00 elements are part of this matrix.
virtual FieldBitNumber get_field_bit_number(const std::string name) const =0
get field bit number
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
const VectorFieldEntities & getFieldEntities() const
Get field entities (const version)
const VectorDofs & getFieldDofs() const
Get DOF data structures (const version)
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
[Storage and set boundary conditions]
Structure for user loop methods on finite elements.
static UId getHiBitNumberUId(const FieldBitNumber bit_number)
static auto getHandleFromUniqueId(const UId uid)
Get the Handle From Unique Id.
static auto getFieldBitNumberFromUniqueId(const UId uid)
Get the Field Bit Number From Unique Id.
UId getLocalUniqueIdCalculate()
Get the Local Unique Id Calculate object.
static UId getLoLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
static UId getHiLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
const FEMethod * getFEMethod() const
Return raw pointer to Finite Element Method object.
OpSchurAssembleBaseImpl()=delete
MoFEMErrorCode assembleSchurMat(Mat S, const UId &uid_row, VectorInt &row_ind, const UId &uid_col, VectorInt &col_ind, MatrixDouble &m, InsertMode iora)
Assemble Schur complement.
OpSchurAssembleBase()=delete
Clear Schur complement internal data.
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
Assemble Schur complement (Implementation)
SmartPetscObj< AO > schurAO
MoFEMErrorCode doWorkImpl(int side, EntityType type, EntitiesFieldData::EntData &data)
SmartPetscObj< Mat > schurMat
std::vector< boost::shared_ptr< Range > > fieldEnts
OpSchurAssembleEndImpl(std::vector< std::string > fields_name, std::vector< boost::shared_ptr< Range > > field_ents, SmartPetscObj< AO > schur_ao, SmartPetscObj< Mat > schur_mat, bool sym_schur, bool symm_op)
Construct a new Op Schur Assemble End object.
std::vector< std::string > fieldsName
Assemble Schur complement.
OpSchurZeroRowsAndCols(boost::shared_ptr< std::vector< unsigned char > > marker_ptr, double diag_val)
boost::shared_ptr< std::vector< unsigned char > > markerPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
Operator for linear form, usually to calculate values on right hand side.
boost::function< MoFEMErrorCode(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)> MatSetValuesPtr
static auto invertMat(MatrixDouble &m, MatrixDouble &inv)
static auto invertMat(MatrixDouble &m, MatrixDouble &inv)
Schur complement data storage.
static MoFEMErrorCode assembleStorage(const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)
static boost::ptr_vector< VectorInt > colIndices
static boost::ptr_vector< MatrixDouble > locMats
SchurElemMats(const size_t idx, const UId uid_row, const UId uid_col)
virtual ~SchurElemMats()=default
static size_t maxIndexCounter
static boost::ptr_vector< VectorInt > rowIndices
static MoFEMErrorCode MatSetValues(Mat M, const EntitiesFieldData::EntData &row_data, const EntitiesFieldData::EntData &col_data, const MatrixDouble &mat, InsertMode iora)
static boost::ptr_vector< SchurElemMats > schurElemMats
static SchurElemStorage schurL2Storage
multi_index_container< const SchurElemMats *, indexed_by< ordered_unique< tag< uid_mi_tag >, composite_key< SchurElemMats, member< SchurElemMats, const UId, &SchurElemMats::uidRow >, member< SchurElemMats, const UId, &SchurElemMats::uidCol > > >, ordered_non_unique< tag< col_mi_tag >, member< SchurElemMats, const UId, &SchurElemMats::uidCol > > > > SchurElemStorage
static PetscLogEvent MOFEM_EVENT_BlockStructureSetValues
static PetscLogEvent MOFEM_EVENT_BlockStructureMult
static PetscLogEvent MOFEM_EVENT_zeroRowsAndCols
static PetscLogEvent MOFEM_EVENT_opSchurAssembleEnd
static PetscLogEvent MOFEM_EVENT_BlockStructureSolve
static PetscLogEvent MOFEM_EVENT_schurMatSetValues
static PetscLogEvent MOFEM_EVENT_AssembleSchurMat
intrusive_ptr for managing petsc objects