63 DMType dm_name =
"DMMOFEM";
65 DMType dm_name_mg =
"DMMOFEM_MG";
73 auto core_log = logging::core::get();
75 LogManager::createSink(LogManager::getStrmWorld(),
"AT"));
77 LogManager::createSink(LogManager::getStrmWorld(),
"TIMER"));
78 LogManager::setLog(
"AT");
79 LogManager::setLog(
"TIMER");
89 simple->getAddBoundaryFE() =
true;
92 auto add_shared_entities_on_skeleton = [&]() {
94 auto boundary_meshset =
simple->getBoundaryMeshSet();
95 auto skeleton_meshset =
simple->getSkeletonMeshSet();
101 0,
simple->getDim() - 1, skeleton_ents,
true);
102 skeleton_ents = subtract(skeleton_ents, bdy_ents);
104 CHKERR m_field.
get_moab().add_entities(skeleton_meshset, skeleton_ents);
108 CHKERR add_shared_entities_on_skeleton();
118 const char *list_bases[] = {
"ainsworth",
"ainsworth_lobatto",
"demkowicz",
121 PetscInt choice_base_value = AINSWORTH;
123 LASBASETOP, &choice_base_value, &flg);
125 if (flg != PETSC_TRUE)
128 if (choice_base_value == AINSWORTH)
130 if (choice_base_value == AINSWORTH_LOBATTO)
132 else if (choice_base_value == DEMKOWICZ)
134 else if (choice_base_value == BERNSTEIN)
137 enum spaces { hdiv, hcurl, last_space };
138 const char *list_spaces[] = {
"hdiv",
"hcurl"};
139 PetscInt choice_space_value = hdiv;
141 last_space, &choice_space_value, &flg);
142 if (flg != PETSC_TRUE)
145 if (choice_space_value == hdiv)
147 else if (choice_space_value == hcurl)
153 CHKERR simple->addDomainBrokenField(
"BROKEN", space, base, 1);
164 CHKERR bc_mng->removeSideDOFs(
simple->getProblemName(),
"ZERO_FLUX",
169 auto assemble_domain_lhs = [&](
auto &pip) {
176 IT>::OpMixDivTimesScalar<SPACE_DIM>;
182 pip.push_back(
new OpHdivHdiv(
"BROKEN",
"BROKEN", beta));
183 auto unity = []() constexpr {
return 1; };
184 pip.push_back(
new OpHdivU(
"BROKEN",
"U", unity,
true));
192 op_loop_skeleton_side->getOpPtrVector(), {});
196 auto broken_data_ptr =
197 boost::make_shared<std::vector<BrokenBaseSideData>>();
202 op_loop_domain_side->getOpPtrVector(), {HDIV});
203 op_loop_domain_side->getOpPtrVector().push_back(
206 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
208 IT>::OpBrokenSpaceConstrain<1>;
209 op_loop_skeleton_side->getOpPtrVector().push_back(
210 new OpC(
"HYBRID", broken_data_ptr, 1.,
true,
false));
214 constexpr
int partition = 1;
216 op_print->doWorkRhsHook = [&](
DataOperator *base_op_ptr,
int side,
220 if (
auto op_ptr =
dynamic_cast<BdyEleOp *
>(base_op_ptr)) {
221 auto fe_method = op_ptr->getFEMethod();
222 auto num_fe = fe_method->numeredEntFiniteElementPtr;
225 if (num_fe->getPStatus() & PSTATUS_SHARED)
226 MOFEM_LOG(
"SELF", Sev::inform) <<
"Num FE: " << *num_fe;
231 op_loop_skeleton_side->getOpPtrVector().push_back(op_print);
234 pip.push_back(op_loop_skeleton_side);
239 auto assemble_domain_rhs = [&](
auto &pip) {
243 AT>::LinearForm<IT>::OpSource<1, 1>;
244 auto source = [&](
const double x,
const double y,
245 const double z) constexpr {
254 CHKERR assemble_domain_lhs(pip_mng->getOpDomainLhsPipeline());
255 CHKERR assemble_domain_rhs(pip_mng->getOpDomainRhsPipeline());
262 TetPolynomialBase::switchCacheBaseOn<HDIV>(
263 {pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
264 TetPolynomialBase::switchCacheBaseOn<L2>(
265 {pip_mng->getDomainLhsFE().get(), pip_mng->getDomainRhsFE().get()});
271 auto ksp = pip_mng->createKSP();
273 CHKERR KSPSetFromOptions(ksp);
274 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
275 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSetUp";
277 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSetUp <= Done";
279 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSolve";
281 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSolve <= Done";
283 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
284 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
288 auto ksp = pip_mng->createKSP();
290 BOOST_LOG_SCOPED_THREAD_ATTR(
"Timeline", attrs::timer());
291 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSetUp";
292 CHKERR schur_ptr->setUp(ksp);
293 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSetUp <= Done";
295 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSolve";
297 MOFEM_LOG(
"TIMER", Sev::inform) <<
"KSPSolve <= Done";
299 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
300 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
305 auto check_residual = [&](
auto x,
auto f) {
311 auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
317 auto div_flux_ptr = boost::make_shared<VectorDouble>();
319 "BROKEN", div_flux_ptr));
321 AT>::LinearForm<IT>::OpBaseTimesScalarField<1>;
323 domain_rhs.push_back(
new OpUDivFlux(
"U", div_flux_ptr, beta));
324 auto source = [&](
const double x,
const double y,
325 const double z) constexpr {
return 1; };
327 AT>::LinearForm<IT>::OpSource<1, 1>;
331 IT>::OpMixDivTimesU<3, 1, SPACE_DIM>;
333 AT>::LinearForm<IT>::OpBaseTimesVector<3, 3, 1>;
334 auto flux_ptr = boost::make_shared<MatrixDouble>();
335 domain_rhs.push_back(
337 boost::shared_ptr<VectorDouble> u_ptr =
338 boost::make_shared<VectorDouble>();
340 domain_rhs.push_back(
new OpHDivH(
"BROKEN", u_ptr, beta));
341 domain_rhs.push_back(
new OpHdivFlux(
"BROKEN", flux_ptr, beta));
349 op_loop_skeleton_side->getOpPtrVector(), {});
353 auto broken_data_ptr =
354 boost::make_shared<std::vector<BrokenBaseSideData>>();
359 op_loop_domain_side->getOpPtrVector(), {HDIV});
360 op_loop_domain_side->getOpPtrVector().push_back(
362 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
363 op_loop_domain_side->getOpPtrVector().push_back(
365 op_loop_domain_side->getOpPtrVector().push_back(
369 op_loop_skeleton_side->getOpPtrVector().push_back(op_loop_domain_side);
371 IT>::OpBrokenSpaceConstrainDHybrid<1>;
373 IT>::OpBrokenSpaceConstrainDFlux<1>;
374 op_loop_skeleton_side->getOpPtrVector().push_back(
375 new OpC_dHybrid(
"HYBRID", broken_data_ptr, 1.));
376 auto hybrid_ptr = boost::make_shared<MatrixDouble>();
377 op_loop_skeleton_side->getOpPtrVector().push_back(
379 op_loop_skeleton_side->getOpPtrVector().push_back(
380 new OpC_dBroken(broken_data_ptr, hybrid_ptr, 1.));
383 domain_rhs.push_back(op_loop_skeleton_side);
386 CHKERR VecGhostUpdateBegin(
f, INSERT_VALUES, SCATTER_FORWARD);
387 CHKERR VecGhostUpdateEnd(
f, INSERT_VALUES, SCATTER_FORWARD);
389 pip_mng->getDomainRhsFE()->f =
f;
390 pip_mng->getSkeletonRhsFE()->f =
f;
391 pip_mng->getDomainRhsFE()->x = x;
392 pip_mng->getSkeletonRhsFE()->x = x;
395 simple->getDomainFEName(),
396 pip_mng->getDomainRhsFE());
398 CHKERR VecGhostUpdateBegin(
f, ADD_VALUES, SCATTER_REVERSE);
399 CHKERR VecGhostUpdateEnd(
f, ADD_VALUES, SCATTER_REVERSE);
404 CHKERR VecNorm(
f, NORM_2, &fnrm);
405 MOFEM_LOG_C(
"AT", Sev::inform,
"Residual %3.4e", fnrm);
407 constexpr
double eps = 1e-8;
410 "Residual norm larger than accepted");
415 auto calculate_error = [&]() {
419 auto &domain_rhs = pip_mng->getOpDomainRhsPipeline();
425 auto u_grad_ptr = boost::make_shared<MatrixDouble>();
426 auto flux_val_ptr = boost::make_shared<MatrixDouble>();
427 auto div_val_ptr = boost::make_shared<VectorDouble>();
428 auto source_ptr = boost::make_shared<VectorDouble>();
430 domain_rhs.push_back(
432 domain_rhs.push_back(
435 "BROKEN", div_val_ptr));
436 auto source = [&](
const double x,
const double y,
437 const double z) constexpr {
return -1; };
440 enum { DIV, GRAD,
LAST };
443 domain_rhs.push_back(
446 u_grad_ptr, mpi_vec, GRAD, flux_val_ptr));
449 simple->getDomainFEName(),
450 pip_mng->getDomainRhsFE());
451 CHKERR VecAssemblyBegin(mpi_vec);
452 CHKERR VecAssemblyEnd(mpi_vec);
455 const double *error_ind;
456 CHKERR VecGetArrayRead(mpi_vec, &error_ind);
458 <<
"Approximation error ||div flux - source||: "
459 << std::sqrt(error_ind[DIV]);
460 MOFEM_LOG(
"AT", Sev::inform) <<
"Approximation error ||grad-flux||: "
461 << std::sqrt(error_ind[GRAD]);
462 CHKERR VecRestoreArrayRead(mpi_vec, &error_ind);
468 auto get_post_proc_fe = [&]() {
471 auto post_proc_fe = boost::make_shared<PostProcEle>(m_field);
477 post_proc_fe->getOpPtrVector().push_back(op_loop_side);
480 op_loop_side->getOpPtrVector(), {HDIV});
481 auto u_vec_ptr = boost::make_shared<VectorDouble>();
482 auto flux_mat_ptr = boost::make_shared<MatrixDouble>();
483 op_loop_side->getOpPtrVector().push_back(
485 op_loop_side->getOpPtrVector().push_back(
487 op_loop_side->getOpPtrVector().push_back(
491 post_proc_fe->getPostProcMesh(),
493 post_proc_fe->getMapGaussPts(),
497 {{
"BROKEN", flux_mat_ptr}},
506 auto post_proc_fe = get_post_proc_fe();
508 simple->getBoundaryFEName(), post_proc_fe);
509 CHKERR post_proc_fe->writeFile(
"out_result.h5m");