14 #include "libmesh/enum_elem_type.h" 15 #include "libmesh/remote_elem.h" 25 std::vector<const libMesh::Node *> & tentative_coarse_nodes,
26 std::set<const libMesh::Elem *> & fine_elements)
28 const auto elem_type = fine_elem.
type();
34 fine_elements.insert(&fine_elem);
39 const auto node_index = neigh->get_node_index(&interior_node);
44 fine_elements.insert(neigh);
45 for (
const auto neigh_two : neigh->neighbor_ptr_range())
49 const auto node_index_2 = neigh_two->get_node_index(&interior_node);
53 fine_elements.insert(neigh_two);
57 for (
const auto neigh_three : neigh_two->neighbor_ptr_range())
61 const auto node_index_3 = neigh_three->get_node_index(&interior_node);
63 fine_elements.insert(neigh_three);
72 for (
auto elem : fine_elements)
73 if (elem && fine_elem.
type() != elem_type)
79 if (fine_elements.size() != 4)
84 tentative_coarse_nodes.resize(4);
87 unsigned int neighbor_i = 0;
88 for (
auto neighbor : fine_elements)
90 const auto interior_node_number = neighbor->get_node_index(&interior_node);
91 unsigned int opposite_node_index = (interior_node_number + 2) % 4;
93 tentative_coarse_nodes[neighbor_i++] = neighbor->node_ptr(opposite_node_index);
98 (fine_elem.
vertex_average() - interior_node).cross(interior_node - reference_node);
99 reorderNodes(tentative_coarse_nodes, interior_node, reference_node, axis);
107 if (fine_elements.size() != 8)
110 tentative_coarse_nodes.resize(4);
115 const Elem * one_fine_elem =
nullptr;
116 unsigned int max_id = 0;
117 for (
const auto elem_ptr : fine_elements)
118 if (elem_ptr->id() > max_id)
120 max_id = elem_ptr->
id();
121 one_fine_elem = elem_ptr;
123 const auto interior_node_index = one_fine_elem->
get_node_index(&interior_node);
126 unsigned int an_interior_node_side = 0;
130 an_interior_node_side = s;
135 const auto center_face_node_index =
136 one_fine_elem->
opposite_node(interior_node_index, an_interior_node_side);
137 const auto center_face_node = one_fine_elem->
node_ptr(center_face_node_index);
141 unsigned int neighbor_i = 0;
142 std::vector<const libMesh::Elem *> other_fine_elems;
143 for (
auto neighbor : fine_elements)
147 other_fine_elems.push_back(neighbor);
151 const auto interior_node_number = neighbor->get_node_index(&interior_node);
152 unsigned int opposite_node_index =
155 tentative_coarse_nodes[neighbor_i++] = neighbor->node_ptr(opposite_node_index);
160 if (neighbor_i != 4 || other_fine_elems.size() != 4)
164 auto cmp_node = [](
const Node * a,
const Node * b) {
return a->
id() < b->id(); };
165 std::sort(tentative_coarse_nodes.begin(), tentative_coarse_nodes.end(), cmp_node);
171 reorderNodes(tentative_coarse_nodes, *center_face_node, clock_start, axis);
174 for (
const auto coarse_node_index :
make_range(4))
177 const Elem * fine_elem =
nullptr;
178 for (
auto elem : fine_elements)
179 if (elem->get_node_index(tentative_coarse_nodes[coarse_node_index]) !=
185 mooseAssert(fine_elem,
"Search for fine element should have worked");
188 const Elem * fine_neighbor =
nullptr;
189 for (
auto neighbor : other_fine_elems)
196 fine_neighbor = neighbor;
205 const auto interior_node_index_neighbor = fine_neighbor->
get_node_index(&interior_node);
206 tentative_coarse_nodes.push_back(fine_neighbor->
node_ptr(
211 if (tentative_coarse_nodes.size() == 8)
226 mooseAssert(axis.
norm() != 0,
"Invalid rotation axis when ordering nodes");
227 mooseAssert(origin != clock_start,
"Invalid starting direction when ordering nodes");
232 auto start_clock = origin - clock_start;
233 start_clock /= start_clock.
norm();
236 std::vector<std::pair<unsigned int, libMesh::Real>> nodes_angles(nodes.size());
239 mooseAssert(nodes[angle_i],
"Nodes cant be nullptr");
240 auto vec = *nodes[angle_i] - origin;
242 const auto angle = atan2(vec.cross(start_clock) * axis, vec * start_clock);
243 nodes_angles[angle_i] = std::make_pair(angle_i, angle);
247 std::sort(nodes_angles.begin(),
249 [](
auto & left,
auto & right) {
return left.second < right.second; });
252 std::vector<const libMesh::Node *> new_nodes(nodes.size());
254 new_nodes[old_index] = nodes[nodes_angles[old_index].first];
256 nodes[index] = new_nodes[index];
265 return (node_index + 2) % 4;
268 mooseAssert(node_index < 8,
"Node index too high: " + std::to_string(node_index));
269 return std::vector<unsigned int>({6, 7, 4, 5, 2, 3, 0, 1})[node_index];
272 mooseError(
"Unsupported element type for retrieving the opposite node");
auto norm() const -> decltype(std::norm(Real()))
const unsigned int invalid_uint
unsigned int get_node_index(const Node *node_ptr) const
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application...
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const=0
The following methods are specializations for using the libMesh::Parallel::packed_range_* routines fo...
virtual unsigned int opposite_node(const unsigned int n, const unsigned int s) const
std::string stringify(const T &t)
conversion to string
virtual unsigned int n_sides() const=0
const Node * node_ptr(const unsigned int i) const
IntRange< T > make_range(T beg, T end)
SimpleRange< NeighborPtrIter > neighbor_ptr_range()
void reorderNodes(std::vector< const libMesh::Node *> &nodes, const libMesh::Point &origin, const libMesh::Point &clock_start, libMesh::Point &axis)
Utility routine to re-order a vector of nodes so that they can form a valid quad element.
virtual ElemType type() const=0
auto index_range(const T &sizable)
unsigned int getOppositeNodeIndex(libMesh::ElemType elem_type, unsigned int node_index)
Utility routine to get the index of the node opposite, in the element, to the node of interest...
Point vertex_average() const
bool getFineElementsFromInteriorNode(const libMesh::Node &interior_node, const libMesh::Node &reference_node, const libMesh::Elem &fine_elem, std::vector< const libMesh::Node *> &tentative_coarse_nodes, std::set< const libMesh::Elem *> &fine_elements)
const RemoteElem * remote_elem