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;
73auto save_range = [](moab::Interface &moab,
const std::string name,
74 const Range r, std::vector<Tag> tags = {}) {
77 CHKERR moab.add_entities(*out_meshset, r);
79 CHKERR moab.write_file(name.c_str(),
"VTK",
"", out_meshset->get_ptr(), 1,
80 tags.data(), tags.size());
82 MOFEM_LOG(
"SELF", Sev::warning) <<
"Empty range for " << name;
90 OpError(boost::shared_ptr<MatrixDouble> data_ptr,
98 auto fe_ptr = getNumeredEntFiniteElementPtr();
99 auto fe_bit = fe_ptr->getBitRefLevel();
101 const int nb_integration_pts = getGaussPts().size2();
103 auto t_val = getFTensor1FromMat<1>(*(
dataPtr));
104 auto t_coords = getFTensor1CoordsAtGaussPts();
106 for (
int gg = 0; gg != nb_integration_pts; ++gg) {
108 double projected_value = t_val(0);
109 double analytical_value =
fun(t_coords(0), t_coords(1), t_coords(2));
110 double error = projected_value - analytical_value;
112 constexpr double eps = 1e-8;
113 if (std::abs(error) >
eps) {
115 <<
"Projection error too large: " << error <<
" at point ("
116 << t_coords(0) <<
", " << t_coords(1) <<
")"
117 <<
" projected=" << projected_value
118 <<
" analytical=" << analytical_value;
120 "DG projection failed accuracy test");
128 <<
"DG projection accuracy validation passed";
173 char mesh_File_Name[255];
175 mesh_File_Name, 255, PETSC_NULLPTR);
204 auto rule = [](
int,
int,
int p) ->
int {
return 2 * p; };
233 MOFEM_LOG(
"WORLD", Sev::inform) <<
"Solving DG projection system";
236 CHKERR KSPSetFromOptions(solver);
245 CHKERR VecGhostUpdateBegin(
D, INSERT_VALUES, SCATTER_FORWARD);
246 CHKERR VecGhostUpdateEnd(
D, INSERT_VALUES, SCATTER_FORWARD);
262 pipeline_mng->getDomainLhsFE().reset();
263 pipeline_mng->getDomainRhsFE().reset();
264 pipeline_mng->getOpDomainRhsPipeline().clear();
266 auto rule = [](int, int,
int p) ->
int {
return 2 * p; };
267 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
272 auto get_child_op = [&](
auto &pip) {
275 child_bit | refine_bit, Sev::noisy);
276 auto fe_child_ptr = op_this_child->getThisFEPtr();
277 fe_child_ptr->getRuleHook = [] (int, int,
int p) {
return -1; };
280 refine_bit, child_bit | refine_bit, MBEDGE, child_edges);
282 CHKERR setDGSetIntegrationPoints<SPACE_DIM>(
283 fe_child_ptr->setRuleHook, [](
int,
int,
int p) { return 2 * p; },
284 boost::make_shared<Range>(child_edges));
285 pip.push_back(op_this_child);
291 auto get_field_eval_op = [&](
auto fe_child_ptr) {
300 parent_bit | child_bit);
303 auto data_U_ptr = boost::make_shared<MatrixDouble>();
304 auto eval_data_U_ptr = boost::make_shared<MatrixDouble>();
305 auto data_S_ptr = boost::make_shared<MatrixDouble>();
306 auto eval_data_S_ptr = boost::make_shared<MatrixDouble>();
309 if (
auto fe_eval_ptr = field_eval_data->feMethodPtr) {
310 fe_eval_ptr->getRuleHook = [] (int, int,
int p) {
return -1; };
311 fe_eval_ptr->getOpPtrVector().push_back(
314 fe_eval_ptr->getOpPtrVector().push_back(
319 op_test->doWorkRhsHook =
324 auto op_ptr =
static_cast<DomainEleOp *
>(base_op_ptr);
327 <<
"Field evaluator method pointer is valid";
329 << op_ptr->getGaussPts();
331 <<
"Loop size " << op_ptr->getPtrFE()->getLoopSize();
333 <<
"Coords at gauss pts: " << op_ptr->getCoordsAtGaussPts();
338 fe_eval_ptr->getOpPtrVector().push_back(op_test);
342 "Field evaluator method pointer is expired");
345 auto op_ptr = field_eval_ptr->getDataOperator<
SPACE_DIM>(
346 {{eval_data_U_ptr, data_U_ptr}, {eval_data_S_ptr, data_S_ptr}},
351 fe_child_ptr->getOpPtrVector().push_back(op_ptr);
352 return std::make_pair(
354 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
357 std::vector<std::pair<std::string, boost::shared_ptr<MatrixDouble>>>{
365 auto dg_projection_base = [&](
auto fe_child_ptr,
auto vec_data_ptr,
auto mat,
368 constexpr int projection_order =
order;
369 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
370 auto mass_ptr = boost::make_shared<MatrixDouble>();
371 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
374 for (
auto &p : vec_data_ptr.first) {
376 auto data_ptr = p.second;
382 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
390 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
394 op_set_coeffs->doWorkRhsHook =
398 auto field_ents = data.getFieldEntities();
399 auto nb_dofs = data.getIndices().size();
400 if (!field_ents.size())
402 if (
auto e_ptr = field_ents[0]) {
403 auto field_ent_data = e_ptr->getEntFieldData();
404 std::copy(coeffs_ptr->data().data(),
405 coeffs_ptr->data().data() + nb_dofs,
406 field_ent_data.begin());
410 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
414 for (
auto &p : vec_data_ptr.second) {
416 auto data_ptr = p.second;
422 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
430 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
434 fe_child_ptr->getOpPtrVector().push_back(
437 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, FIELD_DIM>;
438 fe_child_ptr->getOpPtrVector().push_back(
452 auto ref_entities_ptr = boost::make_shared<Range>();
454 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
457 ref_entities_ptr->merge(verts);
467 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
470 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
475 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
476 pipeline_mng->getOpDomainRhsPipeline().push_back(
479 pipeline_mng->getOpDomainRhsPipeline().push_back(
482 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<
DomainEle>();
488 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
490 CHKERR VecAssemblyBegin(vec);
491 CHKERR VecAssemblyEnd(vec);
492 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
493 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
494 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
495 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
498 CHKERR KSPSetOperators(ksp, mat, mat);
499 CHKERR KSPSetFromOptions(ksp);
502 CHKERR KSPSolve(ksp, vec, sol);
503 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
504 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
507 pipeline_mng->getOpDomainRhsPipeline().clear();
508 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
509 pipeline_mng->getOpDomainRhsPipeline().push_back(
512 pipeline_mng->getOpDomainRhsPipeline().push_back(
525 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(
mField);
527 post_proc_fe->getOpPtrVector(), {H1});
529 auto u_ptr = boost::make_shared<VectorDouble>();
530 post_proc_fe->getOpPtrVector().push_back(
532 auto s_ptr = boost::make_shared<VectorDouble>();
533 post_proc_fe->getOpPtrVector().push_back(
536 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
537 post_proc_fe->getOpPtrVector().push_back(
539 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
540 post_proc_fe->getOpPtrVector().push_back(
546 post_proc_fe->getOpPtrVector().push_back(
549 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
570 CHKERR post_proc_fe->writeFile(file_name);
583 auto make_edge_flip = [&](
auto edge,
auto adj_faces,
Range &new_tris) {
586 auto get_conn = [&](EntityHandle e, EntityHandle *conn_cpy) {
588 const EntityHandle *conn;
590 CHKERR moab.get_connectivity(e, conn, num_nodes,
true);
591 std::copy(conn, conn + num_nodes, conn_cpy);
595 auto get_tri_normals = [&](
auto &conn) {
596 std::array<double, 18> coords;
597 CHKERR moab.get_coords(conn.data(), 6, coords.data());
598 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
599 for (
int t = 0;
t != 2; ++
t) {
605 auto test_flip = [&](
auto &&t_normals) {
607 if (t_normals[0](
i) * t_normals[1](
i) <
608 std::numeric_limits<float>::epsilon())
613 std::array<EntityHandle, 6> adj_conn;
614 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
615 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
616 std::array<EntityHandle, 2> edge_conn;
617 CHKERR get_conn(edge, edge_conn.data());
618 std::array<EntityHandle, 2> new_edge_conn;
621 for (
int i = 0;
i != 6; ++
i) {
622 if (adj_conn[
i] != edge_conn[0] && adj_conn[
i] != edge_conn[1]) {
623 new_edge_conn[
j] = adj_conn[
i];
628 auto &new_conn = adj_conn;
629 for (
int t = 0;
t != 2; ++
t) {
630 for (
int i = 0;
i != 3; ++
i) {
633 (adj_conn[3 *
t +
i % 3] == edge_conn[0] &&
634 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[1])
638 (adj_conn[3 *
t +
i % 3] == edge_conn[1] &&
639 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[0])
642 new_conn[3 *
t + (
i + 1) % 3] = new_edge_conn[
t];
648 if (test_flip(get_tri_normals(new_conn))) {
649 for (
int t = 0;
t != 2; ++
t) {
657 new_tris.insert(tri);
660 if (rtri.size() != 1) {
662 <<
"Multiple tries created during edge flip for edge " << edge
663 <<
" adjacent faces " << std::endl
666 "Multiple tries created during edge flip");
669 new_tris.merge(rtri);
675 moab::Interface::UNION);
680 <<
"Edge flip rejected for edge " << edge <<
" adjacent faces "
693 CHKERR skin.find_skin(0, tris,
false, skin_edges);
697 edges = subtract(edges, skin_edges);
701 Range new_tris, flipped_tris, forbidden_tris;
703 for (
auto edge : edges) {
707 adjacent_tris = intersect(adjacent_tris, tris);
708 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
709 if (adjacent_tris.size() == 2) {
712 int side_number0, sense0, offset0;
715 int side_number1, sense1, offset1;
718 if (sense0 * sense1 > 0)
721 "Cannot flip edge with same orientation in both adjacent faces");
724 Range new_flipped_tris;
725 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
726 if (new_flipped_tris.size()) {
727 flipped_tris.merge(adjacent_tris);
728 forbidden_tris.merge(adjacent_tris);
729 new_tris.merge(new_flipped_tris);
733 "flipped_tris_" + std::to_string(flip_count) +
".vtk",
736 moab,
"new_flipped_tris_" + std::to_string(flip_count) +
".vtk",
748 Range not_flipped_tris = subtract(all_tris, flipped_tris);
751 <<
"Flipped " << flip_count <<
" edges with two adjacent faces.";
757 child_bit,
BitRefLevel().set(),
"edge_flips_before_refinement.vtk",
"VTK",
777 CHKERR skin.find_skin(0, tris,
false, skin_edges);
789 child_bit,
BitRefLevel().set(),
"edge_flips_after_refinement.vtk",
"VTK",
805int main(
int argc,
char *argv[]) {
812 DMType dm_name =
"DMMOFEM";
817 moab::Core mb_instance;
818 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.
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.
DomainEle::UserDataOperator DomainEleOp
PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle DomainEle