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
526 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(mField);
528 post_proc_fe->getOpPtrVector(), {H1});
529
530 auto u_ptr = boost::make_shared<VectorDouble>();
531 post_proc_fe->getOpPtrVector().push_back(
533 auto s_ptr = boost::make_shared<VectorDouble>();
534 post_proc_fe->getOpPtrVector().push_back(
536
537 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
538 post_proc_fe->getOpPtrVector().push_back(
540 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
541 post_proc_fe->getOpPtrVector().push_back(
543
544
546
547 post_proc_fe->getOpPtrVector().push_back(
548
549 new OpPPMap(
550 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
551
552 OpPPMap::DataMapVec{{FIELD_NAME_U, u_ptr}, {FIELD_NAME_S, s_ptr}},
553
555
556 {"GRAD_" + std::string(FIELD_NAME_U), grad_u_ptr},
557 {"GRAD_" + std::string(FIELD_NAME_S), grad_s_ptr}
558
559 },
560
562
564
565 )
566
567 );
568
569 pipeline_mng->getDomainPostProcFE() = post_proc_fe;
570 CHKERR pipeline_mng->loopFiniteElementsPostProc();
571 CHKERR post_proc_fe->writeFile(file_name);
572
574}
575//! [Output results]
576
577//! [Edge flips]
579 BitRefLevel child_bit) {
581
582 moab::Interface &moab = mField.get_moab();
583
584 auto make_edge_flip = [&](auto edge, auto adj_faces, Range &new_tris) {
586
587 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
589 const EntityHandle *conn;
590 int num_nodes;
591 CHKERR moab.get_connectivity(e, conn, num_nodes, true);
592 std::copy(conn, conn + num_nodes, conn_cpy);
594 };
595
596 auto get_tri_normals = [&](auto &conn) {
597 std::array<double, 18> coords;
598 CHKERR moab.get_coords(conn.data(), 6, coords.data());
599 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
600 for (int t = 0; t != 2; ++t) {
601 CHKERR Tools::getTriNormal(&coords[9 * t], &tri_normals[t](0));
602 }
603 return tri_normals;
604 };
605
606 auto test_flip = [&](auto &&t_normals) {
607 FTENSOR_INDEX(3, i);
608 if (t_normals[0](i) * t_normals[1](i) <
609 std::numeric_limits<float>::epsilon())
610 return false;
611 return true;
612 };
613
614 std::array<EntityHandle, 6> adj_conn;
615 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
616 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
617 std::array<EntityHandle, 2> edge_conn;
618 CHKERR get_conn(edge, edge_conn.data());
619 std::array<EntityHandle, 2> new_edge_conn;
620
621 int j = 1;
622 for (int i = 0; i != 6; ++i) {
623 if (adj_conn[i] != edge_conn[0] && adj_conn[i] != edge_conn[1]) {
624 new_edge_conn[j] = adj_conn[i];
625 --j;
626 }
627 }
628
629 auto &new_conn = adj_conn; //< just alias this
630 for (int t = 0; t != 2; ++t) {
631 for (int i = 0; i != 3; ++i) {
632 if (
633
634 (adj_conn[3 * t + i % 3] == edge_conn[0] &&
635 adj_conn[3 * t + (i + 1) % 3] == edge_conn[1])
636
637 ||
638
639 (adj_conn[3 * t + i % 3] == edge_conn[1] &&
640 adj_conn[3 * t + (i + 1) % 3] == edge_conn[0])
641
642 ) {
643 new_conn[3 * t + (i + 1) % 3] = new_edge_conn[t];
644 break;
645 }
646 }
647 }
648
649 if (test_flip(get_tri_normals(new_conn))) {
650 for (int t = 0; t != 2; ++t) {
651 Range rtri;
652 CHKERR moab.get_adjacencies(&new_conn[3 * t], SPACE_DIM + 1, SPACE_DIM,
653 false, rtri);
654 if (!rtri.size()) {
655 EntityHandle tri;
656 CHKERR moab.create_element(MBTRI, &new_conn[3 * t], SPACE_DIM + 1,
657 tri);
658 new_tris.insert(tri);
659 } else {
660#ifndef NDEBUG
661 if (rtri.size() != 1) {
662 MOFEM_LOG("SELF", Sev::error)
663 << "Multiple tries created during edge flip for edge " << edge
664 << " adjacent faces " << std::endl
665 << rtri;
666 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
667 "Multiple tries created during edge flip");
668 }
669#endif // NDEBUG
670 new_tris.merge(rtri);
671 }
672 }
673
674 Range new_edges;
675 CHKERR moab.get_adjacencies(new_tris, SPACE_DIM - 1, true, new_edges,
676 moab::Interface::UNION);
677 } else {
678
679 MOFEM_LOG_CHANNEL("SELF");
680 MOFEM_LOG("SELF", Sev::warning)
681 << "Edge flip rejected for edge " << edge << " adjacent faces "
682 << adj_faces;
683 }
684
686 };
687
688 Range tris;
689 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
690 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
691 parent_bit, BitRefLevel().set(), tris);
692 Skinner skin(&moab);
693 Range skin_edges;
694 CHKERR skin.find_skin(0, tris, false, skin_edges);
695
696 Range edges;
697 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM - 1, edges);
698 edges = subtract(edges, skin_edges);
699 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
700 parent_bit, BitRefLevel().set(), edges);
701
702 Range new_tris, flipped_tris, forbidden_tris;
703 int flip_count = 0;
704 for (auto edge : edges) {
705 Range adjacent_tris;
706 CHKERR moab.get_adjacencies(&edge, 1, SPACE_DIM, true, adjacent_tris);
707
708 adjacent_tris = intersect(adjacent_tris, tris);
709 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
710 if (adjacent_tris.size() == 2) {
711
712#ifndef NDEBUG
713 int side_number0, sense0, offset0;
714 CHKERR mField.get_moab().side_number(adjacent_tris[0], edge, side_number0,
715 sense0, offset0);
716 int side_number1, sense1, offset1;
717 CHKERR mField.get_moab().side_number(adjacent_tris[1], edge, side_number1,
718 sense1, offset1);
719 if (sense0 * sense1 > 0)
720 SETERRQ(
721 PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
722 "Cannot flip edge with same orientation in both adjacent faces");
723#endif // NDEBUG
724
725 Range new_flipped_tris;
726 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
727 if (new_flipped_tris.size()) {
728 flipped_tris.merge(adjacent_tris);
729 forbidden_tris.merge(adjacent_tris);
730 new_tris.merge(new_flipped_tris);
731
732#ifndef NDEBUG
733 CHKERR save_range(moab,
734 "flipped_tris_" + std::to_string(flip_count) + ".vtk",
735 adjacent_tris);
737 moab, "new_flipped_tris_" + std::to_string(flip_count) + ".vtk",
738 new_flipped_tris);
739
740#endif // NDEBUG
741
742 ++flip_count;
743 }
744 }
745 }
746
747 Range all_tris;
748 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, all_tris);
749 Range not_flipped_tris = subtract(all_tris, flipped_tris);
750
751 MOFEM_LOG("SELF", Sev::noisy)
752 << "Flipped " << flip_count << " edges with two adjacent faces.";
753 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(not_flipped_tris,
754 child_bit);
755 CHKERR mField.getInterface<BitRefManager>()->setBitRefLevel(new_tris,
756 child_bit);
757 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
758 child_bit, BitRefLevel().set(), "edge_flips_before_refinement.vtk", "VTK",
759 "");
760
762}
763//! [Edge flips]
764
765//! [Refine skin]
767 BitRefLevel child_bit) {
769
770 moab::Interface &moab = mField.get_moab();
771 Range tris;
772 CHKERR moab.get_entities_by_dimension(0, SPACE_DIM, tris);
773 CHKERR mField.getInterface<BitRefManager>()->filterEntitiesByRefLevel(
774 parent_bit, BitRefLevel().set(), tris);
775
776 Skinner skin(&moab);
777 Range skin_edges;
778 CHKERR skin.find_skin(0, tris, false, skin_edges);
779
780 auto refine = mField.getInterface<MeshRefinement>();
781 CHKERR refine->addVerticesInTheMiddleOfEdges(skin_edges, child_bit);
782#ifndef NDEBUG
783 auto debug = true;
784#else
785 auto debug = false;
786#endif
787 CHKERR refine->refineTris(tris, child_bit, QUIET, debug);
788
789 CHKERR mField.getInterface<BitRefManager>()->writeBitLevel(
790 child_bit, BitRefLevel().set(), "edge_flips_after_refinement.vtk", "VTK",
791 "");
792
794}
795//! [Refine skin]
796
797//! [Re-setup problem after mesh modification
804//! [Re-setup problem after mesh modification]
805
806int main(int argc, char *argv[]) {
807
808 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
809
810 try {
811
812 //! [Register MoFEM discrete manager in PETSc]
813 DMType dm_name = "DMMOFEM";
814 CHKERR DMRegister_MoFEM(dm_name);
815 //! [Register MoFEM discrete manager in PETSc]
816
817 //! [Create MoAB]
818 moab::Core mb_instance;
819 moab::Interface &moab = mb_instance;
820 //! [Create MoAB]
821
822 //! [Create MoFEM]
823 MoFEM::Core core(moab);
824 MoFEM::Interface &m_field = core;
825 //! [Create MoFEM]
826
827 //! [Execute DG Projection Test]
828 Example ex(m_field);
829 CHKERR ex.runProblem();
830 //! [Execute DG Projection Test]
831 }
833
835}
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
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
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 > & getDomainPostProcFE()
Get domain postprocessing finite element.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode reSetUp(bool only_dm=false)
Rebuild internal MoFEM data structures.
Definition Simple.cpp:761
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
const std::string getDomainFEName() const
Get the Domain FE Name.
Definition Simple.hpp:429
BitRefLevel & getBitRefLevel()
Get the BitRefLevel.
Definition Simple.hpp:415
intrusive_ptr for managing petsc objects
static MoFEMErrorCode getTriNormal(const double *coords, double *normal, double *d_normal=nullptr)
Get the Tri Normal objectGet triangle normal.
Definition Tools.cpp:353
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
auto save_range
constexpr int SPACE_DIM
DomainEle::UserDataOperator DomainEleOp
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle