v0.15.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/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 =
274 new OpLoopThis<DomainEle>(mField, simple->getDomainFEName(), refine_bit,
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.lock()) {
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,
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 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
390
391 // set coefficients to flipped element
392 auto op_set_coeffs = new DomainEleOp(field_name, DomainEleOp::OPROW);
393 op_set_coeffs->doWorkRhsHook =
394 [coeffs_ptr](DataOperator *base_op_ptr, int side, EntityType type,
397 auto field_ents = data.getFieldEntities();
398 auto nb_dofs = data.getIndices().size();
399 if (!field_ents.size())
401 if (auto e_ptr = field_ents[0]) {
402 auto field_ent_data = e_ptr->getEntFieldData();
403 std::copy(coeffs_ptr->data().data(),
404 coeffs_ptr->data().data() + nb_dofs,
405 field_ent_data.begin());
406 }
408 };
409 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
410 }
411
412 // project H1 (via coefficients)
413 for (auto &p : vec_data_ptr.second) {
414 auto field_name = p.first;
415 auto data_ptr = p.second;
416
417 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
418 projection_order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
419 L2));
420 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
421 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
423
424 // next two lines are only for testing if projection is correct, they are not
425 // essential
426 fe_child_ptr->getOpPtrVector().push_back(new OpDGProjectionEvaluation(
427 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2));
428 fe_child_ptr->getOpPtrVector().push_back(new OpError(data_ptr));
429
430 // assemble to global matrix, since this is H1 (you will do the shame for Hcurl of Hdiv)
431 auto beta = [](const double, const double, const double) { return 1; };
432 fe_child_ptr->getOpPtrVector().push_back(
435 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, 1>;
436 fe_child_ptr->getOpPtrVector().push_back(
437 new OpVec(FIELD_NAME_S, data_ptr, beta));
438 }
439
441 };
442
443 auto dm = simple->getDM();
444 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
445 CHKERR DMMoFEMCreateSubDM(sub_dm, dm, "SUB");
446 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
447 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
448
449 // get only refinement bit DOFs
450 auto ref_entities_ptr = boost::make_shared<Range>();
451 CHKERR mField.getInterface<BitRefManager>()->getEntitiesByRefLevel(
452 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
453 Range verts;
454 CHKERR mField.get_moab().get_connectivity(*ref_entities_ptr, verts, true);
455 ref_entities_ptr->merge(verts);
456
457 CHKERR DMMoFEMAddSubFieldRow(sub_dm, FIELD_NAME_S, ref_entities_ptr);
458 CHKERR DMMoFEMAddSubFieldCol(sub_dm, FIELD_NAME_S, ref_entities_ptr);
459 CHKERR DMSetUp(sub_dm);
460
461 auto mat = createDMMatrix(sub_dm);
462 auto vec = createDMVector(sub_dm);
463
464 // create child operator, and fe_child_ptr element in it
465 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
466 // run dg projection, note that get_field_eval_op,
467 // pass data_ptr values used to project and calculate coefficients
468 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
469 vec);
470
471 // That is to test, if projection works, and coefficients are set in correctly
472 // Note: FIELD_S is not tested, it is in H1, so we have to solve KSP problem first
473 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
474 pipeline_mng->getOpDomainRhsPipeline().push_back(
476 test_U_data_ptr));
477 pipeline_mng->getOpDomainRhsPipeline().push_back(
478 new OpError(test_U_data_ptr, refine_bit, BitRefLevel().set()));
479
480 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<DomainEle>();
481 fe_rhs->ksp_A = mat;
482 fe_rhs->ksp_B = mat;
483 fe_rhs->ksp_f = vec;
484 fe_rhs->data_ctx =
486 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
487
488 CHKERR VecAssemblyBegin(vec);
489 CHKERR VecAssemblyEnd(vec);
490 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
491 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
492 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
493 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
494
495 auto ksp = createKSP(mField.get_comm());
496 CHKERR KSPSetOperators(ksp, mat, mat);
497 CHKERR KSPSetFromOptions(ksp);
498
499 auto sol = createDMVector(sub_dm);
500 CHKERR KSPSolve(ksp, vec, sol);
501 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
502 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
503 CHKERR DMoFEMMeshToLocalVector(sub_dm, sol, INSERT_VALUES, SCATTER_REVERSE);
504
505 pipeline_mng->getOpDomainRhsPipeline().clear();
506 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
507 pipeline_mng->getOpDomainRhsPipeline().push_back(
509 test_S_data_ptr));
510 pipeline_mng->getOpDomainRhsPipeline().push_back(
511 new OpError(test_S_data_ptr, refine_bit, BitRefLevel().set()));
512
514}
515//! [Project results]
516
517//! [Output results]
520
521 auto pipeline_mng = mField.getInterface<PipelineManager>();
522 pipeline_mng->getDomainLhsFE().reset();
523
524 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(mField);
526 post_proc_fe->getOpPtrVector(), {H1});
527
528 auto u_ptr = boost::make_shared<VectorDouble>();
529 post_proc_fe->getOpPtrVector().push_back(
531 auto s_ptr = boost::make_shared<VectorDouble>();
532 post_proc_fe->getOpPtrVector().push_back(
534
535 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
536 post_proc_fe->getOpPtrVector().push_back(
538 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
539 post_proc_fe->getOpPtrVector().push_back(
541
542
544
545 post_proc_fe->getOpPtrVector().push_back(
546
547 new OpPPMap(
548 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
549
550 OpPPMap::DataMapVec{{FIELD_NAME_U, u_ptr}, {FIELD_NAME_S, s_ptr}},
551
553
554 {"GRAD_" + std::string(FIELD_NAME_U), grad_u_ptr},
555 {"GRAD_" + std::string(FIELD_NAME_S), grad_s_ptr}
556
557 },
558
560
562
563 )
564
565 );
566
567 pipeline_mng->getDomainRhsFE() = post_proc_fe;
568 CHKERR pipeline_mng->loopFiniteElements();
569 CHKERR post_proc_fe->writeFile(file_name);
570
572}
573//! [Output results]
574
575//! [Edge flips]
577 BitRefLevel child_bit) {
579
580 moab::Interface &moab = mField.get_moab();
581
582 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
584
585 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
587 const EntityHandle *conn;
588 int num_nodes;
589 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
590 std::copy(conn, conn + num_nodes, conn_cpy);
592 };
593
594 auto get_tri_normals = [&](auto &conn) {
595 std::array<double, 18> coords;
596 CHKERR moab.get_coords(conn.data(), 6, coords.data());
597 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
598 for (int t = 0; t != 2; ++t) {
599 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
600 }
601 return tri_normals;
602 };
603
604 auto test_flip = [&](auto &&t_normals) {
605 FTENSOR_INDEX(3, i);
606 if (t_normals[0](i) * t_normals[1](i) <
607 std::numeric_limits<float>::epsilon())
608 return false;
609 return true;
610 };
611
612 std::array<EntityHandle, 6> adj_conn;
613 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
614 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
615 std::array<EntityHandle, 2> edge_conn;
616 CHKERR get_conn(edge, edge_conn.data());
617 std::array<EntityHandle, 2> new_edge_conn;
618
619 int j = 1;
620 for (int i = 0; i != 6; ++i) {
621 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
622 new_edge_conn[j] = adj_conn[i];
623 --j;
624 }
625 }
626
627 auto &new_conn = adj_conn; //< just alias this
628 for (int t = 0; t != 2; ++t) {
629 for (int i = 0; i != 3; ++i) {
630 if (
631
632 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
633 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
634
635 ||
636
637 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
638 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
639
640 ) {
641 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
642 break;
643 }
644 }
645 }
646
647 if (test_flip(get_tri_normals(new_conn))) {
648 for (int t = 0; t != 2; ++t) {
649 Range rtri;
650 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
651 false, rtri);
652 if (!rtri.size()) {
653 EntityHandle tri;
654 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
655 tri);
656 new_tris.insert(tri);
657 } else {
658#ifndef NDEBUG
659 if (rtri.size() != 1) {
660 MOFEM_LOG("SELF", Sev::error)
661 << "Multiple tries created during edge flip for edge " << edge
662 << " adjacent faces " << std::endl
663 << rtri;
664 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
665 "Multiple tries created during edge flip");
666 }
667#endif // NDEBUG
668 new_tris.merge(rtri);
669 }
670 }
671
672 Range new_edges;
673 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
674 moab::Interface::UNION);
675 } else {
676
677 MOFEM_LOG_CHANNEL("SELF");
678 MOFEM_LOG("SELF", Sev::warning)
679 << "Edge flip rejected for edge " << edge << " adjacent faces "
680 << adj_faces;
681 }
682
684 };
685
686 Range tris;
687 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
688 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
689 parent_bit, BitRefLevel().set(), tris);
690 Skinner skin(&moab);
691 Range skin_edges;
692 CHKERR skin.find_skin(0, tris, false, skin_edges);
693
694 Range edges;
695 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
696 edges = subtract(edges, skin_edges);
697 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
698 parent_bit, BitRefLevel().set(), edges);
699
700 Range new_tris, flipped_tris, forbidden_tris;
701 int flip_count = 0;
702 for (auto edge : edges) {
703 Range adjacent_tris;
704 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
705
706 adjacent_tris = intersect(adjacent_tris, tris);
707 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
708 if (adjacent_tris.size() == 2) {
709
710#ifndef NDEBUG
711 int side_number0, sense0, offset0;
712 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
713 sense0, offset0);
714 int side_number1, sense1, offset1;
715 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
716 sense1, offset1);
717 if (sense0 * sense1 > 0)
718 SETERRQ(
719 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
720 "Cannot flip edge with same orientation in both adjacent faces");
721#endif // NDEBUG
722
723 Range new_flipped_tris;
724 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
725 if (new_flipped_tris.size()) {
726 flipped_tris.merge(adjacent_tris);
727 forbidden_tris.merge(adjacent_tris);
728 new_tris.merge(new_flipped_tris);
729
730#ifndef NDEBUG
731 CHKERR save_range(moab,
732 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
733 adjacent_tris);
735 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
736 new_flipped_tris);
737
738#endif // NDEBUG
739
740 ++flip_count;
741 }
742 }
743 }
744
745 Range all_tris;
746 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
747 Range not_flipped_tris = subtract(all_tris, flipped_tris);
748
749 MOFEM_LOG("SELF", Sev::noisy)
750 << "Flipped " << flip_count << " edges with two adjacent faces.";
751 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
752 child_bit);
753 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
754 child_bit);
755 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
756 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
757 "");
758
760}
761//! [Edge flips]
762
763//! [Refine skin]
765 BitRefLevel child_bit) {
767
768 moab::Interface &moab = mField.get_moab();
769 Range tris;
770 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
771 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
772 parent_bit, BitRefLevel().set(), tris);
773
774 Skinner skin(&moab);
775 Range skin_edges;
776 CHKERR skin.find_skin(0, tris, false, skin_edges);
777
778 auto refine = mField.getInterface<MeshRefinement>();
779 CHKERR refine->addVerticesInTheMiddleOfEdges(skin_edges, child_bit);
780#ifndef NDEBUG
781 auto debug = true;
782#else
783 auto debug = false;
784#endif
785 CHKERR refine->refineTris(tris, child_bit, QUIET, debug);
786
787 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
788 child_bit, BitRefLevel().set(), "edge_flips_after_refinement.vtk", "VTK",
789 "");
790
792}
793//! [Refine skin]
794
795//! [Re-setup problem after mesh modification
802//! [Re-setup problem after mesh modification]
803
804int main(int argc, char *argv[]) {
805
806 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
807
808 try {
809
810 //! [Register MoFEM discrete manager in PETSc]
811 DMType dm_name = "DMMOFEM";
812 CHKERR DMRegister_MoFEM(dm_name);
813 //! [Register MoFEM discrete manager in PETSc]
814
815 //! [Create MoAB]
816 moab::Core mb_instance;
817 moab::Interface &moab = mb_instance;
818 //! [Create MoAB]
819
820 //! [Create MoFEM]
821 MoFEM::Core core(moab);
822 MoFEM::Interface &m_field = core;
823 //! [Create MoFEM]
824
825 //! [Execute DG Projection Test]
826 Example ex(m_field);
827 CHKERR ex.runProblem();
828 //! [Execute DG Projection Test]
829 }
831
833}
#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
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
constexpr int FIELD_DIM
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
Order displacement.
@ 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 DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:238
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
auto createDMVector(DM dm)
Get smart vector from DM.
Definition DMMoFEM.hpp:1234
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
Definition DMMoFEM.cpp:280
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1191
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
constexpr 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:8
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]
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]
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:82
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:72
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:118
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 double precision vector field values calculation.
Execute "this" element in the operator.
Post post-proc data at points from hash maps.
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
std::map< std::string, boost::shared_ptr< VectorDouble > > DataMapVec
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:762
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:800
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:736
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