85int main(
int argc,
char *argv[]) {
94 moab::Interface &moab = moab_core;
101 DMType dm_name =
"DMMOFEM";
105 auto core_log = logging::core::get();
130 PetscBool no_preconditioner_block = PETSC_FALSE;
132 &no_preconditioner_block, PETSC_NULLPTR);
136 PetscBool uncoupled_so = PETSC_FALSE;
138 &uncoupled_so, PETSC_NULLPTR);
139 PetscBool empty_oo = PETSC_FALSE;
149 PetscBool overflow_pivot = PETSC_FALSE;
151 &overflow_pivot, PETSC_NULLPTR);
152 PetscBool overflow_pivot_element = PETSC_FALSE;
154 &overflow_pivot_element, PETSC_NULLPTR);
155 if (overflow_pivot_element)
156 overflow_pivot = PETSC_TRUE;
194 std::vector<SchurFieldPair> block_pairs{
195 {
"V",
"V"}, {
"T",
"T"}, {
"S",
"S"}, {
"O",
"O"}, {
"V",
"T"},
196 {
"T",
"V"}, {
"S",
"T"}, {
"T",
"S"}, {
"T",
"O"}, {
"O",
"T"}};
198 block_pairs.push_back({
"S",
"O"});
199 block_pairs.push_back({
"O",
"S"});
205 {{simple->getDomainFEName(), block_pairs}}));
207 auto [mat, block_data_ptr] = shell_data;
210 std::vector<std::string> fields{
"T",
"S",
"O"};
216 {schur_dm, block_dm}, block_data_ptr,
218 fields, {
nullptr,
nullptr,
nullptr},
219 no_preconditioner_block ? false : true
229 using OpMassBlockPreconditionerAssemble =
231 BiLinearForm<GAUSS>::OpMass<1,
FIELD_DIM>;
241 std::array<double, 12> bad_tet;
242 if (overflow_pivot_element) {
243 auto prb = m_field.get_problem(
simple->getProblemName());
245 for (
auto &fe : *prb->numeredFiniteElementsPtr)
246 if (fe->getPart() == m_field.get_comm_rank() &&
247 fe->getName() ==
simple->getDomainFEName())
248 owned.insert(fe->getEnt());
251 const EntityHandle *conn;
253 CHKERR moab.get_connectivity(owned.back(), conn, num_nodes,
true);
254 CHKERR moab.get_coords(conn, 4, bad_tet.data());
257 auto in_bad = [&](
double x,
double y,
double z) {
260 if (!overflow_pivot_element)
265 for (
int i = 0;
i != 3; ++
i)
266 for (
int j = 0;
j != 3; ++
j)
267 t_jac(
i,
j) = bad_tet[3 * (
j + 1) +
i] - bad_tet[
i];
273 for (
int i = 0;
i != 3; ++
i) {
275 for (
int j = 0;
j != 3; ++
j)
276 l += t_inv(
i,
j) * t_p(
j);
281 return sum < 1 + 1e-10;
283 auto ss_coeff = [&](
double x,
double y,
double z) {
284 return in_bad(x, y, z) ? 1e-300 : 1.;
286 auto st_coeff = [&](
double x,
double y,
double z) {
287 return in_bad(x, y, z) ? -1e10 / 2 : -1. / 2;
290 pip_mng->setDomainLhsIntegrationRule([](
int,
int,
int o) {
return 2 * o; });
291 auto &pip_lhs = pip_mng->getOpDomainLhsPipeline();
293 pip_lhs.push_back(
new OpMassPETSCAssemble(
"V",
"V"));
296 if (no_preconditioner_block)
297 pip_lhs.push_back(
new OpMassPETSCAssemble(
"T",
"T"));
298 pip_lhs.push_back(
new OpMassPETSCAssemble(
"V",
"T"));
299 pip_lhs.push_back(
new OpMassPETSCAssemble(
"T",
"V"));
300 pip_lhs.push_back(
new OpMassPETSCAssemble(
"S",
"S", ss_coeff));
301 pip_lhs.push_back(
new OpMassPETSCAssemble(
"S",
"T", st_coeff));
302 pip_lhs.push_back(
new OpMassPETSCAssemble(
"T",
"S", st_coeff));
304 pip_lhs.push_back(
new OpMassPETSCAssemble(
"O",
"O", close_zero));
305 pip_lhs.push_back(
new OpMassPETSCAssemble(
"T",
"O", beta));
306 pip_lhs.push_back(
new OpMassPETSCAssemble(
"O",
"T", beta));
308 pip_lhs.push_back(
new OpMassPETSCAssemble(
"S",
"O", gamma));
309 pip_lhs.push_back(
new OpMassPETSCAssemble(
"O",
"S", beta));
313 pip_lhs.push_back(
new OpMassBlockAssemble(
"V",
"V"));
314 if (no_preconditioner_block)
315 pip_lhs.push_back(
new OpMassBlockAssemble(
"T",
"T"));
316 pip_lhs.push_back(
new OpMassBlockAssemble(
"V",
"T"));
317 pip_lhs.push_back(
new OpMassBlockAssemble(
"T",
"V"));
318 pip_lhs.push_back(
new OpMassBlockAssemble(
"S",
"S", ss_coeff));
319 pip_lhs.push_back(
new OpMassBlockAssemble(
"S",
"T", st_coeff));
320 pip_lhs.push_back(
new OpMassBlockAssemble(
"T",
"S", st_coeff));
322 pip_lhs.push_back(
new OpMassBlockAssemble(
"O",
"O", close_zero));
323 pip_lhs.push_back(
new OpMassBlockAssemble(
"T",
"O", beta));
324 pip_lhs.push_back(
new OpMassBlockAssemble(
"O",
"T", beta));
326 pip_lhs.push_back(
new OpMassBlockAssemble(
"S",
"O", gamma));
327 pip_lhs.push_back(
new OpMassBlockAssemble(
"O",
"S", beta));
329 if (!no_preconditioner_block)
330 pip_lhs.push_back(
new OpMassBlockPreconditionerAssemble(
"T",
"T"));
332 auto schur_is =
getDMSubData(schur_dm)->getSmartRowIs();
337 fields, {
nullptr,
nullptr,
nullptr}, ao_up, S,
false,
false)
344 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
345 MOFEM_LOG(
"Timeline", Sev::inform) <<
"Assemble start";
347 simple->getDomainFEName(),
348 pip_mng->getDomainLhsFE());
349 MOFEM_LOG(
"Timeline", Sev::inform) <<
"Assemble end";
354 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
355 MOFEM_LOG(
"Timeline", Sev::inform) <<
"Mat assemble start";
358 MOFEM_LOG(
"Timeline", Sev::inform) <<
"Mat assemble end";
361 auto get_random_vector = [&](
auto dm) {
364 PetscRandomCreate(PETSC_COMM_WORLD, &rctx);
366 PetscRandomDestroy(&rctx);
369 auto v = get_random_vector(
simple->getDM());
374 auto test = [](
auto msg,
auto y,
double norm0) {
382 CHKERR VecNorm(y, NORM_2, &norm);
386 << msg <<
": norm of difference: " << norm;
387 if (norm >
eps || std::isnan(norm) || std::isinf(norm)) {
388 SETERRQ(PETSC_COMM_WORLD, 1,
"norm of difference is too big");
393 std::vector<int> zero_rows_and_cols = {
397 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
400 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
407 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
409 <<
"MatMult(petsc_mat, v, y_petsc) star";
412 <<
"MatMult(petsc_mat, v, y_petsc) end";
415 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
420 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
422 <<
"MatMult(block_mat, v, y_block) star";
425 <<
"MatMult(block_mat, v, y_block) end";
427 CHKERR VecAXPY(y_petsc, -1.0, y_block);
428 CHKERR test(
"mult", y_petsc, nrm0);
439 CHKERR VecAXPY(y_petsc, -1.0, y_block);
440 CHKERR test(
"mult add", y_petsc, nrm0);
445 CHKERR VecAXPY(y_petsc, -1.0, y_block);
446 CHKERR test(
"mult transpose", y_petsc, nrm0);
453 CHKERR VecAXPY(y_petsc, -1.0, y_block);
454 CHKERR test(
"mult add transpose", y_petsc, nrm0);
457 if (!no_preconditioner_block)
461 CHKERR MatMult(nested_mat,
v, y_nested);
462 CHKERR VecAXPY(y_petsc, -1.0, y_nested);
463 CHKERR test(
"mult nested", y_petsc, nrm0);
465 if (!no_preconditioner_block)
467 auto diag_mat = std::get<0>(*nested_data_ptr)[3];
468 auto diag_block_x = get_random_vector(block_dm);
471 CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
475 CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
477 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
478 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
479 CHKERR test(
"diag solve", diag_block_f_test, nrm0);
481 CHKERR MatSolveTranspose(diag_mat, diag_block_f, block_solved_x);
482 CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
483 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
484 CHKERR test(
"diag transpose solve", diag_block_f_test, nrm0);
487 CHKERR DMSetMatType(block_dm, MATSHELL);
490 CHKERR DMKSPSetComputeOperators(
492 [](KSP, Mat, Mat,
void *) {
493 MOFEM_LOG(
"WORLD", Sev::inform) <<
"empty operator";
503 auto get_pc = [](
auto ksp) {
511 CHKERR VecZeroEntries(block_solved_x);
512 CHKERR KSPSolve(
ksp, diag_block_f, block_solved_x);
514 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
515 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
516 CHKERR test(
"diag solve", diag_block_f_test, nrm0);
519 CHKERR VecZeroEntries(block_solved_x);
520 CHKERR KSPSolveTranspose(
ksp, diag_block_f, block_solved_x);
521 CHKERR MatMultTranspose(diag_mat, block_solved_x, diag_block_f_test);
522 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
523 CHKERR test(
"diag transpose solve", diag_block_f_test, nrm0);
529 CHKERR VecAXPY(y_petsc, -1.0, y_block);
530 CHKERR test(
"mult after solve", y_petsc, nrm0);
533 CHKERR VecAXPY(y_petsc, -1.0, y_block);
534 CHKERR test(
"mult transpose after solve", y_petsc, nrm0);
535 if (no_preconditioner_block) {
537 CHKERR MatMult(nested_mat,
v, y_nested);
538 CHKERR VecAXPY(y_petsc, -1.0, y_nested);
539 CHKERR test(
"mult nested after solve", y_petsc, nrm0);
544 auto test_schur = [&](
auto msg, std::vector<boost::shared_ptr<Range>> ents,
549 CHKERR MatAssemblyBegin(s, MAT_FINAL_ASSEMBLY);
550 CHKERR MatAssemblyEnd(s, MAT_FINAL_ASSEMBLY);
552 CHKERR MatNorm(s_ref, NORM_FROBENIUS, &nrm_ref);
553 CHKERR MatAXPY(s, -1.0, s_ref, DIFFERENT_NONZERO_PATTERN);
555 CHKERR MatNorm(s, NORM_FROBENIUS, &nrm);
562 << msg <<
": norm of difference: " << nrm;
563 if (nrm >
eps || std::isnan(nrm) || std::isinf(nrm))
564 SETERRQ(PETSC_COMM_WORLD, 1,
"norm of difference is too big");
570 auto reassemble = [&]() {
572 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
573 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
577 for (
int i = 0;
i != 2; ++
i)
579 simple->getDomainFEName(),
580 pip_mng->getDomainLhsFE());
583 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
584 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
589 std::vector<boost::shared_ptr<Range>> all_ents = {
nullptr,
nullptr,
593 if (!no_preconditioner_block)
595 CHKERR test_schur(
"schur from block", all_ents, S);
598 Range vols, part_vols;
599 CHKERR moab.get_entities_by_dimension(0, 3, vols,
true);
602 if (nb_vols++ % 2 == 0)
604 auto part_ptr = boost::make_shared<Range>(part_vols);
605 std::vector<boost::shared_ptr<Range>> part_ents = {part_ptr, part_ptr,
612 PetscPushErrorHandler(PetscIgnoreErrorHandler, PETSC_NULLPTR);
615 PetscPopErrorHandler();
617 SETERRQ(PETSC_COMM_WORLD, 1,
618 "Schur assembly with different elimination set should fail "
619 "on factorised matrix");
621 <<
"schur assembly with inconsistent elimination set rejected";
623 if (!no_preconditioner_block)
627 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
629 CHKERR VecAXPY(y_petsc, -1.0, y_block);
630 CHKERR test(
"mult after reassembly", y_petsc, nrm0);
632 CHKERR MatMult(diag_mat, diag_block_x, diag_block_f);
633 CHKERR MatSolve(diag_mat, diag_block_f, block_solved_x);
634 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
635 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
636 CHKERR test(
"diag solve after reassembly", diag_block_f_test, nrm0);
640 CHKERR VecAXPY(y_petsc, -1.0, y_block);
641 CHKERR test(
"mult after reassembly and solve", y_petsc, nrm0);
644 CHKERR VecAXPY(y_petsc, -1.0, y_block);
645 CHKERR test(
"mult transpose after reassembly and solve", y_petsc, nrm0);
647 CHKERR VecZeroEntries(block_solved_x);
648 CHKERR KSPSolve(
ksp, diag_block_f, block_solved_x);
649 CHKERR MatMult(diag_mat, block_solved_x, diag_block_f_test);
650 CHKERR VecAXPY(diag_block_f_test, -1.0, diag_block_f);
651 CHKERR test(
"ksp solve after reassembly", diag_block_f_test, nrm0);
655 if (no_preconditioner_block) {
663 CHKERR test_schur(
"schur from block, part of A00 eliminated", part_ents,
666 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
668 CHKERR VecAXPY(y_petsc, -1.0, y_block);
669 CHKERR test(
"mult after partial schur assembly", y_petsc, nrm0);
672 if (m_field.get_comm_rank() == 0) {