117 const std::vector<MeshLib::Node*>& nodes,
118 unsigned const i,
unsigned const j)
124 auto order_nodes_quadratic_quad =
126 const std::vector<MeshLib::Node*>& nodes)
128 swap_nodes_i_j(element, nodes, 1, 3);
129 swap_nodes_i_j(element, nodes, 5, 6);
130 swap_nodes_i_j(element, nodes, 4, 7);
141 const std::vector<MeshLib::Node*>& nodes)
142 { swap_nodes_i_j(element, nodes, 0, 1); });
148 const std::vector<MeshLib::Node*>& nodes)
149 { swap_nodes_i_j(element, nodes, 0, 1); });
153 {1.0 / 3.0, 1.0 / 3.0},
155 const std::vector<MeshLib::Node*>& nodes)
156 { swap_nodes_i_j(element, nodes, 1, 2); });
160 {1.0 / 3.0, 1.0 / 3.0},
162 const std::vector<MeshLib::Node*>& nodes)
164 swap_nodes_i_j(element, nodes, 1, 2);
165 swap_nodes_i_j(element, nodes, 3, 5);
172 const std::vector<MeshLib::Node*>& nodes)
173 { swap_nodes_i_j(element, nodes, 0, 2); });
178 [&order_nodes_quadratic_quad](
180 const std::vector<MeshLib::Node*>& nodes)
181 { order_nodes_quadratic_quad(element, nodes); });
185 [&order_nodes_quadratic_quad](
187 const std::vector<MeshLib::Node*>& nodes)
188 { order_nodes_quadratic_quad(element, nodes); });
193 const std::vector<MeshLib::Node*>& nodes)
194 { swap_nodes_i_j(element, nodes, 1, 2); });
200 const std::vector<MeshLib::Node*>& nodes)
202 swap_nodes_i_j(element, nodes, 1, 2);
203 swap_nodes_i_j(element, nodes, 4, 6);
204 swap_nodes_i_j(element, nodes, 8, 9);
208 {1.0 / 3.0, 1.0 / 3.0, 0.5},
210 const std::vector<MeshLib::Node*>& nodes)
212 swap_nodes_i_j(element, nodes, 1, 2);
213 swap_nodes_i_j(element, nodes, 4, 5);
218 {1.0 / 3.0, 1.0 / 3., 0.5},
220 const std::vector<MeshLib::Node*>& nodes)
222 swap_nodes_i_j(element, nodes, 0, 3);
223 swap_nodes_i_j(element, nodes, 1, 4);
224 swap_nodes_i_j(element, nodes, 2, 5);
225 swap_nodes_i_j(element, nodes, 6, 9);
226 swap_nodes_i_j(element, nodes, 7, 10);
227 swap_nodes_i_j(element, nodes, 8, 11);
234 const std::vector<MeshLib::Node*>& nodes)
235 { swap_nodes_i_j(element, nodes, 0, 2); });
241 const std::vector<MeshLib::Node*>& nodes)
243 swap_nodes_i_j(element, nodes, 0, 2);
244 swap_nodes_i_j(element, nodes, 9, 11);
245 swap_nodes_i_j(element, nodes, 5, 6);
246 swap_nodes_i_j(element, nodes, 7, 8);
252 const std::vector<MeshLib::Node*>& nodes)
254 swap_nodes_i_j(element, nodes, 0, 2);
255 swap_nodes_i_j(element, nodes, 4, 6);
262 const std::vector<MeshLib::Node*>& nodes)
264 swap_nodes_i_j(element, nodes, 0, 2);
265 swap_nodes_i_j(element, nodes, 4, 6);
266 swap_nodes_i_j(element, nodes, 16, 18);
267 swap_nodes_i_j(element, nodes, 8, 9);
268 swap_nodes_i_j(element, nodes, 10, 11);
269 swap_nodes_i_j(element, nodes, 12, 13);
270 swap_nodes_i_j(element, nodes, 14, 15);
286 int const mesh_space_dimension,
bool const forced,
287 bool const volume_check)
289 std::size_t n_corrected_elements = 0;
291 for (
auto* element : elements)
293 auto const cell_type = element->getCellType();
297 OGS_FATAL(
"Element type `{:s}' does not exist.",
305 OGS_FATAL(
"Element type `{:s}' is not supported in OGS.",
314 const auto& element_config =
317 if (element_config.is_node_ordering_correct(
318 *element, mesh_space_dimension,
false ))
324 const unsigned nElemNodes = element->getNumberOfNodes();
325 std::vector<MeshLib::Node*> nodes(element->getNodes(),
326 element->getNodes() + nElemNodes);
330 double const element_volume_origin = element->computeVolume();
332 element_config.reorder_element_nodes(*element, nodes);
335 double const element_volume = element->computeVolume();
338 if (std::fabs(element_volume - element_volume_origin) /
339 element_volume_origin >
340 100 * std::numeric_limits<double>::epsilon())
343 "Reordering the nodes of element {:d} failed as its volume "
344 "changed from {:.20g} to {:.20g}, the relative difference "
345 "is {:.20g} and the threshold is {:.20g}.",
346 element->getID(), element_volume_origin, element_volume,
347 std::fabs(element_volume_origin - element_volume) /
348 element_volume_origin,
349 100 * std::numeric_limits<double>::epsilon());
354 element_config.reorder_element_nodes(*element, nodes);
363 element_config.is_node_ordering_correct(
364 *element, mesh_space_dimension,
true );
367 ++n_corrected_elements;
370 INFO(
"Corrected {:d} elements.", n_corrected_elements);
435int main(
int argc,
char* argv[])
437 enum class ExpectedCellType
461 constexpr bool are_expected_cell_types =
462 static_cast<int>(ExpectedCellType::enum_length) ==
464 static_cast<int>(ExpectedCellType::INVALID) ==
466 static_cast<int>(ExpectedCellType::POINT1) ==
468 static_cast<int>(ExpectedCellType::LINE2) ==
470 static_cast<int>(ExpectedCellType::LINE3) ==
472 static_cast<int>(ExpectedCellType::TRI3) ==
474 static_cast<int>(ExpectedCellType::TRI6) ==
476 static_cast<int>(ExpectedCellType::QUAD4) ==
478 static_cast<int>(ExpectedCellType::QUAD8) ==
480 static_cast<int>(ExpectedCellType::QUAD9) ==
482 static_cast<int>(ExpectedCellType::TET4) ==
484 static_cast<int>(ExpectedCellType::TET10) ==
486 static_cast<int>(ExpectedCellType::HEX8) ==
488 static_cast<int>(ExpectedCellType::HEX20) ==
490 static_cast<int>(ExpectedCellType::HEX27) ==
492 static_cast<int>(ExpectedCellType::PRISM6) ==
494 static_cast<int>(ExpectedCellType::PRISM15) ==
496 static_cast<int>(ExpectedCellType::PRISM18) ==
498 static_cast<int>(ExpectedCellType::PYRAMID5) ==
500 static_cast<int>(ExpectedCellType::PYRAMID13) ==
505 if (!are_expected_cell_types)
508 "The enum class MeshLib::CellType has changed. Please adapt the "
509 "array 'element_configs_array' in NodeReordering.cpp accordingly.");
513 "Reorders mesh nodes in elements to make old or incorrectly ordered "
514 "meshes compatible with OGS6.\n"
515 "Three options are available:\n"
516 "Method 0: Reversing order of nodes and checking again for all "
518 "Method 1: Reversing order of nodes unless it's perceived correct by "
519 "OGS6 standards. This is the default selection.\n"
520 "Method 2: Fixing node ordering issues between VTK and OGS6 (only "
521 "applies to prism-elements)\n"
522 "Method 3: Re-ordering of mesh node vector such that all base nodes "
523 "are sorted before all nonlinear nodes.\n\n"
524 "OpenGeoSys-6 software, version " +
527 "Copyright (c) 2012-2026, OpenGeoSys Community "
528 "(http://www.opengeosys.org)",
531 TCLAP::SwitchArg no_volume_check_arg(
532 "",
"no_volume_check",
533 "By default the volumes of original and reordered elements are "
534 "compared if they are numerically equal, i.e., relative volume "
535 "difference is smaller than a threshold. This switch disables the "
536 "volume comparison.");
537 cmd.add(no_volume_check_arg);
539 std::vector<int> method_ids{0, 1, 2, 3};
540 TCLAP::ValuesConstraint<int> allowed_values(method_ids);
541 TCLAP::ValueArg<int> method_arg(
"m",
"method",
542 "reordering method selection",
false, 1,
545 TCLAP::ValueArg<std::string> output_mesh_arg(
546 "o",
"output_mesh",
"Output (.vtu). The name of the output mesh file",
547 true,
"",
"OUTPUT_FILE");
548 cmd.add(output_mesh_arg);
549 TCLAP::ValueArg<std::string> input_mesh_arg(
551 "Input (.vtu | .vtk | .msh). The name of the input mesh file",
true,
"",
553 cmd.add(input_mesh_arg);
555 cmd.add(log_level_arg);
556 cmd.parse(argc, argv);
561 std::unique_ptr<MeshLib::Mesh> mesh(
569 INFO(
"Reordering nodes... ");
570 if (!method_arg.isSet() || method_arg.getValue() < 2)
572 bool const forced = (method_arg.getValue() == 0);
576 INFO(
"Method 0: Reversing order of nodes will be checked again.");
579 "Method: Reversing order of nodes unless it is considered correct "
580 "by the OGS6 standard, i.e. such that det(J) > 0, where J is the "
581 "Jacobian of the global-to-local coordinate transformation.");
582 int const mesh_space_dimension =
585 const_cast<std::vector<MeshLib::Element*>&
>(mesh->getElements()),
586 mesh_space_dimension, forced, !no_volume_check_arg.isSet());
588 else if (method_arg.getValue() == 2)
591 const_cast<std::vector<MeshLib::Element*>&
>(mesh->getElements()));
593 else if (method_arg.getValue() == 3)
600 INFO(
"VTU file written.");