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
73[[maybe_unused]] auto save_range = [](moab::Interface &moab,
74 const std::string name, const Range r,
75 std::vector<Tag> tags = {}) {
77 auto out_meshset = get_temp_meshset_ptr(moab);
78 CHKERR moab.add_entities(*out_meshset, r);
79 if (r.size()) {
80 CHKERR moab.write_file(name.c_str(), "VTK", "", out_meshset->get_ptr(), 1,
81 tags.data(), tags.size());
82 } else {
83 MOFEM_LOG("SELF", Sev::warning) << "Empty range for " << name;
84 }
86};
87
89 boost::shared_ptr<CommonData> commonDataPtr;
90
91 OpError(boost::shared_ptr<MatrixDouble> data_ptr,
93 : DomainEleOp(NOSPACE, OPSPACE), dataPtr(data_ptr), bitsEle(bits),
94 maskEle(mask) {}
95
96 MoFEMErrorCode doWork(int side, EntityType type, EntData &data) {
98
99 auto fe_ptr = getNumeredEntFiniteElementPtr();
100 auto fe_bit = fe_ptr->getBitRefLevel();
101 if ((fe_bit & bitsEle).any() && ((fe_bit & maskEle) == fe_bit)) {
102 const int nb_integration_pts = getGaussPts().size2();
103
104 auto t_val = getFTensor1FromMat<1>(*(dataPtr));
105 auto t_coords = getFTensor1CoordsAtGaussPts();
106
107 for (int gg = 0; gg != nb_integration_pts; ++gg) {
108
109 double projected_value = t_val(0);
110 double analytical_value = fun(t_coords(0), t_coords(1), t_coords(2));
111 double error = projected_value - analytical_value;
112
113 constexpr double eps = 1e-8;
114 if (std::abs(error) > eps) {
115 MOFEM_LOG("SELF", Sev::error)
116 << "Projection error too large: " << error << " at point ("
117 << t_coords(0) << ", " << t_coords(1) << ")"
118 << " projected=" << projected_value
119 << " analytical=" << analytical_value;
120 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
121 "DG projection failed accuracy test");
122 }
123
124 ++t_val;
125 ++t_coords;
126 }
127
128 MOFEM_LOG("SELF", Sev::noisy)
129 << "DG projection accuracy validation passed";
130 }
131
133 }
134
135private:
136 boost::shared_ptr<MatrixDouble> dataPtr;
139};
140
141//! [Run programme]
148 CHKERR outputResults("out_initial.h5m");
149
150 auto parent_bit = BitRefLevel().set(0);
151 auto child_bit = BitRefLevel().set(1);
152 auto refine_bit = BitRefLevel().set(2);
153
154 CHKERR edgeFlips(parent_bit, child_bit);
155 CHKERR refineSkin(child_bit, refine_bit);
157 CHKERR projectResults(parent_bit, child_bit, refine_bit);
158
159 CHKERR reSetupProblem(refine_bit);
160 CHKERR outputResults("out_projected.h5m");
161
163}
164//! [Run programme]
165
166//! [Read mesh]
169
171
173
174 char mesh_File_Name[255];
175 CHKERR PetscOptionsGetString(PETSC_NULLPTR, PETSC_NULLPTR, "-file_name",
176 mesh_File_Name, 255, PETSC_NULLPTR);
177 CHKERR simpleInterface->loadFile("", mesh_File_Name);
178
180}
181//! [Read mesh]
182
183//! [Set up problem]
186
191
194
195 CHKERR simpleInterface->setUp(PETSC_FALSE);
196
198}
199//! [Set up problem]
200
201//! [Push operators to pipeline]
204
205 auto rule = [](int, int, int p) -> int { return 2 * p; };
206
208
209 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
210 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
211
212 auto beta = [](const double, const double, const double) { return 1; };
213
214 pipeline_mng->getOpDomainLhsPipeline().push_back(
216 pipeline_mng->getOpDomainRhsPipeline().push_back(
218
219 pipeline_mng->getOpDomainLhsPipeline().push_back(
221 pipeline_mng->getOpDomainRhsPipeline().push_back(
223
224
226}
227//! [Push operators to pipeline]
228
229//! [Solve]
233
234 MOFEM_LOG("WORLD", Sev::inform) << "Solving DG projection system";
235
236 auto solver = pipeline_mng->createKSP();
237 CHKERR KSPSetFromOptions(solver);
238 CHKERR KSPSetUp(solver);
239
240 auto dm = simpleInterface->getDM();
241 auto D = createDMVector(dm);
242 auto F = vectorDuplicate(D);
243
244 CHKERR KSPSolve(solver, F, D);
246 solver, "DG projection solve");
247
248 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
249 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
250
251 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
252
254}
255//! [Solve]
256
257//! [Project results]
259 BitRefLevel child_bit,
260 BitRefLevel refine_bit) {
263 auto pipeline_mng = mField.getInterface<PipelineManager>();
264
265 pipeline_mng->getDomainLhsFE().reset();
266 pipeline_mng->getDomainRhsFE().reset();
267 pipeline_mng->getOpDomainRhsPipeline().clear();
268
269 auto rule = [](int, int, int p) -> int { return 2 * p; };
270 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
271
272 // OpLoopThis, is child operator, and is use to execute
273 // fe_child_ptr, only on bit ref level and mask
274 // for child elements
275 auto get_child_op = [&](auto &pip) {
276 auto op_this_child =
278 child_bit | refine_bit, Sev::noisy);
279 auto fe_child_ptr = op_this_child->getThisFEPtr();
280 fe_child_ptr->getRuleHook = [] (int, int, int p) { return -1; };
281 Range child_edges;
282 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
283 refine_bit, child_bit | refine_bit, MBEDGE, child_edges);
284 // set integration rule, such that integration points are not on flipped edge
285 CHKERR setDGSetIntegrationPoints<SPACE_DIM>(
286 fe_child_ptr->setRuleHook, [](int, int, int p) { return 2 * p; },
287 boost::make_shared<Range>(child_edges));
288 pip.push_back(op_this_child);
289 return fe_child_ptr;
290 };
291
292 // Use field evaluator to calculate field values on parent bitref level,
293 // i.e. elements which were flipped.
294 auto get_field_eval_op = [&](auto fe_child_ptr) {
295 auto field_eval_ptr = mField.getInterface<FieldEvaluatorInterface>();
296
297 // Get pointer of FieldEvaluator data. Note finite element and method
298 // set integration points is destroyed when this pointer is releases
299 auto field_eval_data = field_eval_ptr->getData<DomainEle>();
300 // Build tree for particular element
301 CHKERR field_eval_ptr->buildTree<SPACE_DIM>(
302 field_eval_data, simpleInterface->getDomainFEName(), parent_bit,
303 parent_bit | child_bit);
304
305 // You can add more fields here
306 auto data_U_ptr = boost::make_shared<MatrixDouble>();
307 auto eval_data_U_ptr = boost::make_shared<MatrixDouble>();
308 auto data_S_ptr = boost::make_shared<MatrixDouble>();
309 auto eval_data_S_ptr = boost::make_shared<MatrixDouble>();
310
311
312 if (auto fe_eval_ptr = field_eval_data->feMethodPtr) {
313 fe_eval_ptr->getRuleHook = [] (int, int, int p) { return -1; };
314 fe_eval_ptr->getOpPtrVector().push_back(
316 eval_data_U_ptr));
317 fe_eval_ptr->getOpPtrVector().push_back(
319 eval_data_S_ptr));
320
321 auto op_test = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
322 op_test->doWorkRhsHook =
323 [](DataOperator *base_op_ptr, int side, EntityType type,
326
327 auto op_ptr = static_cast<DomainEleOp *>(base_op_ptr);
328 MOFEM_LOG_CHANNEL("SELF");
329 MOFEM_LOG("SELF", Sev::noisy)
330 << "Field evaluator method pointer is valid";
331 MOFEM_LOG("SELF", Sev::noisy)
332 << op_ptr->getGaussPts();
333 MOFEM_LOG("SELF", Sev::noisy)
334 << "Loop size " << op_ptr->getPtrFE()->getLoopSize();
335 MOFEM_LOG("SELF", Sev::noisy)
336 << "Coords at gauss pts: " << op_ptr->getCoordsAtGaussPts();
337
339 };
340
341 fe_eval_ptr->getOpPtrVector().push_back(op_test);
342
343 } else {
345 "Field evaluator method pointer is expired");
346 }
347
348 auto op_ptr = field_eval_ptr->getDataOperator<SPACE_DIM>(
349 {{eval_data_U_ptr, data_U_ptr}, {eval_data_S_ptr, data_S_ptr}},
350 simpleInterface->getDomainFEName(), field_eval_data, 0,
351 mField.get_comm_size(), parent_bit, parent_bit | child_bit, MF_EXIST,
352 QUIET);
353
354 fe_child_ptr->getOpPtrVector().push_back(op_ptr);
355 return std::make_pair(
356
357 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
358 {FIELD_NAME_U, data_U_ptr}},
359
360 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
361 {FIELD_NAME_S, data_S_ptr}}
362
363 );
364
365 };
366
367 // calculate coefficients on child (flipped) elements
368 auto dg_projection_base = [&](auto fe_child_ptr, auto vec_data_ptr, auto mat,
369 auto vec) {
371 constexpr int projection_order = order;
372 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
373 auto mass_ptr = boost::make_shared<MatrixDouble>();
374 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
375
376 // project L2 (directly from coefficients)
377 for (auto &p : vec_data_ptr.first) {
378 auto field_name = p.first;
379 auto data_ptr = p.second;
380
381 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
382 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
383 L2));
384 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
385 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
386 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
387
388 // next two lines are only for testing if projection is correct, they are not
389 // essential
390 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
391 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
392 Sev::noisy));
393 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
394
395 // set coefficients to flipped element
396 auto op_set_coeffs = new DomainEleOp(field_name, DomainEleOp::OPROW);
397 op_set_coeffs->doWorkRhsHook =
398 [coeffs_ptr](DataOperator *base_op_ptr, int side, EntityType type,
401 auto field_ents = data.getFieldEntities();
402 auto nb_dofs = data.getIndices().size();
403 if (!field_ents.size())
405 if (auto e_ptr = field_ents[0]) {
406 auto field_ent_data = e_ptr->getEntFieldData();
407 std::copy(coeffs_ptr->data().data(),
408 coeffs_ptr->data().data() + nb_dofs,
409 field_ent_data.begin());
410 }
412 };
413 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
414 }
415
416 // project H1 (via coefficients)
417 for (auto &p : vec_data_ptr.second) {
418 auto field_name = p.first;
419 auto data_ptr = p.second;
420
421 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
422 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
423 L2));
424 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
425 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
426 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
427
428 // next two lines are only for testing if projection is correct, they are not
429 // essential
430 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
431 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
432 Sev::noisy));
433 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
434
435 // assemble to global matrix, since this is H1 (you will do the shame for Hcurl of Hdiv)
436 auto beta = [](const double, const double, const double) { return 1; };
437 fe_child_ptr->getOpPtrVector().push_back(
440 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, FIELD_DIM>;
441 fe_child_ptr->getOpPtrVector().push_back(
442 new OpVec(FIELD_NAME_S, data_ptr, beta));
443 }
444
446 };
447
448 auto dm = simple->getDM();
449 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
450 CHKERR DMMoFEMCreateSubDM(sub_dm, dm, "SUB");
451 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
453
454 // get only refinement bit DOFs
455 auto ref_entities_ptr = boost::make_shared<Range>();
456 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
457 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
458 Range verts;
459 CHKERR mField.get_moab().get_connectivity(*ref_entities_ptr, verts, true);
460 ref_entities_ptr->merge(verts);
461
462 CHKERR DMMoFEMAddSubFieldRow(sub_dm, FIELD_NAME_S, ref_entities_ptr);
463 CHKERR DMMoFEMAddSubFieldCol(sub_dm, FIELD_NAME_S, ref_entities_ptr);
464 CHKERR DMSetUp(sub_dm);
465
466 auto mat = createDMMatrix(sub_dm);
467 auto vec = createDMVector(sub_dm);
468
469 // create child operator, and fe_child_ptr element in it
470 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
471 // run dg projection, note that get_field_eval_op,
472 // pass data_ptr values used to project and calculate coefficients
473 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
474 vec);
475
476 // That is to test, if projection works, and coefficients are set in correctly
477 // Note: FIELD_S is not tested, it is in H1, so we have to solve KSP problem first
478 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
479 pipeline_mng->getOpDomainRhsPipeline().push_back(
481 test_U_data_ptr));
482 pipeline_mng->getOpDomainRhsPipeline().push_back(
483 new OpError(test_U_data_ptr, refine_bit, BitRefLevel().set()));
484
485 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<DomainEle>();
486 fe_rhs->ksp_A = mat;
487 fe_rhs->ksp_B = mat;
488 fe_rhs->ksp_f = vec;
489 fe_rhs->data_ctx =
491 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
492
493 CHKERR VecAssemblyBegin(vec);
494 CHKERR VecAssemblyEnd(vec);
495 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
496 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
497 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
498 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
499
500 auto ksp = createKSP(mField.get_comm());
501 CHKERR KSPSetOperators(ksp, mat, mat);
502 CHKERR KSPSetFromOptions(ksp);
503
504 auto sol = createDMVector(sub_dm);
505 CHKERR KSPSolve(ksp, vec, sol);
507 ksp, "DG projection result");
508 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
509 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
510 CHKERR DMoFEMMeshToLocalVector(sub_dm, sol, INSERT_VALUES, SCATTER_REVERSE);
511
512 pipeline_mng->getOpDomainRhsPipeline().clear();
513 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
514 pipeline_mng->getOpDomainRhsPipeline().push_back(
516 test_S_data_ptr));
517 pipeline_mng->getOpDomainRhsPipeline().push_back(
518 new OpError(test_S_data_ptr, refine_bit, BitRefLevel().set()));
519
521}
522//! [Project results]
523
524//! [Output results]
527
528 auto pipeline_mng = mField.getInterface<PipelineManager>();
529
530 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(mField);
532 post_proc_fe->getOpPtrVector(), {H1});
533
534 auto u_ptr = boost::make_shared<VectorDouble>();
535 post_proc_fe->getOpPtrVector().push_back(
537 auto s_ptr = boost::make_shared<VectorDouble>();
538 post_proc_fe->getOpPtrVector().push_back(
540
541 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
542 post_proc_fe->getOpPtrVector().push_back(
544 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
545 post_proc_fe->getOpPtrVector().push_back(
547
548
550
551 post_proc_fe->getOpPtrVector().push_back(
552
553 new OpPPMap(
554 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
555
556 OpPPMap::DataMapVec{{FIELD_NAME_U, u_ptr}, {FIELD_NAME_S, s_ptr}},
557
559
560 {"GRAD_" + std::string(FIELD_NAME_U), grad_u_ptr},
561 {"GRAD_" + std::string(FIELD_NAME_S), grad_s_ptr}
562
563 },
564
566
568
569 )
570
571 );
572
573 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
574 CHKERR pipeline_mng->loopFiniteElementsPostProc();
575 CHKERR post_proc_fe->writeFile(file_name);
576
578}
579//! [Output results]
580
581//! [Edge flips]
583 BitRefLevel child_bit) {
585
586 moab::Interface &moab = mField.get_moab();
587
588 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
590
591 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
593 const EntityHandle *conn;
594 int num_nodes;
595 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
596 std::copy(conn, conn + num_nodes, conn_cpy);
598 };
599
600 auto get_tri_normals = [&](auto &conn) {
601 std::array<double, 18> coords;
602 CHKERR moab.get_coords(conn.data(), 6, coords.data());
603 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
604 for (int t = 0; t != 2; ++t) {
605 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
606 }
607 return tri_normals;
608 };
609
610 auto test_flip = [&](auto &&t_normals) {
611 FTENSOR_INDEX(3, i);
612 if (t_normals[0](i) * t_normals[1](i) <
613 std::numeric_limits<float>::epsilon())
614 return false;
615 return true;
616 };
617
618 std::array<EntityHandle, 6> adj_conn;
619 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
620 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
621 std::array<EntityHandle, 2> edge_conn;
622 CHKERR get_conn(edge, edge_conn.data());
623 std::array<EntityHandle, 2> new_edge_conn;
624
625 int j = 1;
626 for (int i = 0; i != 6; ++i) {
627 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
628 new_edge_conn[j] = adj_conn[i];
629 --j;
630 }
631 }
632
633 auto &new_conn = adj_conn; //< just alias this
634 for (int t = 0; t != 2; ++t) {
635 for (int i = 0; i != 3; ++i) {
636 if (
637
638 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
639 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
640
641 ||
642
643 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
644 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
645
646 ) {
647 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
648 break;
649 }
650 }
651 }
652
653 if (test_flip(get_tri_normals(new_conn))) {
654 for (int t = 0; t != 2; ++t) {
655 Range rtri;
656 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
657 false, rtri);
658 if (!rtri.size()) {
659 EntityHandle tri;
660 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
661 tri);
662 new_tris.insert(tri);
663 } else {
664#ifndef NDEBUG
665 if (rtri.size() != 1) {
666 MOFEM_LOG("SELF", Sev::error)
667 << "Multiple tries created during edge flip for edge " << edge
668 << " adjacent faces " << std::endl
669 << rtri;
670 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
671 "Multiple tries created during edge flip");
672 }
673#endif // NDEBUG
674 new_tris.merge(rtri);
675 }
676 }
677
678 Range new_edges;
679 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
680 moab::Interface::UNION);
681 } else {
682
683 MOFEM_LOG_CHANNEL("SELF");
684 MOFEM_LOG("SELF", Sev::warning)
685 << "Edge flip rejected for edge " << edge << " adjacent faces "
686 << adj_faces;
687 }
688
690 };
691
692 Range tris;
693 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
694 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
695 parent_bit, BitRefLevel().set(), tris);
696 Skinner skin(&moab);
697 Range skin_edges;
698 CHKERR skin.find_skin(0, tris, false, skin_edges);
699
700 Range edges;
701 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
702 edges = subtract(edges, skin_edges);
703 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
704 parent_bit, BitRefLevel().set(), edges);
705
706 Range new_tris, flipped_tris, forbidden_tris;
707 int flip_count = 0;
708 for (auto edge : edges) {
709 Range adjacent_tris;
710 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
711
712 adjacent_tris = intersect(adjacent_tris, tris);
713 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
714 if (adjacent_tris.size() == 2) {
715
716#ifndef NDEBUG
717 int side_number0, sense0, offset0;
718 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
719 sense0, offset0);
720 int side_number1, sense1, offset1;
721 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
722 sense1, offset1);
723 if (sense0 * sense1 > 0)
724 SETERRQ(
725 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
726 "Cannot flip edge with same orientation in both adjacent faces");
727#endif // NDEBUG
728
729 Range new_flipped_tris;
730 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
731 if (new_flipped_tris.size()) {
732 flipped_tris.merge(adjacent_tris);
733 forbidden_tris.merge(adjacent_tris);
734 new_tris.merge(new_flipped_tris);
735
736#ifndef NDEBUG
737 CHKERR save_range(moab,
738 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
739 adjacent_tris);
741 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
742 new_flipped_tris);
743
744#endif // NDEBUG
745
746 ++flip_count;
747 }
748 }
749 }
750
751 Range all_tris;
752 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
753 Range not_flipped_tris = subtract(all_tris, flipped_tris);
754
755 MOFEM_LOG("SELF", Sev::noisy)
756 << "Flipped " << flip_count << " edges with two adjacent faces.";
757 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
758 child_bit);
759 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
760 child_bit);
761 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
762 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
763 "");
764
766}
767//! [Edge flips]
768
769//! [Refine skin]
771 BitRefLevel child_bit) {
773
774 moab::Interface &moab = mField.get_moab();
775 Range tris;
776 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
777 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
778 parent_bit, BitRefLevel().set(), tris);
779
780 Skinner skin(&moab);
781 Range skin_edges;
782 CHKERR skin.find_skin(0, tris, false, skin_edges);
783
784 auto refine = mField.getInterface<MeshRefinement>();
785 CHKERR refine->addVerticesInTheMiddleOfEdges(skin_edges, child_bit);
786#ifndef NDEBUG
787 auto debug = true;
788#else
789 auto debug = false;
790#endif
791 CHKERR refine->refineTris(tris, child_bit, QUIET, debug);
792
793 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
794 child_bit, BitRefLevel().set(), "edge_flips_after_refinement.vtk", "VTK",
795 "");
796
798}
799//! [Refine skin]
800
801//! [Re-setup problem after mesh modification
808//! [Re-setup problem after mesh modification]
809
810int main(int argc, char *argv[]) {
811
812 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
813
814 try {
815
816 //! [Register MoFEM discrete manager in PETSc]
817 DMType dm_name = "DMMOFEM";
818 CHKERR DMRegister_MoFEM(dm_name);
819 //! [Register MoFEM discrete manager in PETSc]
820
821 //! [Create MoAB]
822 moab::Core mb_instance;
823 moab::Interface &moab = mb_instance;
824 //! [Create MoAB]
825
826 //! [Create MoFEM]
827 MoFEM::Core core(moab);
828 MoFEM::Interface &m_field = core;
829 //! [Create MoFEM]
830
831 //! [Execute DG Projection Test]
832 Example ex(m_field);
833 CHKERR ex.runProblem();
834 //! [Execute DG Projection Test]
835 }
837
839}
SmartPetscObj< KSP > ksp
std::string type
#define FTENSOR_INDEX(DIM, I)
std::string name
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
static const bool debug
@ F
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle
Domain finite elements.
Definition gradient.cpp:45
constexpr int SPACE_DIM
[Define dimension]
Definition gradient.cpp:19
DomainEle::UserDataOperator DomainEleOp
Domain element operators.
Definition gradient.cpp:48
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:244
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:517
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:479
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:267
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:543
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:1250
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:309
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1207
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)
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:217
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:227
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