v0.15.5
Loading...
Searching...
No Matches
mofem/tools/mesh_smoothing.cpp
/** \file mesh_smoothing.cpp
* \brief Improve mesh quality using Volume-length quality measure with barrier
* \example mofem/tools/mesh_smoothing.cpp
*
*/
#include <MoFEM.hpp>
using namespace MoFEM;
#include <PostProc.hpp>
using namespace MoFEM;
static char help[] = "mesh smoothing\n\n";
PetscBool output_vtk = PETSC_TRUE;
double tol = 0.1;
double gamma_factor = 0.8;
constexpr bool fix_edge_blocks = true;
int main(int argc, char *argv[]) {
MoFEM::Core::Initialize(&argc, &argv, (char *)0, help);
try {
PetscOptionsBegin(PETSC_COMM_WORLD, "", "Mesh cut options", "none");
CHKERR PetscOptionsInt("-edges_block_set", "edges side set", "",
edges_block_set, &edges_block_set, PETSC_NULLPTR);
CHKERR PetscOptionsInt("-vertex_block_set", "vertex side set", "",
CHKERR PetscOptionsBool("-output_vtk", "if true outout vtk file", "",
output_vtk, &output_vtk, PETSC_NULLPTR);
CHKERR PetscOptionsScalar("-quality_reduction_tol", "",
"Tolerance of quality reduction", tol, &tol,
PETSC_NULLPTR);
CHKERR PetscOptionsScalar("-gamma_factor", "",
"Gamma factor", gamma_factor, &gamma_factor,
PETSC_NULLPTR);
PetscOptionsEnd();
// Create MoAB database
moab::Core moab_core; // create database
moab::Interface &moab = moab_core; // create interface to database
// Create MoFEM database and link it to MoAB
MoFEM::Core mofem_core(moab); // create database
MoFEM::Interface &m_field = mofem_core; // create interface to database
// Register DM Manager
CHKERR DMRegister_MoFEM("DMMOFEM"); // register MoFEM DM in PETSc
// Get simple interface is simplified version enabling quick and
// easy construction of problem.
Simple *simple_interface = m_field.getInterface<Simple>();
Range edges, vertices, fixed_vertex;
// Build problem with simple interface
{
// Get options for simple interface from command line
CHKERR simple_interface->getOptions();
// Load mesh file to database
CHKERR simple_interface->loadFile();
// Add domain field "U" in space H1 and Legendre base, Ainsworth recipe is
// used to construct base functions.
CHKERR simple_interface->addDomainField("MESH_NODE_POSITIONS", H1,
// Add Lagrange multiplier field on body boundary
CHKERR simple_interface->addBoundaryField("LAMBDA_SURFACE", H1,
// Set fields order domain and boundary fields.
CHKERR simple_interface->setFieldOrder("MESH_NODE_POSITIONS",
1); // to approximate function
CHKERR simple_interface->setFieldOrder("LAMBDA_SURFACE",
1); // to Lagrange multipliers
simple_interface->getDomainFEName() = "SMOOTHING";
simple_interface->getBoundaryFEName() = "SURFACE_SLIDING";
// Other fields and finite elements added to database directly
->getEntitiesByDimension(edges_block_set, BLOCKSET, 1, edges,
true);
} else {
CHKERR Smoother::extractMeshEdges(m_field, edges, fixed_vertex);
}
->getEntitiesByDimension(vertex_block_set, BLOCKSET, 0,
fixed_vertex, true);
}
CHKERR m_field.get_moab().get_connectivity(edges, vertices, true);
if(!edges.empty() && !fix_edge_blocks) {
// Declare approximation fields
CHKERR m_field.add_field("LAMBDA_EDGE", H1, AINSWORTH_LOBATTO_BASE, 2,
MB_TAG_SPARSE, MF_ZERO);
CHKERR m_field.add_ents_to_field_by_type(edges, MBEDGE,
"LAMBDA_EDGE");
->synchroniseFieldEntities("LAMBDA_EDGE");
CHKERR m_field.set_field_order(0, MBVERTEX, "LAMBDA_EDGE", 1);
CHKERR m_field.add_finite_element("EDGE_SLIDING");
"EDGE_SLIDING", "MESH_NODE_POSITIONS");
"EDGE_SLIDING", "MESH_NODE_POSITIONS");
"EDGE_SLIDING", "MESH_NODE_POSITIONS");
"LAMBDA_EDGE");
"LAMBDA_EDGE");
"LAMBDA_EDGE");
"EDGE_SLIDING");
simple_interface->getOtherFiniteElements().push_back("EDGE_SLIDING");
}
CHKERR simple_interface->defineFiniteElements();
CHKERR simple_interface->defineProblem();
CHKERR simple_interface->buildFields();
CHKERR simple_interface->buildFiniteElements();
CHKERR simple_interface->buildProblem();
// Remove vertices form LAMBDA_SURFACE which are on the edges
if (!edges.empty()) {
Range edges;
CHKERR m_field.getInterface<MeshsetsManager>()->getEntitiesByDimension(
edges_block_set, BLOCKSET, 1, edges, true);
Range verts;
CHKERR m_field.get_moab().get_connectivity(edges, verts, true);
Simple *simple_interface = m_field.getInterface<Simple>();
auto prb_mng = m_field.getInterface<ProblemsManager>();
CHKERR prb_mng->removeDofsOnEntities(simple_interface->getProblemName(),
"LAMBDA_SURFACE", verts, 0, 1);
CHKERR prb_mng->removeDofsOnEntities(
simple_interface->getProblemName(), "MESH_NODE_POSITIONS", verts,
0, 3);
}
}
}
MeshSmoothingOps::Config smoothing_cfg;
smoothing_cfg.geometryField = "MESH_NODE_POSITIONS";
smoothing_cfg.meshReferenceField = "NONE";
smoothing_cfg.lambdaSurfaceField = "LAMBDA_SURFACE";
smoothing_cfg.lambdaEdgeField = "LAMBDA_EDGE";
smoothing_cfg.enableSurfaceSliding = true;
smoothing_cfg.fixEdgeBlocks = fix_edge_blocks;
smoothing_cfg.alpha = 1.0;
smoothing_cfg.gamma = 0.0;
MeshSmoothingOps::Handles smoothing_handles;
CHKERR MeshSmoothingOps::createOperators(m_field, smoothing_cfg, fixed_vertex,
edges, smoothing_handles);
DM dm;
CHKERR simple_interface->getDM(&dm);
CHKERR MeshSmoothingOps::addToSnesDM(dm, smoothing_cfg, smoothing_handles);
struct Solve {
MoFEMErrorCode operator()(DM dm) const {
auto solver = SmartPetscObj<SNES>();
auto hook = [&](SNES snes, Vec x, Vec F,
boost::shared_ptr<CacheTuple> cache_ptr,
void *ctx) -> MoFEMErrorCode {
auto *m_field_ptr = getInterfacePtr(dm);
auto post_proc_fe =
boost::make_shared<PostProcEleDomain>(*m_field_ptr);
auto &pip = post_proc_fe->getOpPtrVector();
auto X_ptr = boost::make_shared<MatrixDouble>();
"MESH_NODE_POSITIONS", X_ptr));
auto res_X_ptr = boost::make_shared<MatrixDouble>();
"MESH_NODE_POSITIONS", res_X_ptr, SmartPetscObj<Vec>(F, true)));
auto lambda_ptr = boost::make_shared<VectorDouble>();
pip.push_back(
new OpCalculateScalarFieldValues("LAMBDA_SURFACE", lambda_ptr));
auto res_lambda_ptr = boost::make_shared<VectorDouble>();
pip.push_back(new OpCalculateScalarFieldValues(
"LAMBDA_SURFACE", res_lambda_ptr, SmartPetscObj<Vec>(F, true)));
pip.push_back(
new OpPPMap(
post_proc_fe->getPostProcMesh(),
post_proc_fe->getMapGaussPts(),
{{"LAMBDA_SURFACE", lambda_ptr},
{"RES_LAMBDA_SURFACE", res_lambda_ptr}},
{{"MESH_NODE_POSITIONS", X_ptr},
{"RES_MESH_NODE_POSITIONS", res_X_ptr}},
{},
{}
)
);
CHKERR DMoFEMLoopFiniteElements(dm, "SURFACE_SLIDING", post_proc_fe);
CHKERR post_proc_fe->writeFile("debug_smoothing.h5m");
};
auto snes_ctx_ptr = getDMSnesCtx(dm);
snes_ctx_ptr->getRhsHook() = hook;
CHKERR MeshSmoothingOps::solveSnes(dm, solver, {"LAMBDA_SURFACE"});
}
MoFEMErrorCode setCoordsFromField(DM dm) const {
MoFEM::Interface *m_field_ptr;
CHKERR DMoFEMGetInterfacePtr(dm, &m_field_ptr);
"MESH_NODE_POSITIONS", it)) {
if (it->get()->getEntType() != MBVERTEX)
continue;
VectorDouble3 coords(3);
for(int dd = 0;dd!=3;++dd)
coords[dd] = it->get()->getEntFieldData()[dd];
EntityHandle ent = it->get()->getEnt();
CHKERR m_field_ptr->get_moab().set_coords(&ent, 1, &*coords.begin());
}
}
MoFEMErrorCode setFieldFromCoords(DM dm) const {
MoFEM::Interface *m_field_ptr;
CHKERR DMoFEMGetInterfacePtr(dm, &m_field_ptr);
"MESH_NODE_POSITIONS", it)) {
if (it->get()->getEntType() != MBVERTEX)
continue;
EntityHandle ent = it->get()->getEnt();
VectorDouble3 coords(3);
CHKERR m_field_ptr->get_moab().get_coords(&ent, 1, &*coords.begin());
for(int dd = 0;dd!=3;++dd)
it->get()->getEntFieldData()[dd] = coords[dd];
}
}
};
Solve solve;
CHKERR solve.setFieldFromCoords(dm);
double min_quality = 0;
dm, simple_interface->getDomainFEName(), smoothing_handles, min_quality);
PetscPrintf(PETSC_COMM_WORLD, "Min quality = %4.3f\n", min_quality);
double gamma = min_quality > 0 ? gamma_factor * min_quality
: min_quality / gamma_factor;
CHKERR MeshSmoothingOps::updateBarrierGamma(smoothing_handles, gamma);
double min_quality_p, eps;
do {
min_quality_p = min_quality;
CHKERR solve(dm);
CHKERR solve.setCoordsFromField(dm);
dm, simple_interface->getDomainFEName(), smoothing_handles,
min_quality);
eps = (min_quality - min_quality_p) / min_quality;
PetscPrintf(PETSC_COMM_WORLD, "Min quality = %4.3f eps = %4.3f\n",
min_quality, eps);
double gamma = min_quality > 0 ? gamma_factor * min_quality
: min_quality / gamma_factor;
CHKERR MeshSmoothingOps::updateBarrierGamma(smoothing_handles, gamma);
} while (eps > tol);
// if (m_field.getInterface<MeshsetsManager>()->checkMeshset(edges_block_set,
// BLOCKSET)) {
// Range edges;
// CHKERR m_field.getInterface<MeshsetsManager>()->getEntitiesByDimension(
// edges_block_set, BLOCKSET, 1, edges, true);
// Range tets;
// CHKERR moab.get_entities_by_type(0,MBTET,tets);
// Skinner skin(&moab);
// Range skin_faces; // skin faces from 3d ents
// CHKERR skin.find_skin(0, tets, false, skin_faces);
// CHKERR EdgeSlidingConstrains::CalculateEdgeBase::setTags(moab, edges,
// skin_faces);
// CHKERR EdgeSlidingConstrains::CalculateEdgeBase::saveEdges(
// moab, "out_edges.vtk", edges);
// }
CHKERR m_field.getInterface<BitRefManager>()->writeBitLevelByType(
BitRefLevel().set(0), BitRefLevel().set(), MBTET, "out.vtk", "VTK",
"");
}
}
Post-process fields on refined mesh.
static char help[]
int main()
static const double eps
#define CATCH_ERRORS
Catch errors.
@ MF_ZERO
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ AINSWORTH_LOBATTO_BASE
Definition definitions.h:62
@ H1
continuous field
Definition definitions.h:85
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ BLOCKSET
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
PostProcEleByDim< SPACE_DIM >::PostProcEleDomain PostProcEleDomain
@ F
#define _IT_GET_ENT_FIELD_BY_NAME_FOR_LOOP_(MFIELD, NAME, IT)
loop over all dofs from a moFEM field and particular field
virtual MoFEMErrorCode add_finite_element(const std::string &fe_name, enum MoFEMTypes bh=MF_EXCL, int verb=DEFAULT_VERBOSITY)=0
add finite element
virtual MoFEMErrorCode modify_finite_element_add_field_col(const std::string &fe_name, const std::string name_row)=0
set field col which finite element use
virtual MoFEMErrorCode add_ents_to_finite_element_by_type(const EntityHandle entities, const EntityType type, const std::string name, const bool recursive=true)=0
add entities to finite element
virtual MoFEMErrorCode modify_finite_element_add_field_row(const std::string &fe_name, const std::string name_row)=0
set field row which finite element use
virtual MoFEMErrorCode modify_finite_element_add_field_data(const std::string &fe_name, const std::string name_field)=0
set finite element field data
virtual MoFEMErrorCode set_field_order(const EntityHandle meshset, const EntityType type, const std::string &name, const ApproximationOrder order, int verb=DEFAULT_VERBOSITY)=0
Set order approximation of the entities in the field.
virtual MoFEMErrorCode add_ents_to_field_by_type(const Range &ents, const EntityType type, const std::string &name, int verb=DEFAULT_VERBOSITY)=0
Add entities to field meshset.
bool checkMeshset(const int ms_id, const CubitBCType cubit_bc_type) const
Check for CUBIT meshset by ID and type.
MoFEM::PipelineManager::ElementsAndOpsByDim< SPACE_DIM >::DomainEle Ele
MoFEMErrorCode updateBarrierGamma(Handles &handles, double gamma)
MoFEMErrorCode evaluateMinQuality(DM dm, const std::string &domain_fe_name, const Handles &handles, double &min_quality)
MoFEMErrorCode createSnes(DM dm, SmartPetscObj< SNES > &snes)
MoFEMErrorCode solveSnes(DM dm, SNES snes, const std::vector< std::string > &zero_vertex_fields={})
MoFEMErrorCode createOperators(MoFEM::Interface &m_field, const Config &cfg, const Range &fixed_vertices, const Range &edge_entities, Handles &handles)
MoFEMErrorCode addToSnesDM(DM dm, const Config &cfg, const Handles &handles)
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
VectorBoundedArray< double, 3 > VectorDouble3
Definition Types.hpp:92
std::bitset< BITREFLEVEL_SIZE > BitRefLevel
Bit structure attached to each entity identifying to what mesh entity is attached.
Definition Types.hpp:40
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
OpPostProcMapInMoab< SPACE_DIM, SPACE_DIM > OpPPMap
VolumeLengthQualityType qualityType
Managing BitRefLevels.
Managing BitRefLevels.
virtual moab::Interface & get_moab()=0
virtual MoFEMErrorCode add_field(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_EXCL, int verb=DEFAULT_VERBOSITY)=0
Add field.
Core (interface) class.
Definition Core.hpp:82
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:72
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:118
Deprecated interface functions.
Interface for managing meshsets containing materials and boundary conditions.
Specialization for double precision scalar field values calculation.
Specialization for double precision vector field values calculation.
Post post-proc data at points from hash maps.
Template struct for dimension-specific finite element types.
Problem manager is used to build and partition problems.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode buildProblem()
Build problem.
Definition Simple.cpp:721
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
const std::string getBoundaryFEName() const
Get the Boundary FE Name.
Definition Simple.hpp:436
MoFEMErrorCode defineFiniteElements()
Define finite elements.
Definition Simple.cpp:471
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode buildFiniteElements()
Build finite elements.
Definition Simple.cpp:659
MoFEMErrorCode addBoundaryField(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 boundary.
Definition Simple.cpp:355
std::vector< std::string > & getOtherFiniteElements()
Get the Other Finite Elements.
Definition Simple.hpp:508
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode buildFields()
Build fields.
Definition Simple.cpp:584
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode defineProblem(const PetscBool is_partitioned=PETSC_TRUE)
define problem
Definition Simple.cpp:551
const std::string getProblemName() const
Get the Problem Name.
Definition Simple.hpp:450
const std::string getDomainFEName() const
Get the Domain FE Name.
Definition Simple.hpp:429
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.
static MoFEMErrorCode extractMeshEdges(MoFEM::Interface &m_field, Range &output_edges, Range &output_vertices)
Definition Smoother.hpp:10
double tol
PetscBool output_vtk
constexpr bool fix_edge_blocks
double gamma_factor
int vertex_block_set
int edges_block_set
@ BARRIER_AND_QUALITY