v0.16.3
Loading...
Searching...
No Matches
level_set.cpp
Go to the documentation of this file.
1/**
2 * @file level_set.cpp
3 * @example mofem/tutorials/adv-3_level_set/level_set.cpp
4 * @brief Implementation DG upwind method for advection/level set problem
5 * @date 2022-12-15
6 *
7 * @copyright Copyright (c) 2022
8 *
9 */
10
11#include <MoFEM.hpp>
12using namespace MoFEM;
13
14static char help[] = "...\n\n";
15
16//! [Define dimension]
17
18// We can have 2D elements embedded in 3D space or 2D element embedded in 2D
19constexpr int FE_DIM = EXECUTABLE_DIMENSION; //< dimension of the element
20constexpr int SPACE_DIM = FE_DIM; //< dimension of the space
21constexpr int DIM1 = 1;
22constexpr int DIM2 = 1;
23
24// \todo We do not have implemented embedding of the edge elements in 3D space,
25// thus integration on skeleton will not work for
26// case FE_DIM = 2 and SPACE_DIM = 3. Since FE_DIM = 2, skeleton is 1D, i.e.
27// edge elements.
28
31
32constexpr AssemblyType A = AssemblyType::PETSC; //< selected assembly type
33constexpr IntegrationType G =
34 IntegrationType::GAUSS; //< selected integration type
35
42
43using DomainEleOp = DomainEle::UserDataOperator;
44using BoundaryEleOp = BoundaryEle::UserDataOperator;
45using FaceSideEleOp = FaceSideEle::UserDataOperator;
46
48
50constexpr size_t potential_velocity_field_dim = FE_DIM == 2 ? 1 : 3;
51
52// #ifndef NDEBUG
53constexpr bool debug = true;
54// #else
55// constexpr bool debug = true;
56// #endif
57
58constexpr int nb_levels = 3; //< number of refinement levels
59
60constexpr int start_bit =
61 nb_levels + 1; //< first refinement level for computational mesh
62
63constexpr int current_bit =
64 2 * start_bit + 1; ///< dofs bit used to do calculations
65constexpr int skeleton_bit = 2 * start_bit + 2; ///< skeleton elements bit
66constexpr int aggregate_bit =
67 2 * start_bit + 3; ///< all bits for advection problem
68constexpr int projection_bit =
69 2 * start_bit + 4; //< bit from which data are projected
71 2 * start_bit + 5; ///< all bits for projection problem
72
73struct LevelSet {
74
75 LevelSet(MoFEM::Interface &m_field) : mField(m_field) {}
76
78
79private:
80 using MatSideArray = std::array<MatrixDouble, 2>;
81
82 /**
83 * @brief data structure carrying information on skeleton on both sides.
84 *
85 */
86 struct SideData {
87 // data for skeleton computation
88 std::array<EntityHandle, 2> feSideHandle;
89 std::array<VectorInt, 2>
90 indicesRowSideMap; ///< indices on rows for left hand-side
91 std::array<VectorInt, 2>
92 indicesColSideMap; ///< indices on columns for left hand-side
93 std::array<MatrixDouble, 2> rowBaseSideMap; // base functions on rows
94 std::array<MatrixDouble, 2> colBaseSideMap; // base function on columns
95 std::array<int, 2> senseMap; // orientation of local element edge/face in
96 // respect to global orientation of edge/face
97
98 MatSideArray lVec; //< Values of level set field
99 MatSideArray velMat; //< Values of velocity field
100
101 int currentFESide; ///< current side counter
102 };
103
104 /**
105 * @brief advection velocity field
106 *
107 * \note in current implementation is assumed that advection field has zero
108 * normal component.
109 *
110 * \note function define a vector velocity potential field, curl of potential
111 * field gives velocity, thus velocity is divergence free.
112 *
113 * @tparam FE_DIM
114 * @param x
115 * @param y
116 * @param z
117 * @return auto
118 */
119 template <int FE_DIM>
120 static double get_velocity_potential(double x, double y, double z);
121
122 /**
123 * @brief inital level set, i.e. advected field
124 *
125 * @param x
126 * @param y
127 * @param z
128 * @return double
129 */
130 static double get_level_set(const double x, const double y, const double z);
131
132 /**
133 * @brief read mesh
134 *
135 * @return MoFEMErrorCode
136 */
138
139 /**
140 * @brief create fields, and set approximation order
141 *
142 * @return MoFEMErrorCode
143 */
145
146 /**
147 * @brief push operators to integrate operators on domain
148 *
149 * @return MoFEMErrorCode
150 */
152
153 /**
154 * @brief evaluate error
155 *
156 * @return MoFEMErrorCode
157 */
158 std::tuple<double, Tag> evaluateError();
159
160 /**
161 * @brief Get operator calculating velocity on coarse mesh
162 *
163 * @param vel_ptr
164 * @return DomainEleOp*
165 */
167 getZeroLevelVelOp(boost::shared_ptr<MatrixDouble> vel_ptr);
168
169 /**
170 * @brief create side element to assemble data from sides
171 *
172 * @param side_data_ptr
173 * @return boost::shared_ptr<FaceSideEle>
174 */
175 boost::shared_ptr<FaceSideEle>
176 getSideFE(boost::shared_ptr<SideData> side_data_ptr);
177
178 /**
179 * @brief push operator to integrate on skeleton
180 *
181 * @return MoFEMErrorCode
182 */
184
185 /**
186 * @brief test integration side elements
187 *
188 * Check consistency between volume and skeleton integral.
189 *
190 * @return MoFEMErrorCode
191 */
193
194 /**
195 * @brief test consistency between tangent matrix and the right hand side
196 * vectors
197 *
198 * @return MoFEMErrorCode
199 */
201
202 /**
203 * @brief initialise field set
204 *
205 * @param level_fun
206 * @return MoFEMErrorCode
207 */
209 boost::function<double(double, double, double)> level_fun =
211
212 /**
213 * @brief initialise potential velocity field
214 *
215 * @param vel_fun
216 * @return MoFEMErrorCode
217 */
219 boost::function<double(double, double, double)> vel_fun =
220 get_velocity_potential<FE_DIM>);
221
222 /**
223 * @brief dg level set projection
224 *
225 * @param prj_bit
226 * @param mesh_bit
227 * @return MoFEMErrorCode
228 */
229 MoFEMErrorCode dgProjection(const int prj_bit = projection_bit);
230
231 /**
232 * @brief solve advection problem
233 *
234 * @return * MoFEMErrorCode
235 */
237
238 /**
239 * @brief Wrapper executing stages while mesh refinement
240 */
242 WrapperClass() = default;
243
244 /**
245 * @brief Set bit ref level to problem
246 */
247 virtual MoFEMErrorCode setBits(LevelSet &level_set, int l) = 0;
248
249 /**
250 * @brief Run calculations
251 */
252 virtual MoFEMErrorCode runCalcs(LevelSet &level_set, int l) = 0;
253
254 /**
255 * @brief Add bit to current element, so it aggregate all previious current
256 * elements
257 */
258 virtual MoFEMErrorCode setAggregateBit(LevelSet &level_set, int l) = 0;
259 virtual double getThreshold(const double max) = 0;
260 };
261
262 /**
263 * @brief Used to execute inital mesh approximation while mesh refinement
264 *
265 */
267
268 WrapperClassInitalSolution(boost::shared_ptr<double> max_ptr)
269 : WrapperClass(), maxPtr(max_ptr) {}
270
271 MoFEMErrorCode setBits(LevelSet &level_set, int l) {
273 auto simple = level_set.mField.getInterface<Simple>();
276 simple->getBitRefLevelMask() = BitRefLevel().set();
277 simple->reSetUp(true);
279 };
280
286
288 auto bit_mng = level_set.mField.getInterface<BitRefManager>();
289 auto set_bit = [](auto l) { return BitRefLevel().set(l); };
291 Range level;
292 CHKERR bit_mng->getEntitiesByRefLevel(set_bit(start_bit + l),
293 BitRefLevel().set(), level);
295 ->synchroniseEntities(level);
296 CHKERR bit_mng->setNthBitRefLevel(current_bit, false);
297 CHKERR bit_mng->setNthBitRefLevel(level, current_bit, true);
298 CHKERR bit_mng->setNthBitRefLevel(level, aggregate_bit, true);
300 }
301
302 double getThreshold(const double max) {
303 *maxPtr = std::max(*maxPtr, max);
304 return 0.05 * (*maxPtr);
305 }
306
307 private:
308 boost::shared_ptr<double> maxPtr;
309 };
310
311 /**
312 * @brief Use peculated errors on all levels while mesh projection
313 *
314 */
316 WrapperClassErrorProjection(boost::shared_ptr<double> max_ptr)
317 : maxPtr(max_ptr) {}
318
319 MoFEMErrorCode setBits(LevelSet &level_set, int l) { return 0; };
320 MoFEMErrorCode runCalcs(LevelSet &level_set, int l) { return 0; }
322 auto bit_mng = level_set.mField.getInterface<BitRefManager>();
323 auto set_bit = [](auto l) { return BitRefLevel().set(l); };
325 Range level;
326 CHKERR bit_mng->getEntitiesByRefLevel(set_bit(start_bit + l),
327 BitRefLevel().set(), level);
329 ->synchroniseEntities(level);
330 CHKERR bit_mng->setNthBitRefLevel(current_bit, false);
331 CHKERR bit_mng->setNthBitRefLevel(level, current_bit, true);
332 CHKERR bit_mng->setNthBitRefLevel(level, aggregate_bit, true);
334 }
335 double getThreshold(const double max) { return 0.05 * (*maxPtr); }
336
337 private:
338 boost::shared_ptr<double> maxPtr;
339 };
340
342
343 struct OpRhsDomain; ///< integrate volume operators on rhs
344 struct OpLhsDomain; ///< integrate volume operator on lhs
345 struct OpRhsSkeleton; ///< integrate skeleton operators on rhs
346 struct OpLhsSkeleton; ///< integrate skeleton operators on khs
347
348 // Main interfaces
350
356 G>::OpSource<1, DIM1 * DIM2>;
360 G>::OpSource<potential_velocity_field_dim, potential_velocity_field_dim>;
362 G>::OpBaseTimesVector<1, DIM1 * DIM2, 1>;
363
366
368
369private:
370 boost::shared_ptr<double> maxPtr;
371};
372
373template <>
374double LevelSet::get_velocity_potential<2>(double x, double y, double z) {
375 return (x * x - 0.25) * (y * y - 0.25);
376}
377
378double LevelSet::get_level_set(const double x, const double y, const double z) {
379 constexpr double xc = 0.1;
380 constexpr double yc = 0.;
381 constexpr double zc = 0.;
382 constexpr double r = 0.2;
383 return std::sqrt(pow(x - xc, 2) + pow(y - yc, 2) + pow(z - zc, 2)) - r;
384}
385
390
391 if constexpr (debug) {
393 CHKERR testOp();
394 }
395
397
398 maxPtr = boost::make_shared<double>(0);
400
404 simple->getBitRefLevelMask() = BitRefLevel().set();
405 simple->reSetUp(true);
406
408
410}
411
413
414 OpRhsDomain(const std::string field_name,
415 boost::shared_ptr<MatrixDouble> l_ptr,
416 boost::shared_ptr<MatrixDouble> l_dot_ptr,
417 boost::shared_ptr<MatrixDouble> vel_ptr);
419
420private:
421 boost::shared_ptr<MatrixDouble> lPtr;
422 boost::shared_ptr<MatrixDouble> lDotPtr;
423 boost::shared_ptr<MatrixDouble> velPtr;
424};
425
427 OpLhsDomain(const std::string field_name,
428 boost::shared_ptr<MatrixDouble> vel_ptr);
429 MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data);
430
431private:
432 boost::shared_ptr<MatrixDouble> velPtr;
433};
434
436
437 OpRhsSkeleton(boost::shared_ptr<SideData> side_data_ptr,
438 boost::shared_ptr<FaceSideEle> side_fe_ptr);
439 MoFEMErrorCode doWork(int side, EntityType type,
441
442private:
443 boost::shared_ptr<SideData> sideDataPtr;
444 boost::shared_ptr<FaceSideEle>
445 sideFEPtr; ///< pointer to element to get data on edge/face sides
446
448};
449
451 OpLhsSkeleton(boost::shared_ptr<SideData> side_data_ptr,
452 boost::shared_ptr<FaceSideEle> side_fe_ptr);
453 MoFEMErrorCode doWork(int side, EntityType type,
455
456private:
457 boost::shared_ptr<SideData> sideDataPtr;
458 boost::shared_ptr<FaceSideEle>
459 sideFEPtr; ///< pointer to element to get data on edge/face sides
460
462};
463
464int main(int argc, char *argv[]) {
465
466 // Initialisation of MoFEM/PETSc and MOAB data structures
467 const char param_file[] = "param_file.petsc";
468 MoFEM::Core::Initialize(&argc, &argv, param_file, help);
469
470 try {
471
472 // Create MoAB database
473 moab::Core moab_core;
474 moab::Interface &moab = moab_core;
475
476 // Create MoFEM database and link it to MoAB
477 MoFEM::Core mofem_core(moab);
478 MoFEM::Interface &m_field = mofem_core;
479
480 // Register DM Manager
481 DMType dm_name = "DMMOFEM";
482 CHKERR DMRegister_MoFEM(dm_name);
483
484 // Add logging channel for example
485 auto core_log = logging::core::get();
486 core_log->add_sink(
488 LogManager::setLog("LevelSet");
489 MOFEM_LOG_TAG("LevelSet", "LevelSet");
490
491 LevelSet level_set(m_field);
492 CHKERR level_set.runProblem();
493 }
495
496 // finish work cleaning memory, getting statistics, etc.
498
499 return 0;
500}
501
505 // get options from command line
507
508 // Only L2 field is set in this example. Two lines bellow forces simple
509 // interface to creat lower dimension (edge) elements, despite that fact that
510 // there is no field spanning on such elements. We need them for DG method.
511 simple->getAddSkeletonFE() = true;
512 simple->getAddBoundaryFE() = true;
513
514 // load mesh file
515 simple->getBitRefLevel() = BitRefLevel();
516 CHKERR simple->loadFile();
517
518 // Initialise bit ref levels
519 auto set_problem_bit = [&]() {
521 auto bit0 = BitRefLevel().set(start_bit);
522 BitRefLevel start_mask;
523 for (auto s = 0; s != start_bit; ++s)
524 start_mask[s] = true;
525
526 auto bit_mng = mField.getInterface<BitRefManager>();
527
528 Range level0;
529 CHKERR bit_mng->getEntitiesByRefLevel(BitRefLevel().set(0),
530 BitRefLevel().set(), level0);
531
532 CHKERR bit_mng->setNthBitRefLevel(level0, current_bit, true);
533 CHKERR bit_mng->setNthBitRefLevel(level0, aggregate_bit, true);
534 CHKERR bit_mng->setNthBitRefLevel(level0, skeleton_bit, true);
535
536 // Set bits to build adjacencies between parents and children. That is used
537 // by simple interface.
538 simple->getBitAdjEnt() = BitRefLevel().set();
539 simple->getBitAdjParent() = BitRefLevel().set();
540 simple->getBitRefLevel() = BitRefLevel().set(current_bit);
541 simple->getBitRefLevelMask() = BitRefLevel().set();
542
543#ifndef NDEBUG
544 if constexpr (debug) {
545 auto proc_str = boost::lexical_cast<std::string>(mField.get_comm_rank());
546 CHKERR bit_mng->writeBitLevelByDim(
547 BitRefLevel().set(0), BitRefLevel().set(), FE_DIM,
548 (proc_str + "level_base.vtk").c_str(), "VTK", "");
549 }
550#endif
551
553 };
554
555 CHKERR set_problem_bit();
556
558}
559
563 // Scalar fields and vector field is tested. Add more fields, i.e. vector
564 // field if needed.
566 CHKERR simple->addDomainField("V", potential_velocity_space,
568
569 // set fields order, i.e. for most first cases order is sufficient.
570 CHKERR simple->setFieldOrder("L", 4);
571 CHKERR simple->setFieldOrder("V", 4);
572
573 // setup problem
574 CHKERR simple->setUp();
575
577}
578
582
584 boost::shared_ptr<MatrixDouble> l_ptr,
585 boost::shared_ptr<MatrixDouble> l_dot_ptr,
586 boost::shared_ptr<MatrixDouble> vel_ptr)
588 lPtr(l_ptr), lDotPtr(l_dot_ptr), velPtr(vel_ptr) {}
589
591 boost::shared_ptr<MatrixDouble> vel_ptr)
593 AssemblyDomainEleOp::OPROWCOL),
594 velPtr(vel_ptr) {
595 this->sYmm = false;
596}
597
599 boost::shared_ptr<SideData> side_data_ptr,
600 boost::shared_ptr<FaceSideEle> side_fe_ptr)
602 sideDataPtr(side_data_ptr), sideFEPtr(side_fe_ptr) {}
603
605 boost::shared_ptr<SideData> side_data_ptr,
606 boost::shared_ptr<FaceSideEle> side_fe_ptr)
608 sideDataPtr(side_data_ptr), sideFEPtr(side_fe_ptr) {}
609
612
613 const auto nb_int_points = getGaussPts().size2();
614 const auto nb_dofs = data.getIndices().size();
615 const auto nb_base_func = data.getN().size2();
616
617 auto t_l = getFTensor2FromMat<DIM1, DIM2>(*lPtr);
618 auto t_l_dot = getFTensor2FromMat<DIM1, DIM2>(*lDotPtr);
619 auto t_vel = getFTensor1FromMat<SPACE_DIM>(*velPtr);
620
621 auto t_base = data.getFTensor0N();
622 auto t_diff_base = data.getFTensor1DiffN<SPACE_DIM>();
623
624 auto t_w = getFTensor0IntegrationWeight();
625 for (auto gg = 0; gg != nb_int_points; ++gg) {
626 const auto alpha = t_w * getMeasure();
628 t_res0(I, J) = alpha * t_l_dot(I, J);
630 t_res1(i, I, J) = (alpha * t_l(I, J)) * t_vel(i);
631 ++t_w;
632 ++t_l;
633 ++t_l_dot;
634 ++t_vel;
635
636 auto &nf = this->locF;
637 auto t_nf = getFTensor2FromPtr<DIM1, DIM2>(&*nf.begin());
638
639 int rr = 0;
640 for (; rr != nb_dofs; ++rr) {
641 t_nf(I, J) += t_res0(I, J) * t_base - t_res1(i, I, J) * t_diff_base(i);
642 ++t_base;
643 ++t_diff_base;
644 ++t_nf;
645 }
646 for (; rr < nb_base_func; ++rr) {
647 ++t_base;
648 ++t_diff_base;
649 }
650 }
651
653}
654
656 EntData &col_data) {
658
659 const auto nb_int_points = getGaussPts().size2();
660 const auto nb_base_func = row_data.getN().size2();
661 const auto nb_row_dofs = row_data.getIndices().size();
662 const auto nb_col_dofs = col_data.getIndices().size();
663
664 auto t_vel = getFTensor1FromMat<SPACE_DIM>(*velPtr);
665
666 auto t_row_base = row_data.getFTensor0N();
667 auto t_row_diff_base = row_data.getFTensor1DiffN<SPACE_DIM>();
668
669 auto t_w = getFTensor0IntegrationWeight();
670 for (auto gg = 0; gg != nb_int_points; ++gg) {
671 const auto alpha = t_w * getMeasure();
672 const auto beta = alpha * getTSa();
673 ++t_w;
674
675 auto &mat = this->locMat;
676
677 int rr = 0;
678 for (; rr != nb_row_dofs; ++rr) {
679 auto t_col_base = col_data.getFTensor0N(gg, 0);
680 auto t_mat = getFTensor2FromPtr<DIM1, DIM2>(&mat(rr * DIM1, 0));
681 for (int cc = 0; cc != nb_col_dofs; ++cc) {
682 t_mat(I, J) +=
683 (beta * t_row_base - alpha * (t_row_diff_base(i) * t_vel(i))) *
684 t_col_base;
685 ++t_col_base;
686 ++t_mat;
687 }
688 ++t_row_base;
689 ++t_row_diff_base;
690 }
691 for (; rr < nb_base_func; ++rr) {
692 ++t_row_base;
693 ++t_row_diff_base;
694 }
695
696 ++t_vel;
697 }
698
700}
701
706
707 // Collect data from side domain elements
708 CHKERR loopSideFaces("dFE", *sideFEPtr);
709 const auto in_the_loop =
710 sideFEPtr->nInTheLoop; // return number of elements on the side
711
712 auto not_side = [](auto s) {
713 return s == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE;
714 };
715
716 auto get_ntensor = [](auto &base_mat) {
718 &*base_mat.data().begin());
719 };
720
721 if (in_the_loop > 0) {
722
723 // get normal of the face or edge
724 auto t_normal = getFTensor1Normal();
725 const auto nb_gauss_pts = getGaussPts().size2();
726
727 for (auto s0 : {LEFT_SIDE, RIGHT_SIDE}) {
728
729 // gent number of DOFs on the right side.
730 const auto nb_rows = sideDataPtr->indicesRowSideMap[s0].size();
731
732 if (nb_rows) {
733
734 resSkelton.resize(nb_rows, false);
735 resSkelton.clear();
736
737 // get orientation of the local element edge
738 const auto opposite_s0 = not_side(s0);
739 const auto sense_row = sideDataPtr->senseMap[s0];
740#ifndef NDEBUG
741 const auto opposite_sense_row = sideDataPtr->senseMap[opposite_s0];
742 if (sense_row * opposite_sense_row > 0)
743 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
744 "Should be opposite sign");
745#endif
746
747 // iterate the side cols
748 const auto nb_row_base_functions =
749 sideDataPtr->rowBaseSideMap[s0].size2();
750
751 auto t_w = getFTensor0IntegrationWeight();
752 auto arr_t_l = make_array(
753 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[LEFT_SIDE]),
754 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[RIGHT_SIDE]));
755 auto arr_t_vel = make_array(
756 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[LEFT_SIDE]),
757 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[RIGHT_SIDE]));
758
759 auto next = [&]() {
760 for (auto &t_l : arr_t_l)
761 ++t_l;
762 for (auto &t_vel : arr_t_vel)
763 ++t_vel;
764 };
765
766#ifndef NDEBUG
767 if (nb_gauss_pts != sideDataPtr->rowBaseSideMap[s0].size1())
768 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
769 "Inconsistent number of DOFs");
770#endif
771
772 auto t_row_base = get_ntensor(sideDataPtr->rowBaseSideMap[s0]);
773 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
775 t_vel(i) = (arr_t_vel[LEFT_SIDE](i) + arr_t_vel[RIGHT_SIDE](i)) / 2.;
776 const auto dot = sense_row * (t_normal(i) * t_vel(i));
777 const auto l_upwind_side = (dot > 0) ? s0 : opposite_s0;
778 const auto l_upwind = arr_t_l[l_upwind_side];
780 t_res(I, J) = t_w * dot * l_upwind(I, J);
781 next();
782 ++t_w;
783
784 auto t_res_skeleton =
785 getFTensor2FromPtr<DIM1, DIM2>(&*resSkelton.data().begin());
786 auto rr = 0;
787 for (; rr != nb_rows; ++rr) {
788 t_res_skeleton(I, J) += t_row_base * t_res(I, J);
789 ++t_row_base;
790 ++t_res_skeleton;
791 }
792 for (; rr < nb_row_base_functions; ++rr) {
793 ++t_row_base;
794 }
795 }
796 // assemble local operator vector to global vector
797 CHKERR ::VecSetValues(getTSf(),
798 sideDataPtr->indicesRowSideMap[s0].size(),
799 &*sideDataPtr->indicesRowSideMap[s0].begin(),
800 &*resSkelton.begin(), ADD_VALUES);
801 }
802 }
803 }
804
806}
807
812
813 // Collect data from side domain elements
814 CHKERR loopSideFaces("dFE", *sideFEPtr);
815 const auto in_the_loop =
816 sideFEPtr->nInTheLoop; // return number of elements on the side
817
818 auto not_side = [](auto s) {
819 return s == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE;
820 };
821
822 auto get_ntensor = [](auto &base_mat) {
824 &*base_mat.data().begin());
825 };
826
827 if (in_the_loop > 0) {
828
829 // get normal of the face or edge
830 auto t_normal = getFTensor1Normal();
831 const auto nb_gauss_pts = getGaussPts().size2();
832
833 for (auto s0 : {LEFT_SIDE, RIGHT_SIDE}) {
834
835 // gent number of DOFs on the right side.
836 const auto nb_rows = sideDataPtr->indicesRowSideMap[s0].size();
837
838 if (nb_rows) {
839
840 // get orientation of the local element edge
841 const auto opposite_s0 = not_side(s0);
842 const auto sense_row = sideDataPtr->senseMap[s0];
843
844 // iterate the side cols
845 const auto nb_row_base_functions =
846 sideDataPtr->rowBaseSideMap[s0].size2();
847
848 for (auto s1 : {LEFT_SIDE, RIGHT_SIDE}) {
849
850 // gent number of DOFs on the right side.
851 const auto nb_cols = sideDataPtr->indicesColSideMap[s1].size();
852
853 // resize local element matrix
854 matSkeleton.resize(nb_rows, nb_cols, false);
855 matSkeleton.clear();
856
857 auto t_w = getFTensor0IntegrationWeight();
858 auto arr_t_vel = make_array(
859 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[LEFT_SIDE]),
860 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[RIGHT_SIDE]));
861
862 auto next = [&]() {
863 for (auto &t_vel : arr_t_vel)
864 ++t_vel;
865 };
866
867 auto t_row_base = get_ntensor(sideDataPtr->rowBaseSideMap[s0]);
868 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
870 t_vel(i) =
871 (arr_t_vel[LEFT_SIDE](i) + arr_t_vel[RIGHT_SIDE](i)) / 2.;
872 const auto dot = sense_row * (t_normal(i) * t_vel(i));
873 const auto l_upwind_side = (dot > 0) ? s0 : opposite_s0;
875 t_res(I, J) = t_w * dot;
876 next();
877 ++t_w;
878 auto rr = 0;
879 if (s1 == l_upwind_side) {
880 for (; rr != nb_rows; ++rr) {
881 auto get_ntensor = [](auto &base_mat, auto gg, auto bb) {
882 double *ptr = &base_mat(gg, bb);
884 };
885 auto t_col_base =
886 get_ntensor(sideDataPtr->colBaseSideMap[s1], gg, 0);
887
888 auto t_mat_skeleton =
889 getFTensor2FromPtr<DIM1, DIM2>(&matSkeleton(rr * DIM1, 0));
891 t_res_row(I, J) = t_res(I, J) * t_row_base;
892 ++t_row_base;
893 // iterate columns
894 for (size_t cc = 0; cc != nb_cols; ++cc) {
895 t_mat_skeleton(I, J) += t_res_row(I, J) * t_col_base;
896 ++t_col_base;
897 ++t_mat_skeleton;
898 }
899 }
900 }
901 for (; rr < nb_row_base_functions; ++rr) {
902 ++t_row_base;
903 }
904 }
905 // assemble system
906 CHKERR ::MatSetValues(getTSB(),
907 sideDataPtr->indicesRowSideMap[s0].size(),
908 &*sideDataPtr->indicesRowSideMap[s0].begin(),
909 sideDataPtr->indicesColSideMap[s1].size(),
910 &*sideDataPtr->indicesColSideMap[s1].begin(),
911 &*matSkeleton.data().begin(), ADD_VALUES);
912 }
913 }
914 }
915 }
917}
918
920LevelSet::getZeroLevelVelOp(boost::shared_ptr<MatrixDouble> vel_ptr) {
921 auto get_parent_vel_this = [&]() {
922 auto parent_fe_ptr = boost::make_shared<DomainParentEle>(mField);
924 parent_fe_ptr->getOpPtrVector(), {potential_velocity_space});
925 parent_fe_ptr->getOpPtrVector().push_back(
927 "V", vel_ptr));
928 return parent_fe_ptr;
929 };
930
931 auto get_parents_vel_fe_ptr = [&](auto this_fe_ptr) {
932 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
933 for (int l = 0; l <= nb_levels; ++l)
934 parents_elems_ptr_vec.emplace_back(
935 boost::make_shared<DomainParentEle>(mField));
936 for (auto l = 1; l <= nb_levels; ++l) {
937 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
938 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
939 BitRefLevel().set(0).flip(), this_fe_ptr,
940 BitRefLevel().set(0), BitRefLevel().set()));
941 }
942 return parents_elems_ptr_vec[0];
943 };
944
945 auto this_fe_ptr = get_parent_vel_this();
946 auto parent_fe_ptr = get_parents_vel_fe_ptr(this_fe_ptr);
947 return new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
948 BitRefLevel().set(0).flip(), this_fe_ptr,
949 BitRefLevel().set(0), BitRefLevel().set());
950}
951
954 auto pip = mField.getInterface<PipelineManager>(); // get interface to
955 // pipeline manager
956
957 pip->getOpDomainLhsPipeline().clear();
958 pip->getOpDomainRhsPipeline().clear();
959
960 pip->setDomainLhsIntegrationRule([](int, int, int o) { return 3 * o; });
961 pip->setDomainRhsIntegrationRule([](int, int, int o) { return 3 * o; });
962
963 pip->getDomainLhsFE()->exeTestHook = [&](FEMethod *fe_ptr) {
964 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
966 };
967 pip->getDomainRhsFE()->exeTestHook = [&](FEMethod *fe_ptr) {
968 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
970 };
971
972 auto l_ptr = boost::make_shared<MatrixDouble>();
973 auto l_dot_ptr = boost::make_shared<MatrixDouble>();
974 auto vel_ptr = boost::make_shared<MatrixDouble>();
975
976 pip->getOpDomainRhsPipeline().push_back(getZeroLevelVelOp(vel_ptr));
977 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainRhsPipeline(),
978 {L2});
979 pip->getOpDomainRhsPipeline().push_back(
981 pip->getOpDomainRhsPipeline().push_back(
983 pip->getOpDomainRhsPipeline().push_back(
984 new OpRhsDomain("L", l_ptr, l_dot_ptr, vel_ptr));
985
986 pip->getOpDomainLhsPipeline().push_back(getZeroLevelVelOp(vel_ptr));
987 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainLhsPipeline(),
988 {L2});
989 pip->getOpDomainLhsPipeline().push_back(new OpLhsDomain("L", vel_ptr));
990
992}
993
994boost::shared_ptr<FaceSideEle>
995LevelSet::getSideFE(boost::shared_ptr<SideData> side_data_ptr) {
996
997
998 auto l_ptr = boost::make_shared<MatrixDouble>();
999 auto vel_ptr = boost::make_shared<MatrixDouble>();
1000
1001 struct OpSideData : public FaceSideEleOp {
1002 OpSideData(boost::shared_ptr<SideData> side_data_ptr)
1003 : FaceSideEleOp("L", "L", FaceSideEleOp::OPROWCOL),
1004 sideDataPtr(side_data_ptr) {
1005 std::fill(&doEntities[MBVERTEX], &doEntities[MBMAXTYPE], false);
1006 for (auto t = moab::CN::TypeDimensionMap[FE_DIM].first;
1007 t <= moab::CN::TypeDimensionMap[FE_DIM].second; ++t)
1008 doEntities[t] = true;
1009 sYmm = false;
1010 }
1011
1012 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
1013 EntityType col_type, EntData &row_data,
1014 EntData &col_data) {
1016 if ((CN::Dimension(row_type) == FE_DIM) &&
1017 (CN::Dimension(col_type) == FE_DIM)) {
1018
1019 auto reset = [&](auto nb_in_loop) {
1020 sideDataPtr->feSideHandle[nb_in_loop] = 0;
1021 sideDataPtr->indicesRowSideMap[nb_in_loop].clear();
1022 sideDataPtr->indicesColSideMap[nb_in_loop].clear();
1023 sideDataPtr->rowBaseSideMap[nb_in_loop].clear();
1024 sideDataPtr->colBaseSideMap[nb_in_loop].clear();
1025 sideDataPtr->senseMap[nb_in_loop] = 0;
1026 };
1027
1028 const auto nb_in_loop = getFEMethod()->nInTheLoop;
1029 if (nb_in_loop == 0)
1030 for (auto s : {0, 1})
1031 reset(s);
1032
1033 sideDataPtr->currentFESide = nb_in_loop;
1034 sideDataPtr->senseMap[nb_in_loop] = getSkeletonSense();
1035
1036 } else {
1037 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Should not happen");
1038 }
1039
1041 };
1042
1043 private:
1044 boost::shared_ptr<SideData> sideDataPtr;
1045 };
1046
1047 struct OpSideDataOnParent : public DomainEleOp {
1048
1049 OpSideDataOnParent(boost::shared_ptr<SideData> side_data_ptr,
1050 boost::shared_ptr<MatrixDouble> l_ptr,
1051 boost::shared_ptr<MatrixDouble> vel_ptr)
1052 : DomainEleOp("L", "L", DomainEleOp::OPROWCOL),
1053 sideDataPtr(side_data_ptr), lPtr(l_ptr), velPtr(vel_ptr) {
1054 std::fill(&doEntities[MBVERTEX], &doEntities[MBMAXTYPE], false);
1055 for (auto t = moab::CN::TypeDimensionMap[FE_DIM].first;
1056 t <= moab::CN::TypeDimensionMap[FE_DIM].second; ++t)
1057 doEntities[t] = true;
1058 sYmm = false;
1059 }
1060
1061 MoFEMErrorCode doWork(int row_side, int col_side, EntityType row_type,
1062 EntityType col_type, EntData &row_data,
1063 EntData &col_data) {
1065
1066 if ((CN::Dimension(row_type) == FE_DIM) &&
1067 (CN::Dimension(col_type) == FE_DIM)) {
1068 const auto nb_in_loop = sideDataPtr->currentFESide;
1069 sideDataPtr->feSideHandle[nb_in_loop] = getFEEntityHandle();
1070 sideDataPtr->indicesRowSideMap[nb_in_loop] = row_data.getIndices();
1071 sideDataPtr->indicesColSideMap[nb_in_loop] = col_data.getIndices();
1072 sideDataPtr->rowBaseSideMap[nb_in_loop] = row_data.getN();
1073 sideDataPtr->colBaseSideMap[nb_in_loop] = col_data.getN();
1074 (sideDataPtr->lVec)[nb_in_loop] = *lPtr;
1075 (sideDataPtr->velMat)[nb_in_loop] = *velPtr;
1076
1077#ifndef NDEBUG
1078 if ((sideDataPtr->lVec)[nb_in_loop].size1() !=
1079 (sideDataPtr->velMat)[nb_in_loop].size1())
1080 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1081 "Wrong number of integaration pts %zu != %zu",
1082 (sideDataPtr->lVec)[nb_in_loop].size1(),
1083 (sideDataPtr->velMat)[nb_in_loop].size1());
1084 if ((sideDataPtr->velMat)[nb_in_loop].size2() != SPACE_DIM)
1085 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1086 "Wrong size of velocity vector size = %zu",
1087 (sideDataPtr->velMat)[nb_in_loop].size2());
1088#endif
1089
1090 if (!nb_in_loop) {
1091 (sideDataPtr->lVec)[1] = sideDataPtr->lVec[0];
1092 (sideDataPtr->velMat)[1] = (sideDataPtr->velMat)[0];
1093 } else {
1094#ifndef NDEBUG
1095 if (sideDataPtr->rowBaseSideMap[0].size1() !=
1096 sideDataPtr->rowBaseSideMap[1].size1()) {
1097 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1098 "Wrong number of integration pt %zu != %zu",
1099 sideDataPtr->rowBaseSideMap[0].size1(),
1100 sideDataPtr->rowBaseSideMap[1].size1());
1101 }
1102 if (sideDataPtr->colBaseSideMap[0].size1() !=
1103 sideDataPtr->colBaseSideMap[1].size1()) {
1104 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1105 "Wrong number of integration pt");
1106 }
1107#endif
1108 }
1109
1110 } else {
1111 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY, "Should not happen");
1112 }
1113
1115 };
1116
1117 private:
1118 boost::shared_ptr<SideData> sideDataPtr;
1119 boost::shared_ptr<MatrixDouble> lPtr;
1120 boost::shared_ptr<MatrixDouble> velPtr;
1121 };
1122
1123 // Calculate fields on param mesh bit element
1124 auto get_parent_this = [&]() {
1125 auto parent_fe_ptr = boost::make_shared<DomainParentEle>(mField);
1127 parent_fe_ptr->getOpPtrVector(), {L2});
1128 parent_fe_ptr->getOpPtrVector().push_back(
1130 parent_fe_ptr->getOpPtrVector().push_back(
1131 new OpSideDataOnParent(side_data_ptr, l_ptr, vel_ptr));
1132 return parent_fe_ptr;
1133 };
1134
1135 auto get_parents_fe_ptr = [&](auto this_fe_ptr) {
1136 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
1137 for (int l = 0; l <= nb_levels; ++l)
1138 parents_elems_ptr_vec.emplace_back(
1139 boost::make_shared<DomainParentEle>(mField));
1140 for (auto l = 1; l <= nb_levels; ++l) {
1141 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
1142 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
1143 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
1144 BitRefLevel().set(current_bit), BitRefLevel().set()));
1145 }
1146 return parents_elems_ptr_vec[0];
1147 };
1148
1149 // Create aliased shared pointers, all elements are destroyed if side_fe_ptr
1150 // is destroyed
1151 auto get_side_fe_ptr = [&]() {
1152 auto side_fe_ptr = boost::make_shared<FaceSideEle>(mField);
1153
1154 auto this_fe_ptr = get_parent_this();
1155 auto parent_fe_ptr = get_parents_fe_ptr(this_fe_ptr);
1156
1157 side_fe_ptr->getOpPtrVector().push_back(new OpSideData(side_data_ptr));
1158 side_fe_ptr->getOpPtrVector().push_back(getZeroLevelVelOp(vel_ptr));
1159 side_fe_ptr->getOpPtrVector().push_back(
1160 new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
1161 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
1162 BitRefLevel().set(current_bit), BitRefLevel().set()));
1163
1164 return side_fe_ptr;
1165 };
1166
1167 return get_side_fe_ptr();
1168};
1169
1172 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1173
1174 pip->getOpSkeletonLhsPipeline().clear();
1175 pip->getOpSkeletonRhsPipeline().clear();
1176
1177 pip->setSkeletonLhsIntegrationRule([](int, int, int o) { return 18; });
1178 pip->setSkeletonRhsIntegrationRule([](int, int, int o) { return 18; });
1179
1180 pip->getSkeletonLhsFE()->exeTestHook = [&](FEMethod *fe_ptr) {
1181 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1182 skeleton_bit);
1183 };
1184 pip->getSkeletonRhsFE()->exeTestHook = [&](FEMethod *fe_ptr) {
1185 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1186 skeleton_bit);
1187 };
1188
1189 auto side_data_ptr = boost::make_shared<SideData>();
1190 auto side_fe_ptr = getSideFE(side_data_ptr);
1191
1192 pip->getOpSkeletonRhsPipeline().push_back(
1193 new OpRhsSkeleton(side_data_ptr, side_fe_ptr));
1194 pip->getOpSkeletonLhsPipeline().push_back(
1195 new OpLhsSkeleton(side_data_ptr, side_fe_ptr));
1196
1198}
1199
1200std::tuple<double, Tag> LevelSet::evaluateError() {
1201
1202 struct OpErrorSkel : BoundaryEleOp {
1203
1204 OpErrorSkel(boost::shared_ptr<FaceSideEle> side_fe_ptr,
1205 boost::shared_ptr<SideData> side_data_ptr,
1206 SmartPetscObj<Vec> error_sum_ptr, Tag th_error)
1207 : BoundaryEleOp(NOSPACE, BoundaryEleOp::OPSPACE),
1208 sideFEPtr(side_fe_ptr), sideDataPtr(side_data_ptr),
1209 errorSumPtr(error_sum_ptr), thError(th_error) {}
1210
1211 MoFEMErrorCode doWork(int side, EntityType type, EntData &data) {
1213
1214 // Collect data from side domain elements
1215 CHKERR loopSideFaces("dFE", *sideFEPtr);
1216
1217 auto nb_gauss_pts = getGaussPts().size2();
1218
1219 for ([[maybe_unused]] auto s : {LEFT_SIDE, RIGHT_SIDE}) {
1220
1221 auto arr_t_l = make_array(
1222 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[LEFT_SIDE]),
1223 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[RIGHT_SIDE]));
1224 auto arr_t_vel = make_array(
1225 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[LEFT_SIDE]),
1226 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[RIGHT_SIDE]));
1227
1228 auto next = [&]() {
1229 for (auto &t_l : arr_t_l)
1230 ++t_l;
1231 for (auto &t_vel : arr_t_vel)
1232 ++t_vel;
1233 };
1234
1235 double e = 0;
1236 auto t_w = getFTensor0IntegrationWeight();
1237 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1239 t_diff(I, J) = arr_t_l[LEFT_SIDE](I, J) - arr_t_l[RIGHT_SIDE](I, J);
1240 e += t_w * getMeasure() * t_diff(I, J) * t_diff(I, J);
1241 next();
1242 ++t_w;
1243 }
1244 e = std::sqrt(e);
1245
1246 moab::Interface &moab =
1247 getNumeredEntFiniteElementPtr()->getBasicDataPtr()->moab;
1248 const void *tags_ptr[2];
1249 CHKERR moab.tag_get_by_ptr(thError, sideDataPtr->feSideHandle.data(), 2,
1250 tags_ptr);
1251 for (auto ff : {0, 1}) {
1252 *((double *)tags_ptr[ff]) += e;
1253 }
1254 CHKERR VecSetValue(errorSumPtr, 0, e, ADD_VALUES);
1255 };
1256
1258 }
1259
1260 private:
1261 boost::shared_ptr<FaceSideEle> sideFEPtr;
1262 boost::shared_ptr<SideData> sideDataPtr;
1263 SmartPetscObj<Vec> errorSumPtr;
1264 Tag thError;
1265 };
1266
1267 auto simple = mField.getInterface<Simple>();
1268
1269 auto error_sum_ptr = createVectorMPI(mField.get_comm(), PETSC_DECIDE, 1);
1270 Tag th_error;
1271 double def_val = 0;
1272 CHKERR mField.get_moab().tag_get_handle("Error", 1, MB_TYPE_DOUBLE, th_error,
1273 MB_TAG_CREAT | MB_TAG_SPARSE,
1274 &def_val);
1275
1276 auto clear_tags = [&]() {
1278 Range fe_ents;
1279 CHKERR mField.get_moab().get_entities_by_dimension(0, FE_DIM, fe_ents);
1280 double zero = 0;
1281 CHKERR mField.get_moab().tag_clear_data(th_error, fe_ents, &zero);
1283 };
1284
1285 auto evaluate_error = [&]() {
1287 auto skel_fe = boost::make_shared<BoundaryEle>(mField);
1288 skel_fe->getRuleHook = [](int, int, int o) { return 3 * o; };
1289 auto side_data_ptr = boost::make_shared<SideData>();
1290 auto side_fe_ptr = getSideFE(side_data_ptr);
1291 skel_fe->getOpPtrVector().push_back(
1292 new OpErrorSkel(side_fe_ptr, side_data_ptr, error_sum_ptr, th_error));
1293 auto simple = mField.getInterface<Simple>();
1294
1295 skel_fe->exeTestHook = [&](FEMethod *fe_ptr) {
1296 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1297 skeleton_bit);
1298 };
1299
1301 simple->getSkeletonFEName(), skel_fe);
1302
1304 };
1305
1306 auto assemble_and_sum = [](auto vec) {
1307 CHK_THROW_MESSAGE(VecAssemblyBegin(vec), "assemble");
1308 CHK_THROW_MESSAGE(VecAssemblyEnd(vec), "assemble");
1309 double sum;
1310 CHK_THROW_MESSAGE(VecSum(vec, &sum), "assemble");
1311 return sum;
1312 };
1313
1314 auto propagate_error_to_parents = [&]() {
1316
1317 auto &moab = mField.get_moab();
1318 auto fe_ptr = boost::make_shared<FEMethod>();
1319 fe_ptr->exeTestHook = [&](FEMethod *fe_ptr) {
1320 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1321 current_bit);
1322 };
1323
1324 fe_ptr->preProcessHook = []() { return 0; };
1325 fe_ptr->postProcessHook = []() { return 0; };
1326 fe_ptr->operatorHook = [&]() {
1328
1329 auto fe_ent = fe_ptr->numeredEntFiniteElementPtr->getEnt();
1330 auto parent = fe_ptr->numeredEntFiniteElementPtr->getParentEnt();
1331 auto th_parent = fe_ptr->numeredEntFiniteElementPtr->getBasicDataPtr()
1332 ->th_RefParentHandle;
1333
1334 double error;
1335 CHKERR moab.tag_get_data(th_error, &fe_ent, 1, &error);
1336
1337 boost::function<MoFEMErrorCode(EntityHandle, double)> add_error =
1338 [&](auto fe_ent, auto error) {
1340 double *e_ptr;
1341 CHKERR moab.tag_get_by_ptr(th_error, &fe_ent, 1,
1342 (const void **)&e_ptr);
1343 (*e_ptr) += error;
1344
1345 EntityHandle parent;
1346 CHKERR moab.tag_get_data(th_parent, &fe_ent, 1, &parent);
1347 if (parent != fe_ent && parent)
1348 CHKERR add_error(parent, *e_ptr);
1349
1351 };
1352
1353 CHKERR add_error(parent, error);
1354
1356 };
1357
1358 CHKERR DMoFEMLoopFiniteElements(simple->getDM(), simple->getDomainFEName(),
1359 fe_ptr);
1360
1362 };
1363
1364 CHK_THROW_MESSAGE(clear_tags(), "clear error tags");
1365 CHK_THROW_MESSAGE(evaluate_error(), "evaluate error");
1366 CHK_THROW_MESSAGE(propagate_error_to_parents(), "propagate error");
1367
1368 return std::make_tuple(assemble_and_sum(error_sum_ptr), th_error);
1369}
1370
1371/**
1372 * @brief test side element
1373 *
1374 * Check consistency between volume and skeleton integral
1375 *
1376 * @return MoFEMErrorCode
1377 */
1380
1381 /**
1382 * @brief calculate volume
1383 *
1384 */
1385 struct DivergenceVol : public DomainEleOp {
1386 DivergenceVol(boost::shared_ptr<MatrixDouble> l_ptr,
1387 boost::shared_ptr<MatrixDouble> vel_ptr,
1388 SmartPetscObj<Vec> div_vec)
1389 : DomainEleOp("L", DomainEleOp::OPROW), lPtr(l_ptr), velPtr(vel_ptr),
1390 divVec(div_vec) {}
1391 MoFEMErrorCode doWork(int side, EntityType type,
1394 const auto nb_dofs = data.getIndices().size();
1395 if (nb_dofs) {
1396 const auto nb_gauss_pts = getGaussPts().size2();
1397 const auto t_w = getFTensor0IntegrationWeight();
1398 auto t_diff = data.getFTensor1DiffN<SPACE_DIM>();
1399 auto t_l = getFTensor2FromMat<DIM1, DIM2>(*lPtr);
1400 auto t_vel = getFTensor1FromMat<SPACE_DIM>(*velPtr);
1401 double div = 0;
1402 for (auto gg = 0; gg != nb_gauss_pts; ++gg) {
1403 for (int rr = 0; rr != nb_dofs; ++rr) {
1404 div += getMeasure() * t_w * t_l(I, I) * (t_diff(i) * t_vel(i));
1405 ++t_diff;
1406 }
1407 ++t_w;
1408 ++t_l;
1409 ++t_vel;
1410 }
1411 CHKERR VecSetValue(divVec, 0, div, ADD_VALUES);
1412 }
1414 }
1415
1416 private:
1417 boost::shared_ptr<MatrixDouble> lPtr;
1418 boost::shared_ptr<MatrixDouble> velPtr;
1419 SmartPetscObj<Vec> divVec;
1420 };
1421
1422 /**
1423 * @brief calculate skeleton integral
1424 *
1425 */
1426 struct DivergenceSkeleton : public BoundaryEleOp {
1427 DivergenceSkeleton(boost::shared_ptr<SideData> side_data_ptr,
1428 boost::shared_ptr<FaceSideEle> side_fe_ptr,
1429 SmartPetscObj<Vec> div_vec)
1430 : BoundaryEleOp(NOSPACE, BoundaryEleOp::OPSPACE),
1431 sideDataPtr(side_data_ptr), sideFEPtr(side_fe_ptr), divVec(div_vec) {}
1432 MoFEMErrorCode doWork(int side, EntityType type,
1435
1436 auto get_ntensor = [](auto &base_mat) {
1438 &*base_mat.data().begin());
1439 };
1440
1441 auto not_side = [](auto s) {
1442 return s == LEFT_SIDE ? RIGHT_SIDE : LEFT_SIDE;
1443 };
1444
1445 // Collect data from side domain elements
1446 CHKERR loopSideFaces("dFE", *sideFEPtr);
1447 const auto in_the_loop =
1448 sideFEPtr->nInTheLoop; // return number of elements on the side
1449
1450 auto t_normal = getFTensor1Normal();
1451 const auto nb_gauss_pts = getGaussPts().size2();
1452 for (auto s0 : {LEFT_SIDE, RIGHT_SIDE}) {
1453 const auto nb_dofs = sideDataPtr->indicesRowSideMap[s0].size();
1454 if (nb_dofs) {
1455 auto t_base = get_ntensor(sideDataPtr->rowBaseSideMap[s0]);
1456 auto nb_row_base_functions = sideDataPtr->rowBaseSideMap[s0].size2();
1457 auto side_sense = sideDataPtr->senseMap[s0];
1458 auto opposite_s0 = not_side(s0);
1459
1460 auto arr_t_l = make_array(
1461 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[LEFT_SIDE]),
1462 getFTensor2FromMat<DIM1, DIM2>(sideDataPtr->lVec[RIGHT_SIDE]));
1463 auto arr_t_vel = make_array(
1464 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[LEFT_SIDE]),
1465 getFTensor1FromMat<SPACE_DIM>(sideDataPtr->velMat[RIGHT_SIDE]));
1466
1467 auto next = [&]() {
1468 for (auto &t_l : arr_t_l)
1469 ++t_l;
1470 for (auto &t_vel : arr_t_vel)
1471 ++t_vel;
1472 };
1473
1474 double div = 0;
1475
1476 auto t_w = getFTensor0IntegrationWeight();
1477 for (int gg = 0; gg != nb_gauss_pts; ++gg) {
1479 t_vel(i) =
1480 (arr_t_vel[LEFT_SIDE](i) + arr_t_vel[RIGHT_SIDE](i)) / 2.;
1481 const auto dot = (t_normal(i) * t_vel(i)) * side_sense;
1482 const auto l_upwind_side = (dot > 0) ? s0 : opposite_s0;
1483 const auto l_upwind =
1484 arr_t_l[l_upwind_side]; //< assume that field is continues,
1485 // initialisation field has to be smooth
1486 // and exactly approximated by approx
1487 // base
1488 auto res = t_w * l_upwind(I, I) * dot;
1489 ++t_w;
1490 next();
1491 int rr = 0;
1492 for (; rr != nb_dofs; ++rr) {
1493 div += t_base * res;
1494 ++t_base;
1495 }
1496 for (; rr < nb_row_base_functions; ++rr) {
1497 ++t_base;
1498 }
1499 }
1500 CHKERR VecSetValue(divVec, 0, div, ADD_VALUES);
1501 }
1502 if (!in_the_loop)
1503 break;
1504 }
1505
1507 }
1508
1509 private:
1510 boost::shared_ptr<SideData> sideDataPtr;
1511 boost::shared_ptr<FaceSideEle> sideFEPtr;
1512 boost::shared_ptr<MatrixDouble> velPtr;
1513 SmartPetscObj<Vec> divVec;
1514 };
1515
1516 auto vol_fe = boost::make_shared<DomainEle>(mField);
1517 auto skel_fe = boost::make_shared<BoundaryEle>(mField);
1518
1519 vol_fe->getRuleHook = [](int, int, int o) { return 3 * o; };
1520 skel_fe->getRuleHook = [](int, int, int o) { return 3 * o; };
1521
1522 auto div_vol_vec = createVectorMPI(mField.get_comm(), PETSC_DECIDE, 1);
1523 auto div_skel_vec = createVectorMPI(mField.get_comm(), PETSC_DECIDE, 1);
1524
1525 auto l_ptr = boost::make_shared<MatrixDouble>();
1526 auto vel_ptr = boost::make_shared<MatrixDouble>();
1527 auto side_data_ptr = boost::make_shared<SideData>();
1528 auto side_fe_ptr = getSideFE(side_data_ptr);
1529
1530 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(vol_fe->getOpPtrVector(),
1531 {L2});
1532 vol_fe->getOpPtrVector().push_back(
1534 vol_fe->getOpPtrVector().push_back(getZeroLevelVelOp(vel_ptr));
1535 vol_fe->getOpPtrVector().push_back(
1536 new DivergenceVol(l_ptr, vel_ptr, div_vol_vec));
1537
1538 skel_fe->getOpPtrVector().push_back(
1539 new DivergenceSkeleton(side_data_ptr, side_fe_ptr, div_skel_vec));
1540
1541 auto simple = mField.getInterface<Simple>();
1542 auto dm = simple->getDM();
1543
1544 /**
1545 * Set up problem such that gradient of level set field is orthogonal to
1546 * velocity field. Then volume and skeleton integral should yield the same
1547 * value.
1548 */
1549
1551 [](double x, double y, double) { return x - y; });
1553 [](double x, double y, double) { return x - y; });
1554
1555 vol_fe->exeTestHook = [&](FEMethod *fe_ptr) {
1556 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1557 current_bit);
1558 };
1559 skel_fe->exeTestHook = [&](FEMethod *fe_ptr) {
1560 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1561 skeleton_bit);
1562 };
1563
1567
1568 auto assemble_and_sum = [](auto vec) {
1569 CHK_THROW_MESSAGE(VecAssemblyBegin(vec), "assemble");
1570 CHK_THROW_MESSAGE(VecAssemblyEnd(vec), "assemble");
1571 double sum;
1572 CHK_THROW_MESSAGE(VecSum(vec, &sum), "assemble");
1573 return sum;
1574 };
1575
1576 auto div_vol = assemble_and_sum(div_vol_vec);
1577 auto div_skel = assemble_and_sum(div_skel_vec);
1578
1579 auto eps = std::abs((div_vol - div_skel) / (div_vol + div_skel));
1580
1581 MOFEM_LOG("WORLD", Sev::inform) << "Testing divergence volume: " << div_vol;
1582 MOFEM_LOG("WORLD", Sev::inform) << "Testing divergence skeleton: " << div_skel
1583 << " relative difference: " << eps;
1584
1585 constexpr double eps_err = 1e-6;
1586 if (eps > eps_err)
1587 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
1588 "No consistency between skeleton integral and volume integral");
1589
1591};
1592
1595
1596 // get operators tester
1597 auto simple = mField.getInterface<Simple>();
1598 auto opt = mField.getInterface<OperatorsTester>(); // get interface to
1599 // OperatorsTester
1600 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1601 // pipeline manager
1602
1605
1606 auto post_proc = [&](auto dm, auto f_res, auto out_name) {
1608 auto post_proc_fe =
1609 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
1610
1611 if constexpr (DIM1 == 1 && DIM2 == 1) {
1613
1614 auto l_vec = boost::make_shared<VectorDouble>();
1615 post_proc_fe->getOpPtrVector().push_back(
1616 new OpCalculateScalarFieldValues("L", l_vec, f_res));
1617
1618 post_proc_fe->getOpPtrVector().push_back(
1619
1620 new OpPPMap(
1621
1622 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1623
1624 {{"L", l_vec}},
1625
1626 {},
1627
1628 {}, {})
1629
1630 );
1631 }
1632
1633 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1634 post_proc_fe);
1635 post_proc_fe->writeFile(out_name);
1637 };
1638
1639 constexpr double eps = 1e-4;
1640
1641 auto x =
1642 opt->setRandomFields(simple->getDM(), {{"L", {-1, 1}}, {"V", {-1, 1}}});
1643 auto dot_x = opt->setRandomFields(simple->getDM(), {{"L", {-1, 1}}});
1644 auto diff_x = opt->setRandomFields(simple->getDM(), {{"L", {-1, 1}}});
1645
1646 auto test_domain_ops = [&](auto fe_name, auto lhs_pipeline,
1647 auto rhs_pipeline) {
1649
1650 auto diff_res = opt->checkCentralFiniteDifference(
1651 simple->getDM(), fe_name, rhs_pipeline, lhs_pipeline, x, dot_x,
1652 SmartPetscObj<Vec>(), diff_x, 0, 1, eps);
1653
1654 if constexpr (debug) {
1655 // Example how to plot direction in direction diff_x. If instead
1656 // directionalCentralFiniteDifference(...) diff_res is used, then error
1657 // on directive is plotted.
1658 CHKERR post_proc(simple->getDM(), diff_res, "tangent_op_error.h5m");
1659 }
1660
1661 // Calculate norm of difference between directive calculated from finite
1662 // difference, and tangent matrix.
1663 double fnorm;
1664 CHKERR VecNorm(diff_res, NORM_2, &fnorm);
1665 MOFEM_LOG_C("LevelSet", Sev::inform,
1666 "Test consistency of tangent matrix %3.4e", fnorm);
1667
1668 constexpr double err = 1e-9;
1669 if (fnorm > err)
1670 SETERRQ(PETSC_COMM_WORLD, MOFEM_ATOM_TEST_INVALID,
1671 "Norm of directional derivative too large err = %3.4e", fnorm);
1672
1674 };
1675
1676 CHKERR test_domain_ops(simple->getDomainFEName(), pip->getDomainLhsFE(),
1677 pip->getDomainRhsFE());
1678 CHKERR test_domain_ops(simple->getSkeletonFEName(), pip->getSkeletonLhsFE(),
1679 pip->getSkeletonRhsFE());
1680
1682};
1683
1685 boost::function<double(double, double, double)> level_fun) {
1687
1688 // get operators tester
1689 auto simple = mField.getInterface<Simple>();
1690 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1691 // pipeline manager
1692 auto prb_mng = mField.getInterface<ProblemsManager>();
1693
1694 boost::shared_ptr<FEMethod> lhs_fe = boost::make_shared<DomainEle>(mField);
1695 boost::shared_ptr<FEMethod> rhs_fe = boost::make_shared<DomainEle>(mField);
1696 auto swap_fe = [&]() {
1697 lhs_fe.swap(pip->getDomainLhsFE());
1698 rhs_fe.swap(pip->getDomainRhsFE());
1699 };
1700 swap_fe();
1701
1702 pip->setDomainLhsIntegrationRule([](int, int, int o) { return 3 * o; });
1703 pip->setDomainRhsIntegrationRule([](int, int, int o) { return 3 * o; });
1704
1705 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
1706 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "LEVELSET_POJECTION");
1707 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
1708 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
1709 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
1710 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "L");
1711 CHKERR DMSetUp(sub_dm);
1712
1713 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
1714 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
1715 CHKERR prb_mng->removeDofsOnEntities("LEVELSET_POJECTION", "L",
1716 BitRefLevel().set(), remove_mask);
1717 auto test_bit_ele = [&](FEMethod *fe_ptr) {
1718 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1719 current_bit);
1720 };
1721 pip->getDomainLhsFE()->exeTestHook = test_bit_ele;
1722 pip->getDomainRhsFE()->exeTestHook = test_bit_ele;
1723
1724 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainRhsPipeline(),
1725 {L2});
1726 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainLhsPipeline(),
1727 {L2});
1728 pip->getOpDomainLhsPipeline().push_back(new OpMassLL("L", "L"));
1729 pip->getOpDomainRhsPipeline().push_back(new OpSourceL("L", level_fun));
1730
1731 CHKERR mField.getInterface<FieldBlas>()->setField(0, "L");
1732
1733 auto ksp = pip->createKSP(sub_dm);
1734 CHKERR KSPSetDM(ksp, sub_dm);
1735 CHKERR KSPSetFromOptions(ksp);
1736 CHKERR KSPSetUp(ksp);
1737
1738 auto L = createDMVector(sub_dm);
1739 auto F = vectorDuplicate(L);
1740
1741 CHKERR KSPSolve(ksp, F, L);
1742 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
1743 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
1744 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
1745
1746 auto [error, th_error] = evaluateError();
1747 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
1748#ifndef NDEBUG
1749 auto fe_meshset =
1750 mField.get_finite_element_meshset(simple->getDomainFEName());
1751 std::vector<Tag> tags{th_error};
1752 CHKERR mField.get_moab().write_file("error.h5m", "MOAB",
1753 "PARALLEL=WRITE_PART", &fe_meshset, 1,
1754 &*tags.begin(), tags.size());
1755#endif
1756
1757 auto post_proc = [&](auto dm, auto out_name, auto th_error) {
1759 auto post_proc_fe =
1760 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
1761 post_proc_fe->setTagsToTransfer({th_error});
1762 post_proc_fe->exeTestHook = test_bit_ele;
1763
1764 if constexpr (DIM1 == 1 && DIM2 == 1) {
1766
1767 auto l_vec = boost::make_shared<VectorDouble>();
1768 auto l_grad_mat = boost::make_shared<MatrixDouble>();
1770 post_proc_fe->getOpPtrVector(), {L2});
1771 post_proc_fe->getOpPtrVector().push_back(
1772 new OpCalculateScalarFieldValues("L", l_vec));
1773 post_proc_fe->getOpPtrVector().push_back(
1774 new OpCalculateScalarFieldGradient<SPACE_DIM>("L", l_grad_mat));
1775
1776 post_proc_fe->getOpPtrVector().push_back(
1777
1778 new OpPPMap(
1779
1780 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1781
1782 {{"L", l_vec}},
1783
1784 {{"GradL", l_grad_mat}},
1785
1786 {}, {})
1787
1788 );
1789 }
1790
1791 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1792 post_proc_fe);
1793 post_proc_fe->writeFile(out_name);
1795 };
1796
1797 if constexpr (debug)
1798 CHKERR post_proc(sub_dm, "initial_level_set.h5m", th_error);
1799
1800 swap_fe();
1801
1803}
1804
1806 boost::function<double(double, double, double)> vel_fun) {
1808
1809 // get operators tester
1810 auto simple = mField.getInterface<Simple>();
1811 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1812 // pipeline manager
1813 auto prb_mng = mField.getInterface<ProblemsManager>();
1814
1815 boost::shared_ptr<FEMethod> lhs_fe = boost::make_shared<DomainEle>(mField);
1816 boost::shared_ptr<FEMethod> rhs_fe = boost::make_shared<DomainEle>(mField);
1817 auto swap_fe = [&]() {
1818 lhs_fe.swap(pip->getDomainLhsFE());
1819 rhs_fe.swap(pip->getDomainRhsFE());
1820 };
1821 swap_fe();
1822
1823 pip->setDomainLhsIntegrationRule([](int, int, int o) { return 3 * o; });
1824 pip->setDomainRhsIntegrationRule([](int, int, int o) { return 3 * o; });
1825
1826 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
1827 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "VELOCITY_PROJECTION");
1828 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
1829 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
1830 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
1831 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "V");
1832 CHKERR DMSetUp(sub_dm);
1833
1834 // Velocities are calculated only on corse mesh
1835 BitRefLevel remove_mask = BitRefLevel().set(0);
1836 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
1837 CHKERR prb_mng->removeDofsOnEntities("VELOCITY_PROJECTION", "V",
1838 BitRefLevel().set(), remove_mask);
1839
1840 auto test_bit = [&](FEMethod *fe_ptr) {
1841 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(0);
1842 };
1843 pip->getDomainLhsFE()->exeTestHook = test_bit;
1844 pip->getDomainRhsFE()->exeTestHook = test_bit;
1845
1846 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainLhsPipeline(),
1847 {potential_velocity_space});
1848 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainRhsPipeline(),
1849 {potential_velocity_space});
1850
1851 pip->getOpDomainLhsPipeline().push_back(new OpMassVV("V", "V"));
1852 pip->getOpDomainRhsPipeline().push_back(new OpSourceV("V", vel_fun));
1853
1854 auto ksp = pip->createKSP(sub_dm);
1855 CHKERR KSPSetDM(ksp, sub_dm);
1856 CHKERR KSPSetFromOptions(ksp);
1857 CHKERR KSPSetUp(ksp);
1858
1859 auto L = createDMVector(sub_dm);
1860 auto F = vectorDuplicate(L);
1861
1862 CHKERR KSPSolve(ksp, F, L);
1863 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
1864 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
1865 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
1866
1867 auto post_proc = [&](auto dm, auto out_name) {
1869 auto post_proc_fe =
1870 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
1871 post_proc_fe->exeTestHook = test_bit;
1872
1873 if constexpr (FE_DIM == 2) {
1874
1876 post_proc_fe->getOpPtrVector(), {potential_velocity_space});
1877
1879
1880 auto potential_vec = boost::make_shared<VectorDouble>();
1881 auto velocity_mat = boost::make_shared<MatrixDouble>();
1882
1883 post_proc_fe->getOpPtrVector().push_back(
1884 new OpCalculateScalarFieldValues("V", potential_vec));
1885 post_proc_fe->getOpPtrVector().push_back(
1887 SPACE_DIM>("V", velocity_mat));
1888
1889 post_proc_fe->getOpPtrVector().push_back(
1890
1891 new OpPPMap(
1892
1893 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1894
1895 {{"VelocityPotential", potential_vec}},
1896
1897 {{"Velocity", velocity_mat}},
1898
1899 {}, {})
1900
1901 );
1902
1903 } else {
1904 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
1905 "3d case not implemented");
1906 }
1907
1908 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1909 post_proc_fe);
1910 post_proc_fe->writeFile(out_name);
1912 };
1913
1914 if constexpr (debug)
1915 CHKERR post_proc(sub_dm, "initial_velocity_potential.h5m");
1916
1917 swap_fe();
1918
1920}
1921
1924
1927
1928 // get operators tester
1929 auto simple = mField.getInterface<Simple>();
1930 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1931 auto prb_mng = mField.getInterface<ProblemsManager>();
1932
1935
1936 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
1937 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "ADVECTION");
1938 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
1939 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
1940 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
1941 CHKERR DMMoFEMAddElement(sub_dm, simple->getSkeletonFEName());
1942 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "L");
1943 CHKERR DMSetUp(sub_dm);
1944
1945 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
1946 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
1947 CHKERR prb_mng->removeDofsOnEntities("ADVECTION", "L", BitRefLevel().set(),
1948 remove_mask);
1949
1950 auto add_post_proc_fe = [&]() {
1951 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
1952
1953 Tag th_error;
1954 double def_val = 0;
1955 CHKERR mField.get_moab().tag_get_handle(
1956 "Error", 1, MB_TYPE_DOUBLE, th_error, MB_TAG_CREAT | MB_TAG_SPARSE,
1957 &def_val);
1958 post_proc_fe->setTagsToTransfer({th_error});
1959
1960 post_proc_fe->exeTestHook = [&](FEMethod *fe_ptr) {
1961 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1962 current_bit);
1963 };
1964
1966
1967 auto vel_ptr = boost::make_shared<MatrixDouble>();
1968
1970 post_proc_fe->getOpPtrVector(), {L2});
1971 post_proc_fe->getOpPtrVector().push_back(getZeroLevelVelOp(vel_ptr));
1972
1973 if constexpr (DIM1 == 1 && DIM2 == 1) {
1974 auto l_vec = boost::make_shared<VectorDouble>();
1975 post_proc_fe->getOpPtrVector().push_back(
1976 new OpCalculateScalarFieldValues("L", l_vec));
1977 post_proc_fe->getOpPtrVector().push_back(
1978
1979 new OpPPMap(
1980
1981 post_proc_fe->getPostProcMesh(),
1982
1983 post_proc_fe->getMapGaussPts(),
1984
1985 {{"L", l_vec}},
1986
1987 {{"V", vel_ptr}},
1988
1989 {}, {})
1990
1991 );
1992 }
1993 return post_proc_fe;
1994 };
1995
1996 auto post_proc_fe = add_post_proc_fe();
1997
1998 auto set_time_monitor = [&](auto dm, auto ts) {
1999 auto monitor_ptr = boost::make_shared<FEMethod>();
2000
2001 monitor_ptr->preProcessHook = []() { return 0; };
2002 monitor_ptr->operatorHook = []() { return 0; };
2003 monitor_ptr->postProcessHook = [&]() {
2005
2006 if (!post_proc_fe)
2007 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
2008 "Null pointer for post proc element");
2009
2010 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
2011 post_proc_fe);
2012 CHKERR post_proc_fe->writeFile(
2013 "level_set_" +
2014 boost::lexical_cast<std::string>(monitor_ptr->ts_step) + ".h5m");
2016 };
2017
2018 boost::shared_ptr<FEMethod> null;
2019 DMMoFEMTSSetMonitor(sub_dm, ts, simple->getDomainFEName(), monitor_ptr,
2020 null, null);
2021
2022 return monitor_ptr;
2023 };
2024
2025 auto ts = pip->createTSIM(sub_dm);
2026
2027 auto set_solution = [&](auto ts) {
2029 auto D = createDMVector(sub_dm);
2030 CHKERR DMoFEMMeshToLocalVector(sub_dm, D, INSERT_VALUES, SCATTER_FORWARD);
2031 CHKERR TSSetSolution(ts, D);
2033 };
2034 CHKERR set_solution(ts);
2035
2036 auto monitor_pt = set_time_monitor(sub_dm, ts);
2037 CHKERR TSSetFromOptions(ts);
2038
2039 auto B = createDMMatrix(sub_dm);
2040 CHKERR TSSetIJacobian(ts, B, B, TsSetIJacobian, nullptr);
2041 level_set_raw_ptr = this;
2042
2043 CHKERR TSSetUp(ts);
2044
2045 auto ts_pre_step = [](TS ts) {
2046 auto &m_field = level_set_raw_ptr->mField;
2047 auto simple = m_field.getInterface<Simple>();
2049
2050 auto [error, th_error] = level_set_raw_ptr->evaluateError();
2051 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
2052
2053 auto get_norm = [&](auto x) {
2054 double nrm;
2055 CHKERR VecNorm(x, NORM_2, &nrm);
2056 return nrm;
2057 };
2058
2059 auto set_solution = [&](auto ts) {
2061 DM dm;
2062 CHKERR TSGetDM(ts, &dm);
2063 auto prb_ptr = getProblemPtr(dm);
2064
2065 auto x = createDMVector(dm);
2066 CHKERR DMoFEMMeshToLocalVector(dm, x, INSERT_VALUES, SCATTER_FORWARD);
2067 CHKERR VecGhostUpdateBegin(x, INSERT_VALUES, SCATTER_FORWARD);
2068 CHKERR VecGhostUpdateEnd(x, INSERT_VALUES, SCATTER_FORWARD);
2069
2070 MOFEM_LOG("LevelSet", Sev::inform)
2071 << "Problem " << prb_ptr->getName() << " solution vector norm "
2072 << get_norm(x);
2073 CHKERR TSSetSolution(ts, x);
2074
2076 };
2077
2078 auto refine_and_project = [&](auto ts) {
2080
2082 WrapperClassErrorProjection(level_set_raw_ptr->maxPtr));
2083 simple->getBitRefLevel() = BitRefLevel().set(skeleton_bit) |
2084 BitRefLevel().set(aggregate_bit) |
2086
2087 simple->reSetUp(true);
2088 DM dm;
2089 CHKERR TSGetDM(ts, &dm);
2091
2092 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
2093 remove_mask
2094 .flip(); // DOFs which are not on bit_domain_ele should be removed
2096 ->removeDofsOnEntities("ADVECTION", "L", BitRefLevel().set(),
2097 remove_mask);
2098
2100 };
2101
2102 auto ts_reset_theta = [&](auto ts) {
2104 DM dm;
2105 CHKERR TSGetDM(ts, &dm);
2106
2107 // FIXME: Look into vec-5_free_surface how to transfer internal theta method variables
2108
2109 CHKERR TSReset(ts);
2110 CHKERR TSSetUp(ts);
2111
2113 CHKERR set_solution(ts);
2114
2115 auto B = createDMMatrix(dm);
2116 CHKERR TSSetIJacobian(ts, B, B, TsSetIJacobian, nullptr);
2117
2119 };
2120
2121 CHKERR refine_and_project(ts);
2122 CHKERR ts_reset_theta(ts);
2123
2125 };
2126
2127 auto ts_post_step = [](TS ts) { return 0; };
2128
2129 CHKERR TSSetPreStep(ts, ts_pre_step);
2130 CHKERR TSSetPostStep(ts, ts_post_step);
2131
2132 CHKERR TSSolve(ts, NULL);
2133
2135}
2136
2139
2140 auto bit_mng = mField.getInterface<BitRefManager>();
2141 auto proc_str = boost::lexical_cast<std::string>(mField.get_comm_rank());
2142
2143 auto set_bit = [](auto l) { return BitRefLevel().set(l); };
2144
2145 auto save_range = [&](const std::string name, const Range &r) {
2147 auto meshset_ptr = get_temp_meshset_ptr(mField.get_moab());
2148 CHKERR mField.get_moab().add_entities(*meshset_ptr, r);
2149 CHKERR mField.get_moab().write_file(name.c_str(), "VTK", "",
2150 meshset_ptr->get_ptr(), 1);
2152 };
2153
2154 // select domain elements to refine by threshold
2155 auto get_refined_elements_meshset = [&](auto bit, auto mask) {
2156 Range fe_ents;
2157 CHKERR bit_mng->getEntitiesByDimAndRefLevel(bit, mask, FE_DIM, fe_ents);
2158
2159 Tag th_error;
2160 CHK_MOAB_THROW(mField.get_moab().tag_get_handle("Error", th_error),
2161 "get error handle");
2162 std::vector<double> errors(fe_ents.size());
2164 mField.get_moab().tag_get_data(th_error, fe_ents, &*errors.begin()),
2165 "get tag data");
2166 auto it = std::max_element(errors.begin(), errors.end());
2167 double max;
2168 MPI_Allreduce(&*it, &max, 1, MPI_DOUBLE, MPI_MAX, mField.get_comm());
2169 MOFEM_LOG("LevelSet", Sev::inform) << "Max error: " << max;
2170 auto threshold = wp.getThreshold(max);
2171
2172 std::vector<EntityHandle> fe_to_refine;
2173 fe_to_refine.reserve(fe_ents.size());
2174
2175 auto fe_it = fe_ents.begin();
2176 auto error_it = errors.begin();
2177 for (auto i = 0; i != fe_ents.size(); ++i) {
2178 if (*error_it > threshold) {
2179 fe_to_refine.push_back(*fe_it);
2180 }
2181 ++fe_it;
2182 ++error_it;
2183 }
2184
2185 Range ents;
2186 ents.insert_list(fe_to_refine.begin(), fe_to_refine.end());
2187 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2188 ents, nullptr, NOISY);
2189
2190 auto get_neighbours_by_bridge_vertices = [&](auto &&ents) {
2191 Range verts;
2192 CHKERR mField.get_moab().get_connectivity(ents, verts, true);
2193 CHKERR mField.get_moab().get_adjacencies(verts, FE_DIM, false, ents,
2194 moab::Interface::UNION);
2195 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(ents);
2196 return ents;
2197 };
2198
2199 ents = get_neighbours_by_bridge_vertices(ents);
2200
2201#ifndef NDEBUG
2202 if (debug) {
2203 auto meshset_ptr = get_temp_meshset_ptr(mField.get_moab());
2204 CHK_MOAB_THROW(mField.get_moab().add_entities(*meshset_ptr, ents),
2205 "add entities to meshset");
2206 CHKERR mField.get_moab().write_file(
2207 (proc_str + "_fe_to_refine.vtk").c_str(), "VTK", "",
2208 meshset_ptr->get_ptr(), 1);
2209 }
2210#endif
2211
2212 return ents;
2213 };
2214
2215 // refine elements, and set bit ref level
2216 auto refine_mesh = [&](auto l, auto &&fe_to_refine) {
2217 Skinner skin(&mField.get_moab());
2219
2220 // get entities in "l-1" level
2221 Range level_ents;
2222 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2223 set_bit(start_bit + l - 1), BitRefLevel().set(), FE_DIM, level_ents);
2224 // select entities to refine
2225 fe_to_refine = intersect(level_ents, fe_to_refine);
2226 // select entities not to refine
2227 level_ents = subtract(level_ents, fe_to_refine);
2228
2229 // for entities to refine get children, i.e. redlined entities
2230 Range fe_to_refine_children;
2231 bit_mng->updateRangeByChildren(fe_to_refine, fe_to_refine_children);
2232 // add entities to to level "l"
2233 fe_to_refine_children = fe_to_refine_children.subset_by_dimension(FE_DIM);
2234 level_ents.merge(fe_to_refine_children);
2235
2236 auto fix_neighbour_level = [&](auto ll) {
2238 // filter entities on level ll
2239 auto level_ll = level_ents;
2240 CHKERR bit_mng->filterEntitiesByRefLevel(set_bit(ll), BitRefLevel().set(),
2241 level_ll);
2242 // find skin of ll level
2243 Range skin_edges;
2244 CHKERR skin.find_skin(0, level_ll, false, skin_edges);
2245 // get parents of skin of level ll
2246 Range skin_parents;
2247 for (auto lll = 0; lll <= ll; ++lll) {
2248 CHKERR bit_mng->updateRangeByParent(skin_edges, skin_parents);
2249 }
2250 // filter parents on level ll - 1
2251 BitRefLevel bad_bit;
2252 for (auto lll = 0; lll <= ll - 2; ++lll) {
2253 bad_bit[lll] = true;
2254 }
2255 // get adjacents to parents
2256 Range skin_adj_ents;
2257 CHKERR mField.get_moab().get_adjacencies(
2258 skin_parents, FE_DIM, false, skin_adj_ents, moab::Interface::UNION);
2259 CHKERR bit_mng->filterEntitiesByRefLevel(bad_bit, BitRefLevel().set(),
2260 skin_adj_ents);
2261 skin_adj_ents = intersect(skin_adj_ents, level_ents);
2262 if (!skin_adj_ents.empty()) {
2263 level_ents = subtract(level_ents, skin_adj_ents);
2264 Range skin_adj_ents_children;
2265 bit_mng->updateRangeByChildren(skin_adj_ents, skin_adj_ents_children);
2266 level_ents.merge(skin_adj_ents_children);
2267 }
2269 };
2270
2271 CHKERR fix_neighbour_level(l);
2272
2273 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2274 level_ents);
2275
2276 // get lower dimension entities for level "l"
2277 for (auto d = 0; d != FE_DIM; ++d) {
2278 if (d == 0) {
2279 CHKERR mField.get_moab().get_connectivity(
2280 level_ents.subset_by_dimension(FE_DIM), level_ents, true);
2281 } else {
2282 CHKERR mField.get_moab().get_adjacencies(
2283 level_ents.subset_by_dimension(FE_DIM), d, false, level_ents,
2284 moab::Interface::UNION);
2285 }
2286 }
2287 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2288 level_ents);
2289
2290 // set bit ref level to level entities
2291 CHKERR bit_mng->setNthBitRefLevel(start_bit + l, false);
2292 CHKERR bit_mng->setNthBitRefLevel(level_ents, start_bit + l, true);
2293
2294#ifndef NDEBUG
2295 auto proc_str = boost::lexical_cast<std::string>(mField.get_comm_rank());
2296 CHKERR bit_mng->writeBitLevelByDim(
2297 set_bit(start_bit + l), BitRefLevel().set(), FE_DIM,
2298 (boost::lexical_cast<std::string>(l) + "_" + proc_str + "_ref_mesh.vtk")
2299 .c_str(),
2300 "VTK", "");
2301#endif
2302
2304 };
2305
2306 // set skeleton
2307 auto set_skelton_bit = [&](auto l) {
2309
2310 // get entities of dim-1 on level "l"
2311 Range level_edges;
2312 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2313 set_bit(start_bit + l), BitRefLevel().set(), FE_DIM - 1, level_edges);
2314
2315 // get parent of entities of level "l"
2316 Range level_edges_parents;
2317 CHKERR bit_mng->updateRangeByParent(level_edges, level_edges_parents);
2318 level_edges_parents = level_edges_parents.subset_by_dimension(FE_DIM - 1);
2319 CHKERR bit_mng->filterEntitiesByRefLevel(
2320 set_bit(start_bit + l), BitRefLevel().set(), level_edges_parents);
2321
2322 // skeleton entities which do not have parents
2323 auto parent_skeleton = intersect(level_edges, level_edges_parents);
2324 auto skeleton = subtract(level_edges, level_edges_parents);
2325
2326 // add adjacent domain entities
2327 CHKERR mField.get_moab().get_adjacencies(unite(parent_skeleton, skeleton),
2328 FE_DIM, false, skeleton,
2329 moab::Interface::UNION);
2330
2331 // set levels
2332 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(skeleton);
2333 CHKERR bit_mng->setNthBitRefLevel(skeleton_bit, false);
2334 CHKERR bit_mng->setNthBitRefLevel(skeleton, skeleton_bit, true);
2335
2336#ifndef NDEBUG
2337 CHKERR bit_mng->writeBitLevel(
2338 set_bit(skeleton_bit), BitRefLevel().set(),
2339 (boost::lexical_cast<std::string>(l) + "_" + proc_str + "_skeleton.vtk")
2340 .c_str(),
2341 "VTK", "");
2342#endif
2344 };
2345
2346 // Reset bit sand set old current and aggregate bits as projection bits
2347 Range level0_current;
2348 CHKERR bit_mng->getEntitiesByRefLevel(BitRefLevel().set(current_bit),
2349 BitRefLevel().set(), level0_current);
2350
2351 Range level0_aggregate;
2352 CHKERR bit_mng->getEntitiesByRefLevel(BitRefLevel().set(aggregate_bit),
2353 BitRefLevel().set(), level0_aggregate);
2354
2355 BitRefLevel start_mask;
2356 for (auto s = 0; s != start_bit; ++s)
2357 start_mask[s] = true;
2358 CHKERR bit_mng->lambdaBitRefLevel(
2359 [&](EntityHandle ent, BitRefLevel &bit) { bit &= start_mask; });
2360 CHKERR bit_mng->setNthBitRefLevel(level0_current, projection_bit, true);
2361 CHKERR bit_mng->setNthBitRefLevel(level0_aggregate, aggregate_projection_bit,
2362 true);
2363
2364 // Set zero bit ref level
2365 Range level0;
2366 CHKERR bit_mng->getEntitiesByRefLevel(set_bit(0), BitRefLevel().set(),
2367 level0);
2368 CHKERR bit_mng->setNthBitRefLevel(level0, start_bit, true);
2369 CHKERR bit_mng->setNthBitRefLevel(level0, current_bit, true);
2370 CHKERR bit_mng->setNthBitRefLevel(level0, aggregate_bit, true);
2371 CHKERR bit_mng->setNthBitRefLevel(level0, skeleton_bit, true);
2372
2373 CHKERR wp.setBits(*this, 0);
2374 CHKERR wp.runCalcs(*this, 0);
2375 for (auto l = 0; l != nb_levels; ++l) {
2376 MOFEM_LOG("WORLD", Sev::inform) << "Process level: " << l;
2377 CHKERR refine_mesh(l + 1, get_refined_elements_meshset(
2378 set_bit(start_bit + l), BitRefLevel().set()));
2379 CHKERR set_skelton_bit(l + 1);
2380 CHKERR wp.setAggregateBit(*this, l + 1);
2381 CHKERR wp.setBits(*this, l + 1);
2382 CHKERR wp.runCalcs(*this, l + 1);
2383 }
2384
2386}
2387
2390
2391 // get operators tester
2392 auto simple = mField.getInterface<Simple>();
2393 auto bit_mng = mField.getInterface<BitRefManager>();
2394 auto prb_mng = mField.getInterface<ProblemsManager>();
2395
2396 auto lhs_fe = boost::make_shared<DomainEle>(mField);
2397 auto rhs_fe_prj = boost::make_shared<DomainEle>(mField);
2398 auto rhs_fe_current = boost::make_shared<DomainEle>(mField);
2399
2400 lhs_fe->getRuleHook = [](int, int, int o) { return 3 * o; };
2401 rhs_fe_prj->getRuleHook = [](int, int, int o) { return 3 * o; };
2402 rhs_fe_current->getRuleHook = [](int, int, int o) { return 3 * o; };
2403
2404 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
2405 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "DG_PROJECTION");
2406 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
2407 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
2408 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
2409 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "L");
2410 CHKERR DMSetUp(sub_dm);
2411
2412 Range current_ents; // ents used to do calculations
2413 CHKERR bit_mng->getEntitiesByDimAndRefLevel(BitRefLevel().set(current_bit),
2414 BitRefLevel().set(), FE_DIM,
2415 current_ents);
2416 Range prj_ents; // ents from which data are projected
2417 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2418 BitRefLevel().set(projection_bit), BitRefLevel().set(), FE_DIM, prj_ents);
2419 for (auto l = 0; l != nb_levels; ++l) {
2420 CHKERR bit_mng->updateRangeByParent(prj_ents, prj_ents);
2421 }
2422 current_ents = subtract(
2423 current_ents, prj_ents); // only restric to entities needed projection
2424
2425 auto test_mesh_bit = [&](FEMethod *fe_ptr) {
2426 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2427 current_bit);
2428 };
2429 auto test_prj_bit = [&](FEMethod *fe_ptr) {
2430 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2432 };
2433 auto test_current_bit = [&](FEMethod *fe_ptr) {
2434 return current_ents.find(fe_ptr->getFEEntityHandle()) != current_ents.end();
2435 };
2436
2437 lhs_fe->exeTestHook =
2438 test_mesh_bit; // that element only is run when current bit is set
2439 rhs_fe_prj->exeTestHook =
2440 test_prj_bit; // that element is run only when projection bit is set
2441 rhs_fe_current->exeTestHook =
2442 test_current_bit; // that element is only run when current bit is set
2443
2444 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
2445 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
2446 CHKERR prb_mng->removeDofsOnEntities(
2447 "DG_PROJECTION", "L", BitRefLevel().set(), remove_mask, nullptr, 0,
2448 MAX_DOFS_ON_ENTITY, 0, 100, NOISY,
2449 true); // remove all DOFs which are not
2450 // on current bit. This case works for L2 space
2451
2452 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(lhs_fe->getOpPtrVector(),
2453 {L2});
2454 lhs_fe->getOpPtrVector().push_back(
2455 new OpMassLL("L", "L")); // Assemble projection matrix
2456
2457 auto make_tensor_mat_to_vec_mat_op = [](auto src_mat_ptr, auto dst_mat_ptr) {
2458 auto op_ptr = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
2459 op_ptr->doWorkRhsHook = [src_mat_ptr, dst_mat_ptr](DataOperator *op_ptr,
2460 int, EntityType,
2461 EntData &) {
2463 const auto nb_gauss_pts =
2464 static_cast<DomainEleOp *>(op_ptr)->getGaussPts().size2();
2465 auto &src_mat = *src_mat_ptr;
2466 auto &dst_mat = *dst_mat_ptr;
2467#ifndef NDEBUG
2468 if (src_mat.size1() != nb_gauss_pts)
2469 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2470 "Wrong number of integration pts %zu != %zu", src_mat.size1(),
2471 nb_gauss_pts);
2472 if (src_mat.size2() != DIM1 * DIM2)
2473 SETERRQ(PETSC_COMM_SELF, MOFEM_DATA_INCONSISTENCY,
2474 "Wrong tensor components layout %zu != %d", src_mat.size2(),
2475 DIM1 * DIM2);
2476#endif
2477 dst_mat.resize(nb_gauss_pts, DIM1 * DIM2, false);
2478 for (size_t gg = 0; gg != nb_gauss_pts; ++gg)
2479 for (size_t dd = 0; dd != DIM1 * DIM2; ++dd)
2480 dst_mat(gg, dd) = src_mat(gg, dd);
2482 };
2483 return op_ptr;
2484 };
2485
2486 // This assumes that projection mesh is finer, current mesh is coarsened.
2487 auto set_prj_from_child = [&](auto rhs_fe_prj) {
2489 rhs_fe_prj->getOpPtrVector(), {L2});
2490
2491 // Evaluate field value on projection mesh
2492 auto l_tensor_mat = boost::make_shared<MatrixDouble>();
2493 auto l_vec_mat = boost::make_shared<MatrixDouble>();
2494 rhs_fe_prj->getOpPtrVector().push_back(
2495 new OpCalculateTensor2FieldValues<DIM1, DIM2>("L", l_tensor_mat));
2496 rhs_fe_prj->getOpPtrVector().push_back(
2497 make_tensor_mat_to_vec_mat_op(l_tensor_mat, l_vec_mat));
2498
2499 // This element is used to assemble
2500 auto get_parent_this = [&]() {
2501 auto fe_parent_this = boost::make_shared<DomainParentEle>(mField);
2502 fe_parent_this->getOpPtrVector().push_back(
2503 new OpScalarFieldL("L", l_vec_mat));
2504 return fe_parent_this;
2505 };
2506
2507 // Create levels of parent elements, until current element is reached, and
2508 // then assemble.
2509 auto get_parents_fe_ptr = [&](auto this_fe_ptr) {
2510 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
2511 for (int l = 0; l <= nb_levels; ++l)
2512 parents_elems_ptr_vec.emplace_back(
2513 boost::make_shared<DomainParentEle>(mField));
2514 for (auto l = 1; l <= nb_levels; ++l) {
2515 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
2516 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
2517 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
2518 BitRefLevel().set(current_bit),
2519 BitRefLevel().set()));
2520 }
2521 return parents_elems_ptr_vec[0];
2522 };
2523
2524 auto this_fe_ptr = get_parent_this();
2525 auto parent_fe_ptr = get_parents_fe_ptr(this_fe_ptr);
2526 rhs_fe_prj->getOpPtrVector().push_back(
2527 new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
2528 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
2529 BitRefLevel().set(current_bit), BitRefLevel().set()));
2530 };
2531
2532 // This assumed that current mesh is refined, and projection mesh is coarser
2533 auto set_prj_from_parent = [&](auto rhs_fe_current) {
2534
2535 // Evaluate field value on projection mesh
2536 auto l_tensor_mat = boost::make_shared<MatrixDouble>();
2537 auto l_vec_mat = boost::make_shared<MatrixDouble>();
2538
2539 // Evaluate field on coarser element
2540 auto get_parent_this = [&]() {
2541 auto fe_parent_this = boost::make_shared<DomainParentEle>(mField);
2542 fe_parent_this->getOpPtrVector().push_back(
2543 new OpCalculateTensor2FieldValues<DIM1, DIM2>("L", l_tensor_mat));
2544 fe_parent_this->getOpPtrVector().push_back(
2545 make_tensor_mat_to_vec_mat_op(l_tensor_mat, l_vec_mat));
2546 return fe_parent_this;
2547 };
2548
2549 // Create stack of evaluation on parent elements
2550 auto get_parents_fe_ptr = [&](auto this_fe_ptr) {
2551 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
2552 for (int l = 0; l <= nb_levels; ++l)
2553 parents_elems_ptr_vec.emplace_back(
2554 boost::make_shared<DomainParentEle>(mField));
2555 for (auto l = 1; l <= nb_levels; ++l) {
2556 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
2557 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
2558 BitRefLevel().set(projection_bit).flip(),
2559 this_fe_ptr, BitRefLevel().set(projection_bit),
2560 BitRefLevel().set()));
2561 }
2562 return parents_elems_ptr_vec[0];
2563 };
2564
2565 auto this_fe_ptr = get_parent_this();
2566 auto parent_fe_ptr = get_parents_fe_ptr(this_fe_ptr);
2567
2568 auto reset_op_ptr = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
2569 reset_op_ptr->doWorkRhsHook = [&](DataOperator *op_ptr, int, EntityType,
2570 EntData &) {
2571 l_vec_mat->resize(
2572 static_cast<DomainEleOp *>(op_ptr)->getGaussPts().size2(),
2573 DIM1 * DIM2, false);
2574 l_vec_mat->clear();
2575 return 0;
2576 };
2577 rhs_fe_current->getOpPtrVector().push_back(reset_op_ptr);
2578 rhs_fe_current->getOpPtrVector().push_back(
2579 new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
2580 BitRefLevel().set(projection_bit).flip(), this_fe_ptr,
2581 BitRefLevel(), BitRefLevel()));
2582
2583 // At the end assemble of current finite element
2584 rhs_fe_current->getOpPtrVector().push_back(
2585 new OpScalarFieldL("L", l_vec_mat));
2586 };
2587
2588 set_prj_from_child(rhs_fe_prj);
2589 set_prj_from_parent(rhs_fe_current);
2590
2591 boost::shared_ptr<FEMethod> null_fe;
2592 getDMKspCtx(sub_dm)->clearLoops();
2593 CHKERR DMMoFEMKSPSetComputeOperators(sub_dm, simple->getDomainFEName(),
2594 lhs_fe, null_fe, null_fe);
2595 CHKERR DMMoFEMKSPSetComputeRHS(sub_dm, simple->getDomainFEName(), rhs_fe_prj,
2596 null_fe, null_fe);
2597 CHKERR DMMoFEMKSPSetComputeRHS(sub_dm, simple->getDomainFEName(),
2598 rhs_fe_current, null_fe, null_fe);
2599 auto ksp = MoFEM::createKSP(mField.get_comm());
2600 CHKERR KSPSetDM(ksp, sub_dm);
2601
2602 CHKERR KSPSetDM(ksp, sub_dm);
2603 CHKERR KSPSetFromOptions(ksp);
2604 CHKERR KSPSetUp(ksp);
2605
2606 auto L = createDMVector(sub_dm);
2607 auto F = vectorDuplicate(L);
2608
2609 CHKERR KSPSolve(ksp, F, L);
2610 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
2611 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
2612 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
2613
2614 auto [error, th_error] = evaluateError();
2615 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
2616
2617 auto post_proc = [&](auto dm, auto out_name, auto th_error) {
2619 auto post_proc_fe =
2620 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
2621 post_proc_fe->setTagsToTransfer({th_error});
2622 post_proc_fe->exeTestHook = test_mesh_bit;
2623
2624 if constexpr (DIM1 == 1 && DIM2 == 1) {
2626 auto l_vec = boost::make_shared<VectorDouble>();
2627 auto l_grad_mat = boost::make_shared<MatrixDouble>();
2629 post_proc_fe->getOpPtrVector(), {L2});
2630 post_proc_fe->getOpPtrVector().push_back(
2631 new OpCalculateScalarFieldValues("L", l_vec));
2632 post_proc_fe->getOpPtrVector().push_back(
2633 new OpCalculateScalarFieldGradient<SPACE_DIM>("L", l_grad_mat));
2634
2635 post_proc_fe->getOpPtrVector().push_back(
2636
2637 new OpPPMap(
2638
2639 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
2640
2641 {{"L", l_vec}},
2642
2643 {{"GradL", l_grad_mat}},
2644
2645 {}, {})
2646
2647 );
2648 }
2649
2650 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
2651 post_proc_fe);
2652 post_proc_fe->writeFile(out_name);
2654 };
2655
2656 if constexpr (debug)
2657 CHKERR post_proc(sub_dm, "dg_projection.h5m", th_error);
2658
2660}
std::string type
#define MOFEM_LOG_C(channel, severity, format,...)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
int main()
static const double eps
ElementsAndOps< SPACE_DIM >::DomainParentEle DomainParentEle
constexpr int SPACE_DIM
DomainEle::UserDataOperator DomainEleOp
Finire element operator type.
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
ElementsAndOps< SPACE_DIM >::BoundaryEle BoundaryEle
BoundaryEle::UserDataOperator BoundaryEleOp
@ NOISY
#define CATCH_ERRORS
Catch errors.
#define MAX_DOFS_ON_ENTITY
Maximal number of DOFs on entity.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
FieldSpace
approximation spaces
Definition definitions.h:82
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
@ HCURL
field with continuous tangents
Definition definitions.h:86
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
@ 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
PetscErrorCode DMMoFEMKSPSetComputeRHS(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
set KSP right hand side evaluation function
Definition DMMoFEM.cpp:627
PetscErrorCode DMoFEMLoopFiniteElements(DM dm, const char fe_name[], MoFEM::FEMethod *method, CacheTupleWeakPtr cache_ptr=CacheTupleSharedPtr())
Executes FEMethod for finite elements in DM.
Definition DMMoFEM.cpp:576
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1194
PetscErrorCode DMSubDMSetUp_MoFEM(DM subdm)
Definition DMMoFEM.cpp:1345
PetscErrorCode DMMoFEMKSPSetComputeOperators(DM dm, const char fe_name[], MoFEM::FEMethod *method, MoFEM::BasicMethod *pre_only, MoFEM::BasicMethod *post_only)
Set KSP operators and push mofem finite element methods.
Definition DMMoFEM.cpp:668
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
boost::ptr_deque< UserDataOperator > & getOpSkeletonLhsPipeline()
Get the Op Skeleton Lhs Pipeline object.
virtual EntityHandle get_finite_element_meshset(const std::string name) const =0
IntegrationType
Form integrator integration types.
AssemblyType
[Storage and set boundary conditions]
static LoggerType & setLog(const std::string channel)
Set ans resset chanel logger.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_TAG(channel, tag)
Tag channel.
auto bit
set bit
FTensor::Index< 'i', SPACE_DIM > i
double D
constexpr int FE_DIM
[Define dimension]
Definition level_set.cpp:19
constexpr int skeleton_bit
skeleton elements bit
Definition level_set.cpp:65
FTensor::Index< 'I', DIM1 > I
Definition level_set.cpp:29
FTensor::Index< 'j', SPACE_DIM > j
constexpr int current_bit
dofs bit used to do calculations
Definition level_set.cpp:63
constexpr FieldSpace potential_velocity_space
Definition level_set.cpp:49
static char help[]
Definition level_set.cpp:14
FTensor::Index< 'k', SPACE_DIM > k
constexpr int nb_levels
Definition level_set.cpp:58
FTensor::Index< 'i', SPACE_DIM > i
constexpr int SPACE_DIM
Definition level_set.cpp:20
constexpr int DIM2
Definition level_set.cpp:22
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
constexpr int start_bit
Definition level_set.cpp:60
FaceSideEle::UserDataOperator FaceSideEleOp
Definition level_set.cpp:45
constexpr int aggregate_projection_bit
all bits for projection problem
Definition level_set.cpp:70
PipelineManager::ElementsAndOpsByDim< FE_DIM >::FaceSideEle FaceSideEle
Definition level_set.cpp:41
DomainEle::UserDataOperator DomainEleOp
Definition level_set.cpp:43
constexpr AssemblyType A
Definition level_set.cpp:32
LevelSet * level_set_raw_ptr
constexpr int aggregate_bit
all bits for advection problem
Definition level_set.cpp:66
constexpr int projection_bit
Definition level_set.cpp:68
constexpr IntegrationType G
Definition level_set.cpp:33
constexpr int DIM1
Definition level_set.cpp:21
MoFEM::TsCtx * ts_ctx
constexpr size_t potential_velocity_field_dim
Definition level_set.cpp:50
FTensor::Index< 'l', 3 > l
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)
PetscErrorCode DMMoFEMTSSetMonitor(DM dm, TS ts, const std::string fe_name, boost::shared_ptr< MoFEM::FEMethod > method, boost::shared_ptr< MoFEM::BasicMethod > pre_only, boost::shared_ptr< MoFEM::BasicMethod > post_only)
Set Monitor To TS solver.
Definition DMMoFEM.cpp:1046
PetscErrorCode TsSetIJacobian(TS ts, PetscReal t, Vec u, Vec u_t, PetscReal a, Mat A, Mat B, void *ctx)
Set function evaluating jacobian in TS solver.
Definition TsCtx.cpp:169
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:434
static const bool debug
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
Definition DMMoFEM.hpp:1251
constexpr auto make_array(Arg &&...arg)
Create Array.
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.
auto getProblemPtr(DM dm)
get problem pointer from DM
Definition DMMoFEM.hpp:1182
constexpr IntegrationType I
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
@ LEFT_SIDE
Definition plate.cpp:92
@ RIGHT_SIDE
Definition plate.cpp:92
auto get_ntensor(T &base_mat)
Definition plate.cpp:463
constexpr double t
plate stiffness
Definition plate.cpp:58
constexpr auto field_name
OpBaseImpl< PETSC, EdgeEleOp > OpBase
Definition radiation.cpp:29
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, SPACE_DIM > OpMass
[Only used with Hooke equation (linear material model)]
Definition seepage.cpp:56
OpLhsDomain(const std::string field_name, boost::shared_ptr< MatrixDouble > vel_ptr)
MoFEMErrorCode iNtegrate(EntData &row_data, EntData &col_data)
boost::shared_ptr< MatrixDouble > velPtr
boost::shared_ptr< FaceSideEle > sideFEPtr
pointer to element to get data on edge/face sides
boost::shared_ptr< SideData > sideDataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
OpLhsSkeleton(boost::shared_ptr< SideData > side_data_ptr, boost::shared_ptr< FaceSideEle > side_fe_ptr)
boost::shared_ptr< MatrixDouble > lPtr
MoFEMErrorCode iNtegrate(EntData &data)
boost::shared_ptr< MatrixDouble > velPtr
OpRhsDomain(const std::string field_name, boost::shared_ptr< MatrixDouble > l_ptr, boost::shared_ptr< MatrixDouble > l_dot_ptr, boost::shared_ptr< MatrixDouble > vel_ptr)
boost::shared_ptr< MatrixDouble > lDotPtr
MoFEMErrorCode doWork(int side, EntityType type, EntitiesFieldData::EntData &data)
boost::shared_ptr< SideData > sideDataPtr
OpRhsSkeleton(boost::shared_ptr< SideData > side_data_ptr, boost::shared_ptr< FaceSideEle > side_fe_ptr)
boost::shared_ptr< FaceSideEle > sideFEPtr
pointer to element to get data on edge/face sides
data structure carrying information on skeleton on both sides.
Definition level_set.cpp:86
std::array< VectorInt, 2 > indicesColSideMap
indices on columns for left hand-side
Definition level_set.cpp:92
MatSideArray velMat
Definition level_set.cpp:99
std::array< EntityHandle, 2 > feSideHandle
Definition level_set.cpp:88
int currentFESide
current side counter
std::array< MatrixDouble, 2 > colBaseSideMap
Definition level_set.cpp:94
std::array< MatrixDouble, 2 > rowBaseSideMap
Definition level_set.cpp:93
std::array< VectorInt, 2 > indicesRowSideMap
indices on rows for left hand-side
Definition level_set.cpp:90
MatSideArray lVec
Definition level_set.cpp:98
std::array< int, 2 > senseMap
Definition level_set.cpp:95
Use peculated errors on all levels while mesh projection.
WrapperClassErrorProjection(boost::shared_ptr< double > max_ptr)
MoFEMErrorCode runCalcs(LevelSet &level_set, int l)
Run calculations.
MoFEMErrorCode setBits(LevelSet &level_set, int l)
Set bit ref level to problem.
double getThreshold(const double max)
MoFEMErrorCode setAggregateBit(LevelSet &level_set, int l)
Add bit to current element, so it aggregate all previious current elements.
boost::shared_ptr< double > maxPtr
Used to execute inital mesh approximation while mesh refinement.
double getThreshold(const double max)
MoFEMErrorCode setAggregateBit(LevelSet &level_set, int l)
Add bit to current element, so it aggregate all previious current elements.
boost::shared_ptr< double > maxPtr
MoFEMErrorCode setBits(LevelSet &level_set, int l)
Set bit ref level to problem.
WrapperClassInitalSolution(boost::shared_ptr< double > max_ptr)
MoFEMErrorCode runCalcs(LevelSet &level_set, int l)
Run calculations.
Wrapper executing stages while mesh refinement.
virtual double getThreshold(const double max)=0
virtual MoFEMErrorCode runCalcs(LevelSet &level_set, int l)=0
Run calculations.
virtual MoFEMErrorCode setAggregateBit(LevelSet &level_set, int l)=0
Add bit to current element, so it aggregate all previious current elements.
virtual MoFEMErrorCode setBits(LevelSet &level_set, int l)=0
Set bit ref level to problem.
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< potential_velocity_field_dim, potential_velocity_field_dim > OpMassVV
MoFEM::Interface & mField
integrate skeleton operators on khs
MoFEMErrorCode solveAdvection()
solve advection problem
boost::shared_ptr< double > maxPtr
std::array< MatrixDouble, 2 > MatSideArray
Definition level_set.cpp:80
MoFEMErrorCode readMesh()
read mesh
MoFEMErrorCode setUpProblem()
create fields, and set approximation order
MoFEMErrorCode initialiseFieldLevelSet(boost::function< double(double, double, double)> level_fun=get_level_set)
initialise field set
boost::shared_ptr< FaceSideEle > getSideFE(boost::shared_ptr< SideData > side_data_ptr)
create side element to assemble data from sides
MoFEMErrorCode pushOpDomain()
push operators to integrate operators on domain
MoFEMErrorCode runProblem()
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< 1, DIM1 *DIM2 > OpSourceL
LevelSet(MoFEM::Interface &m_field)
Definition level_set.cpp:75
static double get_velocity_potential(double x, double y, double z)
advection velocity field
MoFEMErrorCode pushOpSkeleton()
push operator to integrate on skeleton
MoFEMErrorCode testOp()
test consistency between tangent matrix and the right hand side vectors
MoFEMErrorCode dgProjection(const int prj_bit=projection_bit)
dg level set projection
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< 1, DIM1 *DIM2 > OpMassLL
static double get_level_set(const double x, const double y, const double z)
inital level set, i.e. advected field
MoFEMErrorCode refineMesh(WrapperClass &&wp)
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpBaseTimesVector< 1, DIM1 *DIM2, 1 > OpScalarFieldL
ForcesAndSourcesCore::UserDataOperator * getZeroLevelVelOp(boost::shared_ptr< MatrixDouble > vel_ptr)
Get operator calculating velocity on coarse mesh.
std::tuple< double, Tag > evaluateError()
evaluate error
MoFEMErrorCode testSideFE()
test integration side elements
MoFEMErrorCode initialiseFieldVelocity(boost::function< double(double, double, double)> vel_fun=get_velocity_potential< FE_DIM >)
initialise potential velocity field
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< potential_velocity_field_dim, potential_velocity_field_dim > OpSourceV
Add operators pushing bases from local to physical configuration.
Managing BitRefLevels.
Managing BitRefLevels.
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
virtual int get_comm_rank() 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)
FTensor::Tensor0< FTensor::PackPtr< double *, 1 > > getFTensor0N(const FieldApproximationBase base)
Get base function as Tensor0.
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MatrixDouble & getN(const FieldApproximationBase base)
get base functions this return matrix (nb. of rows is equal to nb. of Gauss pts, nb....
const VectorInt & getIndices() const
Get global indices of degrees of freedom on entity.
Structure for user loop methods on finite elements.
Basic algebra on fields.
Definition FieldBlas.hpp:21
static boost::shared_ptr< SinkType > createSink(boost::shared_ptr< std::ostream > stream_ptr, std::string comm_filter)
Create a sink object.
static boost::shared_ptr< std::ostream > getStrmWorld()
Get the strm world object.
Calculate curl of vector field.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Get time direvarive values at integration pts for tensor field rank 2, i.e. matrix field.
Get values at integration pts for tensor field rank 2, i.e. matrix field.
Post post-proc data at points from hash maps.
Operator to execute finite element instance on parent element. This operator is typically used to pro...
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...
Template struct for dimension-specific finite element types.
PipelineManager interface.
Problem manager is used to build and partition problems.
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
const std::string getBoundaryFEName() const
Get the Boundary FE Name.
Definition Simple.hpp:436
const std::string getSkeletonFEName() const
Get the Skeleton FE Name.
Definition Simple.hpp:443
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
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
Interface for Time Stepping (TS) solver.
Definition TsCtx.hpp:17
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
#define EXECUTABLE_DIMENSION
Definition plastic.cpp:13
auto save_range