85 {
86
87
89
90 try {
91
92
93 moab::Core moab_core;
94 moab::Interface &moab = moab_core;
95
96
99
100
101 DMType dm_name = "DMMOFEM";
103
104
105 auto core_log = logging::core::get();
106 core_log->add_sink(
110
111
113
114
116
118
123
124
127 PETSC_NULLPTR);
128
129
130 PetscBool no_preconditioner_block = PETSC_FALSE;
132 &no_preconditioner_block, PETSC_NULLPTR);
133
134
135
136 PetscBool uncoupled_so = PETSC_FALSE;
138 &uncoupled_so, PETSC_NULLPTR);
139 PetscBool empty_oo = PETSC_FALSE;
141 PETSC_NULLPTR);
142
143
144
145
146
147
148
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;
161
162
164
165
166
169 "T", 0, 1);
170
178
190
193
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"}};
197 if (!uncoupled_so) {
198 block_pairs.push_back({"S", "O"});
199 block_pairs.push_back({"O", "S"});
200 }
201
205 {{simple->getDomainFEName(), block_pairs}}));
206
207 auto [mat, block_data_ptr] = shell_data;
209
210 std::vector<std::string> fields{"T", "S", "O"};
211
213
215
216 {schur_dm, block_dm}, block_data_ptr,
217
218 fields, {nullptr, nullptr, nullptr},
219 no_preconditioner_block ? false : true
220
221 )
222
223 );
224
229 using OpMassBlockPreconditionerAssemble =
231 BiLinearForm<GAUSS>::OpMass<1,
FIELD_DIM>;
232
233
235
236
240
241 std::array<double, 12> bad_tet;
242 if (overflow_pivot_element) {
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());
249 if (owned.empty())
251 const EntityHandle *conn;
252 int num_nodes;
253 CHKERR moab.get_connectivity(owned.back(), conn, num_nodes,
true);
254 CHKERR moab.get_coords(conn, 4, bad_tet.data());
255 }
256
257 auto in_bad = [&](double x, double y, double z) {
258 if (!overflow_pivot)
259 return false;
260 if (!overflow_pivot_element)
261 return true;
264 z - bad_tet[2]};
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];
269 double det;
272 double sum = 0;
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);
278 return false;
280 }
281 return sum < 1 + 1e-10;
282 };
283 auto ss_coeff = [&](double x, double y, double z) {
284 return in_bad(x, y, z) ? 1e-300 : 1.;
285 };
286 auto st_coeff = [&](double x, double y, double z) {
287 return in_bad(x, y, z) ? -1e10 / 2 : -1. / 2;
288 };
289
290 pip_mng->setDomainLhsIntegrationRule([](int, int, int o) { return 2 * o; });
291 auto &pip_lhs = pip_mng->getOpDomainLhsPipeline();
292
293 pip_lhs.push_back(new OpMassPETSCAssemble("V", "V"));
294
295
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));
303 if (!empty_oo)
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));
307 if (!uncoupled_so) {
308 pip_lhs.push_back(new OpMassPETSCAssemble("S", "O", gamma));
309 pip_lhs.push_back(new OpMassPETSCAssemble("O", "S", beta));
310 }
311
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));
321 if (!empty_oo)
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));
325 if (!uncoupled_so) {
326 pip_lhs.push_back(new OpMassBlockAssemble("S", "O", gamma));
327 pip_lhs.push_back(new OpMassBlockAssemble("O", "S", beta));
328 }
329 if (!no_preconditioner_block)
330 pip_lhs.push_back(new OpMassBlockPreconditionerAssemble("T", "T"));
331
332 auto schur_is =
getDMSubData(schur_dm)->getSmartRowIs();
334
336
337 fields, {nullptr, nullptr, nullptr}, ao_up, S, false, false)
338
339 );
340
341 {
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";
350 }
351 {
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";
359 }
360
361 auto get_random_vector = [&](auto dm) {
363 PetscRandom rctx;
364 PetscRandomCreate(PETSC_COMM_WORLD, &rctx);
366 PetscRandomDestroy(&rctx);
368 };
369 auto v = get_random_vector(
simple->getDM());
370
373
374 auto test = [](auto msg, auto y, double norm0) {
376
379 PETSC_NULLPTR);
380
381 PetscReal norm;
382 CHKERR VecNorm(y, NORM_2, &norm);
383 norm = norm / norm0;
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");
389 }
391 };
392
393 std::vector<int> zero_rows_and_cols = {
394 0, 1, 10, 20,
395 500};
397 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
398 PETSC_NULLPTR);
400 &*zero_rows_and_cols.begin(), 1, PETSC_NULLPTR,
401 PETSC_NULLPTR);
402
403
404 {
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";
413 }
414 double nrm0;
415 CHKERR VecNorm(y_petsc, NORM_2, &nrm0);
416
417 {
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";
426 }
427 CHKERR VecAXPY(y_petsc, -1.0, y_block);
428 CHKERR test(
"mult", y_petsc, nrm0);
429
430
431
434
439 CHKERR VecAXPY(y_petsc, -1.0, y_block);
440 CHKERR test(
"mult add", y_petsc, nrm0);
441
442
445 CHKERR VecAXPY(y_petsc, -1.0, y_block);
446 CHKERR test(
"mult transpose", y_petsc, nrm0);
447
448
453 CHKERR VecAXPY(y_petsc, -1.0, y_block);
454 CHKERR test(
"mult add transpose", y_petsc, nrm0);
455
456
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);
464
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);
472
473
474
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);
480
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);
485
486
487 CHKERR DMSetMatType(block_dm, MATSHELL);
489
490 CHKERR DMKSPSetComputeOperators(
491 block_dm,
492 [](KSP, Mat, Mat, void *) {
493 MOFEM_LOG(
"WORLD", Sev::inform) <<
"empty operator";
494 return 0;
495 },
496 nullptr);
497
501
502
503 auto get_pc = [](
auto ksp) {
504 PC pc_raw;
507 };
510
511 CHKERR VecZeroEntries(block_solved_x);
512 CHKERR KSPSolve(
ksp, diag_block_f, block_solved_x);
513
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);
517
518
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);
524
525
526
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);
540 }
541
542
543
544 auto test_schur = [&](auto msg, std::vector<boost::shared_ptr<Range>> ents,
545 Mat s_ref) {
549 CHKERR MatAssemblyBegin(s, MAT_FINAL_ASSEMBLY);
550 CHKERR MatAssemblyEnd(s, MAT_FINAL_ASSEMBLY);
551 double nrm_ref;
552 CHKERR MatNorm(s_ref, NORM_FROBENIUS, &nrm_ref);
553 CHKERR MatAXPY(s, -1.0, s_ref, DIFFERENT_NONZERO_PATTERN);
554 double nrm;
555 CHKERR MatNorm(s, NORM_FROBENIUS, &nrm);
556 nrm /= nrm_ref;
559 PETSC_NULLPTR);
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");
566 };
567
568
569
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);
586 };
587
589 std::vector<boost::shared_ptr<Range>> all_ents = {nullptr, nullptr,
590 nullptr};
591
592
593 if (!no_preconditioner_block)
595 CHKERR test_schur(
"schur from block", all_ents, S);
596
597
598 Range vols, part_vols;
599 CHKERR moab.get_entities_by_dimension(0, 3, vols,
true);
600 int nb_vols = 0;
601 for (auto e : vols)
602 if (nb_vols++ % 2 == 0)
603 part_vols.insert(e);
604 auto part_ptr = boost::make_shared<Range>(part_vols);
605 std::vector<boost::shared_ptr<Range>> part_ents = {part_ptr, part_ptr,
606 part_ptr};
607
608 {
609
610
611
612 PetscPushErrorHandler(PetscIgnoreErrorHandler, PETSC_NULLPTR);
614 part_ents, ao_up);
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";
622 }
623 if (!no_preconditioner_block)
625
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);
631
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);
637
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);
646
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);
652
653
654
655 if (no_preconditioner_block) {
656
657
658
659 pip_lhs.pop_back();
660 pip_lhs.push_back(
663 CHKERR test_schur(
"schur from block, part of A00 eliminated", part_ents,
664 S);
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);
670 }
671
674 }
675
678 }
680
681
683
684 return 0;
685}
#define MOFEM_TAG_AND_LOG(channel, severity, tag)
Tag and log in channel.
void simple(double P1[], double P2[], double P3[], double c[], const int N)
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
@ L2
field with C-1 continuity
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_ATOM_TEST_INVALID
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
auto createDMMatrix(DM dm)
Get smart matrix from DM.
virtual const Problem * get_problem(const std::string problem_name) const =0
Get the problem object.
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
MoFEMErrorCode removeBlockDOFsOnEntities(const std::string problem_name, const std::string block_name, const std::string field_name, int lo, int hi, bool get_low_dim_ents=true, bool is_distributed_mesh=true)
Remove DOFs from problem based on block entities.
FTensor::Index< 'i', SPACE_DIM > i
const double v
phase velocity of light in medium (cm/ns)
FTensor::Index< 'l', 3 > l
FTensor::Index< 'j', 3 > j
static MoFEMErrorCodeGeneric< PetscErrorCode > ierr
auto createKSP(MPI_Comm comm)
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.
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode schurSwitchPreconditioner(boost::shared_ptr< BlockStructure > block_mat_data)
Switch preconditioner.
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
std::pair< SmartPetscObj< Mat >, boost::shared_ptr< NestSchurData > > createSchurNestedMatrix(boost::shared_ptr< NestSchurData > schur_net_data_ptr)
Create a Mat Diag Blocks object.
PetscErrorCode PetscOptionsGetBool(PetscOptions *, const char pre[], const char name[], PetscBool *bval, PetscBool *set)
PetscErrorCode PetscOptionsGetScalar(PetscOptions *, const char pre[], const char name[], PetscScalar *dval, PetscBool *set)
MoFEMErrorCode invertTensor3by3(ublas::matrix< T, L, A > &jac_data, ublas::vector< T, A > &det_data, ublas::matrix< T, L, A > &inv_jac_data)
Calculate inverse of tensor rank 2 at integration points.
auto getDMSubData(DM dm)
Get sub problem data structure.
MoFEMErrorCode DMMoFEMSetBlocMatData(DM dm, boost::shared_ptr< BlockStructure >)
Set data for block mat.
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].
auto createAOMappingIS(IS isapp, IS ispetsc)
Creates an application mapping using two index sets.
MoFEMErrorCode schurSaveBlockMesh(boost::shared_ptr< BlockStructure > block_mat_data, std::string filename)
Save block matrix as a mesh.
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
static auto determinantTensor3by3(T &t)
Calculate the determinant of a 3x3 matrix or a tensor of rank 2.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
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()
SmartPetscObj< Mat > block_mat
SmartPetscObj< Mat > petsc_mat
Boundary condition manager for finite element problem setup.
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Deprecated interface functions.
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
PipelineManager interface.
Simple interface for fast problem set-up.
MoFEMErrorCode getOptions()
get options
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.