v0.16.3
Loading...
Searching...
No Matches
between_meshes_dg_projection.cpp
Go to the documentation of this file.
1/**
2 * @file between_meshes_dg_projection.cpp
3 * @example mofem/tutorials/adv-6_dg_projection/between_meshes_dg_projection.cpp
4 *
5 * @brief Testing Discontinuous Galerkin (DG) projection operators
6 *
7 *
8 */
9
10#include <MoFEM.hpp>
11
12using namespace MoFEM;
13
14static char help[] = "DG Projection Test - validates discontinuous Galerkin "
15 "projection accuracy\n\n";
16
17constexpr char FIELD_NAME_U[] = "U";
18constexpr char FIELD_NAME_S[] = "S";
19constexpr int BASE_DIM = 1;
20constexpr int FIELD_DIM = 1;
21constexpr int SPACE_DIM = 2;
22constexpr int order = 2;
23
25using DomainEleOp = DomainEle::UserDataOperator;
27
29
30auto fun = [](const double x, const double y, const double z) {
31 return x + y + x * x + y * y;
32};
33
36
39
40struct Example {
41
42 Example(MoFEM::Interface &m_field) : mField(m_field) {}
43
45
46private:
49
54
56 BitRefLevel refine_bit);
58 MoFEMErrorCode edgeFlips(BitRefLevel parent_bit, BitRefLevel child_bit);
59 MoFEMErrorCode refineSkin(BitRefLevel parent_bit, BitRefLevel refine_bit);
61
62 struct CommonData {
63 boost::shared_ptr<MatrixDouble> invJacPtr;
64 boost::shared_ptr<VectorDouble> approxVals;
65 boost::shared_ptr<MatrixDouble> approxGradVals;
66 boost::shared_ptr<MatrixDouble> approxHessianVals;
68 };
69
70 struct OpError;
71};
72
73auto save_range = [](moab::Interface &moab, const std::string name,
74 const Range r, std::vector<Tag> tags = {}) {
76 auto out_meshset = get_temp_meshset_ptr(moab);
77 CHKERR moab.add_entities(*out_meshset, r);
78 if (r.size()) {
79 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(), 1,
80 tags.data(), tags.size());
81 } else {
82 MOFEM_LOG("SELF", Sev::warning) << "Empty range for " << name;
83 }
85};
86
88 boost::shared_ptr<CommonData> commonDataPtr;
89
90 OpError(boost::shared_ptr<MatrixDouble> data_ptr,
92 : DomainEleOp(NOSPACE, OPSPACE), dataPtr(data_ptr), bitsEle(bits),
93 maskEle(mask) {}
94
95 MoFEMErrorCode doWork(int side, EntityType type, EntData &data) {
97
98 auto fe_ptr = getNumeredEntFiniteElementPtr();
99 auto fe_bit = fe_ptr->getBitRefLevel();
100 if ((fe_bit & bitsEle).any() && ((fe_bit & maskEle) == fe_bit)) {
101 const int nb_integration_pts = getGaussPts().size2();
102
103 auto t_val = getFTensor1FromMat<1>(*(dataPtr));
104 auto t_coords = getFTensor1CoordsAtGaussPts();
105
106 for (int gg = 0; gg != nb_integration_pts; ++gg) {
107
108 double projected_value = t_val(0);
109 double analytical_value = fun(t_coords(0), t_coords(1), t_coords(2));
110 double error = projected_value - analytical_value;
111
112 constexpr double eps = 1e-8;
113 if (std::abs(error) > eps) {
114 MOFEM_LOG("SELF", Sev::error)
115 << "Projection error too large: " << error << " at point ("
116 << t_coords(0) << ", " << t_coords(1) << ")"
117 << " projected=" << projected_value
118 << " analytical=" << analytical_value;
119 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
120 "DG projection failed accuracy test");
121 }
122
123 ++t_val;
124 ++t_coords;
125 }
126
127 MOFEM_LOG("SELF", Sev::noisy)
128 << "DG projection accuracy validation passed";
129 }
130
132 }
133
134private:
135 boost::shared_ptr<MatrixDouble> dataPtr;
138};
139
140//! [Run programme]
147 CHKERR outputResults("out_initial.h5m");
148
149 auto parent_bit = BitRefLevel().set(0);
150 auto child_bit = BitRefLevel().set(1);
151 auto refine_bit = BitRefLevel().set(2);
152
153 CHKERR edgeFlips(parent_bit, child_bit);
154 CHKERR refineSkin(child_bit, refine_bit);
156 CHKERR projectResults(parent_bit, child_bit, refine_bit);
157
158 CHKERR reSetupProblem(refine_bit);
159 CHKERR outputResults("out_projected.h5m");
160
162}
163//! [Run programme]
164
165//! [Read mesh]
168
170
172
173 char mesh_File_Name[255];
174 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-file_name",
175 mesh_File_Name, 255, PETSC_NULLPTR);
176 CHKERR simpleInterface->loadFile("", mesh_File_Name);
177
179}
180//! [Read mesh]
181
182//! [Set up problem]
185
190
193
194 CHKERR simpleInterface->setUp(PETSC_FALSE);
195
197}
198//! [Set up problem]
199
200//! [Push operators to pipeline]
203
204 auto rule = [](int, int, int p) -> int { return 2 * p; };
205
207
208 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
209 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
210
211 auto beta = [](const double, const double, const double) { return 1; };
212
213 pipeline_mng->getOpDomainLhsPipeline().push_back(
215 pipeline_mng->getOpDomainRhsPipeline().push_back(
217
218 pipeline_mng->getOpDomainLhsPipeline().push_back(
220 pipeline_mng->getOpDomainRhsPipeline().push_back(
222
223
225}
226//! [Push operators to pipeline]
227
228//! [Solve]
232
233 MOFEM_LOG("WORLD", Sev::inform) << "Solving DG projection system";
234
235 auto solver = pipeline_mng->createKSP();
236 CHKERR KSPSetFromOptions(solver);
237 CHKERR KSPSetUp(solver);
238
239 auto dm = simpleInterface->getDM();
240 auto D = createDMVector(dm);
241 auto F = vectorDuplicate(D);
242
243 CHKERR KSPSolve(solver, F, D);
244
245 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
246 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
247
248 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
249
251}
252//! [Solve]
253
254//! [Project results]
256 BitRefLevel child_bit,
257 BitRefLevel refine_bit) {
260 auto pipeline_mng = mField.getInterface<PipelineManager>();
261
262 pipeline_mng->getDomainLhsFE().reset();
263 pipeline_mng->getDomainRhsFE().reset();
264 pipeline_mng->getOpDomainRhsPipeline().clear();
265
266 auto rule = [](int, int, int p) -> int { return 2 * p; };
267 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
268
269 // OpLoopThis, is child operator, and is use to execute
270 // fe_child_ptr, only on bit ref level and mask
271 // for child elements
272 auto get_child_op = [&](auto &pip) {
273 auto op_this_child =
275 child_bit | refine_bit, Sev::noisy);
276 auto fe_child_ptr = op_this_child->getThisFEPtr();
277 fe_child_ptr->getRuleHook = [] (int, int, int p) { return -1; };
278 Range child_edges;
279 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
280 refine_bit, child_bit | refine_bit, MBEDGE, child_edges);
281 // set integration rule, such that integration points are not on flipped edge
282 CHKERR setDGSetIntegrationPoints<SPACE_DIM>(
283 fe_child_ptr->setRuleHook, [](int, int, int p) { return 2 * p; },
284 boost::make_shared<Range>(child_edges));
285 pip.push_back(op_this_child);
286 return fe_child_ptr;
287 };
288
289 // Use field evaluator to calculate field values on parent bitref level,
290 // i.e. elements which were flipped.
291 auto get_field_eval_op = [&](auto fe_child_ptr) {
292 auto field_eval_ptr = mField.getInterface<FieldEvaluatorInterface>();
293
294 // Get pointer of FieldEvaluator data. Note finite element and method
295 // set integration points is destroyed when this pointer is releases
296 auto field_eval_data = field_eval_ptr->getData<DomainEle>();
297 // Build tree for particular element
298 CHKERR field_eval_ptr->buildTree<SPACE_DIM>(
299 field_eval_data, simpleInterface->getDomainFEName(), parent_bit,
300 parent_bit | child_bit);
301
302 // You can add more fields here
303 auto data_U_ptr = boost::make_shared<MatrixDouble>();
304 auto eval_data_U_ptr = boost::make_shared<MatrixDouble>();
305 auto data_S_ptr = boost::make_shared<MatrixDouble>();
306 auto eval_data_S_ptr = boost::make_shared<MatrixDouble>();
307
308
309 if (auto fe_eval_ptr = field_eval_data->feMethodPtr) {
310 fe_eval_ptr->getRuleHook = [] (int, int, int p) { return -1; };
311 fe_eval_ptr->getOpPtrVector().push_back(
313 eval_data_U_ptr));
314 fe_eval_ptr->getOpPtrVector().push_back(
316 eval_data_S_ptr));
317
318 auto op_test = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
319 op_test->doWorkRhsHook =
320 [](DataOperator *base_op_ptr, int side, EntityType type,
323
324 auto op_ptr = static_cast<DomainEleOp *>(base_op_ptr);
325 MOFEM_LOG_CHANNEL("SELF");
326 MOFEM_LOG("SELF", Sev::noisy)
327 << "Field evaluator method pointer is valid";
328 MOFEM_LOG("SELF", Sev::noisy)
329 << op_ptr->getGaussPts();
330 MOFEM_LOG("SELF", Sev::noisy)
331 << "Loop size " << op_ptr->getPtrFE()->getLoopSize();
332 MOFEM_LOG("SELF", Sev::noisy)
333 << "Coords at gauss pts: " << op_ptr->getCoordsAtGaussPts();
334
336 };
337
338 fe_eval_ptr->getOpPtrVector().push_back(op_test);
339
340 } else {
342 "Field evaluator method pointer is expired");
343 }
344
345 auto op_ptr = field_eval_ptr->getDataOperator<SPACE_DIM>(
346 {{eval_data_U_ptr, data_U_ptr}, {eval_data_S_ptr, data_S_ptr}},
347 simpleInterface->getDomainFEName(), field_eval_data, 0,
348 mField.get_comm_size(), parent_bit, parent_bit | child_bit, MF_EXIST,
349 QUIET);
350
351 fe_child_ptr->getOpPtrVector().push_back(op_ptr);
352 return std::make_pair(
353
354 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
355 {FIELD_NAME_U, data_U_ptr}},
356
357 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
358 {FIELD_NAME_S, data_S_ptr}}
359
360 );
361
362 };
363
364 // calculate coefficients on child (flipped) elements
365 auto dg_projection_base = [&](auto fe_child_ptr, auto vec_data_ptr, auto mat,
366 auto vec) {
368 constexpr int projection_order = order;
369 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
370 auto mass_ptr = boost::make_shared<MatrixDouble>();
371 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
372
373 // project L2 (directly from coefficients)
374 for (auto &p : vec_data_ptr.first) {
375 auto field_name = p.first;
376 auto data_ptr = p.second;
377
378 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
379 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
380 L2));
381 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
382 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
383 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
384
385 // next two lines are only for testing if projection is correct, they are not
386 // essential
387 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
388 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
389 Sev::noisy));
390 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
391
392 // set coefficients to flipped element
393 auto op_set_coeffs = new DomainEleOp(field_name, DomainEleOp::OPROW);
394 op_set_coeffs->doWorkRhsHook =
395 [coeffs_ptr](DataOperator *base_op_ptr, int side, EntityType type,
398 auto field_ents = data.getFieldEntities();
399 auto nb_dofs = data.getIndices().size();
400 if (!field_ents.size())
402 if (auto e_ptr = field_ents[0]) {
403 auto field_ent_data = e_ptr->getEntFieldData();
404 std::copy(coeffs_ptr->data().data(),
405 coeffs_ptr->data().data() + nb_dofs,
406 field_ent_data.begin());
407 }
409 };
410 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
411 }
412
413 // project H1 (via coefficients)
414 for (auto &p : vec_data_ptr.second) {
415 auto field_name = p.first;
416 auto data_ptr = p.second;
417
418 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
419 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
420 L2));
421 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
422 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
423 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
424
425 // next two lines are only for testing if projection is correct, they are not
426 // essential
427 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
428 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
429 Sev::noisy));
430 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
431
432 // assemble to global matrix, since this is H1 (you will do the shame for Hcurl of Hdiv)
433 auto beta = [](const double, const double, const double) { return 1; };
434 fe_child_ptr->getOpPtrVector().push_back(
437 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, FIELD_DIM>;
438 fe_child_ptr->getOpPtrVector().push_back(
439 new OpVec(FIELD_NAME_S, data_ptr, beta));
440 }
441
443 };
444
445 auto dm = simple->getDM();
446 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
447 CHKERR DMMoFEMCreateSubDM(sub_dm, dm, "SUB");
448 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
450
451 // get only refinement bit DOFs
452 auto ref_entities_ptr = boost::make_shared<Range>();
453 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
454 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
455 Range verts;
456 CHKERR mField.get_moab().get_connectivity(*ref_entities_ptr, verts, true);
457 ref_entities_ptr->merge(verts);
458
459 CHKERR DMMoFEMAddSubFieldRow(sub_dm, FIELD_NAME_S, ref_entities_ptr);
460 CHKERR DMMoFEMAddSubFieldCol(sub_dm, FIELD_NAME_S, ref_entities_ptr);
461 CHKERR DMSetUp(sub_dm);
462
463 auto mat = createDMMatrix(sub_dm);
464 auto vec = createDMVector(sub_dm);
465
466 // create child operator, and fe_child_ptr element in it
467 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
468 // run dg projection, note that get_field_eval_op,
469 // pass data_ptr values used to project and calculate coefficients
470 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
471 vec);
472
473 // That is to test, if projection works, and coefficients are set in correctly
474 // Note: FIELD_S is not tested, it is in H1, so we have to solve KSP problem first
475 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
476 pipeline_mng->getOpDomainRhsPipeline().push_back(
478 test_U_data_ptr));
479 pipeline_mng->getOpDomainRhsPipeline().push_back(
480 new OpError(test_U_data_ptr, refine_bit, BitRefLevel().set()));
481
482 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<DomainEle>();
483 fe_rhs->ksp_A = mat;
484 fe_rhs->ksp_B = mat;
485 fe_rhs->ksp_f = vec;
486 fe_rhs->data_ctx =
488 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
489
490 CHKERR VecAssemblyBegin(vec);
491 CHKERR VecAssemblyEnd(vec);
492 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
493 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
494 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
495 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
496
497 auto ksp = createKSP(mField.get_comm());
498 CHKERR KSPSetOperators(ksp, mat, mat);
499 CHKERR KSPSetFromOptions(ksp);
500
501 auto sol = createDMVector(sub_dm);
502 CHKERR KSPSolve(ksp, vec, sol);
503 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
504 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
505 CHKERR DMoFEMMeshToLocalVector(sub_dm, sol, INSERT_VALUES, SCATTER_REVERSE);
506
507 pipeline_mng->getOpDomainRhsPipeline().clear();
508 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
509 pipeline_mng->getOpDomainRhsPipeline().push_back(
511 test_S_data_ptr));
512 pipeline_mng->getOpDomainRhsPipeline().push_back(
513 new OpError(test_S_data_ptr, refine_bit, BitRefLevel().set()));
514
516}
517//! [Project results]
518
519//! [Output results]
522
523 auto pipeline_mng = mField.getInterface<PipelineManager>();
524
525 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(mField);
527 post_proc_fe->getOpPtrVector(), {H1});
528
529 auto u_ptr = boost::make_shared<VectorDouble>();
530 post_proc_fe->getOpPtrVector().push_back(
532 auto s_ptr = boost::make_shared<VectorDouble>();
533 post_proc_fe->getOpPtrVector().push_back(
535
536 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
537 post_proc_fe->getOpPtrVector().push_back(
539 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
540 post_proc_fe->getOpPtrVector().push_back(
542
543
545
546 post_proc_fe->getOpPtrVector().push_back(
547
548 new OpPPMap(
549 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
550
551 OpPPMap::DataMapVec{{FIELD_NAME_U, u_ptr}, {FIELD_NAME_S, s_ptr}},
552
554
555 {"GRAD_" + std::string(FIELD_NAME_U), grad_u_ptr},
556 {"GRAD_" + std::string(FIELD_NAME_S), grad_s_ptr}
557
558 },
559
561
563
564 )
565
566 );
567
568 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
569 CHKERR pipeline_mng->loopFiniteElementsPostProc();
570 CHKERR post_proc_fe->writeFile(file_name);
571
573}
574//! [Output results]
575
576//! [Edge flips]
578 BitRefLevel child_bit) {
580
581 moab::Interface &moab = mField.get_moab();
582
583 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
585
586 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
588 const EntityHandle *conn;
589 int num_nodes;
590 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
591 std::copy(conn, conn + num_nodes, conn_cpy);
593 };
594
595 auto get_tri_normals = [&](auto &conn) {
596 std::array<double, 18> coords;
597 CHKERR moab.get_coords(conn.data(), 6, coords.data());
598 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
599 for (int t = 0; t != 2; ++t) {
600 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
601 }
602 return tri_normals;
603 };
604
605 auto test_flip = [&](auto &&t_normals) {
606 FTENSOR_INDEX(3, i);
607 if (t_normals[0](i) * t_normals[1](i) <
608 std::numeric_limits<float>::epsilon())
609 return false;
610 return true;
611 };
612
613 std::array<EntityHandle, 6> adj_conn;
614 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
615 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
616 std::array<EntityHandle, 2> edge_conn;
617 CHKERR get_conn(edge, edge_conn.data());
618 std::array<EntityHandle, 2> new_edge_conn;
619
620 int j = 1;
621 for (int i = 0; i != 6; ++i) {
622 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
623 new_edge_conn[j] = adj_conn[i];
624 --j;
625 }
626 }
627
628 auto &new_conn = adj_conn; //< just alias this
629 for (int t = 0; t != 2; ++t) {
630 for (int i = 0; i != 3; ++i) {
631 if (
632
633 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
634 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
635
636 ||
637
638 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
639 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
640
641 ) {
642 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
643 break;
644 }
645 }
646 }
647
648 if (test_flip(get_tri_normals(new_conn))) {
649 for (int t = 0; t != 2; ++t) {
650 Range rtri;
651 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
652 false, rtri);
653 if (!rtri.size()) {
654 EntityHandle tri;
655 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
656 tri);
657 new_tris.insert(tri);
658 } else {
659#ifndef NDEBUG
660 if (rtri.size() != 1) {
661 MOFEM_LOG("SELF", Sev::error)
662 << "Multiple tries created during edge flip for edge " << edge
663 << " adjacent faces " << std::endl
664 << rtri;
665 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
666 "Multiple tries created during edge flip");
667 }
668#endif // NDEBUG
669 new_tris.merge(rtri);
670 }
671 }
672
673 Range new_edges;
674 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
675 moab::Interface::UNION);
676 } else {
677
678 MOFEM_LOG_CHANNEL("SELF");
679 MOFEM_LOG("SELF", Sev::warning)
680 << "Edge flip rejected for edge " << edge << " adjacent faces "
681 << adj_faces;
682 }
683
685 };
686
687 Range tris;
688 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
689 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
690 parent_bit, BitRefLevel().set(), tris);
691 Skinner skin(&moab);
692 Range skin_edges;
693 CHKERR skin.find_skin(0, tris, false, skin_edges);
694
695 Range edges;
696 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
697 edges = subtract(edges, skin_edges);
698 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
699 parent_bit, BitRefLevel().set(), edges);
700
701 Range new_tris, flipped_tris, forbidden_tris;
702 int flip_count = 0;
703 for (auto edge : edges) {
704 Range adjacent_tris;
705 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
706
707 adjacent_tris = intersect(adjacent_tris, tris);
708 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
709 if (adjacent_tris.size() == 2) {
710
711#ifndef NDEBUG
712 int side_number0, sense0, offset0;
713 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
714 sense0, offset0);
715 int side_number1, sense1, offset1;
716 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
717 sense1, offset1);
718 if (sense0 * sense1 > 0)
719 SETERRQ(
720 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
721 "Cannot flip edge with same orientation in both adjacent faces");
722#endif // NDEBUG
723
724 Range new_flipped_tris;
725 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
726 if (new_flipped_tris.size()) {
727 flipped_tris.merge(adjacent_tris);
728 forbidden_tris.merge(adjacent_tris);
729 new_tris.merge(new_flipped_tris);
730
731#ifndef NDEBUG
732 CHKERR save_range(moab,
733 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
734 adjacent_tris);
736 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
737 new_flipped_tris);
738
739#endif // NDEBUG
740
741 ++flip_count;
742 }
743 }
744 }
745
746 Range all_tris;
747 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
748 Range not_flipped_tris = subtract(all_tris, flipped_tris);
749
750 MOFEM_LOG("SELF", Sev::noisy)
751 << "Flipped " << flip_count << " edges with two adjacent faces.";
752 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
753 child_bit);
754 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
755 child_bit);
756 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
757 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
758 "");
759
761}
762//! [Edge flips]
763
764//! [Refine skin]
766 BitRefLevel child_bit) {
768
769 moab::Interface &moab = mField.get_moab();
770 Range tris;
771 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
772 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
773 parent_bit, BitRefLevel().set(), tris);
774
775 Skinner skin(&moab);
776 Range skin_edges;
777 CHKERR skin.find_skin(0, tris, false, skin_edges);
778
779 auto refine = mField.getInterface<MeshRefinement>();
780 CHKERR refine->addVerticesInTheMiddleOfEdges(skin_edges, child_bit);
781#ifndef NDEBUG
782 auto debug = true;
783#else
784 auto debug = false;
785#endif
786 CHKERR refine->refineTris(tris, child_bit, QUIET, debug);
787
788 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
789 child_bit, BitRefLevel().set(), "edge_flips_after_refinement.vtk", "VTK",
790 "");
791
793}
794//! [Refine skin]
795
796//! [Re-setup problem after mesh modification
803//! [Re-setup problem after mesh modification]
804
805int main(int argc, char *argv[]) {
806
807 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
808
809 try {
810
811 //! [Register MoFEM discrete manager in PETSc]
812 DMType dm_name = "DMMOFEM";
813 CHKERR DMRegister_MoFEM(dm_name);
814 //! [Register MoFEM discrete manager in PETSc]
815
816 //! [Create MoAB]
817 moab::Core mb_instance;
818 moab::Interface &moab = mb_instance;
819 //! [Create MoAB]
820
821 //! [Create MoFEM]
822 MoFEM::Core core(moab);
823 MoFEM::Interface &m_field = core;
824 //! [Create MoFEM]
825
826 //! [Execute DG Projection Test]
827 Example ex(m_field);
828 CHKERR ex.runProblem();
829 //! [Execute DG Projection Test]
830 }
832
834}
std::string type
#define FTENSOR_INDEX(DIM, I)
int main()
static char help[]
constexpr int SPACE_DIM
constexpr char FIELD_NAME_U[]
constexpr int FIELD_DIM
constexpr int BASE_DIM
constexpr char FIELD_NAME_S[]
constexpr int order
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
constexpr int FIELD_DIM
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, FIELD_DIM > OpDomainMass
@ QUIET
#define CATCH_ERRORS
Catch errors.
@ MF_EXIST
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
#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()
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ 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 fun
constexpr int order
@ F
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
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
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1194
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
MoFEMErrorCode loopFiniteElementsPostProc(SmartPetscObj< DM > dm=nullptr)
Iterate postprocessing finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
@ GAUSS
Gaussian quadrature integration.
@ PETSC
Standard PETSc assembly.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
FTensor::Index< 'i', SPACE_DIM > i
double D
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
auto createKSP(MPI_Comm comm)
static const bool debug
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
int r
Definition sdf.py:205
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr auto field_name
boost::shared_ptr< VectorDouble > approxVals
boost::shared_ptr< MatrixDouble > invJacPtr
boost::shared_ptr< MatrixDouble > approxGradVals
boost::shared_ptr< MatrixDouble > approxHessianVals
MoFEMErrorCode doWork(int side, EntityType type, EntData &data)
boost::shared_ptr< MatrixDouble > dataPtr
boost::shared_ptr< CommonData > commonDataPtr
OpError(boost::shared_ptr< MatrixDouble > data_ptr, BitRefLevel bits=BitRefLevel(), BitRefLevel mask=BitRefLevel())
[Example]
Definition plastic.cpp:216
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
MoFEMErrorCode reSetupProblem(BitRefLevel child_bit)
[Refine skin]
MoFEMErrorCode edgeFlips(BitRefLevel parent_bit, BitRefLevel child_bit)
[Output results]
MoFEMErrorCode projectResults(BitRefLevel parent_bit, BitRefLevel child_bit, BitRefLevel refine_bit)
[Solve]
Simple * simple
MoFEMErrorCode solveSystem()
MoFEMErrorCode refineSkin(BitRefLevel parent_bit, BitRefLevel refine_bit)
[Edge flips]
Example(MoFEM::Interface &m_field)
MoFEMErrorCode runProblem()
MoFEM::Interface & mField
Reference to MoFEM interface.
Definition plastic.cpp:226
MoFEMErrorCode setupProblem()
MoFEMErrorCode outputResults()
[Solve]
SmartPetscObj< EPS > eps
Add operators pushing bases from local to physical configuration.
Managing BitRefLevels.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() 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)
Field evaluator interface.
boost::shared_ptr< SPD > getData(const double *ptr=nullptr, const int nb_eval_points=0, const double eps=1e-12, VERBOSITY_LEVELS verb=QUIET)
Get the Data object.
Mesh refinement interface.
MoFEMErrorCode addVerticesInTheMiddleOfEdges(const EntityHandle meshset, const BitRefLevel &bit, const bool recursive=false, int verb=QUIET, EntityHandle start_v=0)
make vertices in the middle of edges in meshset and add them to refinement levels defined by bit
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.
Evaluate field for given DG projection coefficients.
Evaluate right hand side for given data coefficients.
Execute "this" element in the operator.
Post post-proc data at points from hash maps.
std::map< std::string, ScalarDataPtr > DataMapVec
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
static constexpr Switches CtxSetA
Jacobian matrix switch.
static constexpr Switches CtxSetF
Residual vector switch.
static constexpr Switches CtxSetB
Preconditioner matrix switch.
Template struct for dimension-specific finite element types.
PipelineManager interface.
boost::shared_ptr< FEMethod > & getDomainPostProcFE()
Get domain postprocessing finite element.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode reSetUp(bool only_dm=false)
Rebuild internal MoFEM data structures.
Definition Simple.cpp:761
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
const std::string getDomainFEName() const
Get the Domain FE Name.
Definition Simple.hpp:429
BitRefLevel & getBitRefLevel()
Get the BitRefLevel.
Definition Simple.hpp:415
intrusive_ptr for managing petsc objects
static MoFEMErrorCode getTriNormal(const double *coords, double *normal, double *d_normal=nullptr)
Get the Tri Normal objectGet triangle normal.
Definition Tools.cpp:353
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
auto save_range
constexpr int SPACE_DIM
DomainEle::UserDataOperator DomainEleOp
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle