14static char help[] =
"DG Projection Test - validates discontinuous Galerkin "
15 "projection accuracy\n\n";
30auto fun = [](
const double x,
const double y,
const double z) {
31 return x + y + x * x + y * y;
73[[maybe_unused]]
auto save_range = [](moab::Interface &moab,
75 std::vector<Tag> tags = {}) {
78 CHKERR moab.add_entities(*out_meshset, r);
80 CHKERR moab.write_file(
name.c_str(),
"VTK",
"", out_meshset->get_ptr(), 1,
81 tags.data(), tags.size());
83 MOFEM_LOG(
"SELF", Sev::warning) <<
"Empty range for " <<
name;
91 OpError(boost::shared_ptr<MatrixDouble> data_ptr,
99 auto fe_ptr = getNumeredEntFiniteElementPtr();
100 auto fe_bit = fe_ptr->getBitRefLevel();
102 const int nb_integration_pts = getGaussPts().size2();
104 auto t_val = getFTensor1FromMat<1>(*(
dataPtr));
105 auto t_coords = getFTensor1CoordsAtGaussPts();
107 for (
int gg = 0; gg != nb_integration_pts; ++gg) {
109 double projected_value = t_val(0);
110 double analytical_value =
fun(t_coords(0), t_coords(1), t_coords(2));
111 double error = projected_value - analytical_value;
113 constexpr double eps = 1e-8;
114 if (std::abs(error) >
eps) {
116 <<
"Projection error too large: " << error <<
" at point ("
117 << t_coords(0) <<
", " << t_coords(1) <<
")"
118 <<
" projected=" << projected_value
119 <<
" analytical=" << analytical_value;
121 "DG projection failed accuracy test");
129 <<
"DG projection accuracy validation passed";
174 char mesh_File_Name[255];
176 mesh_File_Name, 255, PETSC_NULLPTR);
205 auto rule = [](
int,
int,
int p) ->
int {
return 2 * p; };
234 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Solving DG projection system";
237 CHKERR KSPSetFromOptions(solver);
246 solver,
"DG projection solve");
248 CHKERR VecGhostUpdateBegin(
D, INSERT_VALUES, SCATTER_FORWARD);
249 CHKERR VecGhostUpdateEnd(
D, INSERT_VALUES, SCATTER_FORWARD);
265 pipeline_mng->getDomainLhsFE().reset();
266 pipeline_mng->getDomainRhsFE().reset();
267 pipeline_mng->getOpDomainRhsPipeline().clear();
269 auto rule = [](int, int,
int p) ->
int {
return 2 * p; };
270 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
275 auto get_child_op = [&](
auto &pip) {
278 child_bit | refine_bit, Sev::noisy);
279 auto fe_child_ptr = op_this_child->getThisFEPtr();
280 fe_child_ptr->getRuleHook = [] (int, int,
int p) {
return -1; };
283 refine_bit, child_bit | refine_bit, MBEDGE, child_edges);
285 CHKERR setDGSetIntegrationPoints<SPACE_DIM>(
286 fe_child_ptr->setRuleHook, [](
int,
int,
int p) { return 2 * p; },
287 boost::make_shared<Range>(child_edges));
288 pip.push_back(op_this_child);
294 auto get_field_eval_op = [&](
auto fe_child_ptr) {
303 parent_bit | child_bit);
306 auto data_U_ptr = boost::make_shared<MatrixDouble>();
307 auto eval_data_U_ptr = boost::make_shared<MatrixDouble>();
308 auto data_S_ptr = boost::make_shared<MatrixDouble>();
309 auto eval_data_S_ptr = boost::make_shared<MatrixDouble>();
312 if (
auto fe_eval_ptr = field_eval_data->feMethodPtr) {
313 fe_eval_ptr->getRuleHook = [] (int, int,
int p) {
return -1; };
314 fe_eval_ptr->getOpPtrVector().push_back(
317 fe_eval_ptr->getOpPtrVector().push_back(
322 op_test->doWorkRhsHook =
327 auto op_ptr =
static_cast<DomainEleOp *
>(base_op_ptr);
330 <<
"Field evaluator method pointer is valid";
332 << op_ptr->getGaussPts();
334 <<
"Loop size " << op_ptr->getPtrFE()->getLoopSize();
336 <<
"Coords at gauss pts: " << op_ptr->getCoordsAtGaussPts();
341 fe_eval_ptr->getOpPtrVector().push_back(op_test);
345 "Field evaluator method pointer is expired");
348 auto op_ptr = field_eval_ptr->getDataOperator<
SPACE_DIM>(
349 {{eval_data_U_ptr, data_U_ptr}, {eval_data_S_ptr, data_S_ptr}},
354 fe_child_ptr->getOpPtrVector().push_back(op_ptr);
355 return std::make_pair(
357 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
360 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
368 auto dg_projection_base = [&](
auto fe_child_ptr,
auto vec_data_ptr,
auto mat,
371 constexpr int projection_order =
order;
372 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
373 auto mass_ptr = boost::make_shared<MatrixDouble>();
374 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
377 for (
auto &p : vec_data_ptr.first) {
379 auto data_ptr = p.second;
385 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
393 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
397 op_set_coeffs->doWorkRhsHook =
401 auto field_ents = data.getFieldEntities();
402 auto nb_dofs = data.getIndices().size();
403 if (!field_ents.size())
405 if (
auto e_ptr = field_ents[0]) {
406 auto field_ent_data = e_ptr->getEntFieldData();
407 std::copy(coeffs_ptr->data().data(),
408 coeffs_ptr->data().data() + nb_dofs,
409 field_ent_data.begin());
413 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
417 for (
auto &p : vec_data_ptr.second) {
419 auto data_ptr = p.second;
425 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
433 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
437 fe_child_ptr->getOpPtrVector().push_back(
440 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, FIELD_DIM>;
441 fe_child_ptr->getOpPtrVector().push_back(
455 auto ref_entities_ptr = boost::make_shared<Range>();
457 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
460 ref_entities_ptr->merge(verts);
470 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
473 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
478 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
479 pipeline_mng->getOpDomainRhsPipeline().push_back(
482 pipeline_mng->getOpDomainRhsPipeline().push_back(
485 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<
DomainEle>();
491 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
493 CHKERR VecAssemblyBegin(vec);
494 CHKERR VecAssemblyEnd(vec);
495 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
496 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
497 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
498 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
507 ksp,
"DG projection result");
508 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
509 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
512 pipeline_mng->getOpDomainRhsPipeline().clear();
513 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
514 pipeline_mng->getOpDomainRhsPipeline().push_back(
517 pipeline_mng->getOpDomainRhsPipeline().push_back(
530 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(
mField);
532 post_proc_fe->getOpPtrVector(), {H1});
534 auto u_ptr = boost::make_shared<VectorDouble>();
535 post_proc_fe->getOpPtrVector().push_back(
537 auto s_ptr = boost::make_shared<VectorDouble>();
538 post_proc_fe->getOpPtrVector().push_back(
541 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
542 post_proc_fe->getOpPtrVector().push_back(
544 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
545 post_proc_fe->getOpPtrVector().push_back(
551 post_proc_fe->getOpPtrVector().push_back(
554 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
575 CHKERR post_proc_fe->writeFile(file_name);
588 auto make_edge_flip = [&](
auto edge,
auto adj_faces,
Range &new_tris) {
591 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
593 const EntityHandle *conn;
595 CHKERR moab.get_connectivity(e, conn, num_nodes,
true);
596 std::copy(conn, conn + num_nodes, conn_cpy);
600 auto get_tri_normals = [&](
auto &conn) {
601 std::array<double, 18> coords;
602 CHKERR moab.get_coords(conn.data(), 6, coords.data());
603 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
604 for (
int t = 0;
t != 2; ++
t) {
610 auto test_flip = [&](
auto &&t_normals) {
612 if (t_normals[0](
i) * t_normals[1](
i) <
613 std::numeric_limits<float>::epsilon())
618 std::array<EntityHandle, 6> adj_conn;
619 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
620 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
621 std::array<EntityHandle, 2> edge_conn;
622 CHKERR get_conn(edge, edge_conn.data());
623 std::array<EntityHandle, 2> new_edge_conn;
626 for (
int i = 0;
i != 6; ++
i) {
627 if (adj_conn[
i] != edge_conn[0] && adj_conn[
i] != edge_conn[1]) {
628 new_edge_conn[
j] = adj_conn[
i];
633 auto &new_conn = adj_conn;
634 for (
int t = 0;
t != 2; ++
t) {
635 for (
int i = 0;
i != 3; ++
i) {
638 (adj_conn[3 *
t +
i % 3] == edge_conn[0] &&
639 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[1])
643 (adj_conn[3 *
t +
i % 3] == edge_conn[1] &&
644 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[0])
647 new_conn[3 *
t + (
i + 1) % 3] = new_edge_conn[
t];
653 if (test_flip(get_tri_normals(new_conn))) {
654 for (
int t = 0;
t != 2; ++
t) {
662 new_tris.insert(tri);
665 if (rtri.size() != 1) {
667 <<
"Multiple tries created during edge flip for edge " << edge
668 <<
" adjacent faces " << std::endl
671 "Multiple tries created during edge flip");
674 new_tris.merge(rtri);
680 moab::Interface::UNION);
685 <<
"Edge flip rejected for edge " << edge <<
" adjacent faces "
698 CHKERR skin.find_skin(0, tris,
false, skin_edges);
702 edges = subtract(edges, skin_edges);
706 Range new_tris, flipped_tris, forbidden_tris;
708 for (
auto edge : edges) {
712 adjacent_tris = intersect(adjacent_tris, tris);
713 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
714 if (adjacent_tris.size() == 2) {
717 int side_number0, sense0, offset0;
720 int side_number1, sense1, offset1;
723 if (sense0 * sense1 > 0)
726 "Cannot flip edge with same orientation in both adjacent faces");
729 Range new_flipped_tris;
730 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
731 if (new_flipped_tris.size()) {
732 flipped_tris.merge(adjacent_tris);
733 forbidden_tris.merge(adjacent_tris);
734 new_tris.merge(new_flipped_tris);
738 "flipped_tris_" + std::to_string(flip_count) +
".vtk",
741 moab,
"new_flipped_tris_" + std::to_string(flip_count) +
".vtk",
753 Range not_flipped_tris = subtract(all_tris, flipped_tris);
756 <<
"Flipped " << flip_count <<
" edges with two adjacent faces.";
762 child_bit,
BitRefLevel().set(),
"edge_flips_before_refinement.vtk",
"VTK",
782 CHKERR skin.find_skin(0, tris,
false, skin_edges);
794 child_bit,
BitRefLevel().set(),
"edge_flips_after_refinement.vtk",
"VTK",
810int main(
int argc,
char *argv[]) {
817 DMType dm_name =
"DMMOFEM";
822 moab::Core mb_instance;
823 moab::Interface &moab = mb_instance;
#define FTENSOR_INDEX(DIM, I)
constexpr char FIELD_NAME_U[]
constexpr char FIELD_NAME_S[]
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, FIELD_DIM > OpDomainMass
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
#define CHK_THROW_MESSAGE(err, msg)
Check and throw MoFEM exception.
#define MoFEMFunctionReturnHot(a)
Last executable line of each PETSc function used for error handling. Replaces return()
@ L2
field with C-1 continuity
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle
Domain finite elements.
constexpr int SPACE_DIM
[Define dimension]
DomainEle::UserDataOperator DomainEleOp
Domain element operators.
PetscErrorCode DMMoFEMCreateSubDM(DM subdm, DM dm, const char problem_name[])
Must be called by user to set Sub DM MoFEM data structures.
PetscErrorCode DMMoFEMAddElement(DM dm, std::string fe_name)
add element to dm
PetscErrorCode DMMoFEMSetSquareProblem(DM dm, PetscBool square_problem)
set squared problem
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
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
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
auto createDMMatrix(DM dm)
Get smart matrix from DM.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
MoFEMErrorCode loopFiniteElementsPostProc(SmartPetscObj< DM > dm=nullptr)
Iterate postprocessing finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
#define MOFEM_LOG(channel, severity)
Log.
#define MOFEM_LOG_CHANNEL(channel)
Set and reset channel.
FTensor::Index< 'i', SPACE_DIM > i
FTensor::Index< 'j', 3 > j
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
implementation of Data Operators for Forces and Sources
auto createKSP(MPI_Comm comm)
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
PetscErrorCode PetscOptionsGetString(PetscOptions *, const char pre[], const char name[], char str[], size_t size, PetscBool *set)
auto get_temp_meshset_ptr(moab::Interface &moab)
Create smart pointer to temporary meshset.
auto createDM(MPI_Comm comm, const std::string dm_type_name)
Creates smart DM object.
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
constexpr double t
plate stiffness
constexpr auto field_name
SmartPetscObj< Vec > L2Vec
boost::shared_ptr< VectorDouble > approxVals
boost::shared_ptr< MatrixDouble > invJacPtr
boost::shared_ptr< MatrixDouble > approxGradVals
boost::shared_ptr< MatrixDouble > approxHessianVals
MoFEMErrorCode doWork(int side, EntityType type, EntData &data)
boost::shared_ptr< MatrixDouble > dataPtr
boost::shared_ptr< CommonData > commonDataPtr
OpError(boost::shared_ptr< MatrixDouble > data_ptr, BitRefLevel bits=BitRefLevel(), BitRefLevel mask=BitRefLevel())
MoFEMErrorCode assembleSystem()
MoFEMErrorCode readMesh()
MoFEMErrorCode reSetupProblem(BitRefLevel child_bit)
[Refine skin]
MoFEMErrorCode edgeFlips(BitRefLevel parent_bit, BitRefLevel child_bit)
[Output results]
MoFEMErrorCode projectResults(BitRefLevel parent_bit, BitRefLevel child_bit, BitRefLevel refine_bit)
[Solve]
MoFEMErrorCode solveSystem()
MoFEMErrorCode refineSkin(BitRefLevel parent_bit, BitRefLevel refine_bit)
[Edge flips]
Example(MoFEM::Interface &m_field)
MoFEMErrorCode runProblem()
MoFEM::Interface & mField
Reference to MoFEM interface.
MoFEMErrorCode setupProblem()
MoFEMErrorCode outputResults()
[Solve]
Add operators pushing bases from local to physical configuration.
virtual int get_comm_size() const =0
virtual moab::Interface & get_moab()=0
virtual MPI_Comm & get_comm() const =0
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
base operator to do operations at Gauss Pt. level
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
Field evaluator interface.
boost::shared_ptr< SPD > getData(const double *ptr=nullptr, const int nb_eval_points=0, const double eps=1e-12, VERBOSITY_LEVELS verb=QUIET)
Get the Data object.
Mesh refinement interface.
MoFEMErrorCode addVerticesInTheMiddleOfEdges(const EntityHandle meshset, const BitRefLevel &bit, const bool recursive=false, int verb=QUIET, EntityHandle start_v=0)
make vertices in the middle of edges in meshset and add them to refinement levels defined by bit
Get field gradients at integration pts for scalar field rank 0, i.e. vector field.
Specialization for double precision scalar field values calculation.
Specialization for MatrixDouble vector field values calculation.
Evaluate field for given DG projection coefficients.
Evaluate right hand side for given data coefficients.
Execute "this" element in the operator.
Post post-proc data at points from hash maps.
std::map< std::string, ScalarDataPtr > DataMapVec
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
static constexpr Switches CtxSetA
Jacobian matrix switch.
static constexpr Switches CtxSetF
Residual vector switch.
static constexpr Switches CtxSetB
Preconditioner matrix switch.
Template struct for dimension-specific finite element types.
PipelineManager interface.
boost::shared_ptr< FEMethod > & getDomainPostProcFE()
Get domain postprocessing finite element.
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
Simple interface for fast problem set-up.
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.
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
MoFEMErrorCode reSetUp(bool only_dm=false)
Rebuild internal MoFEM data structures.
MoFEMErrorCode getOptions()
get options
MoFEMErrorCode getDM(DM *dm)
Get DM.
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
const std::string getDomainFEName() const
Get the Domain FE Name.
BitRefLevel & getBitRefLevel()
Get the BitRefLevel.
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.