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.lock()) {
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 =
320 [](
DataOperator *base_op_ptr,
int side, EntityType type,
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,
389 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
393 op_set_coeffs->doWorkRhsHook =
394 [coeffs_ptr](
DataOperator *base_op_ptr,
int side, EntityType type,
397 auto field_ents = data.getFieldEntities();
398 auto nb_dofs = data.getIndices().size();
399 if (!field_ents.size())
401 if (
auto e_ptr = field_ents[0]) {
402 auto field_ent_data = e_ptr->getEntFieldData();
403 std::copy(coeffs_ptr->data().data(),
404 coeffs_ptr->data().data() + nb_dofs,
405 field_ent_data.begin());
409 fe_child_ptr->getOpPtrVector().push_back(op_set_coeffs);
413 for (
auto &p : vec_data_ptr.second) {
415 auto data_ptr = p.second;
421 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2,
428 fe_child_ptr->getOpPtrVector().push_back(
new OpError(data_ptr));
432 fe_child_ptr->getOpPtrVector().push_back(
435 GAUSS>::OpBaseTimesVector<1, FIELD_DIM, 1>;
436 fe_child_ptr->getOpPtrVector().push_back(
443 auto dm =
simple->getDM();
450 auto ref_entities_ptr = boost::make_shared<Range>();
452 refine_bit, child_bit | refine_bit, *ref_entities_ptr);
455 ref_entities_ptr->merge(verts);
465 auto fe_child_ptr = get_child_op(pipeline_mng->getOpDomainRhsPipeline());
468 CHKERR dg_projection_base(fe_child_ptr, get_field_eval_op(fe_child_ptr), mat,
473 auto test_U_data_ptr = boost::make_shared<MatrixDouble>();
474 pipeline_mng->getOpDomainRhsPipeline().push_back(
477 pipeline_mng->getOpDomainRhsPipeline().push_back(
480 auto fe_rhs = pipeline_mng->getCastDomainRhsFE<
DomainEle>();
486 CHKERR pipeline_mng->loopFiniteElements(sub_dm);
488 CHKERR VecAssemblyBegin(vec);
489 CHKERR VecAssemblyEnd(vec);
490 CHKERR VecGhostUpdateBegin(vec, ADD_VALUES, SCATTER_REVERSE);
491 CHKERR VecGhostUpdateEnd(vec, ADD_VALUES, SCATTER_REVERSE);
492 CHKERR MatAssemblyBegin(mat, MAT_FINAL_ASSEMBLY);
493 CHKERR MatAssemblyEnd(mat, MAT_FINAL_ASSEMBLY);
496 CHKERR KSPSetOperators(ksp, mat, mat);
497 CHKERR KSPSetFromOptions(ksp);
500 CHKERR KSPSolve(ksp, vec, sol);
501 CHKERR VecGhostUpdateBegin(sol, INSERT_VALUES, SCATTER_FORWARD);
502 CHKERR VecGhostUpdateEnd(sol, INSERT_VALUES, SCATTER_FORWARD);
505 pipeline_mng->getOpDomainRhsPipeline().clear();
506 auto test_S_data_ptr = boost::make_shared<MatrixDouble>();
507 pipeline_mng->getOpDomainRhsPipeline().push_back(
510 pipeline_mng->getOpDomainRhsPipeline().push_back(
524 auto post_proc_fe = boost::make_shared<PostProcFaceEle>(
mField);
526 post_proc_fe->getOpPtrVector(), {H1});
528 auto u_ptr = boost::make_shared<VectorDouble>();
529 post_proc_fe->getOpPtrVector().push_back(
531 auto s_ptr = boost::make_shared<VectorDouble>();
532 post_proc_fe->getOpPtrVector().push_back(
535 auto grad_u_ptr = boost::make_shared<MatrixDouble>();
536 post_proc_fe->getOpPtrVector().push_back(
538 auto grad_s_ptr = boost::make_shared<MatrixDouble>();
539 post_proc_fe->getOpPtrVector().push_back(
545 post_proc_fe->getOpPtrVector().push_back(
548 post_proc_fe->getPostProcMesh(), post_proc_fe->getMapGaussPts(),
569 CHKERR post_proc_fe->writeFile(file_name);
582 auto make_edge_flip = [&](
auto edge,
auto adj_faces,
Range &new_tris) {
589 CHKERR moab.get_connectivity(e, conn, num_nodes,
true);
590 std::copy(conn, conn + num_nodes, conn_cpy);
594 auto get_tri_normals = [&](
auto &conn) {
595 std::array<double, 18> coords;
596 CHKERR moab.get_coords(conn.data(), 6, coords.data());
597 std::array<FTensor::Tensor1<double, 3>, 2> tri_normals;
598 for (
int t = 0;
t != 2; ++
t) {
604 auto test_flip = [&](
auto &&t_normals) {
606 if (t_normals[0](
i) * t_normals[1](
i) <
607 std::numeric_limits<float>::epsilon())
612 std::array<EntityHandle, 6> adj_conn;
613 CHKERR get_conn(adj_faces[0], &adj_conn[0]);
614 CHKERR get_conn(adj_faces[1], &adj_conn[3]);
615 std::array<EntityHandle, 2> edge_conn;
616 CHKERR get_conn(edge, edge_conn.data());
617 std::array<EntityHandle, 2> new_edge_conn;
620 for (
int i = 0;
i != 6; ++
i) {
621 if (adj_conn[
i] != edge_conn[0] && adj_conn[
i] != edge_conn[1]) {
622 new_edge_conn[
j] = adj_conn[
i];
627 auto &new_conn = adj_conn;
628 for (
int t = 0;
t != 2; ++
t) {
629 for (
int i = 0;
i != 3; ++
i) {
632 (adj_conn[3 *
t +
i % 3] == edge_conn[0] &&
633 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[1])
637 (adj_conn[3 *
t +
i % 3] == edge_conn[1] &&
638 adj_conn[3 *
t + (
i + 1) % 3] == edge_conn[0])
641 new_conn[3 *
t + (
i + 1) % 3] = new_edge_conn[
t];
647 if (test_flip(get_tri_normals(new_conn))) {
648 for (
int t = 0;
t != 2; ++
t) {
656 new_tris.insert(tri);
659 if (rtri.size() != 1) {
661 <<
"Multiple tries created during edge flip for edge " << edge
662 <<
" adjacent faces " << std::endl
665 "Multiple tries created during edge flip");
668 new_tris.merge(rtri);
674 moab::Interface::UNION);
679 <<
"Edge flip rejected for edge " << edge <<
" adjacent faces "
692 CHKERR skin.find_skin(0, tris,
false, skin_edges);
696 edges = subtract(edges, skin_edges);
700 Range new_tris, flipped_tris, forbidden_tris;
702 for (
auto edge : edges) {
706 adjacent_tris = intersect(adjacent_tris, tris);
707 adjacent_tris = subtract(adjacent_tris, forbidden_tris);
708 if (adjacent_tris.size() == 2) {
711 int side_number0, sense0, offset0;
714 int side_number1, sense1, offset1;
717 if (sense0 * sense1 > 0)
720 "Cannot flip edge with same orientation in both adjacent faces");
723 Range new_flipped_tris;
724 CHKERR make_edge_flip(edge, adjacent_tris, new_flipped_tris);
725 if (new_flipped_tris.size()) {
726 flipped_tris.merge(adjacent_tris);
727 forbidden_tris.merge(adjacent_tris);
728 new_tris.merge(new_flipped_tris);
732 "flipped_tris_" + std::to_string(flip_count) +
".vtk",
735 moab,
"new_flipped_tris_" + std::to_string(flip_count) +
".vtk",
747 Range not_flipped_tris = subtract(all_tris, flipped_tris);
750 <<
"Flipped " << flip_count <<
" edges with two adjacent faces.";
756 child_bit,
BitRefLevel().set(),
"edge_flips_before_refinement.vtk",
"VTK",
776 CHKERR skin.find_skin(0, tris,
false, skin_edges);
788 child_bit,
BitRefLevel().set(),
"edge_flips_after_refinement.vtk",
"VTK",
804int main(
int argc,
char *argv[]) {
811 DMType dm_name =
"DMMOFEM";
816 moab::Core mb_instance;
817 moab::Interface &moab = mb_instance;
#define FTENSOR_INDEX(DIM, I)
void simple(double P1[], double P2[], double P3[], double c[], const int N)
constexpr char FIELD_NAME_U[]
constexpr char FIELD_NAME_S[]
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
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.
constexpr int order
Order displacement.
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 DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode)
set local (or ghosted) vector values on mesh for partition only
PetscErrorCode DMMoFEMAddSubFieldRow(DM dm, const char field_name[])
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
auto createDMVector(DM dm)
Get smart vector from DM.
PetscErrorCode DMMoFEMAddSubFieldCol(DM dm, const char field_name[])
auto createDMMatrix(DM dm)
Get smart matrix from DM.
MoFEMErrorCode loopFiniteElements(SmartPetscObj< DM > dm=nullptr)
Iterate finite elements.
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
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 double precision vector field values calculation.
Execute "this" element in the operator.
Post post-proc data at points from hash maps.
std::map< std::string, boost::shared_ptr< MatrixDouble > > DataMapMat
std::map< std::string, boost::shared_ptr< VectorDouble > > DataMapVec
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 > & getDomainRhsFE()
Get domain right-hand side finite element.
boost::shared_ptr< FEMethod > & getDomainLhsFE()
Get domain left-hand side 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