v0.16.0
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);
245
246 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
247 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
248
249 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
250
252}
253//! [Solve]
254
255//! [Project results]
257 BitRefLevel child_bit,
258 BitRefLevel refine_bit) {
261 auto pipeline_mng = mField.getInterface<PipelineManager>();
262
263 pipeline_mng->getDomainLhsFE().reset();
264 pipeline_mng->getDomainRhsFE().reset();
265 pipeline_mng->getOpDomainRhsPipeline().clear();
266
267 auto rule = [](int, int, int p) -> int { return 2 * p; };
268 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
269
270 // OpLoopThis, is child operator, and is use to execute
271 // fe_child_ptr, only on bit ref level and mask
272 // for child elements
273 auto get_child_op = [&](auto &pip) {
274 auto op_this_child =
275 new OpLoopThis<DomainEle>(mField, simple->getDomainFEName(), refine_bit,
276 child_bit | refine_bit, Sev::noisy);
277 auto fe_child_ptr = op_this_child->getThisFEPtr();
278 fe_child_ptr->getRuleHook = [] (int, int, int p) { return -1; };
279 Range child_edges;
280 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByTypeAndRefLevel(
281 refine_bit, child_bit | refine_bit, MBEDGE, child_edges);
282 // set integration rule, such that integration points are not on flipped edge
283 CHKERR setDGSetIntegrationPoints<SPACE_DIM>(
284 fe_child_ptr->setRuleHook, [](int, int, int p) { return 2 * p; },
285 boost::make_shared<Range>(child_edges));
286 pip.push_back(op_this_child);
287 return fe_child_ptr;
288 };
289
290 // Use field evaluator to calculate field values on parent bitref level,
291 // i.e. elements which were flipped.
292 auto get_field_eval_op = [&](auto fe_child_ptr) {
293 auto field_eval_ptr = mField.getInterface<FieldEvaluatorInterface>();
294
295 // Get pointer of FieldEvaluator data. Note finite element and method
296 // set integration points is destroyed when this pointer is releases
297 auto field_eval_data = field_eval_ptr->getData<DomainEle>();
298 // Build tree for particular element
299 CHKERR field_eval_ptr->buildTree<SPACE_DIM>(
300 field_eval_data, simpleInterface->getDomainFEName(), parent_bit,
301 parent_bit | child_bit);
302
303 // You can add more fields here
304 auto data_U_ptr = boost::make_shared<MatrixDouble>();
305 auto eval_data_U_ptr = boost::make_shared<MatrixDouble>();
306 auto data_S_ptr = boost::make_shared<MatrixDouble>();
307 auto eval_data_S_ptr = boost::make_shared<MatrixDouble>();
308
309
310 if (auto fe_eval_ptr = field_eval_data->feMethodPtr) {
311 fe_eval_ptr->getRuleHook = [] (int, int, int p) { return -1; };
312 fe_eval_ptr->getOpPtrVector().push_back(
314 eval_data_U_ptr));
315 fe_eval_ptr->getOpPtrVector().push_back(
317 eval_data_S_ptr));
318
319 auto op_test = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
320 op_test->doWorkRhsHook =
321 [](DataOperator *base_op_ptr, int side, EntityType type,
324
325 auto op_ptr = static_cast<DomainEleOp *>(base_op_ptr);
326 MOFEM_LOG_CHANNEL("SELF");
327 MOFEM_LOG("SELF", Sev::noisy)
328 << "Field evaluator method pointer is valid";
329 MOFEM_LOG("SELF", Sev::noisy)
330 << op_ptr->getGaussPts();
331 MOFEM_LOG("SELF", Sev::noisy)
332 << "Loop size " << op_ptr->getPtrFE()->getLoopSize();
333 MOFEM_LOG("SELF", Sev::noisy)
334 << "Coords at gauss pts: " << op_ptr->getCoordsAtGaussPts();
335
337 };
338
339 fe_eval_ptr->getOpPtrVector().push_back(op_test);
340
341 } else {
343 "Field evaluator method pointer is expired");
344 }
345
346 auto op_ptr = field_eval_ptr->getDataOperator<SPACE_DIM>(
347 {{eval_data_U_ptr, data_U_ptr}, {eval_data_S_ptr, data_S_ptr}},
348 simpleInterface->getDomainFEName(), field_eval_data, 0,
349 mField.get_comm_size(), parent_bit, parent_bit | child_bit, MF_EXIST,
350 QUIET);
351
352 fe_child_ptr->getOpPtrVector().push_back(op_ptr);
353 return std::make_pair(
354
355 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
356 {FIELD_NAME_U, data_U_ptr}},
357
358 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
359 {FIELD_NAME_S, data_S_ptr}}
360
361 );
362
363 };
364
365 // calculate coefficients on child (flipped) elements
366 auto dg_projection_base = [&](auto fe_child_ptr, auto vec_data_ptr, auto mat,
367 auto vec) {
369 constexpr int projection_order = order;
370 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
371 auto mass_ptr = boost::make_shared<MatrixDouble>();
372 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
373
374 // project L2 (directly from coefficients)
375 for (auto &p : vec_data_ptr.first) {
376 auto field_name = p.first;
377 auto data_ptr = p.second;
378
379 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
380 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
381 L2));
382 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
383 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
384 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
385
386 // next two lines are only for testing if projection is correct, they are not
387 // essential
388 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
389 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
390 Sev::noisy));
391 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
392
393 // set coefficients to flipped element
394 auto op_set_coeffs = new DomainEleOp(field_name, DomainEleOp::OPROW);
395 op_set_coeffs->doWorkRhsHook =
396 [coeffs_ptr](DataOperator *base_op_ptr, int side, EntityType type,
399 auto field_ents = data.getFieldEntities();
400 auto nb_dofs = data.getIndices().size();
401 if (!field_ents.size())
403 if (auto e_ptr = field_ents[0]) {
404 auto field_ent_data = e_ptr->getEntFieldData();
405 std::copy(coeffs_ptr->data().data(),
406 coeffs_ptr->data().data() + nb_dofs,
407 field_ent_data.begin());
408 }
410 };
411 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
412 }
413
414 // project H1 (via coefficients)
415 for (auto &p : vec_data_ptr.second) {
416 auto field_name = p.first;
417 auto data_ptr = p.second;
418
419 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
420 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
421 L2));
422 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
423 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
424 AINSWORTH_LEGENDRE_BASE, L2, Sev::noisy));
425
426 // next two lines are only for testing if projection is correct, they are not
427 // essential
428 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
429 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2,
430 Sev::noisy));
431 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
432
433 // assemble to global matrix, since this is H1 (you will do the shame for Hcurl of Hdiv)
434 auto beta = [](const double, const double, const double) { return 1; };
435 fe_child_ptr->getOpPtrVector().push_back(
438 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, FIELD_DIM>;
439 fe_child_ptr->getOpPtrVector().push_back(
440 new OpVec(FIELD_NAME_S, data_ptr, beta));
441 }
442
444 };
445
446 auto dm = simple->getDM();
447 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
448 CHKERR DMMoFEMCreateSubDM(sub_dm, dm, "SUB");
449 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
450 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
451
452 // get only refinement bit DOFs
453 auto ref_entities_ptr = boost::make_shared<Range>();
454 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
455 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
456 Range verts;
457 CHKERR mField.get_moab().get_connectivity(*ref_entities_ptr, verts, true);
458 ref_entities_ptr->merge(verts);
459
460 CHKERR DMMoFEMAddSubFieldRow(sub_dm, FIELD_NAME_S, ref_entities_ptr);
461 CHKERR DMMoFEMAddSubFieldCol(sub_dm, FIELD_NAME_S, ref_entities_ptr);
462 CHKERR DMSetUp(sub_dm);
463
464 auto mat = createDMMatrix(sub_dm);
465 auto vec = createDMVector(sub_dm);
466
467 // create child operator, and fe_child_ptr element in it
468 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
469 // run dg projection, note that get_field_eval_op,
470 // pass data_ptr values used to project and calculate coefficients
471 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
472 vec);
473
474 // That is to test, if projection works, and coefficients are set in correctly
475 // Note: FIELD_S is not tested, it is in H1, so we have to solve KSP problem first
476 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
477 pipeline_mng->getOpDomainRhsPipeline().push_back(
479 test_U_data_ptr));
480 pipeline_mng->getOpDomainRhsPipeline().push_back(
481 new OpError(test_U_data_ptr, refine_bit, BitRefLevel().set()));
482
483 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<DomainEle>();
484 fe_rhs->ksp_A = mat;
485 fe_rhs->ksp_B = mat;
486 fe_rhs->ksp_f = vec;
487 fe_rhs->data_ctx =
489 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
490
491 CHKERR VecAssemblyBegin(vec);
492 CHKERR VecAssemblyEnd(vec);
493 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
494 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
495 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
496 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
497
498 auto ksp = createKSP(mField.get_comm());
499 CHKERR KSPSetOperators(ksp, mat, mat);
500 CHKERR KSPSetFromOptions(ksp);
501
502 auto sol = createDMVector(sub_dm);
503 CHKERR KSPSolve(ksp, vec, sol);
504 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
505 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
506 CHKERR DMoFEMMeshToLocalVector(sub_dm, sol, INSERT_VALUES, SCATTER_REVERSE);
507
508 pipeline_mng->getOpDomainRhsPipeline().clear();
509 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
510 pipeline_mng->getOpDomainRhsPipeline().push_back(
512 test_S_data_ptr));
513 pipeline_mng->getOpDomainRhsPipeline().push_back(
514 new OpError(test_S_data_ptr, refine_bit, BitRefLevel().set()));
515
517}
518//! [Project results]
519
520//! [Output results]
523
524 auto pipeline_mng = mField.getInterface<PipelineManager>();
525 pipeline_mng->getDomainLhsFE().reset();
526
527 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(mField);
529 post_proc_fe->getOpPtrVector(), {H1});
530
531 auto u_ptr = boost::make_shared<VectorDouble>();
532 post_proc_fe->getOpPtrVector().push_back(
534 auto s_ptr = boost::make_shared<VectorDouble>();
535 post_proc_fe->getOpPtrVector().push_back(
537
538 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
539 post_proc_fe->getOpPtrVector().push_back(
541 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
542 post_proc_fe->getOpPtrVector().push_back(
544
545
547
548 post_proc_fe->getOpPtrVector().push_back(
549
550 new OpPPMap(
551 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
552
553 OpPPMap::DataMapVec{{FIELD_NAME_U, u_ptr}, {FIELD_NAME_S, s_ptr}},
554
556
557 {"GRAD_" + std::string(FIELD_NAME_U), grad_u_ptr},
558 {"GRAD_" + std::string(FIELD_NAME_S), grad_s_ptr}
559
560 },
561
563
565
566 )
567
568 );
569
570 pipeline_mng->getDomainRhsFE() = post_proc_fe;
571 CHKERR pipeline_mng->loopFiniteElements();
572 CHKERR post_proc_fe->writeFile(file_name);
573
575}
576//! [Output results]
577
578//! [Edge flips]
580 BitRefLevel child_bit) {
582
583 moab::Interface &moab = mField.get_moab();
584
585 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
587
588 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
590 const EntityHandle *conn;
591 int num_nodes;
592 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
593 std::copy(conn, conn + num_nodes, conn_cpy);
595 };
596
597 auto get_tri_normals = [&](auto &conn) {
598 std::array<double, 18> coords;
599 CHKERR moab.get_coords(conn.data(), 6, coords.data());
600 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
601 for (int t = 0; t != 2; ++t) {
602 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
603 }
604 return tri_normals;
605 };
606
607 auto test_flip = [&](auto &&t_normals) {
608 FTENSOR_INDEX(3, i);
609 if (t_normals[0](i) * t_normals[1](i) <
610 std::numeric_limits<float>::epsilon())
611 return false;
612 return true;
613 };
614
615 std::array<EntityHandle, 6> adj_conn;
616 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
617 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
618 std::array<EntityHandle, 2> edge_conn;
619 CHKERR get_conn(edge, edge_conn.data());
620 std::array<EntityHandle, 2> new_edge_conn;
621
622 int j = 1;
623 for (int i = 0; i != 6; ++i) {
624 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
625 new_edge_conn[j] = adj_conn[i];
626 --j;
627 }
628 }
629
630 auto &new_conn = adj_conn; //< just alias this
631 for (int t = 0; t != 2; ++t) {
632 for (int i = 0; i != 3; ++i) {
633 if (
634
635 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
636 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
637
638 ||
639
640 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
641 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
642
643 ) {
644 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
645 break;
646 }
647 }
648 }
649
650 if (test_flip(get_tri_normals(new_conn))) {
651 for (int t = 0; t != 2; ++t) {
652 Range rtri;
653 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
654 false, rtri);
655 if (!rtri.size()) {
656 EntityHandle tri;
657 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
658 tri);
659 new_tris.insert(tri);
660 } else {
661#ifndef NDEBUG
662 if (rtri.size() != 1) {
663 MOFEM_LOG("SELF", Sev::error)
664 << "Multiple tries created during edge flip for edge " << edge
665 << " adjacent faces " << std::endl
666 << rtri;
667 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
668 "Multiple tries created during edge flip");
669 }
670#endif // NDEBUG
671 new_tris.merge(rtri);
672 }
673 }
674
675 Range new_edges;
676 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
677 moab::Interface::UNION);
678 } else {
679
680 MOFEM_LOG_CHANNEL("SELF");
681 MOFEM_LOG("SELF", Sev::warning)
682 << "Edge flip rejected for edge " << edge << " adjacent faces "
683 << adj_faces;
684 }
685
687 };
688
689 Range tris;
690 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
691 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
692 parent_bit, BitRefLevel().set(), tris);
693 Skinner skin(&moab);
694 Range skin_edges;
695 CHKERR skin.find_skin(0, tris, false, skin_edges);
696
697 Range edges;
698 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
699 edges = subtract(edges, skin_edges);
700 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
701 parent_bit, BitRefLevel().set(), edges);
702
703 Range new_tris, flipped_tris, forbidden_tris;
704 int flip_count = 0;
705 for (auto edge : edges) {
706 Range adjacent_tris;
707 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
708
709 adjacent_tris = intersect(adjacent_tris, tris);
710 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
711 if (adjacent_tris.size() == 2) {
712
713#ifndef NDEBUG
714 int side_number0, sense0, offset0;
715 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
716 sense0, offset0);
717 int side_number1, sense1, offset1;
718 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
719 sense1, offset1);
720 if (sense0 * sense1 > 0)
721 SETERRQ(
722 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
723 "Cannot flip edge with same orientation in both adjacent faces");
724#endif // NDEBUG
725
726 Range new_flipped_tris;
727 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
728 if (new_flipped_tris.size()) {
729 flipped_tris.merge(adjacent_tris);
730 forbidden_tris.merge(adjacent_tris);
731 new_tris.merge(new_flipped_tris);
732
733#ifndef NDEBUG
734 CHKERR save_range(moab,
735 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
736 adjacent_tris);
738 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
739 new_flipped_tris);
740
741#endif // NDEBUG
742
743 ++flip_count;
744 }
745 }
746 }
747
748 Range all_tris;
749 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
750 Range not_flipped_tris = subtract(all_tris, flipped_tris);
751
752 MOFEM_LOG("SELF", Sev::noisy)
753 << "Flipped " << flip_count << " edges with two adjacent faces.";
754 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
755 child_bit);
756 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
757 child_bit);
758 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
759 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
760 "");
761
763}
764//! [Edge flips]
765
766//! [Refine skin]
768 BitRefLevel child_bit) {
770
771 moab::Interface &moab = mField.get_moab();
772 Range tris;
773 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
774 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
775 parent_bit, BitRefLevel().set(), tris);
776
777 Skinner skin(&moab);
778 Range skin_edges;
779 CHKERR skin.find_skin(0, tris, false, skin_edges);
780
781 auto refine = mField.getInterface<MeshRefinement>();
782 CHKERR refine->addVerticesInTheMiddleOfEdges(skin_edges, child_bit);
783#ifndef NDEBUG
784 auto debug = true;
785#else
786 auto debug = false;
787#endif
788 CHKERR refine->refineTris(tris, child_bit, QUIET, debug);
789
790 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
791 child_bit, BitRefLevel().set(), "edge_flips_after_refinement.vtk", "VTK",
792 "");
793
795}
796//! [Refine skin]
797
798//! [Re-setup problem after mesh modification
805//! [Re-setup problem after mesh modification]
806
807int main(int argc, char *argv[]) {
808
809 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
810
811 try {
812
813 //! [Register MoFEM discrete manager in PETSc]
814 DMType dm_name = "DMMOFEM";
815 CHKERR DMRegister_MoFEM(dm_name);
816 //! [Register MoFEM discrete manager in PETSc]
817
818 //! [Create MoAB]
819 moab::Core mb_instance;
820 moab::Interface &moab = mb_instance;
821 //! [Create MoAB]
822
823 //! [Create MoFEM]
824 MoFEM::Core core(moab);
825 MoFEM::Interface &m_field = core;
826 //! [Create MoFEM]
827
828 //! [Execute DG Projection Test]
829 Example ex(m_field);
830 CHKERR ex.runProblem();
831 //! [Execute DG Projection Test]
832 }
834
836}
std::string type
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
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
MoFEMErrorCode loopFiniteElements(SmartPetscObj< DM > dm=nullptr)
Iterate finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
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
const double eps
Definition HenckyOps.hpp:13
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: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]
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]
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 > & getDomainRhsFE()
Get domain right-hand side finite element.
boost::shared_ptr< FEMethod > & getDomainLhsFE()
Get domain left-hand side 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