824 {
825
827
828#ifndef NDEBUG
830#endif
831
832#ifndef NDEBUG
834 MOFEM_LOG(
"SELF", Sev::noisy) <<
"Schur assemble begin -> end";
835#endif
836
837 auto get_a00_uids = [&]() {
838 auto get_field_bit = [&](
auto &
name) {
839 return OP::getPtrFE()->mField.get_field_bit_number(
name);
840 };
841
842 std::vector<std::pair<UId, UId>> a00_uids;
844 for (
auto ss = 0; ss !=
fieldsName.size(); ++ss) {
845 auto field_bit = get_field_bit(
fieldsName[ss]);
847 if (row_ents) {
848 for (auto p = row_ents->pair_begin(); p != row_ents->pair_end(); ++p) {
849 auto lo_uid =
851 auto hi_uid =
853 a00_uids.push_back(std::make_pair(lo_uid, hi_uid));
854 }
855 } else {
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));
861 }
862 }
863 return a00_uids;
864 };
865
866#ifndef NDEBUG
867 auto get_field_name = [&](auto uid) {
870 };
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();
880 }
882 };
883#endif
884
885 auto assemble_dense_blocks = [&]() {
886 using matrix_range = ublas::matrix_range<MatrixDouble>;
887 using range = ublas::range;
890
891 auto assemble_schur = [
this](
auto &
m,
auto &uid_row,
auto &uid_col,
892 auto *row_ind_ptr, auto *col_ind_ptr) {
894
896
897 if (
auto ierr = this->assembleSchurMat(
898
899 schurMat, uid_row, *row_ind_ptr, uid_col, *col_ind_ptr,
m,
900 ADD_VALUES
901
902 )) {
903#ifndef NDEBUG
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();
918#endif
920 }
921 }
922
924 };
925
926 auto a00_uids = get_a00_uids();
927
928 auto get_block_indexing = [&](auto &a00_uids) {
929
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;
936
937 auto it =
938 storage.template get<SchurElemMats::uid_mi_tag>().lower_bound(
939 boost::make_tuple(rlo_uid, clo_uid));
940 auto hi_it =
941 storage.template get<SchurElemMats::uid_mi_tag>().upper_bound(
942 boost::make_tuple(rhi_uid, chi_uid));
943
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);
948 }
949 }
950 }
951 }
952
953
954 std::map<UId, std::pair<size_t, const VectorInt *>>
955 block_indexing;
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()));
960 }
961 }
962
963
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();
972 }
973 }
974
975 return std::make_tuple(block_list, block_indexing, mat_block_size);
976 };
977
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);
985 }
986 }
987 return block_list;
988 };
989
990 auto bi = get_block_indexing(a00_uids);
991 auto &[block_list, block_indexing, block_mat_size] = bi;
992
993 if (block_mat_size == 0) {
994
996 for (auto &s : storage) {
998 &*s->getRowInd().begin());
1000 &*s->getColInd().begin());
1001 }
1002 }
1003
1004 for (auto &s : storage) {
1005 auto &
m = s->getMat();
1006 CHKERR assemble_schur(
m, s->uidRow, s->uidCol, &(s->getRowInd()),
1007 &(s->getColInd()));
1008 }
1010 }
1011
1012 blockMat.resize(block_mat_size, block_mat_size,
false);
1014
1015 auto get_range = [](auto &bi) {
1016 return range(bi.first, bi.first + bi.second->size());
1017 };
1018
1019 for (auto &s : block_list) {
1020 auto &
m = s->getMat();
1021#ifndef NDEBUG
1022 if (block_indexing.find(s->uidRow) == block_indexing.end())
1024 if (block_indexing.find(s->uidCol) == block_indexing.end())
1026#endif
1027
1028 auto &rbi = block_indexing.at(s->uidRow);
1029 auto &cbi = block_indexing.at(s->uidCol);
1030
1031 auto sub_mat = matrix_range(
blockMat, get_range(rbi), get_range(cbi));
1033 }
1034
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) {
1043 if (*it < 0) {
1044 auto idx = bi.first + std::distance(
ind.begin(), it);
1045 zeroed_indices.push_back(idx);
1046 }
1047 }
1048 }
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;
1053 };
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(); });
1060
1061 for (
auto i : zero_rows) {
1064 }
1065 }
1066 for (
auto j : zero_cols) {
1069 }
1070 }
1071 for (
auto i : zero_rows) {
1073 }
1074
1076
1077
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);
1082 }
1083 block_list.clear();
1084
1086 for (auto &s : storage) {
1087 if (block_indexing.find(s->uidRow) == block_indexing.end()) {
1089 &*s->getRowInd().begin());
1090 }
1091 if (block_indexing.find(s->uidCol) == block_indexing.end()) {
1093 &*s->getColInd().begin());
1094 }
1095 }
1096 }
1097
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()),
1102 &(s->getColInd()));
1103 }
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);
1108 }
1109 schur_block_list.clear();
1110
1111 for (
1112
1113 auto rp_uid_it = a00_uids.begin(); rp_uid_it != a00_uids.end();
1114 ++rp_uid_it
1115
1116 ) {
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;
1121
1122 auto a_lo_tmp =
1123 storage.template get<SchurElemMats::col_mi_tag>().lower_bound(
1124 rm->first);
1125 auto a_hi =
1126 storage.template get<SchurElemMats::col_mi_tag>().upper_bound(
1127 rm->first);
1128
1129 for (
1130
1131 auto cp_uid_it = (
symSchur) ? rp_uid_it : a00_uids.begin();
1132 cp_uid_it != a00_uids.end(); ++cp_uid_it
1133
1134 ) {
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;
1139
1140 auto c_lo_tmp =
1141 storage.template get<SchurElemMats::uid_mi_tag>().lower_bound(
1142 boost::make_tuple(cm->first, 0));
1143 auto c_hi =
1144 storage.template get<SchurElemMats::uid_mi_tag>().upper_bound(
1147
1148 auto sub_inv_mat =
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;
1152
1153 for (auto a_lo = a_lo_tmp; a_lo != a_hi; ++a_lo) {
1154#ifndef NDEBUG
1155 if (block_indexing.find((*a_lo)->uidRow) != block_indexing.end())
1157 "Wrong a_lo->uidRow");
1158#endif
1159
1160 auto &
a = (*a_lo)->getMat();
1161 abM.resize(
a.size1(),
bM.size2(),
false);
1163 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
1164
1165 a.size1(),
bM.size2(),
a.size2(), 1.,
1166
1167 &*
a.data().begin(),
a.size2(),
1168
1169 &*
bM.data().begin(),
bM.size2(), 0.,
1170
1171 &*
abM.data().begin(),
abM.size2());
1172
1173 for (auto c_lo = c_lo_tmp; c_lo != c_hi; ++c_lo) {
1174#ifndef NDEBUG
1175 if (block_indexing.find((*c_lo)->uidCol) !=
1176 block_indexing.end())
1178 "Wrong a_lo->uidRow");
1179#endif
1180
1181 auto &
c = (*c_lo)->getMat();
1182
1183 abcM.resize(
abM.size1(),
c.size2(),
false);
1185
1186 cblas_dgemm(CblasRowMajor, CblasNoTrans, CblasNoTrans,
1187 abM.size1(),
c.size2(),
abM.size2(), -1.,
1188
1189 &*
abM.data().begin(),
abM.size2(),
1190
1191 &*
c.data().begin(),
c.size2(), 0.,
1192
1193 &*
abcM.data().begin(),
abcM.size2());
1194
1195 CHKERR assemble_schur(
abcM, (*a_lo)->uidRow, (*c_lo)->uidCol,
1196 &((*a_lo)->getRowInd()),
1197 &((*c_lo)->getColInd()));
1198
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()));
1204 }
1205 }
1206 }
1207 }
1208 }
1209 }
1210 }
1211
1213 };
1214
1215
1216 CHKERR assemble_dense_blocks();
1217
1218#ifndef NDEBUG
1220 MOFEM_LOG(
"SELF", Sev::noisy) <<
"Schur assemble done";
1221#endif
1222
1223#ifndef NDEBUG
1225#endif
1226
1228}
#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_DATA_INCONSISTENCY
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
#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)
FTensor::Index< 'j', 3 > j
static MoFEMErrorCodeGeneric< PetscErrorCode > ierr
UBlasVector< int > VectorInt
constexpr bool debug_schur
auto field_bit_from_bit_number(const int bit_number)
get field bit id from bit number
FTensor::Index< 'm', 3 > m
static UId getHiBitNumberUId(const FieldBitNumber bit_number)
static auto getFieldBitNumberFromUniqueId(const UId uid)
Get the Field Bit Number From Unique Id.
static UId getLoLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
static UId getHiLocalEntityBitNumber(const char bit_number, const EntityHandle ent)
static SchurElemStorage schurL2Storage
static PetscLogEvent MOFEM_EVENT_opSchurAssembleEnd