v0.16.0
Loading...
Searching...
No Matches
test_broken_space.cpp
Go to the documentation of this file.
1/**
2 * \example mofem/atom_tests/test_broken_space.cpp
3 *
4 * Testing broken spaces. Implementations works for 2d and 3d meshes, is aiming
5 * to test H-div broken base functions, and L2 base on skeleton.
6 *
7 * Also, it test block matrix with Schur complement.
8 *
9 */
10
11#include <MoFEM.hpp>
13
14using namespace MoFEM;
15
16static char help[] = "...\n\n";
17
18constexpr bool debug = false;
19
20constexpr AssemblyType BlockAssemblyType = (BLOCK_ASSEMBLE_SELECTION)
21 ? AssemblyType::BLOCK_MAT
23
24constexpr AssemblyType AT =
26 : AssemblyType::PETSC; //< selected assembly type
27
29 IntegrationType::GAUSS; //< selected integration type
30
31constexpr int SPACE_DIM =
32 EXECUTABLE_DIMENSION; //< Space dimension of problem, mesh
33
38
40using DomainEleOp = DomainEle::UserDataOperator;
41using BdyEleOp = BoundaryEle::UserDataOperator;
42using SideEleOp = EleOnSide::UserDataOperator;
43
44struct SetUpSchur {
45 static boost::shared_ptr<SetUpSchur>
48
49protected:
50 SetUpSchur() = default;
51 virtual ~SetUpSchur() = default;
52};
53
56
57int main(int argc, char *argv[]) {
58
59 MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
60
61 try {
62
63 //! [Register MoFEM discrete manager in PETSc]
64 DMType dm_name = "DMMOFEM";
65 CHKERR DMRegister_MoFEM(dm_name);
66 DMType dm_name_mg = "DMMOFEM_MG";
68 //! [Register MoFEM discrete manager in PETSc
69
70 moab::Core mb_instance;
71 moab::Interface &moab = mb_instance;
72
73 // Add logging channel for example
74 auto core_log = logging::core::get();
75 core_log->add_sink(
77 core_log->add_sink(
80 LogManager::setLog("TIMER");
81 MOFEM_LOG_TAG("AT", "atom_test");
82 MOFEM_LOG_TAG("TIMER", "timer");
83
84 // Create MoFEM instance
85 MoFEM::Core core(moab);
86 MoFEM::Interface &m_field = core;
87
88 auto *simple = m_field.getInterface<Simple>();
90 simple->getAddBoundaryFE() = true;
91 CHKERR simple->loadFile();
92
93 auto add_shared_entities_on_skeleton = [&]() {
95 auto boundary_meshset = simple->getBoundaryMeshSet();
96 auto skeleton_meshset = simple->getSkeletonMeshSet();
97 Range bdy_ents;
98 CHKERR m_field.get_moab().get_entities_by_handle(boundary_meshset,
99 bdy_ents, true);
100 Range skeleton_ents;
101 CHKERR m_field.get_moab().get_entities_by_dimension(
102 0, simple->getDim() - 1, skeleton_ents, true);
103 skeleton_ents = subtract(skeleton_ents, bdy_ents);
104 CHKERR m_field.get_moab().clear_meshset(&skeleton_meshset, 1);
105 CHKERR m_field.get_moab().add_entities(skeleton_meshset, skeleton_ents);
107 };
108
109 CHKERR add_shared_entities_on_skeleton();
110
111 // Declare elements
112 enum bases {
113 AINSWORTH,
114 AINSWORTH_LOBATTO,
115 DEMKOWICZ,
116 BERNSTEIN,
117 LASBASETOP
118 };
119 const char *list_bases[] = {"ainsworth", "ainsworth_lobatto", "demkowicz",
120 "bernstein"};
121 PetscBool flg;
122 PetscInt choice_base_value = AINSWORTH;
123 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-base", list_bases,
124 LASBASETOP, &choice_base_value, &flg);
125
126 if (flg != PETSC_TRUE)
127 SETERRQ(PETSC_COMM_SELF, MOFEM_IMPOSSIBLE_CASE, "base not set");
129 if (choice_base_value == AINSWORTH)
131 if (choice_base_value == AINSWORTH_LOBATTO)
133 else if (choice_base_value == DEMKOWICZ)
135 else if (choice_base_value == BERNSTEIN)
137
138 enum spaces { hdiv, hcurl, last_space };
139 const char *list_spaces[] = {"hdiv", "hcurl"};
140 PetscInt choice_space_value = hdiv;
141 CHKERR PetscOptionsGetEList(PETSC_NULLPTR, NULL, "-space", list_spaces,
142 last_space, &choice_space_value, &flg);
143 if (flg != PETSC_TRUE)
144 SETERRQ(PETSC_COMM_SELF, MOFEM_IMPOSSIBLE_CASE, "space not set");
145 FieldSpace space = HDIV;
146 if (choice_space_value == hdiv)
147 space = HDIV;
148 else if (choice_space_value == hcurl)
149 space = HCURL;
150
151 CHKERR PetscOptionsGetInt(PETSC_NULLPTR, "", "-order", &approx_order,
152 PETSC_NULLPTR);
153
154 CHKERR simple->addDomainBrokenField("BROKEN", space, base, 1);
155 CHKERR simple->addDomainField("U", L2, base, 1);
156 CHKERR simple->addSkeletonField("HYBRID", L2, base, 1);
157
158 const auto u_order = approx_order - 1;
160 (space == HDIV &&
164 : u_order;
165
166 CHKERR simple->setFieldOrder("BROKEN", approx_order);
167 CHKERR simple->setFieldOrder("U", u_order);
168 CHKERR simple->setFieldOrder("HYBRID", hybrid_approx_order);
169
170 CHKERR simple->setUp();
171
172 auto bc_mng = m_field.getInterface<BcManager>();
173 CHKERR bc_mng->removeSideDOFs(simple->getProblemName(), "ZERO_FLUX",
174 "BROKEN", SPACE_DIM, 0, 1, true);
175
176 auto integration_rule = [](int, int, int p) { return 2 * p; };
177
178 auto assemble_domain_lhs = [&](auto &pip) {
181
185 IT>::OpMixDivTimesScalar<SPACE_DIM>;
186
187 auto beta = [](const double, const double, const double) constexpr {
188 return 1;
189 };
190
191 pip.push_back(new OpHdivHdiv("BROKEN", "BROKEN", beta));
192 auto unity = []() constexpr { return 1; };
193 pip.push_back(new OpHdivU("BROKEN", "U", unity, true));
194
195 // First: Iterate over skeleton FEs adjacent to Domain FEs
196 // Note: BoundaryEle, i.e. uses skeleton interation rule
197 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
198 m_field, simple->getSkeletonFEName(), SPACE_DIM - 1, Sev::noisy);
199 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = integration_rule;
201 op_loop_skeleton_side->getOpPtrVector(), {});
202
203 // Second: Iterate over domain FEs adjacent to skelton, particularly one
204 // domain element.
205 auto broken_data_ptr =
206 boost::make_shared<std::vector<BrokenBaseSideData>>();
207 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
208 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
209 m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy);
211 op_loop_domain_side->getOpPtrVector(), {HDIV});
212 op_loop_domain_side->getOpPtrVector().push_back(
213 new OpGetBrokenBaseSideData<SideEleOp>("BROKEN", broken_data_ptr));
214
215 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
217 IT>::OpBrokenSpaceConstrain<1>;
218 op_loop_skeleton_side->getOpPtrVector().push_back(
219 new OpC("HYBRID", broken_data_ptr, 1., true, false));
220
221 if (debug) {
222 // print skeleton elements on partition
223 constexpr int partition = 1;
224 auto op_print = new BdyEleOp(NOSPACE, BdyEleOp::OPSPACE);
225 op_print->doWorkRhsHook = [&](DataOperator *base_op_ptr, int side,
226 EntityType type,
229 if (auto op_ptr = dynamic_cast<BdyEleOp *>(base_op_ptr)) {
230 auto fe_method = op_ptr->getFEMethod();
231 auto num_fe = fe_method->numeredEntFiniteElementPtr;
232
233 if (m_field.get_comm_rank() == partition) {
234 if (num_fe->getPStatus() & PSTATUS_SHARED)
235 MOFEM_LOG("SELF", Sev::inform) << "Num FE: " << *num_fe;
236 }
237 }
239 };
240 op_loop_skeleton_side->getOpPtrVector().push_back(op_print);
241 };
242
243 pip.push_back(op_loop_skeleton_side);
244
246 };
247
248 auto assemble_domain_rhs = [&](auto &pip) {
253 auto source = [&](const double x, const double y,
254 const double z) constexpr {
255 return -1; // sin(100 * (x / 10.) * M_PI_2);
256 };
257 pip.push_back(new OpDomainSource("U", source));
259 };
260
261 auto *pip_mng = m_field.getInterface<PipelineManager>();
262
263 CHKERR assemble_domain_lhs(pip_mng->getOpDomainLhsPipeline());
264 CHKERR assemble_domain_rhs(pip_mng->getOpDomainRhsPipeline());
265
266 CHKERR pip_mng->setDomainLhsIntegrationRule(integration_rule);
267 CHKERR pip_mng->setDomainRhsIntegrationRule(integration_rule);
268 CHKERR pip_mng->setSkeletonLhsIntegrationRule(integration_rule);
269 CHKERR pip_mng->setSkeletonRhsIntegrationRule(integration_rule);
270
271 TetPolynomialBase::switchCacheBaseOn<HDIV>(
272 {pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
273 TetPolynomialBase::switchCacheBaseOn<L2>(
274 {pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
275
276 if (m_field.get_comm_rank() == 0)
278 "pipeline_manager_graph.dot", pip_mng);
279
280 auto x = createDMVector(simple->getDM());
281 auto f = vectorDuplicate(x);
282
283 if (AT == PETSC) {
284 auto ksp = pip_mng->createKSP();
285
286 CHKERR KSPSetFromOptions(ksp);
287 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
288 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
289 CHKERR KSPSetUp(ksp);
290 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
291
292 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
293 CHKERR KSPSolve(ksp, f, x);
294 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
295
296 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
297 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
298 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), x, INSERT_VALUES,
299 SCATTER_REVERSE);
300
301 if (m_field.get_comm_rank() == 0) {
302 DM dm;
303 CHKERR KSPGetDM(ksp, &dm);
305 getDMKspCtx(dm).get(), "ksp_manager_graph.dot");
306 }
307
308 } else {
309 auto ksp = pip_mng->createKSP();
310 auto schur_ptr = SetUpSchur::createSetUpSchur(m_field);
311 BOOST_LOG_SCOPED_THREAD_ATTR("Timeline", attrs::timer());
312 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp";
313 CHKERR schur_ptr->setUp(ksp);
314 MOFEM_LOG("TIMER", Sev::inform) << "KSPSetUp <= Done";
315
316 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve";
317 CHKERR KSPSolve(ksp, f, x);
318 MOFEM_LOG("TIMER", Sev::inform) << "KSPSolve <= Done";
319
320 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
321 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
322 CHKERR DMoFEMMeshToLocalVector(simple->getDM(), x, INSERT_VALUES,
323 SCATTER_REVERSE);
324
325 if (m_field.get_comm_rank() == 0) {
326 DM dm;
327 CHKERR KSPGetDM(ksp, &dm);
329 getDMKspCtx(dm).get(), "ksp_manager_graph.dot");
330 }
331
332 }
333
334 auto check_residual = [&](auto x, auto f) {
336 auto *simple = m_field.getInterface<Simple>();
337 auto *pip_mng = m_field.getInterface<PipelineManager>();
338
339 // auto &skeleton_rhs = pip_mng->getOpSkeletonRhsPipeline();
340 auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
341 // skeleton_rhs.clear();
342 domain_rhs.clear();
343
345
346 auto div_flux_ptr = boost::make_shared<VectorDouble>();
347 domain_rhs.push_back(new OpCalculateHdivVectorDivergence<3, SPACE_DIM>(
348 "BROKEN", div_flux_ptr));
351 auto beta = [](double, double, double) constexpr { return 1; };
352 domain_rhs.push_back(new OpUDivFlux("U", div_flux_ptr, beta));
353 auto source = [&](const double x, const double y,
354 const double z) constexpr { return 1; };
357 domain_rhs.push_back(new OpDomainSource("U", source));
358
360 IT>::OpMixDivTimesU<3, 1, SPACE_DIM>;
363 auto flux_ptr = boost::make_shared<MatrixDouble>();
364 domain_rhs.push_back(
365 new OpCalculateHVecVectorField<3>("BROKEN", flux_ptr));
366 boost::shared_ptr<VectorDouble> u_ptr =
367 boost::make_shared<VectorDouble>();
368 domain_rhs.push_back(new OpCalculateScalarFieldValues("U", u_ptr));
369 domain_rhs.push_back(new OpHDivH("BROKEN", u_ptr, beta));
370 domain_rhs.push_back(new OpHdivFlux("BROKEN", flux_ptr, beta));
371
372 // First: Iterate over skeleton FEs adjacent to Domain FEs
373 // Note: BoundaryEle, i.e. uses skeleton interation rule
374 auto op_loop_skeleton_side = new OpLoopSide<BoundaryEle>(
375 m_field, simple->getSkeletonFEName(), SPACE_DIM - 1, Sev::noisy);
376 op_loop_skeleton_side->getSideFEPtr()->getRuleHook = integration_rule;
378 op_loop_skeleton_side->getOpPtrVector(), {});
379
380 // Second: Iterate over domain FEs adjacent to skelton, particularly one
381 // domain element.
382 auto broken_data_ptr =
383 boost::make_shared<std::vector<BrokenBaseSideData>>();
384 // Note: EleOnSide, i.e. uses on domain projected skeleton rule
385 auto op_loop_domain_side = new OpBrokenLoopSide<EleOnSide>(
386 m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy);
388 op_loop_domain_side->getOpPtrVector(), {HDIV});
389 op_loop_domain_side->getOpPtrVector().push_back(
390 new OpGetBrokenBaseSideData<SideEleOp>("BROKEN", broken_data_ptr));
391 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
392 op_loop_domain_side->getOpPtrVector().push_back(
393 new OpCalculateHVecTensorField<1, 3>("BROKEN", flux_mat_ptr));
394 op_loop_domain_side->getOpPtrVector().push_back(
395 new OpSetFlux<SideEleOp>(broken_data_ptr, flux_mat_ptr));
396
397 // Assemble on skeleton
398 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
400 IT>::OpBrokenSpaceConstrainDHybrid<1>;
402 IT>::OpBrokenSpaceConstrainDFlux<1>;
403 op_loop_skeleton_side->getOpPtrVector().push_back(
404 new OpC_dHybrid("HYBRID", broken_data_ptr, 1.));
405 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
406 op_loop_skeleton_side->getOpPtrVector().push_back(
407 new OpCalculateVectorFieldValues<1>("HYBRID", hybrid_ptr));
408 op_loop_skeleton_side->getOpPtrVector().push_back(
409 new OpC_dBroken(broken_data_ptr, hybrid_ptr, 1.));
410
411 // Add skeleton to domain pipeline
412 domain_rhs.push_back(op_loop_skeleton_side);
413
414 CHKERR VecZeroEntries(f);
415 CHKERR VecGhostUpdateBegin(f, INSERT_VALUES, SCATTER_FORWARD);
416 CHKERR VecGhostUpdateEnd(f, INSERT_VALUES, SCATTER_FORWARD);
417
418 pip_mng->getDomainRhsFE()->f = f;
419 pip_mng->getSkeletonRhsFE()->f = f;
420 pip_mng->getDomainRhsFE()->x = x;
421 pip_mng->getSkeletonRhsFE()->x = x;
422
424 simple->getDomainFEName(),
425 pip_mng->getDomainRhsFE());
426
427 CHKERR VecGhostUpdateBegin(f, ADD_VALUES, SCATTER_REVERSE);
428 CHKERR VecGhostUpdateEnd(f, ADD_VALUES, SCATTER_REVERSE);
429 CHKERR VecAssemblyBegin(f);
430 CHKERR VecAssemblyEnd(f);
431
432 double fnrm;
433 CHKERR VecNorm(f, NORM_2, &fnrm);
434 MOFEM_LOG_C("AT", Sev::inform, "Residual %3.4e", fnrm);
435
436 constexpr double eps = 1e-8;
437 if (fnrm > eps)
438 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
439 "Residual norm larger than accepted");
440
442 "domain_rhs_graph.dot", "OpDomainRhsPipeline",
443 pip_mng->getOpDomainRhsPipeline());
444
446 };
447
448 auto calculate_error = [&]() {
450
451 // auto &skeleton_rhs = pip_mng->getOpSkeletonRhsPipeline();
452 auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
453 // skeleton_rhs.clear();
454 domain_rhs.clear();
455
457
458 auto u_grad_ptr = boost::make_shared<MatrixDouble>();
459 auto flux_val_ptr = boost::make_shared<MatrixDouble>();
460 auto div_val_ptr = boost::make_shared<VectorDouble>();
461 auto source_ptr = boost::make_shared<VectorDouble>();
462
463 domain_rhs.push_back(
464 new OpCalculateScalarFieldGradient<SPACE_DIM>("U", u_grad_ptr));
465 domain_rhs.push_back(
466 new OpCalculateHVecVectorField<3, SPACE_DIM>("BROKEN", flux_val_ptr));
467 domain_rhs.push_back(new OpCalculateHdivVectorDivergence<3, SPACE_DIM>(
468 "BROKEN", div_val_ptr));
469 auto source = [&](const double x, const double y,
470 const double z) constexpr { return -1; };
471 domain_rhs.push_back(new OpGetTensor0fromFunc(source_ptr, source));
472
473 enum { DIV, GRAD, LAST };
474 auto mpi_vec = createVectorMPI(
475 m_field.get_comm(), (!m_field.get_comm_rank()) ? LAST : 0, LAST);
476 domain_rhs.push_back(
477 new OpCalcNormL2Tensor0(div_val_ptr, mpi_vec, DIV, source_ptr));
478 domain_rhs.push_back(new OpCalcNormL2Tensor1<SPACE_DIM>(
479 u_grad_ptr, mpi_vec, GRAD, flux_val_ptr));
480
482 simple->getDomainFEName(),
483 pip_mng->getDomainRhsFE());
484 CHKERR VecAssemblyBegin(mpi_vec);
485 CHKERR VecAssemblyEnd(mpi_vec);
486
487 if (!m_field.get_comm_rank()) {
488 const double *error_ind;
489 CHKERR VecGetArrayRead(mpi_vec, &error_ind);
490 MOFEM_LOG("AT", Sev::inform)
491 << "Approximation error ||div flux - source||: "
492 << std::sqrt(error_ind[DIV]);
493 MOFEM_LOG("AT", Sev::inform) << "Approximation error ||grad-flux||: "
494 << std::sqrt(error_ind[GRAD]);
495 CHKERR VecRestoreArrayRead(mpi_vec, &error_ind);
496 }
497
499 };
500
501 auto get_post_proc_fe = [&]() {
504 auto post_proc_fe = boost::make_shared<PostProcEle>(m_field);
505
506 auto op_loop_side = new OpLoopSide<EleOnSide>(
507 m_field, simple->getDomainFEName(), SPACE_DIM, Sev::noisy,
508 boost::make_shared<
510 post_proc_fe->getOpPtrVector().push_back(op_loop_side);
511
513 op_loop_side->getOpPtrVector(), {HDIV});
514 auto u_vec_ptr = boost::make_shared<VectorDouble>();
515 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
516 op_loop_side->getOpPtrVector().push_back(
517 new OpCalculateScalarFieldValues("U", u_vec_ptr));
518 op_loop_side->getOpPtrVector().push_back(
519 new OpCalculateHVecVectorField<3>("BROKEN", flux_mat_ptr));
520 op_loop_side->getOpPtrVector().push_back(
521
522 new OpPPMap(
523
524 post_proc_fe->getPostProcMesh(),
525
526 post_proc_fe->getMapGaussPts(),
527
528 {{"U", u_vec_ptr}},
529
530 {{"BROKEN", flux_mat_ptr}},
531
532 {}, {})
533
534 );
535
536 return post_proc_fe;
537 };
538
539 auto post_proc_fe = get_post_proc_fe();
541 simple->getBoundaryFEName(), post_proc_fe);
542 CHKERR post_proc_fe->writeFile("out_result.h5m");
543
544 CHKERR calculate_error();
545 CHKERR check_residual(x, f);
546 }
548
550}
551
552struct SetUpSchurImpl : public SetUpSchur {
553
555
556 virtual ~SetUpSchurImpl() = default;
557
559
560private:
563 };
564
568 auto pip_mng = mField.getInterface<PipelineManager>();
569
570 CHKERR KSPSetFromOptions(ksp);
571 PC pc;
572 CHKERR KSPGetPC(ksp, &pc);
573
574 PetscBool is_pcfs = PETSC_FALSE;
575 PetscObjectTypeCompare((PetscObject)pc, PCFIELDSPLIT, &is_pcfs);
576 if (is_pcfs) {
577
578 MOFEM_LOG("AT", Sev::inform) << "Setup Schur pc";
579
580 auto create_sub_dm = [&]() {
582
583 auto create_dm = [&](
584
585 std::string problem_name,
586 std::vector<std::string> fe_names,
587 std::vector<std::string> fields,
588
589 auto dm_type
590
591 ) {
592 auto dm = createDM(mField.get_comm(), dm_type);
593 auto create_dm_imp = [&]() {
595 CHKERR DMMoFEMCreateSubDM(dm, simple->getDM(), problem_name.c_str());
596 CHKERR DMMoFEMSetSquareProblem(dm, PETSC_TRUE);
597 for (auto fe : fe_names) {
599 }
600 CHKERR DMMoFEMAddElement(dm, simple->getSkeletonFEName());
601 for (auto field : fields) {
602 CHKERR DMMoFEMAddSubFieldRow(dm, field);
603 CHKERR DMMoFEMAddSubFieldCol(dm, field);
604 }
605 CHKERR DMSetUp(dm);
607 };
609 create_dm_imp(),
610 "Error in creating schurDM. It is possible that schurDM is "
611 "already created");
612 return dm;
613 };
614
615 auto schur_dm = create_dm(
616
617 "SCHUR",
618
619 {simple->getDomainFEName(), simple->getSkeletonFEName()},
620
621 {"HYBRID"},
622
623 "DMMOFEM_MG");
624
625 auto block_dm = create_dm(
626
627 "BLOCK",
628
629 {simple->getDomainFEName(), simple->getSkeletonFEName()},
630
631 {"BROKEN", "U"},
632
633 "DMMOFEM");
634
635 return std::make_tuple(schur_dm, block_dm);
636 };
637
638 auto get_nested_mat_data = [&](auto schur_dm, auto block_dm) {
639 auto block_mat_data = createBlockMatStructure(
640 simple->getDM(),
641
642 {
643
644 {
645
646 simple->getDomainFEName(),
647
648 {
649
650 {"BROKEN", "BROKEN"},
651 {"U", "U"},
652 {"BROKEN", "U"},
653 {"U", "BROKEN"}
654
655 }
656
657 },
658
659 {
660
661 simple->getSkeletonFEName(),
662
663 {
664
665 {"BROKEN", "HYBRID"}, {"HYBRID", "BROKEN"}
666
667 }
668
669 }
670
671 }
672
673 );
674
676
677 {schur_dm, block_dm}, block_mat_data,
678
679 {"BROKEN", "U"}, {nullptr, nullptr}, true
680
681 );
682 };
683
684 auto set_ops = [&](auto schur_dm) {
686 auto dm_is = getDMSubData(schur_dm)->getSmartRowIs();
687 auto ao_up = createAOMappingIS(dm_is, PETSC_NULLPTR);
688
689 boost::shared_ptr<BlockStructure> block_data;
690 CHKERR DMMoFEMGetBlocMatData(simple->getDM(), block_data);
691
692 if (AT == BLOCK_SCHUR) {
693 pip_mng->getOpDomainLhsPipeline().push_front(
695 pip_mng->getOpDomainLhsPipeline().push_back(
696
697 createOpSchurAssembleEnd({"BROKEN", "U"}, {nullptr, nullptr}, ao_up,
698 S, true, true)
699
700 );
701 }
702
703 auto pre_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
704 auto post_proc_schur_lhs_ptr = boost::make_shared<FEMethod>();
705
706 pre_proc_schur_lhs_ptr->preProcessHook = [this]() {
708 CHKERR MatZeroEntries(S);
709 MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble Begin";
711 };
712
713 post_proc_schur_lhs_ptr->postProcessHook = [this, ao_up,
714 post_proc_schur_lhs_ptr]() {
716 MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble End";
717
718 if (AT == BLOCK_SCHUR) {
719 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
720 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
721 if (1) {
722 auto S_from_block = matDuplicate(S, MAT_SHARE_NONZERO_PATTERN);
723 // Create matrix from block mat
724 CHKERR assembleBlockMatSchur(mField, post_proc_schur_lhs_ptr->B,
725 S_from_block, {"BROKEN", "U"},
726 {nullptr, nullptr}, ao_up);
727 CHKERR MatAssemblyBegin(S_from_block, MAT_FINAL_ASSEMBLY);
728 CHKERR MatAssemblyEnd(S_from_block, MAT_FINAL_ASSEMBLY);
729 CHKERR MatAYPX(S_from_block, -1, S, DIFFERENT_NONZERO_PATTERN);
730 double norm;
731 CHKERR MatNorm(S_from_block, NORM_FROBENIUS, &norm);
732 MOFEM_LOG("AT", Sev::inform) << "Norm of difference: " << norm;
733 if (norm > 1e-6)
734 SETERRQ(
735 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
736 "Norm of difference between Schur and block matrix is larger "
737 "than accepted");
738 }
739 } else {
740 CHKERR assembleBlockMatSchur(mField, post_proc_schur_lhs_ptr->B, S,
741 {"BROKEN", "U"}, {nullptr, nullptr}, ao_up);
742 CHKERR MatAssemblyBegin(S, MAT_FINAL_ASSEMBLY);
743 CHKERR MatAssemblyEnd(S, MAT_FINAL_ASSEMBLY);
744 }
745
746 MOFEM_LOG("AT", Sev::verbose) << "Lhs Assemble Finish";
748 };
749
750 auto ksp_ctx_ptr = getDMKspCtx(simple->getDM());
751 ksp_ctx_ptr->getPreProcSetOperators().push_front(pre_proc_schur_lhs_ptr);
752 ksp_ctx_ptr->getPostProcSetOperators().push_back(post_proc_schur_lhs_ptr);
753
755 };
756
757 auto set_pc = [&](auto pc, auto block_dm) {
759 auto block_is = getDMSubData(block_dm)->getSmartRowIs();
760 CHKERR PCFieldSplitSetIS(pc, NULL, block_is);
761 CHKERR PCFieldSplitSetSchurPre(pc, PC_FIELDSPLIT_SCHUR_PRE_USER, S);
763 };
764
765
766
767 auto [schur_dm, block_dm] = create_sub_dm();
768 if (AT == BLOCK_SCHUR || AT == BLOCK_MAT) {
769 auto nested_mat_data = get_nested_mat_data(schur_dm, block_dm);
770 CHKERR DMMoFEMSetNestSchurData(simple->getDM(), nested_mat_data);
771 }
772 S = createDMHybridisedL2Matrix(schur_dm);
773 CHKERR MatSetDM(S, PETSC_NULLPTR);
774
775 int bs = (SPACE_DIM == 2) ? NBEDGE_L2(hybrid_approx_order)
777 CHKERR MatSetBlockSize(S, bs);
778
779 CHKERR set_ops(schur_dm);
780 CHKERR set_pc(pc, block_dm);
781 DM solver_dm;
782 CHKERR KSPGetDM(ksp, &solver_dm);
783 if (AT == BLOCK_SCHUR || AT == BLOCK_MAT)
784 CHKERR DMSetMatType(solver_dm, MATSHELL);
785
786 auto get_pc = [](auto ksp) {
787 PC pc_raw;
788 CHKERR KSPGetPC(ksp, &pc_raw);
789 return pc_raw;
790 };
791
792 auto set_diagonal_pc = [&](auto pc) {
794
795 if (AT == BLOCK_SCHUR || AT == BLOCK_MAT) {
796 auto A = createDMBlockMat(simple->getDM());
797 auto P = createDMNestSchurMat(simple->getDM());
798 CHKERR PCSetOperators(pc, A, P);
799 }
800
801 KSP *subksp;
802 CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULLPTR, &subksp);
803 CHKERR setSchurA00MatSolvePC(SmartPetscObj<PC>(get_pc(subksp[0]), true));
804
805 CHKERR PetscFree(subksp);
807 };
808
809 auto set_mg_for_schur_complement = [&](auto pc, auto schur_dm, auto S) {
811
812 KSP *subksp;
813 CHKERR PCFieldSplitSchurGetSubKSP(pc, PETSC_NULLPTR, &subksp);
814 auto subpc = get_pc(subksp[1]);
815
816 auto set_pc_p_mg = [](auto dm, auto pc, auto S) {
818 CHKERR PCSetDM(pc, dm);
819 PetscBool same = PETSC_FALSE;
820 PetscObjectTypeCompare((PetscObject)pc, PCMG, &same);
821 if (same) {
822 MOFEM_LOG("TIMER", Sev::inform) << "Set up MG";
824 pc, createPCMGSetUpViaApproxOrdersCtx(dm, S, true));
825 CHKERR PCSetFromOptions(pc);
826 }
828 };
829
830 PetscBool same = PETSC_FALSE;
831 PetscObjectTypeCompare((PetscObject)subpc, PCKSP, &same);
832 if (same) {
833 CHKERR PCSetFromOptions(subpc);
834 KSP inner_ksp;
835 CHKERR PCKSPGetKSP(subpc, &inner_ksp);
836 CHKERR KSPSetFromOptions(inner_ksp);
837 PC inner_pc;
838 CHKERR KSPGetPC(inner_ksp, &inner_pc);
839 CHKERR PCSetFromOptions(inner_pc);
840 CHKERR set_pc_p_mg(schur_dm, inner_pc, S);
841 }
842
843 CHKERR PetscFree(subksp);
845 };
846
847 CHKERR KSPSetUp(ksp);
848 if (AT == BLOCK_SCHUR || AT == BLOCK_MAT) {
849 CHKERR set_diagonal_pc(pc);
850 CHKERR set_mg_for_schur_complement(pc, schur_dm, S);
851 }
852
853 } else {
854 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
855 "PC is not set to PCFIELDSPLIT");
856 }
858}
859
860boost::shared_ptr<SetUpSchur>
862 return boost::shared_ptr<SetUpSchur>(new SetUpSchurImpl(m_field));
863}
Integrator for broken space constraints.
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
int main()
static const double eps
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
#define CATCH_ERRORS
Catch errors.
FieldApproximationBase
approximation base
Definition definitions.h:58
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ AINSWORTH_LOBATTO_BASE
Definition definitions.h:62
@ DEMKOWICZ_JACOBI_BASE
Definition definitions.h:66
@ AINSWORTH_BERNSTEIN_BEZIER_BASE
Definition definitions.h:64
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
FieldSpace
approximation spaces
Definition definitions.h:82
@ L2
field with C-1 continuity
Definition definitions.h:88
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
@ HDIV
field with continuous normal traction
Definition definitions.h:87
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_IMPOSSIBLE_CASE
Definition definitions.h:35
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
auto integration_rule
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
Definition DMMoFEM.cpp:215
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:488
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:450
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
MoFEMErrorCode DMRegister_MGViaApproxOrders(const char sname[])
Register DM for Multi-Grid via approximation orders.
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
@ PETSC
Standard PETSc assembly.
@ BLOCK_MAT
Block matrix assembly.
@ BLOCK_SCHUR
Block Schur assembly.
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.
MoFEMErrorCode removeSideDOFs(const std::string problem_name, const std::string block_name, const std::string field_name, int bridge_dim, int lo, int hi, bool is_distributed_mesh=true)
Remove DOFs on side entities from problem.
#define NBFACETRI_L2(P)
Number of base functions on triangle for L2 space.
#define NBEDGE_L2(P)
Number of base functions on edge from L2 space.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMixDivTimesScalar< 2 > OpHdivU
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
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.
Definition Schur.cpp:2675
PetscErrorCode PetscOptionsGetInt(PetscOptions *, const char pre[], const char name[], PetscInt *ivalue, PetscBool *set)
MoFEMErrorCode DMMoFEMGetBlocMatData(DM dm, boost::shared_ptr< BlockStructure > &)
Get data for block mat.
Definition DMMoFEM.cpp:1535
MoFEMErrorCode setSchurA00MatSolvePC(SmartPetscObj< PC > pc)
Set PC for A00 block.
Definition Schur.cpp:2717
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
boost::shared_ptr< PCMGSetUpViaApproxOrdersCtx > createPCMGSetUpViaApproxOrdersCtx(DM dm, Mat A, bool use_shell_mat)
createPCMGSetUpViaApproxOrdersCtx
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
Definition DMMoFEM.hpp:1251
auto createDMHybridisedL2Matrix(DM dm)
Get smart hybridised L2 matrix from DM.
Definition DMMoFEM.hpp:1207
auto getDMSubData(DM dm)
Get sub problem data structure.
Definition DMMoFEM.hpp:1295
MoFEMErrorCode PCMGSetUpViaApproxOrders(PC pc, boost::shared_ptr< PCMGSetUpViaApproxOrdersCtx > ctx, int verb)
Function build MG structure.
boost::shared_ptr< BlockStructure > createBlockMatStructure(DM dm, SchurFEOpsFEandFields schur_fe_op_vec)
Create a Mat Diag Blocks object.
Definition Schur.cpp:1082
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)
Get the Schur Nest Mat Array object.
Definition Schur.cpp:2433
auto createAOMappingIS(IS isapp, IS ispetsc)
Creates an application mapping using two index sets.
PetscErrorCode PetscOptionsGetEList(PetscOptions *, const char pre[], const char name[], const char *const *list, PetscInt next, PetscInt *value, PetscBool *set)
SmartPetscObj< Mat > matDuplicate(Mat mat, MatDuplicateOption op)
MoFEMErrorCode DMMoFEMSetNestSchurData(DM dm, boost::shared_ptr< NestSchurData >)
Definition DMMoFEM.cpp:1555
auto createDMNestSchurMat(DM dm)
Definition DMMoFEM.hpp:1221
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM 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 matrix.
Definition Schur.cpp:1907
OpSchurAssembleBase * createOpSchurAssembleBegin()
Definition Schur.cpp:2670
auto createDMBlockMat(DM dm)
Definition DMMoFEM.hpp:1214
constexpr AssemblyType A
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::FaceSideEle EleOnSide
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpBaseTimesVector< 3, 3, 3 > OpHdivFlux
Integrating Rhs flux base (1/k) flux (FLUX)
Definition seepage.cpp:108
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpMixDivTimesU< 3, 1, SPACE_DIM > OpHDivH
Integrate Rhs div flux base times temperature (T)
Definition seepage.cpp:119
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 3, 3 > OpHdivHdiv
Integrate Lhs base of flux (1/k) base of flux (FLUX x FLUX)
Definition seepage.cpp:86
Add operators pushing bases from local to physical configuration.
Boundary condition manager for finite element problem setup.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() const =0
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
base operator to do operations at Gauss Pt. level
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
std::map< EntityHandle, std::vector< boost::weak_ptr< NumeredEntFiniteElement > > > AdjCache
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.
Operator for broken loop side.
Get norm of input VectorDouble for Tensor0.
Get norm of input MatrixDouble for Tensor1.
Calculate tenor field using vectorial base, i.e. Hdiv/Hcurl.
Get vector field for H-div approximation.
Calculate divergence of vector field.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Specialization for MatrixDouble vector field values calculation.
Get values from scalar function at integration points and save them to VectorDouble for Tensor0.
Element used to execute operators on side of the element.
Post post-proc data at points from hash maps.
static MoFEMErrorCode writeKSPGraphGraphviz(KspCtx *ksp_ctx, std::string filename)
KSP graph to Graphviz file.
static MoFEMErrorCode writeGraphGraphviz(std::string filename, std::string pip_name, const boost::ptr_deque< ForcesAndSourcesCore::UserDataOperator > &pip)
Pipeline graph to Graphviz file.
static MoFEMErrorCode writePiplineManagerGraphGraphviz(std::string filename, PipelineManager *pip_mng)
Write pipeline manager graph to Graphviz file.
Template struct for dimension-specific finite element types.
PipelineManager interface.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
virtual ~SetUpSchurImpl()=default
SmartPetscObj< Mat > S
SetUpSchurImpl(MoFEM::Interface &m_field)
MoFEMErrorCode setUp(SmartPetscObj< KSP >)
MoFEM::Interface & mField
[Push operators to pipeline]
SetUpSchur()=default
virtual MoFEMErrorCode setUp(SmartPetscObj< KSP >)=0
virtual ~SetUpSchur()=default
static boost::shared_ptr< SetUpSchur > createSetUpSchur(MoFEM::Interface &m_field)
constexpr AssemblyType AT
int approx_order
constexpr IntegrationType IT
static char help[]
constexpr AssemblyType BlockAssemblyType
constexpr int SPACE_DIM
constexpr bool debug
BoundaryEle::UserDataOperator BdyEleOp
int hybrid_approx_order
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
#define SCHUR_ASSEMBLE
Definition contact.cpp:18