Skip to content

Commit

Permalink
GRIDEDIT-700 Added setting of nodes inside a box to be invalid
Browse files Browse the repository at this point in the history
  • Loading branch information
BillSenior committed Oct 6, 2023
1 parent 08d27cb commit 9bd09dd
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,10 @@ namespace meshkernel
/// @param[in] point The input point coordinate. The closest grid node will be deleted.
void DeleteNode(Point const& point);

/// @brief Set all the nodes interior to the block to be invalid.
/// @note If any index is the null value or os out of range a ConstraintError will be thrown
void DeleteInterior(const CurvilinearGridNodeIndices& firstNode, const CurvilinearGridNodeIndices& secondNode);

/// @brief Moves a node from one position to another
/// @param[in] fromPoint The input position, the closest node will be used
/// @param[in] toPoint The coordinates of the new position
Expand Down
9 changes: 9 additions & 0 deletions libs/MeshKernel/include/MeshKernel/Point.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ namespace meshkernel

return !isInvalid;
}

/// @brief Set the point to be invalid.
void SetInvalid();
};

/// @brief Unary minus
Expand Down Expand Up @@ -413,3 +416,9 @@ inline meshkernel::Point meshkernel::PointAlongLine(const Point& startPoint, con
{
return (1.0 - lambda) * startPoint + lambda * endPoint;
}

void inline meshkernel::Point::SetInvalid()
{
x = constants::missing::doubleValue;
y = constants::missing::doubleValue;
}
34 changes: 34 additions & 0 deletions libs/MeshKernel/src/CurvilinearGrid/CurvilinearGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

#include <MeshKernel/CurvilinearGrid/CurvilinearGrid.hpp>
#include <MeshKernel/CurvilinearGrid/CurvilinearGridLine.hpp>
#include <MeshKernel/Exceptions.hpp>
#include <MeshKernel/Operations.hpp>
#include <MeshKernel/Polygons.hpp>

Expand Down Expand Up @@ -871,6 +872,39 @@ void CurvilinearGrid::DeleteNode(Point const& point)
}
}

void CurvilinearGrid::DeleteInterior(const CurvilinearGridNodeIndices& firstNode, const CurvilinearGridNodeIndices& secondNode)
{

if (!firstNode.IsValid() || !secondNode.IsValid())
{
throw ConstraintError("Invalid index: first node {{{}, {}}} {{{}, {}}}", firstNode.m_m, firstNode.m_n, secondNode.m_m, secondNode.m_n);
}

if (firstNode.m_m >= m_numM || firstNode.m_n >= m_numN)
{
throw ConstraintError("Invalid index: first index {{{}, {}}} not in mesh limits {{{}, {}}}", firstNode.m_m, firstNode.m_n, m_numM, m_numN);
}

if (secondNode.m_m >= m_numM || secondNode.m_n >= m_numN)
{
throw ConstraintError("Invalid index: second index {{{}, {}}} not in mesh limits {{{}, {}}}", secondNode.m_m, secondNode.m_n, m_numM, m_numN);
}

UInt lowerLimitI = std::min(firstNode.m_n, secondNode.m_n);
UInt upperLimitI = std::max(firstNode.m_n, secondNode.m_n);

UInt lowerLimitJ = std::min(firstNode.m_m, secondNode.m_m);
UInt upperLimitJ = std::max(firstNode.m_m, secondNode.m_m);

for (UInt n = lowerLimitI + 1; n < upperLimitI; ++n)
{
for (UInt m = lowerLimitJ + 1; m < upperLimitJ; ++m)
{
m_gridNodes(n, m).SetInvalid();
}
}
}

void CurvilinearGrid::MoveNode(Point const& fromPoint, Point const& toPoint)
{
// Get the node indices of fromPoint
Expand Down
113 changes: 113 additions & 0 deletions libs/MeshKernel/tests/src/CurvilinearUniformTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <MeshKernel/CurvilinearGrid/CurvilinearGridCreateUniform.hpp>
#include <MeshKernel/Entities.hpp>
#include <MeshKernel/Exceptions.hpp>
#include <MeshKernel/Mesh2D.hpp>
#include <MeshKernel/Polygons.hpp>
#include <TestUtils/MakeCurvilinearGrids.hpp>
Expand Down Expand Up @@ -235,3 +236,115 @@ TEST(CurvilinearGridUniform, DeleteNode_OnUniformGrid_ShouldDeleteNode)
auto const numValidNodes = CurvilinearGridCountValidNodes(curvilinearGrid);
ASSERT_EQ(numValidNodes, 44);
}

void TestDeleteInteriorNodes(std::shared_ptr<meshkernel::CurvilinearGrid> curvilinearGrid,
const meshkernel::CurvilinearGridNodeIndices first,
const meshkernel::CurvilinearGridNodeIndices second)
{

// Check first, that all nodes are valid
for (meshkernel::UInt i = 0; i < curvilinearGrid->m_numN; ++i)
{
for (meshkernel::UInt j = 0; j < curvilinearGrid->m_numM; ++j)
{
EXPECT_TRUE(curvilinearGrid->GetNode(i, j).IsValid());
}
}

meshkernel::UInt lowerLimitI = std::min(first.m_n, second.m_n) + 1;
meshkernel::UInt upperLimitI = std::max(first.m_n, second.m_n) - 1;

meshkernel::UInt lowerLimitJ = std::min(first.m_m, second.m_m) + 1;
meshkernel::UInt upperLimitJ = std::max(first.m_m, second.m_m) - 1;

meshkernel::UInt expectedInvalidated = (upperLimitI - lowerLimitI + 1) * (upperLimitJ - lowerLimitJ + 1);
meshkernel::UInt initialSize = CurvilinearGridCountValidNodes(curvilinearGrid);

// Delete the nodes interior to a block
curvilinearGrid->DeleteInterior(first, second);

auto inRange = [](const meshkernel::UInt v, const meshkernel::UInt l, const meshkernel::UInt u)
{ return l <= v && v <= u; };

EXPECT_EQ(initialSize - expectedInvalidated, CurvilinearGridCountValidNodes(curvilinearGrid));

// Check that these nodes have been set to invalid.
for (meshkernel::UInt i = 0; i < curvilinearGrid->m_numN; ++i)
{
for (meshkernel::UInt j = 0; j < curvilinearGrid->m_numM; ++j)
{
if (inRange(i, lowerLimitI, upperLimitI) && inRange(j, lowerLimitJ, upperLimitJ))
{
EXPECT_FALSE(curvilinearGrid->GetNode(i, j).IsValid()) << "node should be false: " << i << " " << j;
}
else
{
EXPECT_TRUE(curvilinearGrid->GetNode(i, j).IsValid()) << "node should be true: " << i << " " << j;
}
}
}
}

TEST(CurvilinearGridUniform, DeleteInteriorNodesTest)
{
// Basic, testing of setting nodes inside a box to invalid
meshkernel::UInt nx = 10;
meshkernel::UInt ny = 10;
std::shared_ptr<meshkernel::CurvilinearGrid> curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {1, 1}, {4, 4});

// Reset the mesh
curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {2, 1}, {5, 4});

// Reset the mesh
curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {4, 3}, {7, 8});
}

TEST(CurvilinearGridUniform, DeleteInteriorNodesReverseTest)
{
// testing of setting nodes inside a box to invalid, with lower and upper reversed

meshkernel::UInt nx = 10;
meshkernel::UInt ny = 10;

// Prepare
std::shared_ptr<meshkernel::CurvilinearGrid> curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {5, 6}, {1, 2});

// Reset the mesh
curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {5, 6}, {0, 4});
}

TEST(CurvilinearGridUniform, DeleteInteriorNodesMixedTest)
{
// testing of setting nodes inside a box to invalid, with lower and upper reversed for any of i and j index

meshkernel::UInt nx = 100;
meshkernel::UInt ny = 100;

std::shared_ptr<meshkernel::CurvilinearGrid> curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {5, 1}, {1, 6});

// Reset grid
curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);
TestDeleteInteriorNodes(curvilinearGrid, {1, 6}, {5, 2});
}

TEST(CurvilinearGridUniform, DeleteInteriorNodesFailureTest)
{
// testing of setting nodes inside a box to invalid with invalid or out of range indices.

meshkernel::UInt nx = 10;
meshkernel::UInt ny = 10;

// Prepare
std::shared_ptr<meshkernel::CurvilinearGrid> curvilinearGrid = MakeCurvilinearGrid(0.0, 0.0, 1.0, 1.0, nx, ny);

EXPECT_THROW(curvilinearGrid->DeleteInterior({1, meshkernel::constants::missing::uintValue}, {nx, ny}), meshkernel::ConstraintError);
EXPECT_THROW(curvilinearGrid->DeleteInterior({1, 1}, {meshkernel::constants::missing::uintValue, ny}), meshkernel::ConstraintError);
EXPECT_THROW(curvilinearGrid->DeleteInterior({1, 1}, {nx, ny}), meshkernel::ConstraintError);
EXPECT_THROW(curvilinearGrid->DeleteInterior({nx, 1}, {4, 4}), meshkernel::ConstraintError);
}
4 changes: 4 additions & 0 deletions tools/test_utils/include/TestUtils/MakeCurvilinearGrids.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,7 @@ std::shared_ptr<meshkernel::CurvilinearGrid> MakeSmallCurvilinearGrid();
/// @brief Makes a small, real world curvi grid, with missing faces
/// @return A pointer to a curvilinear grid
std::shared_ptr<meshkernel::CurvilinearGrid> MakeSmallCurvilinearGridWithMissingFaces();

/// @brief Makes a curvilinear grid
/// @return A pointer to a curvilinear grid
std::shared_ptr<meshkernel::CurvilinearGrid> MakeCurvilinearGrid(double originX, double originY, double deltaX, double deltaY, size_t nx, size_t ny);
22 changes: 22 additions & 0 deletions tools/test_utils/src/MakeCurvilinearGrids.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -153,3 +153,25 @@ std::shared_ptr<meshkernel::CurvilinearGrid> MakeSmallCurvilinearGridWithMissing

return std::make_shared<meshkernel::CurvilinearGrid>(grid, meshkernel::Projection::cartesian);
}

std::shared_ptr<meshkernel::CurvilinearGrid> MakeCurvilinearGrid(double originX, double originY, double deltaX, double deltaY, size_t nx, size_t ny)
{
double y = originY;

lin_alg::Matrix<meshkernel::Point> points(nx, ny);

for (size_t m = 0; m < ny; ++m)
{
double x = originX;

for (size_t n = 0; n < nx; ++n)
{
points(n, m) = meshkernel::Point(x, y);
x += deltaX;
}

y += deltaY;
}

return std::make_shared<meshkernel::CurvilinearGrid>(points, meshkernel::Projection::cartesian);
}

0 comments on commit 9bd09dd

Please sign in to comment.