286 const auto dim = ref_elem->dim();
289 unsigned int n_elems_per_side = 5;
301 libmesh_error_msg_if(n_elems_per_side % 2 != 1,
302 "n_elems_per_side should be odd.");
311 mesh, n_elems_per_side, n_elems_per_side, 0., 1., 0., 1., type);
329 libmesh_error_msg(
"Unsupported dimension " <<
dim);
333 DistortHyperCube dh(
dim);
337 std::unordered_map<dof_id_type, Point> subdomain_boundary_node_id_to_point;
338 if (multiple_subdomains)
341 for (
auto * elem :
mesh.active_element_ptr_range())
343 unsigned int subdomain_id = 0;
345 if (elem->vertex_average()(d) > 0.5)
347 elem->subdomain_id() += subdomain_id;
353 for (
auto * elem :
mesh.active_element_ptr_range())
354 for (
const auto & s : elem->side_index_range())
356 const auto * neighbor = elem->neighbor_ptr(s);
357 if (neighbor ==
nullptr)
360 if (elem->subdomain_id() != neighbor->subdomain_id())
363 for (
const auto & n : elem->nodes_on_side(s))
364 subdomain_boundary_node_id_to_point[elem->node_id(n)] =
365 Point(*(elem->get_nodes()[n]));
372 libmesh_error_msg_if(
373 elem_orders.size() != 1,
374 "The variational smoother cannot be used for mixed-order meshes!");
375 const auto fe_order = *elem_orders.begin();
379 auto distortion_is = [
380 &n_elems_per_side, &
dim, &boundary_info, &fe_order
384 std::vector<boundary_id_type> boundary_ids;
388 const auto num_dofs =
dim - boundary_ids.size();
408 std::size_t num_zero_or_one = 0;
410 bool distorted =
false;
413 const Real r = node(d);
414 const Real R = r * n_elems_per_side * fe_order;
415 CPPUNIT_ASSERT_GREATER(-distortion_tol * distortion_tol, r);
416 CPPUNIT_ASSERT_GREATER(-distortion_tol * distortion_tol, 1 - r);
418 const bool d_distorted = std::abs(R - std::round(R)) > distortion_tol;
419 distorted |= d_distorted;
424 CPPUNIT_ASSERT_GREATEREQUAL(
dim - num_dofs, num_zero_or_one);
430 return distorted == distortion;
434 auto is_subdomain_boundary_node_the_same = [&subdomain_boundary_node_id_to_point](
436 auto it = subdomain_boundary_node_id_to_point.find(node.id());
437 if (it != subdomain_boundary_node_id_to_point.end())
445 for (
auto node :
mesh.node_ptr_range())
446 CPPUNIT_ASSERT(distortion_is(*node,
true));
453 SquareToParallelogram stp;
465 ParallelogramToSquare pts;
471 for (
auto node :
mesh.node_ptr_range())
473 if (multiple_subdomains)
474 CPPUNIT_ASSERT(is_subdomain_boundary_node_the_same(*node));
476 CPPUNIT_ASSERT(distortion_is(*node,
false, 1e-3));
const std::set< Order > & elem_default_orders() const
A Node is like a Point, but with more information.
static constexpr Real TOLERANCE
void boundary_ids(const Node *node, std::vector< boundary_id_type > &vec_to_fill) const
Fills a user-provided std::vector with the boundary ids associated with Node node.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
virtual void smooth()=0
Function which actually performs the smoothing operations.
std::string enum_to_string(const T e)
bool absolute_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
bool relative_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
A Point defines a location in LIBMESH_DIM dimensional Real space.
const Elem & get(const ElemType type_in)