v0.16.3
Loading...
Searching...
No Matches
Classes | Public Member Functions | Private Types | Private Member Functions | Static Private Member Functions | Private Attributes | List of all members
LevelSet Struct Reference
Collaboration diagram for LevelSet:
[legend]

Classes

struct  OpLhsDomain
 
struct  OpLhsSkeleton
 
struct  OpRhsDomain
 
struct  OpRhsSkeleton
 
struct  SideData
 data structure carrying information on skeleton on both sides. More...
 
struct  WrapperClass
 Wrapper executing stages while mesh refinement. More...
 
struct  WrapperClassErrorProjection
 Use peculated errors on all levels while mesh projection. More...
 
struct  WrapperClassInitalSolution
 Used to execute inital mesh approximation while mesh refinement. More...
 

Public Member Functions

 LevelSet (MoFEM::Interface &m_field)
 
MoFEMErrorCode runProblem ()
 

Private Types

enum  ElementSide { LEFT_SIDE = 0 , RIGHT_SIDE = 1 }
 
using MatSideArray = std::array< MatrixDouble, 2 >
 
using AssemblyDomainEleOp = FormsIntegrators< DomainEleOp >::Assembly< A >::OpBase
 
using OpMassLL = FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< 1, DIM1 *DIM2 >
 
using OpSourceL = FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< 1, DIM1 *DIM2 >
 
using OpMassVV = FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< potential_velocity_field_dim, potential_velocity_field_dim >
 
using OpSourceV = FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< potential_velocity_field_dim, potential_velocity_field_dim >
 
using OpScalarFieldL = FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpBaseTimesVector< 1, DIM1 *DIM2, 1 >
 
using AssemblyBoundaryEleOp = FormsIntegrators< BoundaryEleOp >::Assembly< A >::OpBase
 

Private Member Functions

MoFEMErrorCode readMesh ()
 read mesh
 
MoFEMErrorCode setUpProblem ()
 create fields, and set approximation order
 
MoFEMErrorCode pushOpDomain ()
 push operators to integrate operators on domain
 
std::tuple< double, Tag > evaluateError ()
 evaluate error
 
ForcesAndSourcesCore::UserDataOperator * getZeroLevelVelOp (boost::shared_ptr< MatrixDouble > vel_ptr)
 Get operator calculating velocity on coarse mesh.
 
boost::shared_ptr< FaceSideEle > getSideFE (boost::shared_ptr< SideData > side_data_ptr)
 create side element to assemble data from sides
 
MoFEMErrorCode pushOpSkeleton ()
 push operator to integrate on skeleton
 
MoFEMErrorCode testSideFE ()
 test integration side elements
 
MoFEMErrorCode testOp ()
 test consistency between tangent matrix and the right hand side vectors
 
MoFEMErrorCode initialiseFieldLevelSet (boost::function< double(double, double, double)> level_fun=get_level_set)
 initialise field set
 
MoFEMErrorCode initialiseFieldVelocity (boost::function< double(double, double, double)> vel_fun=get_velocity_potential< FE_DIM >)
 initialise potential velocity field
 
MoFEMErrorCode dgProjection (const int prj_bit=projection_bit)
 dg level set projection
 
MoFEMErrorCode solveAdvection ()
 solve advection problem
 
MoFEMErrorCode refineMesh (WrapperClass &&wp)
 

Static Private Member Functions

template<int FE_DIM>
static double get_velocity_potential (double x, double y, double z)
 advection velocity field
 
static double get_level_set (const double x, const double y, const double z)
 inital level set, i.e. advected field
 
template<>
double get_velocity_potential (double x, double y, double z)
 

Private Attributes

MoFEM::Interface & mField
 integrate skeleton operators on khs
 
boost::shared_ptr< double > maxPtr
 
SmartPetscObj< Vec > tsSolutionVec
 

Detailed Description

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 73 of file level_set.cpp.

Member Typedef Documentation

◆ AssemblyBoundaryEleOp

Definition at line 364 of file level_set.cpp.

◆ AssemblyDomainEleOp

Definition at line 351 of file level_set.cpp.

◆ MatSideArray

using LevelSet::MatSideArray = std::array<MatrixDouble, 2>
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 80 of file level_set.cpp.

◆ OpMassLL

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 353 of file level_set.cpp.

◆ OpMassVV

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 357 of file level_set.cpp.

◆ OpScalarFieldL

using LevelSet::OpScalarFieldL = FormsIntegrators<DomainEleOp>::Assembly<A>::LinearForm< G>::OpBaseTimesVector<1, DIM1 * DIM2, 1>
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 361 of file level_set.cpp.

◆ OpSourceL

using LevelSet::OpSourceL = FormsIntegrators<DomainEleOp>::Assembly<A>::LinearForm< G>::OpSource<1, DIM1 * DIM2>
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 355 of file level_set.cpp.

◆ OpSourceV

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 359 of file level_set.cpp.

Member Enumeration Documentation

◆ ElementSide

enum LevelSet::ElementSide
private
Enumerator
LEFT_SIDE 
RIGHT_SIDE 

Definition at line 367 of file level_set.cpp.

367{ LEFT_SIDE = 0, RIGHT_SIDE = 1 };

Constructor & Destructor Documentation

◆ LevelSet()

LevelSet::LevelSet ( MoFEM::Interface &  m_field)
inline

Definition at line 75 of file level_set.cpp.

75: mField(m_field) {}
MoFEM::Interface & mField
integrate skeleton operators on khs

Member Function Documentation

◆ dgProjection()

MoFEMErrorCode LevelSet::dgProjection ( const int  prj_bit = projection_bit)
private

dg level set projection

Parameters
prj_bit
mesh_bit
Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 2407 of file level_set.cpp.

2407 {
2409
2410 // get operators tester
2411 auto simple = mField.getInterface<Simple>();
2412 auto bit_mng = mField.getInterface<BitRefManager>();
2413 auto prb_mng = mField.getInterface<ProblemsManager>();
2414
2415 auto lhs_fe = boost::make_shared<DomainEle>(mField);
2416 auto rhs_fe_prj = boost::make_shared<DomainEle>(mField);
2417 auto rhs_fe_current = boost::make_shared<DomainEle>(mField);
2418
2419 lhs_fe->getRuleHook = [](int, int, int o) { return 3 * o; };
2420 rhs_fe_prj->getRuleHook = [](int, int, int o) { return 3 * o; };
2421 rhs_fe_current->getRuleHook = [](int, int, int o) { return 3 * o; };
2422
2423 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
2424 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "DG_PROJECTION");
2425 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
2426 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
2427 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
2428 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "L");
2429 CHKERR DMSetUp(sub_dm);
2430
2431 Range current_ents; // ents used to do calculations
2432 CHKERR bit_mng->getEntitiesByDimAndRefLevel(BitRefLevel().set(current_bit),
2433 BitRefLevel().set(), FE_DIM,
2434 current_ents);
2435 Range prj_ents; // ents from which data are projected
2436 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2437 BitRefLevel().set(projection_bit), BitRefLevel().set(), FE_DIM, prj_ents);
2438 for (auto l = 0; l != nb_levels; ++l) {
2439 CHKERR bit_mng->updateRangeByParent(prj_ents, prj_ents);
2440 }
2441 current_ents = subtract(
2442 current_ents, prj_ents); // only restric to entities needed projection
2443
2444 auto test_mesh_bit = [&](FEMethod *fe_ptr) {
2445 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2446 current_bit);
2447 };
2448 auto test_prj_bit = [&](FEMethod *fe_ptr) {
2449 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
2451 };
2452 auto test_current_bit = [&](FEMethod *fe_ptr) {
2453 return current_ents.find(fe_ptr->getFEEntityHandle()) != current_ents.end();
2454 };
2455
2456 lhs_fe->exeTestHook =
2457 test_mesh_bit; // that element only is run when current bit is set
2458 rhs_fe_prj->exeTestHook =
2459 test_prj_bit; // that element is run only when projection bit is set
2460 rhs_fe_current->exeTestHook =
2461 test_current_bit; // that element is only run when current bit is set
2462
2463 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
2464 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
2465 CHKERR prb_mng->removeDofsOnEntities(
2466 "DG_PROJECTION", "L", BitRefLevel().set(), remove_mask, nullptr, 0,
2467 MAX_DOFS_ON_ENTITY, 0, 100, NOISY,
2468 true); // remove all DOFs which are not
2469 // on current bit. This case works for L2 space
2470
2471 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(lhs_fe->getOpPtrVector(),
2472 {L2});
2473 lhs_fe->getOpPtrVector().push_back(
2474 new OpMassLL("L", "L")); // Assemble projection matrix
2475
2476 // This assumes that projection mesh is finer, current mesh is coarsened.
2477 auto set_prj_from_child = [&](auto rhs_fe_prj) {
2479 rhs_fe_prj->getOpPtrVector(), {L2});
2480
2481 // Evaluate field value on projection mesh
2482 auto l_mat = boost::make_shared<MatrixDouble>();
2483 rhs_fe_prj->getOpPtrVector().push_back(
2485
2486 // This element is used to assemble
2487 auto get_parent_this = [&]() {
2488 auto fe_parent_this = boost::make_shared<DomainParentEle>(mField);
2489 fe_parent_this->getOpPtrVector().push_back(new OpScalarFieldL("L", l_mat));
2490 return fe_parent_this;
2491 };
2492
2493 // Create levels of parent elements, until current element is reached, and
2494 // then assemble.
2495 auto get_parents_fe_ptr = [&](auto this_fe_ptr) {
2496 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
2497 for (int l = 0; l <= nb_levels; ++l)
2498 parents_elems_ptr_vec.emplace_back(
2499 boost::make_shared<DomainParentEle>(mField));
2500 for (auto l = 1; l <= nb_levels; ++l) {
2501 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
2502 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
2503 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
2504 BitRefLevel().set(current_bit),
2505 BitRefLevel().set()));
2506 }
2507 return parents_elems_ptr_vec[0];
2508 };
2509
2510 auto this_fe_ptr = get_parent_this();
2511 auto parent_fe_ptr = get_parents_fe_ptr(this_fe_ptr);
2512 rhs_fe_prj->getOpPtrVector().push_back(
2513 new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
2514 BitRefLevel().set(current_bit).flip(), this_fe_ptr,
2515 BitRefLevel().set(current_bit), BitRefLevel().set()));
2516 };
2517
2518 // This assumed that current mesh is refined, and projection mesh is coarser
2519 auto set_prj_from_parent = [&](auto rhs_fe_current) {
2520
2521 // Evaluate field value on projection mesh
2522 auto l_mat = boost::make_shared<MatrixDouble>();
2523
2524 // Evaluate field on coarser element
2525 auto get_parent_this = [&]() {
2526 auto fe_parent_this = boost::make_shared<DomainParentEle>(mField);
2527 fe_parent_this->getOpPtrVector().push_back(
2529 return fe_parent_this;
2530 };
2531
2532 // Create stack of evaluation on parent elements
2533 auto get_parents_fe_ptr = [&](auto this_fe_ptr) {
2534 std::vector<boost::shared_ptr<DomainParentEle>> parents_elems_ptr_vec;
2535 for (int l = 0; l <= nb_levels; ++l)
2536 parents_elems_ptr_vec.emplace_back(
2537 boost::make_shared<DomainParentEle>(mField));
2538 for (auto l = 1; l <= nb_levels; ++l) {
2539 parents_elems_ptr_vec[l - 1]->getOpPtrVector().push_back(
2540 new OpRunParent(parents_elems_ptr_vec[l], BitRefLevel().set(),
2541 BitRefLevel().set(projection_bit).flip(),
2542 this_fe_ptr, BitRefLevel().set(projection_bit),
2543 BitRefLevel().set()));
2544 }
2545 return parents_elems_ptr_vec[0];
2546 };
2547
2548 auto this_fe_ptr = get_parent_this();
2549 auto parent_fe_ptr = get_parents_fe_ptr(this_fe_ptr);
2550
2551 auto reset_op_ptr = new DomainEleOp(NOSPACE, DomainEleOp::OPSPACE);
2552 reset_op_ptr->doWorkRhsHook = [&](DataOperator *op_ptr, int, EntityType,
2553 EntData &) {
2554 l_mat->resize(static_cast<DomainEleOp *>(op_ptr)->getGaussPts().size2(),
2555 DIM1 * DIM2, false);
2556 l_mat->clear();
2557 return 0;
2558 };
2559 rhs_fe_current->getOpPtrVector().push_back(reset_op_ptr);
2560 rhs_fe_current->getOpPtrVector().push_back(
2561 new OpRunParent(parent_fe_ptr, BitRefLevel().set(),
2562 BitRefLevel().set(projection_bit).flip(), this_fe_ptr,
2563 BitRefLevel(), BitRefLevel()));
2564
2565 // At the end assemble of current finite element
2566 rhs_fe_current->getOpPtrVector().push_back(new OpScalarFieldL("L", l_mat));
2567 };
2568
2569 set_prj_from_child(rhs_fe_prj);
2570 set_prj_from_parent(rhs_fe_current);
2571
2572 boost::shared_ptr<FEMethod> null_fe;
2573 getDMKspCtx(sub_dm)->clearLoops();
2574 CHKERR DMMoFEMKSPSetComputeOperators(sub_dm, simple->getDomainFEName(),
2575 lhs_fe, null_fe, null_fe);
2576 CHKERR DMMoFEMKSPSetComputeRHS(sub_dm, simple->getDomainFEName(), rhs_fe_prj,
2577 null_fe, null_fe);
2578 CHKERR DMMoFEMKSPSetComputeRHS(sub_dm, simple->getDomainFEName(),
2579 rhs_fe_current, null_fe, null_fe);
2581 CHKERR KSPSetDM(ksp, sub_dm);
2582
2583 CHKERR KSPSetDM(ksp, sub_dm);
2584 CHKERR KSPSetFromOptions(ksp);
2585 CHKERR KSPSetUp(ksp);
2586
2587 auto L = createDMVector(sub_dm);
2588 auto F = vectorDuplicate(L);
2589
2590 CHKERR KSPSolve(ksp, F, L);
2592 ksp, "level set DG projection");
2593 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
2594 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
2595 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
2596
2597 auto [error, th_error] = evaluateError();
2598 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
2599
2600 auto post_proc = [&](auto dm, auto out_name, auto th_error) {
2602 auto post_proc_fe =
2603 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
2604 post_proc_fe->setTagsToTransfer({th_error});
2605 post_proc_fe->exeTestHook = test_mesh_bit;
2606
2607 if constexpr (DIM1 == 1 && DIM2 == 1) {
2609 auto l_vec = boost::make_shared<VectorDouble>();
2610 auto l_grad_mat = boost::make_shared<MatrixDouble>();
2612 post_proc_fe->getOpPtrVector(), {L2});
2613 post_proc_fe->getOpPtrVector().push_back(
2614 new OpCalculateScalarFieldValues("L", l_vec));
2615 post_proc_fe->getOpPtrVector().push_back(
2616 new OpCalculateScalarFieldGradient<SPACE_DIM>("L", l_grad_mat));
2617
2618 post_proc_fe->getOpPtrVector().push_back(
2619
2620 new OpPPMap(
2621
2622 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
2623
2624 {{"L", l_vec}},
2625
2626 {{"GradL", l_grad_mat}},
2627
2628 {}, {})
2629
2630 );
2631 }
2632
2633 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
2634 post_proc_fe);
2635 post_proc_fe->writeFile(out_name);
2637 };
2638
2639 if constexpr (debug)
2640 CHKERR post_proc(sub_dm, "dg_projection.h5m", th_error);
2641
2643}
SmartPetscObj< KSP > ksp
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
@ NOISY
#define MAX_DOFS_ON_ENTITY
Maximal number of DOFs on entity.
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
#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:244
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
Definition DMMoFEM.cpp:517
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
Definition DMMoFEM.cpp:479
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
Definition DMMoFEM.cpp:267
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:543
PetscErrorCode 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:656
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:605
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1250
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:697
#define MOFEM_LOG(channel, severity)
Log.
constexpr int FE_DIM
[Define dimension]
Definition level_set.cpp:19
constexpr int current_bit
dofs bit used to do calculations
Definition level_set.cpp:63
constexpr int nb_levels
Definition level_set.cpp:58
constexpr int DIM2
Definition level_set.cpp:22
constexpr bool debug
Definition level_set.cpp:53
DomainEle::UserDataOperator DomainEleOp
Definition level_set.cpp:43
constexpr int projection_bit
Definition level_set.cpp:68
constexpr int DIM1
Definition level_set.cpp:21
FTensor::Index< 'l', 3 > l
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
auto createKSP(MPI_Comm comm)
PetscErrorCode DMMoFEMSetDestroyProblem(DM dm, PetscBool destroy_problem)
Definition DMMoFEM.cpp:463
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
auto getDMKspCtx(DM dm)
Get KSP context data structure used by DM.
Definition DMMoFEM.hpp:1264
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< 1, DIM1 *DIM2 > OpMassLL
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpBaseTimesVector< 1, DIM1 *DIM2, 1 > OpScalarFieldL
std::tuple< double, Tag > evaluateError()
evaluate error
Add operators pushing bases from local to physical configuration.
Managing BitRefLevels.
virtual MPI_Comm & get_comm() const =0
base operator to do operations at Gauss Pt. level
Data on single entity (This is passed as argument to DataOperator::doWork)
Structure for user loop methods on finite elements.
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
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...
Problem manager is used to build and partition problems.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.

◆ evaluateError()

std::tuple< double, Tag > LevelSet::evaluateError ( )
private

evaluate error

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1200 of file level_set.cpp.

1200 {
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}
std::string type
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
constexpr int skeleton_bit
skeleton elements bit
Definition level_set.cpp:65
FTensor::Index< 'J', DIM1 > J
Definition level_set.cpp:30
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
auto createVectorMPI(MPI_Comm comm, PetscInt n, PetscInt N)
Create MPI Vector.
constexpr auto make_array(Arg &&...arg)
Create Array.
constexpr IntegrationType I
@ LEFT_SIDE
Definition plate.cpp:92
@ RIGHT_SIDE
Definition plate.cpp:92
boost::shared_ptr< FaceSideEle > getSideFE(boost::shared_ptr< SideData > side_data_ptr)
create side element to assemble data from sides
virtual moab::Interface & get_moab()=0
BitRefLevel & getBitRefLevel()
Get the BitRefLevel.
Definition Simple.hpp:415
intrusive_ptr for managing petsc objects

◆ get_level_set()

double LevelSet::get_level_set ( const double  x,
const double  y,
const double  z 
)
staticprivate

inital level set, i.e. advected field

Parameters
x
y
z
Returns
double
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 379 of file level_set.cpp.

379 {
380 constexpr double xc = 0.1;
381 constexpr double yc = 0.;
382 constexpr double zc = 0.;
383 constexpr double r = 0.2;
384 return std::sqrt(pow(x - xc, 2) + pow(y - yc, 2) + pow(z - zc, 2)) - r;
385}
int r
Definition sdf.py:205

◆ get_velocity_potential() [1/2]

template<int FE_DIM>
static double LevelSet::get_velocity_potential ( double  x,
double  y,
double  z 
)
staticprivate

advection velocity field

Note
in current implementation is assumed that advection field has zero normal component.
function define a vector velocity potential field, curl of potential field gives velocity, thus velocity is divergence free.
Template Parameters
FE_DIM
Parameters
x
y
z
Returns
auto
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

◆ get_velocity_potential() [2/2]

template<>
double LevelSet::get_velocity_potential ( double  x,
double  y,
double  z 
)
staticprivate

Definition at line 375 of file level_set.cpp.

375 {
376 return (x * x - 0.25) * (y * y - 0.25);
377}

◆ getSideFE()

boost::shared_ptr< FaceSideEle > LevelSet::getSideFE ( boost::shared_ptr< SideData >  side_data_ptr)
private

create side element to assemble data from sides

Parameters
side_data_ptr
Returns
boost::shared_ptr<FaceSideEle>
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 995 of file level_set.cpp.

995 {
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};
constexpr int SPACE_DIM
@ MOFEM_DATA_INCONSISTENCY
Definition definitions.h:31
FaceSideEle::UserDataOperator FaceSideEleOp
Definition level_set.cpp:45
constexpr double t
plate stiffness
Definition plate.cpp:58
ForcesAndSourcesCore::UserDataOperator * getZeroLevelVelOp(boost::shared_ptr< MatrixDouble > vel_ptr)
Get operator calculating velocity on coarse mesh.
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.

◆ getZeroLevelVelOp()

ForcesAndSourcesCore::UserDataOperator * LevelSet::getZeroLevelVelOp ( boost::shared_ptr< MatrixDouble >  vel_ptr)
private

Get operator calculating velocity on coarse mesh.

Parameters
vel_ptr
Returns
DomainEleOp*
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 920 of file level_set.cpp.

920 {
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}
Calculate curl of vector field.

◆ initialiseFieldLevelSet()

MoFEMErrorCode LevelSet::initialiseFieldLevelSet ( boost::function< double(double, double, double)>  level_fun = get_level_set)
private

initialise field set

Parameters
level_fun
Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1684 of file level_set.cpp.

1685 {
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);
1743 ksp, "level set initial field");
1744 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
1745 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
1746 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
1747
1748 auto [error, th_error] = evaluateError();
1749 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
1750#ifndef NDEBUG
1751 auto fe_meshset =
1752 mField.get_finite_element_meshset(simple->getDomainFEName());
1753 std::vector<Tag> tags{th_error};
1754 CHKERR mField.get_moab().write_file("error.h5m", "MOAB",
1755 "PARALLEL=WRITE_PART", &fe_meshset, 1,
1756 &*tags.begin(), tags.size());
1757#endif
1758
1759 auto post_proc = [&](auto dm, auto out_name, auto th_error) {
1761 auto post_proc_fe =
1762 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
1763 post_proc_fe->setTagsToTransfer({th_error});
1764 post_proc_fe->exeTestHook = test_bit_ele;
1765
1766 if constexpr (DIM1 == 1 && DIM2 == 1) {
1768
1769 auto l_vec = boost::make_shared<VectorDouble>();
1770 auto l_grad_mat = boost::make_shared<MatrixDouble>();
1772 post_proc_fe->getOpPtrVector(), {L2});
1773 post_proc_fe->getOpPtrVector().push_back(
1774 new OpCalculateScalarFieldValues("L", l_vec));
1775 post_proc_fe->getOpPtrVector().push_back(
1776 new OpCalculateScalarFieldGradient<SPACE_DIM>("L", l_grad_mat));
1777
1778 post_proc_fe->getOpPtrVector().push_back(
1779
1780 new OpPPMap(
1781
1782 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1783
1784 {{"L", l_vec}},
1785
1786 {{"GradL", l_grad_mat}},
1787
1788 {}, {})
1789
1790 );
1791 }
1792
1793 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1794 post_proc_fe);
1795 post_proc_fe->writeFile(out_name);
1797 };
1798
1799 if constexpr (debug)
1800 CHKERR post_proc(sub_dm, "initial_level_set.h5m", th_error);
1801
1802 swap_fe();
1803
1805}
virtual EntityHandle get_finite_element_meshset(const std::string name) const =0
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< 1, DIM1 *DIM2 > OpSourceL
Basic algebra on fields.
Definition FieldBlas.hpp:21
PipelineManager interface.

◆ initialiseFieldVelocity()

MoFEMErrorCode LevelSet::initialiseFieldVelocity ( boost::function< double(double, double, double)>  vel_fun = get_velocity_potential<FE_DIM>)
private

initialise potential velocity field

Parameters
vel_fun
Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1807 of file level_set.cpp.

1808 {
1810
1811 // get operators tester
1812 auto simple = mField.getInterface<Simple>();
1813 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1814 // pipeline manager
1815 auto prb_mng = mField.getInterface<ProblemsManager>();
1816
1817 boost::shared_ptr<FEMethod> lhs_fe = boost::make_shared<DomainEle>(mField);
1818 boost::shared_ptr<FEMethod> rhs_fe = boost::make_shared<DomainEle>(mField);
1819 auto swap_fe = [&]() {
1820 lhs_fe.swap(pip->getDomainLhsFE());
1821 rhs_fe.swap(pip->getDomainRhsFE());
1822 };
1823 swap_fe();
1824
1825 pip->setDomainLhsIntegrationRule([](int, int, int o) { return 3 * o; });
1826 pip->setDomainRhsIntegrationRule([](int, int, int o) { return 3 * o; });
1827
1828 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
1829 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "VELOCITY_PROJECTION");
1830 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
1831 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
1832 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
1833 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "V");
1834 CHKERR DMSetUp(sub_dm);
1835
1836 // Velocities are calculated only on corse mesh
1837 BitRefLevel remove_mask = BitRefLevel().set(0);
1838 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
1839 CHKERR prb_mng->removeDofsOnEntities("VELOCITY_PROJECTION", "V",
1840 BitRefLevel().set(), remove_mask);
1841
1842 auto test_bit = [&](FEMethod *fe_ptr) {
1843 return fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(0);
1844 };
1845 pip->getDomainLhsFE()->exeTestHook = test_bit;
1846 pip->getDomainRhsFE()->exeTestHook = test_bit;
1847
1848 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainLhsPipeline(),
1849 {potential_velocity_space});
1850 CHKERR AddHOOps<FE_DIM, FE_DIM, SPACE_DIM>::add(pip->getOpDomainRhsPipeline(),
1851 {potential_velocity_space});
1852
1853 pip->getOpDomainLhsPipeline().push_back(new OpMassVV("V", "V"));
1854 pip->getOpDomainRhsPipeline().push_back(new OpSourceV("V", vel_fun));
1855
1856 auto ksp = pip->createKSP(sub_dm);
1857 CHKERR KSPSetDM(ksp, sub_dm);
1858 CHKERR KSPSetFromOptions(ksp);
1859 CHKERR KSPSetUp(ksp);
1860
1861 auto L = createDMVector(sub_dm);
1862 auto F = vectorDuplicate(L);
1863
1864 CHKERR KSPSolve(ksp, F, L);
1866 ksp, "level set initial velocity");
1867 CHKERR VecGhostUpdateBegin(L, INSERT_VALUES, SCATTER_FORWARD);
1868 CHKERR VecGhostUpdateEnd(L, INSERT_VALUES, SCATTER_FORWARD);
1869 CHKERR DMoFEMMeshToLocalVector(sub_dm, L, INSERT_VALUES, SCATTER_REVERSE);
1870
1871 auto post_proc = [&](auto dm, auto out_name) {
1873 auto post_proc_fe =
1874 boost::make_shared<PostProcBrokenMeshInMoab<DomainEle>>(mField);
1875 post_proc_fe->exeTestHook = test_bit;
1876
1877 if constexpr (FE_DIM == 2) {
1878
1880 post_proc_fe->getOpPtrVector(), {potential_velocity_space});
1881
1883
1884 auto potential_vec = boost::make_shared<VectorDouble>();
1885 auto velocity_mat = boost::make_shared<MatrixDouble>();
1886
1887 post_proc_fe->getOpPtrVector().push_back(
1888 new OpCalculateScalarFieldValues("V", potential_vec));
1889 post_proc_fe->getOpPtrVector().push_back(
1891 SPACE_DIM>("V", velocity_mat));
1892
1893 post_proc_fe->getOpPtrVector().push_back(
1894
1895 new OpPPMap(
1896
1897 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
1898
1899 {{"VelocityPotential", potential_vec}},
1900
1901 {{"Velocity", velocity_mat}},
1902
1903 {}, {})
1904
1905 );
1906
1907 } else {
1908 SETERRQ(PETSC_COMM_SELF, MOFEM_NOT_IMPLEMENTED,
1909 "3d case not implemented");
1910 }
1911
1912 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
1913 post_proc_fe);
1914 post_proc_fe->writeFile(out_name);
1916 };
1917
1918 if constexpr (debug)
1919 CHKERR post_proc(sub_dm, "initial_velocity_potential.h5m");
1920
1921 swap_fe();
1922
1924}
@ MOFEM_NOT_IMPLEMENTED
Definition definitions.h:32
constexpr int SPACE_DIM
Definition level_set.cpp:20
constexpr size_t potential_velocity_field_dim
Definition level_set.cpp:50
FormsIntegrators< DomainEleOp >::Assembly< A >::BiLinearForm< G >::OpMass< potential_velocity_field_dim, potential_velocity_field_dim > OpMassVV
FormsIntegrators< DomainEleOp >::Assembly< A >::LinearForm< G >::OpSource< potential_velocity_field_dim, potential_velocity_field_dim > OpSourceV

◆ pushOpDomain()

MoFEMErrorCode LevelSet::pushOpDomain ( )
private

push operators to integrate operators on domain

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 952 of file level_set.cpp.

952 {
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}
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
Get time direvarive values at integration pts for tensor field rank 2, i.e. matrix field.

◆ pushOpSkeleton()

MoFEMErrorCode LevelSet::pushOpSkeleton ( )
private

push operator to integrate on skeleton

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1170 of file level_set.cpp.

1170 {
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}
boost::ptr_deque< UserDataOperator > & getOpSkeletonLhsPipeline()
Get the Op Skeleton Lhs Pipeline object.

◆ readMesh()

MoFEMErrorCode LevelSet::readMesh ( )
private

read mesh

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 503 of file level_set.cpp.

503 {
506 // get options from command line
508
509 // Only L2 field is set in this example. Two lines bellow forces simple
510 // interface to creat lower dimension (edge) elements, despite that fact that
511 // there is no field spanning on such elements. We need them for DG method.
512 simple->getAddSkeletonFE() = true;
513 simple->getAddBoundaryFE() = true;
514
515 // load mesh file
516 simple->getBitRefLevel() = BitRefLevel();
517 CHKERR simple->loadFile();
518
519 // Initialise bit ref levels
520 auto set_problem_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}
constexpr int start_bit
Definition level_set.cpp:60
constexpr int aggregate_bit
all bits for advection problem
Definition level_set.cpp:66
virtual int get_comm_rank() const =0
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180

◆ refineMesh()

MoFEMErrorCode LevelSet::refineMesh ( WrapperClass &&  wp)
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 2155 of file level_set.cpp.

2155 {
2157
2158 auto bit_mng = mField.getInterface<BitRefManager>();
2159 auto proc_str = boost::lexical_cast<std::string>(mField.get_comm_rank());
2160
2161 auto set_bit = [](auto l) { return BitRefLevel().set(l); };
2162
2163 [[maybe_unused]] auto save_range = [&](const std::string name,
2164 const Range &r) {
2166 auto meshset_ptr = get_temp_meshset_ptr(mField.get_moab());
2167 CHKERR mField.get_moab().add_entities(*meshset_ptr, r);
2168 CHKERR mField.get_moab().write_file(name.c_str(), "VTK", "",
2169 meshset_ptr->get_ptr(), 1);
2171 };
2172
2173 // select domain elements to refine by threshold
2174 auto get_refined_elements_meshset = [&](auto bit, auto mask) {
2175 Range fe_ents;
2176 CHKERR bit_mng->getEntitiesByDimAndRefLevel(bit, mask, FE_DIM, fe_ents);
2177
2178 Tag th_error;
2179 CHK_MOAB_THROW(mField.get_moab().tag_get_handle("Error", th_error),
2180 "get error handle");
2181 std::vector<double> errors(fe_ents.size());
2183 mField.get_moab().tag_get_data(th_error, fe_ents, &*errors.begin()),
2184 "get tag data");
2185 auto it = std::max_element(errors.begin(), errors.end());
2186 double max;
2187 MPI_Allreduce(&*it, &max, 1, MPI_DOUBLE, MPI_MAX, mField.get_comm());
2188 MOFEM_LOG("LevelSet", Sev::inform) << "Max error: " << max;
2189 auto threshold = wp.getThreshold(max);
2190
2191 std::vector<EntityHandle> fe_to_refine;
2192 fe_to_refine.reserve(fe_ents.size());
2193
2194 auto fe_it = fe_ents.begin();
2195 auto error_it = errors.begin();
2196 for (auto i = 0; i != fe_ents.size(); ++i) {
2197 if (*error_it > threshold) {
2198 fe_to_refine.push_back(*fe_it);
2199 }
2200 ++fe_it;
2201 ++error_it;
2202 }
2203
2204 Range ents;
2205 ents.insert_list(fe_to_refine.begin(), fe_to_refine.end());
2206 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2207 ents, nullptr, NOISY);
2208
2209 auto get_neighbours_by_bridge_vertices = [&](auto &&ents) {
2210 Range verts;
2211 CHKERR mField.get_moab().get_connectivity(ents, verts, true);
2212 CHKERR mField.get_moab().get_adjacencies(verts, FE_DIM, false, ents,
2213 moab::Interface::UNION);
2214 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(ents);
2215 return ents;
2216 };
2217
2218 ents = get_neighbours_by_bridge_vertices(ents);
2219
2220#ifndef NDEBUG
2221 if (debug) {
2222 auto meshset_ptr = get_temp_meshset_ptr(mField.get_moab());
2223 CHK_MOAB_THROW(mField.get_moab().add_entities(*meshset_ptr, ents),
2224 "add entities to meshset");
2225 CHKERR mField.get_moab().write_file(
2226 (proc_str + "_fe_to_refine.vtk").c_str(), "VTK", "",
2227 meshset_ptr->get_ptr(), 1);
2228 }
2229#endif
2230
2231 return ents;
2232 };
2233
2234 // refine elements, and set bit ref level
2235 auto refine_mesh = [&](auto l, auto &&fe_to_refine) {
2236 Skinner skin(&mField.get_moab());
2238
2239 // get entities in "l-1" level
2240 Range level_ents;
2241 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2242 set_bit(start_bit + l - 1), BitRefLevel().set(), FE_DIM, level_ents);
2243 // select entities to refine
2244 fe_to_refine = intersect(level_ents, fe_to_refine);
2245 // select entities not to refine
2246 level_ents = subtract(level_ents, fe_to_refine);
2247
2248 // for entities to refine get children, i.e. redlined entities
2249 Range fe_to_refine_children;
2250 bit_mng->updateRangeByChildren(fe_to_refine, fe_to_refine_children);
2251 // add entities to to level "l"
2252 fe_to_refine_children = fe_to_refine_children.subset_by_dimension(FE_DIM);
2253 level_ents.merge(fe_to_refine_children);
2254
2255 auto fix_neighbour_level = [&](auto ll) {
2257 // filter entities on level ll
2258 auto level_ll = level_ents;
2259 CHKERR bit_mng->filterEntitiesByRefLevel(set_bit(ll), BitRefLevel().set(),
2260 level_ll);
2261 // find skin of ll level
2262 Range skin_edges;
2263 CHKERR skin.find_skin(0, level_ll, false, skin_edges);
2264 // get parents of skin of level ll
2265 Range skin_parents;
2266 for (auto lll = 0; lll <= ll; ++lll) {
2267 CHKERR bit_mng->updateRangeByParent(skin_edges, skin_parents);
2268 }
2269 // filter parents on level ll - 1
2270 BitRefLevel bad_bit;
2271 for (auto lll = 0; lll <= ll - 2; ++lll) {
2272 bad_bit[lll] = true;
2273 }
2274 // get adjacents to parents
2275 Range skin_adj_ents;
2276 CHKERR mField.get_moab().get_adjacencies(
2277 skin_parents, FE_DIM, false, skin_adj_ents, moab::Interface::UNION);
2278 CHKERR bit_mng->filterEntitiesByRefLevel(bad_bit, BitRefLevel().set(),
2279 skin_adj_ents);
2280 skin_adj_ents = intersect(skin_adj_ents, level_ents);
2281 if (!skin_adj_ents.empty()) {
2282 level_ents = subtract(level_ents, skin_adj_ents);
2283 Range skin_adj_ents_children;
2284 bit_mng->updateRangeByChildren(skin_adj_ents, skin_adj_ents_children);
2285 level_ents.merge(skin_adj_ents_children);
2286 }
2288 };
2289
2290 CHKERR fix_neighbour_level(l);
2291
2292 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2293 level_ents);
2294
2295 // get lower dimension entities for level "l"
2296 for (auto d = 0; d != FE_DIM; ++d) {
2297 if (d == 0) {
2298 CHKERR mField.get_moab().get_connectivity(
2299 level_ents.subset_by_dimension(FE_DIM), level_ents, true);
2300 } else {
2301 CHKERR mField.get_moab().get_adjacencies(
2302 level_ents.subset_by_dimension(FE_DIM), d, false, level_ents,
2303 moab::Interface::UNION);
2304 }
2305 }
2306 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(
2307 level_ents);
2308
2309 // set bit ref level to level entities
2310 CHKERR bit_mng->setNthBitRefLevel(start_bit + l, false);
2311 CHKERR bit_mng->setNthBitRefLevel(level_ents, start_bit + l, true);
2312
2313#ifndef NDEBUG
2314 auto proc_str = boost::lexical_cast<std::string>(mField.get_comm_rank());
2315 CHKERR bit_mng->writeBitLevelByDim(
2316 set_bit(start_bit + l), BitRefLevel().set(), FE_DIM,
2317 (boost::lexical_cast<std::string>(l) + "_" + proc_str + "_ref_mesh.vtk")
2318 .c_str(),
2319 "VTK", "");
2320#endif
2321
2323 };
2324
2325 // set skeleton
2326 auto set_skelton_bit = [&](auto l) {
2328
2329 // get entities of dim-1 on level "l"
2330 Range level_edges;
2331 CHKERR bit_mng->getEntitiesByDimAndRefLevel(
2332 set_bit(start_bit + l), BitRefLevel().set(), FE_DIM - 1, level_edges);
2333
2334 // get parent of entities of level "l"
2335 Range level_edges_parents;
2336 CHKERR bit_mng->updateRangeByParent(level_edges, level_edges_parents);
2337 level_edges_parents = level_edges_parents.subset_by_dimension(FE_DIM - 1);
2338 CHKERR bit_mng->filterEntitiesByRefLevel(
2339 set_bit(start_bit + l), BitRefLevel().set(), level_edges_parents);
2340
2341 // skeleton entities which do not have parents
2342 auto parent_skeleton = intersect(level_edges, level_edges_parents);
2343 auto skeleton = subtract(level_edges, level_edges_parents);
2344
2345 // add adjacent domain entities
2346 CHKERR mField.get_moab().get_adjacencies(unite(parent_skeleton, skeleton),
2347 FE_DIM, false, skeleton,
2348 moab::Interface::UNION);
2349
2350 // set levels
2351 CHKERR mField.getInterface<CommInterface>()->synchroniseEntities(skeleton);
2352 CHKERR bit_mng->setNthBitRefLevel(skeleton_bit, false);
2353 CHKERR bit_mng->setNthBitRefLevel(skeleton, skeleton_bit, true);
2354
2355#ifndef NDEBUG
2356 CHKERR bit_mng->writeBitLevel(
2357 set_bit(skeleton_bit), BitRefLevel().set(),
2358 (boost::lexical_cast<std::string>(l) + "_" + proc_str + "_skeleton.vtk")
2359 .c_str(),
2360 "VTK", "");
2361#endif
2363 };
2364
2365 // Reset bit sand set old current and aggregate bits as projection bits
2366 Range level0_current;
2367 CHKERR bit_mng->getEntitiesByRefLevel(BitRefLevel().set(current_bit),
2368 BitRefLevel().set(), level0_current);
2369
2370 Range level0_aggregate;
2371 CHKERR bit_mng->getEntitiesByRefLevel(BitRefLevel().set(aggregate_bit),
2372 BitRefLevel().set(), level0_aggregate);
2373
2374 BitRefLevel start_mask;
2375 for (auto s = 0; s != start_bit; ++s)
2376 start_mask[s] = true;
2377 CHKERR bit_mng->lambdaBitRefLevel(
2378 [&](EntityHandle ent, BitRefLevel &bit) { bit &= start_mask; });
2379 CHKERR bit_mng->setNthBitRefLevel(level0_current, projection_bit, true);
2380 CHKERR bit_mng->setNthBitRefLevel(level0_aggregate, aggregate_projection_bit,
2381 true);
2382
2383 // Set zero bit ref level
2384 Range level0;
2385 CHKERR bit_mng->getEntitiesByRefLevel(set_bit(0), BitRefLevel().set(),
2386 level0);
2387 CHKERR bit_mng->setNthBitRefLevel(level0, start_bit, true);
2388 CHKERR bit_mng->setNthBitRefLevel(level0, current_bit, true);
2389 CHKERR bit_mng->setNthBitRefLevel(level0, aggregate_bit, true);
2390 CHKERR bit_mng->setNthBitRefLevel(level0, skeleton_bit, true);
2391
2392 CHKERR wp.setBits(*this, 0);
2393 CHKERR wp.runCalcs(*this, 0);
2394 for (auto l = 0; l != nb_levels; ++l) {
2395 MOFEM_LOG("WORLD", Sev::inform) << "Process level: " << l;
2396 CHKERR refine_mesh(l + 1, get_refined_elements_meshset(
2397 set_bit(start_bit + l), BitRefLevel().set()));
2398 CHKERR set_skelton_bit(l + 1);
2399 CHKERR wp.setAggregateBit(*this, l + 1);
2400 CHKERR wp.setBits(*this, l + 1);
2401 CHKERR wp.runCalcs(*this, l + 1);
2402 }
2403
2405}
std::string name
#define CHK_MOAB_THROW(err, msg)
Check error code of MoAB function and throw MoFEM exception.
auto bit
set bit
FTensor::Index< 'i', SPACE_DIM > i
constexpr int aggregate_projection_bit
all bits for projection problem
Definition level_set.cpp:70
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
Managing BitRefLevels.
auto save_range

◆ runProblem()

MoFEMErrorCode LevelSet::runProblem ( )
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 387 of file level_set.cpp.

387 {
391
392 if constexpr (debug) {
394 CHKERR testOp();
395 }
396
398
399 maxPtr = boost::make_shared<double>(0);
400 CHKERR refineMesh(WrapperClassInitalSolution(maxPtr));
401
405 simple->getBitRefLevelMask() = BitRefLevel().set();
406 simple->reSetUp(true);
407
409
411}
MoFEMErrorCode solveAdvection()
solve advection problem
boost::shared_ptr< double > maxPtr
MoFEMErrorCode readMesh()
read mesh
MoFEMErrorCode setUpProblem()
create fields, and set approximation order
MoFEMErrorCode testOp()
test consistency between tangent matrix and the right hand side vectors
MoFEMErrorCode refineMesh(WrapperClass &&wp)
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

◆ setUpProblem()

MoFEMErrorCode LevelSet::setUpProblem ( )
private

create fields, and set approximation order

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 560 of file level_set.cpp.

560 {
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}
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ L2
field with C-1 continuity
Definition definitions.h:88
constexpr FieldSpace potential_velocity_space
Definition level_set.cpp:49
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

◆ solveAdvection()

MoFEMErrorCode LevelSet::solveAdvection ( )
private

solve advection problem

Returns
* MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1929 of file level_set.cpp.

1929 {
1931
1932 // get operators tester
1933 auto simple = mField.getInterface<Simple>();
1934 auto pip = mField.getInterface<PipelineManager>(); // get interface to
1935 auto prb_mng = mField.getInterface<ProblemsManager>();
1936
1939
1940 auto sub_dm = createDM(mField.get_comm(), "DMMOFEM");
1941 CHKERR DMMoFEMCreateSubDM(sub_dm, simple->getDM(), "ADVECTION");
1942 CHKERR DMMoFEMSetDestroyProblem(sub_dm, PETSC_TRUE);
1943 CHKERR DMMoFEMSetSquareProblem(sub_dm, PETSC_TRUE);
1944 CHKERR DMMoFEMAddElement(sub_dm, simple->getDomainFEName());
1945 CHKERR DMMoFEMAddElement(sub_dm, simple->getSkeletonFEName());
1946 CHKERR DMMoFEMAddSubFieldRow(sub_dm, "L");
1947 CHKERR DMSetUp(sub_dm);
1948
1949 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
1950 remove_mask.flip(); // DOFs which are not on bit_domain_ele should be removed
1951 CHKERR prb_mng->removeDofsOnEntities("ADVECTION", "L", BitRefLevel().set(),
1952 remove_mask);
1953
1954 auto add_post_proc_fe = [&]() {
1955 auto post_proc_fe = boost::make_shared<PostProcEle>(mField);
1956
1957 Tag th_error;
1958 double def_val = 0;
1959 CHKERR mField.get_moab().tag_get_handle(
1960 "Error", 1, MB_TYPE_DOUBLE, th_error, MB_TAG_CREAT | MB_TAG_SPARSE,
1961 &def_val);
1962 post_proc_fe->setTagsToTransfer({th_error});
1963
1964 post_proc_fe->exeTestHook = [&](FEMethod *fe_ptr) {
1965 return fe_ptr->numeredEntFiniteElementPtr &&
1966 fe_ptr->numeredEntFiniteElementPtr->getBitRefLevel().test(
1967 current_bit);
1968 };
1969
1971
1972 auto vel_ptr = boost::make_shared<MatrixDouble>();
1973
1975 post_proc_fe->getOpPtrVector(), {L2});
1976 post_proc_fe->getOpPtrVector().push_back(getZeroLevelVelOp(vel_ptr));
1977
1978 if constexpr (DIM1 == 1 && DIM2 == 1) {
1979 auto l_vec = boost::make_shared<VectorDouble>();
1980 post_proc_fe->getOpPtrVector().push_back(
1981 new OpCalculateScalarFieldValues("L", l_vec));
1982 post_proc_fe->getOpPtrVector().push_back(
1983
1984 new OpPPMap(
1985
1986 post_proc_fe->getPostProcMesh(),
1987
1988 post_proc_fe->getMapGaussPts(),
1989
1990 {{"L", l_vec}},
1991
1992 {{"V", vel_ptr}},
1993
1994 {}, {})
1995
1996 );
1997 }
1998 return post_proc_fe;
1999 };
2000
2001 auto post_proc_fe = add_post_proc_fe();
2002
2003 auto set_time_monitor = [&](auto dm, auto ts) {
2004 auto monitor_ptr = boost::make_shared<FEMethod>();
2005
2006 monitor_ptr->preProcessHook = []() { return 0; };
2007 monitor_ptr->operatorHook = []() { return 0; };
2008 monitor_ptr->postProcessHook = [dm, simple, post_proc_fe, monitor_ptr]() mutable {
2010
2011 if (!post_proc_fe)
2012 SETERRQ(PETSC_COMM_WORLD, MOFEM_DATA_INCONSISTENCY,
2013 "Null pointer for post proc element");
2014
2015 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(),
2016 post_proc_fe);
2017 CHKERR post_proc_fe->writeFile(
2018 "level_set_" +
2019 boost::lexical_cast<std::string>(monitor_ptr->ts_step) + ".h5m");
2021 };
2022
2023 boost::shared_ptr<FEMethod> null;
2024 DMMoFEMTSSetMonitor(sub_dm, ts, simple->getDomainFEName(), monitor_ptr,
2025 null, null);
2026
2027 return monitor_ptr;
2028 };
2029
2030 auto ts = pip->createTSIM(sub_dm);
2031
2032 auto set_solution = [&](auto ts) {
2034 tsSolutionVec = createDMVector(sub_dm);
2035 CHKERR DMoFEMMeshToLocalVector(sub_dm, tsSolutionVec, INSERT_VALUES,
2036 SCATTER_FORWARD);
2037 CHKERR TSSetSolution(ts, tsSolutionVec);
2039 };
2040 CHKERR set_solution(ts);
2041
2042 auto monitor_pt = set_time_monitor(sub_dm, ts);
2043 CHKERR TSSetFromOptions(ts);
2044
2045 auto B = createDMMatrix(sub_dm);
2046 CHKERR TSSetIJacobian(ts, B, B, TsSetIJacobian, nullptr);
2047 level_set_raw_ptr = this;
2048
2049 CHKERR TSSetUp(ts);
2050
2051 auto ts_pre_step = [](TS ts) {
2052 auto &m_field = level_set_raw_ptr->mField;
2053 auto simple = m_field.getInterface<Simple>();
2055
2056 auto [error, th_error] = level_set_raw_ptr->evaluateError();
2057 MOFEM_LOG("LevelSet", Sev::inform) << "Error indicator " << error;
2058
2059 auto get_norm = [&](auto x) {
2060 double nrm;
2061 CHKERR VecNorm(x, NORM_2, &nrm);
2062 return nrm;
2063 };
2064
2065 auto set_solution = [&](auto ts) {
2067 DM dm;
2068 CHKERR TSGetDM(ts, &dm);
2069 auto prb_ptr = getProblemPtr(dm);
2070
2073 INSERT_VALUES,
2074 SCATTER_FORWARD);
2075 CHKERR VecGhostUpdateBegin(level_set_raw_ptr->tsSolutionVec, INSERT_VALUES,
2076 SCATTER_FORWARD);
2077 CHKERR VecGhostUpdateEnd(level_set_raw_ptr->tsSolutionVec, INSERT_VALUES,
2078 SCATTER_FORWARD);
2079
2080 MOFEM_LOG("LevelSet", Sev::inform)
2081 << "Problem " << prb_ptr->getName() << " solution vector norm "
2082 << get_norm(level_set_raw_ptr->tsSolutionVec);
2083 CHKERR TSSetSolution(ts, level_set_raw_ptr->tsSolutionVec);
2084
2086 };
2087
2088 auto refine_and_project = [&](auto ts) {
2090
2092 WrapperClassErrorProjection(level_set_raw_ptr->maxPtr));
2093 simple->getBitRefLevel() = BitRefLevel().set(skeleton_bit) |
2094 BitRefLevel().set(aggregate_bit) |
2096
2097 simple->reSetUp(true);
2098 DM dm;
2099 CHKERR TSGetDM(ts, &dm);
2101
2102 BitRefLevel remove_mask = BitRefLevel().set(current_bit);
2103 remove_mask
2104 .flip(); // DOFs which are not on bit_domain_ele should be removed
2106 ->removeDofsOnEntities("ADVECTION", "L", BitRefLevel().set(),
2107 remove_mask);
2108
2110 };
2111
2112 auto ts_reset_theta = [&](auto ts) {
2114 DM dm;
2115 CHKERR TSGetDM(ts, &dm);
2116
2117 // FIXME: Look into vec-5_free_surface how to transfer internal theta method variables
2118
2119 CHKERR TSReset(ts);
2120 CHKERR TSSetUp(ts);
2121
2123 CHKERR set_solution(ts);
2124
2125 auto B = createDMMatrix(dm);
2126 CHKERR TSSetIJacobian(ts, B, B, TsSetIJacobian, nullptr);
2127
2129 };
2130
2131 CHKERR refine_and_project(ts);
2132 CHKERR ts_reset_theta(ts);
2133
2135 };
2136
2137 auto ts_post_step = [](TS ts) { return 0; };
2138
2139 CHKERR TSSetPreStep(ts, ts_pre_step);
2140 CHKERR TSSetPostStep(ts, ts_post_step);
2141
2142 CHKERR TSSolve(ts, NULL);
2143 // Solver convergence is cheap to check and carries no magic numbers, so it
2144 // stands alone rather than waiting on a "-test_nb"/"-test_name" selector.
2145 {
2146 PetscReal expected_time;
2147 CHKERR TSGetTime(ts, &expected_time);
2149 ts, expected_time, {1e-12, 1e-12}, "level set advection");
2150 }
2151
2153}
auto createDMMatrix(DM dm)
Get smart matrix from DM.
Definition DMMoFEM.hpp:1207
PetscErrorCode DMSubDMSetUp_MoFEM(DM subdm)
Definition DMMoFEM.cpp:1374
LevelSet * level_set_raw_ptr
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:1075
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
auto getProblemPtr(DM dm)
get problem pointer from DM
Definition DMMoFEM.hpp:1195
MoFEMErrorCode pushOpDomain()
push operators to integrate operators on domain
MoFEMErrorCode pushOpSkeleton()
push operator to integrate on skeleton
MoFEMErrorCode dgProjection(const int prj_bit=projection_bit)
dg level set projection
SmartPetscObj< Vec > tsSolutionVec

◆ testOp()

MoFEMErrorCode LevelSet::testOp ( )
private

test consistency between tangent matrix and the right hand side vectors

Returns
MoFEMErrorCode
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1593 of file level_set.cpp.

1593 {
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};
#define MOFEM_LOG_C(channel, severity, format,...)
static const double eps
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
Calculate directional derivative of the right hand side and compare it with tangent matrix derivative...

◆ testSideFE()

MoFEMErrorCode LevelSet::testSideFE ( )
private

test integration side elements

test side element

Check consistency between volume and skeleton integral.

Returns
MoFEMErrorCode

Check consistency between volume and skeleton integral

Returns
MoFEMErrorCode

calculate volume

calculate skeleton integral

Set up problem such that gradient of level set field is orthogonal to velocity field. Then volume and skeleton integral should yield the same value.

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 1378 of file level_set.cpp.

1378 {
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
1564 CHKERR DMoFEMLoopFiniteElements(dm, simple->getDomainFEName(), vol_fe);
1565 CHKERR DMoFEMLoopFiniteElements(dm, simple->getSkeletonFEName(), skel_fe);
1566 CHKERR DMoFEMLoopFiniteElements(dm, simple->getBoundaryFEName(), skel_fe);
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};
FTensor::Index< 'i', SPACE_DIM > i
auto get_ntensor(T &base_mat)
Definition plate.cpp:465
MoFEMErrorCode initialiseFieldLevelSet(boost::function< double(double, double, double)> level_fun=get_level_set)
initialise field set
auto getFTensor1DiffN(const FieldApproximationBase base)
Get derivatives of base functions.
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799

Member Data Documentation

◆ maxPtr

boost::shared_ptr<double> LevelSet::maxPtr
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 370 of file level_set.cpp.

◆ mField

MoFEM::Interface& LevelSet::mField
private

integrate skeleton operators on khs

Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 349 of file level_set.cpp.

◆ tsSolutionVec

SmartPetscObj<Vec> LevelSet::tsSolutionVec
private
Examples
mofem/tutorials/adv-3_level_set/level_set.cpp.

Definition at line 371 of file level_set.cpp.


The documentation for this struct was generated from the following file: