Commit a60a55e4 authored by Tom Fischer's avatar Tom Fischer
Browse files

Merge branch 'Quad9ConversionLinearToQuadMesh' into 'master'

Quad9 conversion linear to quad mesh

See merge request ogs/ogs!3090
parents 2f1654b1 74a045f0
......@@ -36,6 +36,9 @@ int main(int argc, char *argv[])
cmd.add( input_arg );
TCLAP::ValueArg<std::string> output_arg("o", "output-mesh-file","output mesh file",true,"","string");
cmd.add( output_arg );
TCLAP::SwitchArg add_centre_node_arg("c", "add-centre-node",
"add centre node", false);
cmd.add(add_centre_node_arg);
cmd.parse( argc, argv );
std::unique_ptr<MeshLib::Mesh> mesh(
......@@ -46,7 +49,8 @@ int main(int argc, char *argv[])
}
INFO("Create a quadratic order mesh");
auto new_mesh(MeshLib::createQuadraticOrderMesh(*mesh));
auto new_mesh(MeshLib::createQuadraticOrderMesh(
*mesh, add_centre_node_arg.getValue()));
INFO("Save the new mesh into a file");
MeshLib::IO::writeMeshToFile(*new_mesh, output_arg.getValue());
......
......@@ -52,9 +52,50 @@ std::unique_ptr<QuadraticElement> convertLinearToQuadratic(
return std::make_unique<QuadraticElement>(nodes, e.getID());
}
/// Special case for Quad-9 adding a centre node too.
template <>
std::unique_ptr<MeshLib::Quad9> convertLinearToQuadratic<MeshLib::Quad9>(
MeshLib::Element const& e)
{
int const n_all_nodes = MeshLib::Quad9::n_all_nodes;
int const n_base_nodes = MeshLib::Quad9::n_base_nodes;
assert(n_base_nodes == e.getNumberOfBaseNodes());
// Copy base nodes of element to the quadratic element new nodes'.
std::array<MeshLib::Node*, n_all_nodes> nodes{};
for (int i = 0; i < n_base_nodes; i++)
{
nodes[i] = const_cast<MeshLib::Node*>(e.getNode(i));
}
// For each edge create a middle node.
int const number_of_edges = e.getNumberOfEdges();
for (int i = 0; i < number_of_edges; i++)
{
auto const& a = *e.getEdgeNode(i, 0);
auto const& b = *e.getEdgeNode(i, 1);
nodes[n_base_nodes + i] = new MeshLib::Node(
(a[0] + b[0]) / 2, (a[1] + b[1]) / 2, (a[2] + b[2]) / 2);
}
// Compute the centre point coordinates.
auto* centre_node = new MeshLib::Node(0, 0, 0);
for (int i = 0; i < n_base_nodes; i++)
{
for (int d = 0; d < 3; d++)
{
(*centre_node)[d] += (*nodes[i])[d] / n_base_nodes;
}
}
nodes[n_all_nodes - 1] = centre_node;
return std::make_unique<MeshLib::Quad9>(nodes, e.getID());
}
/// Return a new quadratic element corresponding to the linear element's type.
std::unique_ptr<MeshLib::Element> createQuadraticElement(
MeshLib::Element const& e)
MeshLib::Element const& e, bool const add_centre_node)
{
if (e.getCellType() == MeshLib::CellType::LINE2)
{
......@@ -70,6 +111,10 @@ std::unique_ptr<MeshLib::Element> createQuadraticElement(
}
if (e.getCellType() == MeshLib::CellType::QUAD4)
{
if (add_centre_node)
{
return convertLinearToQuadratic<MeshLib::Quad9>(e);
}
return convertLinearToQuadratic<MeshLib::Quad8>(e);
}
if (e.getCellType() == MeshLib::CellType::HEX8)
......@@ -91,7 +136,8 @@ struct nodeByCoordinatesComparator
namespace MeshLib
{
std::unique_ptr<Mesh> createQuadraticOrderMesh(Mesh const& linear_mesh)
std::unique_ptr<Mesh> createQuadraticOrderMesh(Mesh const& linear_mesh,
bool const add_centre_node)
{
// Clone the linear mesh nodes.
auto quadratic_mesh_nodes = MeshLib::copyNodeVector(linear_mesh.getNodes());
......@@ -104,7 +150,7 @@ std::unique_ptr<Mesh> createQuadraticOrderMesh(Mesh const& linear_mesh)
auto const& linear_mesh_elements = linear_mesh.getElements();
for (MeshLib::Element const* e : linear_mesh_elements)
{
auto quadratic_element = createQuadraticElement(*e);
auto quadratic_element = createQuadraticElement(*e, add_centre_node);
// Replace the base nodes with cloned linear nodes.
int const number_base_nodes = quadratic_element->getNumberOfBaseNodes();
......
......@@ -16,7 +16,10 @@ class Mesh;
namespace MeshLib
{
/// create a quadratic order mesh from the linear order mesh
std::unique_ptr<Mesh> createQuadraticOrderMesh(Mesh const& linear_mesh);
/// Create a quadratic order mesh from the linear order mesh. For some element
/// types like Quad-4, a centre node might be added if the \c add_centre_node
/// flag is set, yielding a Quad-9.
std::unique_ptr<Mesh> createQuadraticOrderMesh(Mesh const& linear_mesh,
bool const add_centre_node);
} // namespace MeshLib
......@@ -30,7 +30,8 @@ public:
{
linear_mesh.reset(
MeshGenerator::generateRegularHexMesh(1.0, mesh_size));
quadratic_mesh = createQuadraticOrderMesh(*linear_mesh);
quadratic_mesh =
createQuadraticOrderMesh(*linear_mesh, false /* add centre node*/);
}
static constexpr int mesh_size = 5;
......
......@@ -270,7 +270,8 @@ TEST_F(MeshLibBoundaryElementSearchInSimpleHexMesh, SurfaceSearch)
TEST_F(MeshLibBoundaryElementSearchInSimpleHexMesh, QuadElementsSurfaceSearch)
{
ASSERT_TRUE(_hex_mesh != nullptr);
auto mesh = MeshLib::createQuadraticOrderMesh(*_hex_mesh);
auto mesh = MeshLib::createQuadraticOrderMesh(*_hex_mesh,
false /* add centre node*/);
const std::size_t& s = _number_of_subdivisions_per_direction;
const std::size_t n_nodes_2d = (s + 1) * (3 * s + 1);
......
......@@ -27,7 +27,8 @@ TEST(MeshLib, QuadraticOrderMesh_Line)
std::unique_ptr<Mesh> linear_mesh(MeshGenerator::generateLineMesh(
1, std::size_t(2)));
std::unique_ptr<Mesh> mesh(createQuadraticOrderMesh(*linear_mesh));
std::unique_ptr<Mesh> mesh(
createQuadraticOrderMesh(*linear_mesh, false /* add centre node*/));
ASSERT_EQ(5u, mesh->getNumberOfNodes());
ASSERT_EQ(3u, mesh->getNumberOfBaseNodes());
ASSERT_EQ(2u, mesh->getNumberOfElements());
......@@ -64,13 +65,14 @@ TEST(MeshLib, QuadraticOrderMesh_Line)
}
}
TEST(MeshLib, QuadraticOrderMesh_Quad)
TEST(MeshLib, QuadraticOrderMesh_Quad8)
{
using namespace MeshLib;
std::unique_ptr<Mesh> linear_mesh(MeshGenerator::generateRegularQuadMesh(
1, 1, std::size_t(2), std::size_t(2)));
std::unique_ptr<Mesh> mesh(createQuadraticOrderMesh(*linear_mesh));
std::unique_ptr<Mesh> mesh(
createQuadraticOrderMesh(*linear_mesh, false /* add centre node*/));
ASSERT_EQ(21u, mesh->getNumberOfNodes());
ASSERT_EQ(9u, mesh->getNumberOfBaseNodes());
ASSERT_EQ(4u, mesh->getNumberOfElements());
......@@ -94,24 +96,23 @@ TEST(MeshLib, QuadraticOrderMesh_Quad)
auto const& mesh_nodes = mesh->getNodes();
// Count nodes shared by four elements and also connected to all 21 other
// nodes.
// Count nodes shared by four elements and also connected to all 21 nodes.
ASSERT_EQ(1, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 4) &&
(n->getConnectedNodes().size() == 21);
}));
// Count nodes belonging to one element and also connected to all 8 other
// nodes of that corner element.
// Count nodes belonging to one element and also connected to all 8 nodes of
// that corner element.
ASSERT_EQ(12, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 1) &&
(n->getConnectedNodes().size() == 8);
}));
// Count nodes shared by two elements and also connected to the 13 other
// nodes of the two elements.
// Count nodes shared by two elements and also connected to the 13 nodes of
// the two elements.
ASSERT_EQ(8, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 2) &&
......@@ -119,6 +120,62 @@ TEST(MeshLib, QuadraticOrderMesh_Quad)
}));
}
TEST(MeshLib, QuadraticOrderMesh_Quad9)
{
using namespace MeshLib;
std::unique_ptr<Mesh> linear_mesh(MeshGenerator::generateRegularQuadMesh(
1, 1, std::size_t(2), std::size_t(2)));
std::unique_ptr<Mesh> mesh(
createQuadraticOrderMesh(*linear_mesh, true /* add centre node*/));
ASSERT_EQ(21u + 4u, mesh->getNumberOfNodes());
ASSERT_EQ(9u, mesh->getNumberOfBaseNodes());
ASSERT_EQ(4u, mesh->getNumberOfElements());
for (MeshLib::Element const* e : mesh->getElements())
{
ASSERT_EQ(MeshLib::CellType::QUAD9, e->getCellType());
ASSERT_EQ(4u, e->getNumberOfBaseNodes());
ASSERT_EQ(9u, e->getNumberOfNodes());
for (unsigned i = 0; i < e->getNumberOfBaseNodes(); i++)
{
ASSERT_TRUE(mesh->isBaseNode(e->getNodeIndex(i)));
}
for (unsigned i = e->getNumberOfBaseNodes(); i < e->getNumberOfNodes();
i++)
{
ASSERT_FALSE(mesh->isBaseNode(e->getNodeIndex(i)));
}
}
auto const& mesh_nodes = mesh->getNodes();
// Count nodes shared by four elements and also connected to all 25 nodes.
ASSERT_EQ(1, std::count_if(
mesh_nodes.begin(), mesh_nodes.end(), [](Node* const n) {
return (n->getElements().size() == 4) &&
(n->getConnectedNodes().size() == 21 + 4);
}));
// Count nodes belonging to one element and also connected to all 9 nodes of
// that corner element---three corners and the centre node.
ASSERT_EQ(
12 + 4,
std::count_if(mesh_nodes.begin(), mesh_nodes.end(), [](Node* const n) {
return (n->getElements().size() == 1) &&
(n->getConnectedNodes().size() == 9);
}));
// Count nodes shared by two elements and also connected to the 15 nodes of
// the two elements.
ASSERT_EQ(8, std::count_if(
mesh_nodes.begin(), mesh_nodes.end(), [](Node* const n) {
return (n->getElements().size() == 2) &&
(n->getConnectedNodes().size() == 13 + 2);
}));
}
TEST(MeshLib, QuadraticOrderMesh_LineQuad)
{
using namespace MeshLib;
......@@ -148,7 +205,8 @@ TEST(MeshLib, QuadraticOrderMesh_LineQuad)
}
ASSERT_EQ(6u, linear_mesh->getNumberOfElements());
std::unique_ptr<Mesh> mesh(createQuadraticOrderMesh(*linear_mesh));
std::unique_ptr<Mesh> mesh(
createQuadraticOrderMesh(*linear_mesh, false /* add centre node*/));
ASSERT_EQ(21u, mesh->getNumberOfNodes());
ASSERT_EQ(9u, mesh->getNumberOfBaseNodes());
ASSERT_EQ(6u, mesh->getNumberOfElements());
......@@ -181,16 +239,15 @@ TEST(MeshLib, QuadraticOrderMesh_LineQuad)
auto const& mesh_nodes = mesh->getNodes();
// Count nodes shared by six elements and also connected to all 21 other
// nodes.
// Count nodes shared by six elements and also connected to all 21 nodes.
ASSERT_EQ(1, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 6) &&
(n->getConnectedNodes().size() == 21);
}));
// Count nodes belonging to one element and also connected to all 8 other
// nodes of that corner element.
// Count nodes belonging to one element and also connected to all 8 nodes of
// that corner element.
ASSERT_EQ(12, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 1) &&
......@@ -198,7 +255,7 @@ TEST(MeshLib, QuadraticOrderMesh_LineQuad)
}));
// Count nodes shared by three elements (quads and the line) and also
// connected to the 13 other nodes of the two elements.
// connected to the 13 nodes of the two elements.
ASSERT_EQ(4, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 3) &&
......@@ -206,7 +263,7 @@ TEST(MeshLib, QuadraticOrderMesh_LineQuad)
}));
// Count nodes shared by two elements (quads) and also connected to the 13
// other nodes of the two elements.
// nodes of the two elements.
ASSERT_EQ(4, std::count_if(mesh_nodes.begin(), mesh_nodes.end(),
[](Node* const n) {
return (n->getElements().size() == 2) &&
......
......@@ -52,8 +52,8 @@ TEST(NumLib_SparsityPattern, DISABLED_SingleComponentQuadraticMesh)
{
std::unique_ptr<MeshLib::Mesh> linear_mesh(
MeshLib::MeshGenerator::generateLineMesh(3u, 1.));
std::unique_ptr<MeshLib::Mesh> mesh(
MeshLib::createQuadraticOrderMesh(*linear_mesh));
std::unique_ptr<MeshLib::Mesh> mesh(MeshLib::createQuadraticOrderMesh(
*linear_mesh, false /* add centre node */));
MeshLib::MeshSubset nodesSubset{*mesh, mesh->getNodes()};
std::vector<MeshLib::MeshSubset> components{nodesSubset};
......@@ -110,8 +110,8 @@ TEST(NumLib_SparsityPattern, DISABLED_MultipleComponentsLinearQuadraticMesh)
{
std::unique_ptr<MeshLib::Mesh> linear_mesh(
MeshLib::MeshGenerator::generateLineMesh(3u, 1.));
std::unique_ptr<MeshLib::Mesh> mesh(
MeshLib::createQuadraticOrderMesh(*linear_mesh));
std::unique_ptr<MeshLib::Mesh> mesh(MeshLib::createQuadraticOrderMesh(
*linear_mesh, false /* add centre node */));
auto base_nodes = MeshLib::getBaseNodes(mesh->getElements());
auto baseNodesSubset =
std::make_unique<MeshLib::MeshSubset const>(*mesh, base_nodes);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment