Skip to content

Commit

Permalink
GRIDEDIT-1336 Added cache for small flow edges
Browse files Browse the repository at this point in the history
  • Loading branch information
BillSenior committed Oct 21, 2024
1 parent 96d3720 commit 2f44c3e
Show file tree
Hide file tree
Showing 6 changed files with 179 additions and 4 deletions.
2 changes: 2 additions & 0 deletions libs/MeshKernelApi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ set(SRC_LIST
${SRC_DIR}/MeshKernel.cpp
${SRC_DIR}/NodeInPolygonCache.cpp
${SRC_DIR}/PolygonRefinementCache.cpp
${SRC_DIR}/SmallFlowEdgeCentreCache.cpp
)

# list of target headers
Expand All @@ -47,6 +48,7 @@ set(
${DOMAIN_INC_DIR}/MeshKernel.hpp
${DOMAIN_INC_DIR}/NodeInPolygonCache.hpp
${DOMAIN_INC_DIR}/PolygonRefinementCache.hpp
${DOMAIN_INC_DIR}/SmallFlowEdgeCentreCache.hpp
${DOMAIN_INC_DIR}/State.hpp
${DOMAIN_INC_DIR}/Utils.hpp
${VERSION_INC_DIR}/Version/Version.hpp
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//---- GPL ---------------------------------------------------------------------
//
// Copyright (C) Stichting Deltares, 2011-2024.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// contact: [email protected]
// Stichting Deltares
// P.O. Box 177
// 2600 MH Delft, The Netherlands
//
// All indications and logos of, and references to, "Delft3D" and "Deltares"
// are registered trademarks of Stichting Deltares, and remain the property of
// Stichting Deltares. All rights reserved.
//
//------------------------------------------------------------------------------

#pragma once

#include <cstring>
#include <vector>

#include "MeshKernel/Point.hpp"

#include "MeshKernelApi/CachedPointValues.hpp"
#include "MeshKernelApi/GeometryList.hpp"

namespace meshkernelapi
{

/// @brief Cache centre of edges
class SmallFlowEdgeCentreCache : public CachedPointValues
{
public:
/// @brief Constructor
SmallFlowEdgeCentreCache(const double lengthThreshold,
const std::vector<meshkernel::Point>& edgeCentres);

/// @brief Determine if current options match those used to construct the object
bool ValidOptions(const double lengthThreshold) const;

private:
/// @brief Threshold for small edge length
double m_lengthThreshold;
};

} // namespace meshkernelapi
2 changes: 2 additions & 0 deletions libs/MeshKernelApi/include/MeshKernelApi/State.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "MeshKernelApi/FacePolygonPropertyCache.hpp"
#include "MeshKernelApi/NodeInPolygonCache.hpp"
#include "MeshKernelApi/PolygonRefinementCache.hpp"
#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp"

namespace meshkernelapi
{
Expand Down Expand Up @@ -85,6 +86,7 @@ namespace meshkernelapi
std::shared_ptr<BoundariesAsPolygonCache> m_boundariesAsPolygonCache; ///< Cache
std::shared_ptr<PolygonRefinementCache> m_polygonRefinementCache; ///< Cache for polygon refinement
std::shared_ptr<NodeInPolygonCache> m_nodeInPolygonCache; ///< Cache for node in polygon
std::shared_ptr<SmallFlowEdgeCentreCache> m_smallFlowEdgeCentreCache; ///< Cache for small flow edge centres
};

} // namespace meshkernelapi
26 changes: 22 additions & 4 deletions libs/MeshKernelApi/src/MeshKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3426,10 +3426,19 @@ namespace meshkernelapi
{
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}

if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache != nullptr)
{
meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
throw meshkernel::ConstraintError("Small flow edge data has already been cached. Cached values will be deleted.");
}

const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesLengthThreshold);
const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges);

numSmallFlowEdges = static_cast<int>(smallFlowEdgeCenters.size());
meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache = std::make_shared<SmallFlowEdgeCentreCache>(smallFlowEdgesLengthThreshold, smallFlowEdgeCenters);

numSmallFlowEdges = meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Size();
}
catch (...)
{
Expand All @@ -3448,10 +3457,19 @@ namespace meshkernelapi
throw meshkernel::MeshKernelError("The selected mesh kernel id does not exist.");
}

const auto edgesCrossingSmallFlowEdges = meshKernelState[meshKernelId].m_mesh2d->GetEdgesCrossingSmallFlowEdges(smallFlowEdgesThreshold);
const auto smallFlowEdgeCenters = meshKernelState[meshKernelId].m_mesh2d->GetFlowEdgesCenters(edgesCrossingSmallFlowEdges);
if (meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache == nullptr)
{
throw meshkernel::ConstraintError("Small flow edge data has not been cached");
}

if (!meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->ValidOptions(smallFlowEdgesThreshold))
{
meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
throw meshkernel::ConstraintError("Given small flow edge options are incompatible with the cached values. Cached values will be deleted.");
}

ConvertPointVectorToGeometryList(smallFlowEdgeCenters, result);
meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache->Copy(result);
meshKernelState[meshKernelId].m_smallFlowEdgeCentreCache.reset();
}
catch (...)
{
Expand Down
37 changes: 37 additions & 0 deletions libs/MeshKernelApi/src/SmallFlowEdgeCentreCache.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//---- GPL ---------------------------------------------------------------------
//
// Copyright (C) Stichting Deltares, 2011-2024.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation version 3.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// contact: [email protected]
// Stichting Deltares
// P.O. Box 177
// 2600 MH Delft, The Netherlands
//
// All indications and logos of, and references to, "Delft3D" and "Deltares"
// are registered trademarks of Stichting Deltares, and remain the property of
// Stichting Deltares. All rights reserved.
//
//------------------------------------------------------------------------------

#include "MeshKernelApi/SmallFlowEdgeCentreCache.hpp"

meshkernelapi::SmallFlowEdgeCentreCache::SmallFlowEdgeCentreCache(const double lengthThreshold,
const std::vector<meshkernel::Point>& edgeCentres)
: CachedPointValues(edgeCentres), m_lengthThreshold(lengthThreshold) {}

bool meshkernelapi::SmallFlowEdgeCentreCache::ValidOptions(const double lengthThreshold) const
{
return lengthThreshold == m_lengthThreshold;
}
59 changes: 59 additions & 0 deletions libs/MeshKernelApi/tests/src/ApiTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1761,6 +1761,65 @@ TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_ShouldGetSmallFlowEdg
ASSERT_NEAR(result.coordinates_y[0], 0.0, tolerance);
}

TEST_F(CartesianApiTestFixture, GetSmallFlowEdges_OnMesh2D_GetSmallFlowEdgesFailures)
{
// Prepare a mesh with two triangles
meshkernelapi::Mesh2D mesh2d;

std::vector<double> node_x{0.0, 1.0, 1.0, 1.0};
std::vector<double> node_y{0.0, 0.0, 0.3, -0.3};
std::vector<int> edge_nodes{0, 3, 3, 1, 1, 0, 1, 2, 2, 0};

mesh2d.node_x = node_x.data();
mesh2d.node_y = node_y.data();
mesh2d.edge_nodes = edge_nodes.data();
mesh2d.num_edges = static_cast<int>(edge_nodes.size() * 0.5);
mesh2d.num_nodes = static_cast<int>(node_x.size());

// Get the meshkernel id
auto const meshKernelId = GetMeshKernelId();
double const smallFlowEdgesThreshold = 100.0;
meshkernelapi::GeometryList result{};

auto errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);

// Execute
errorCode = mkernel_mesh2d_set(meshKernelId, mesh2d);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
int numSmallFlowEdges;
errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);

// Assert
std::vector<double> coordinates_x(numSmallFlowEdges);
std::vector<double> coordinates_y(numSmallFlowEdges);
result.coordinates_x = coordinates_x.data();
result.coordinates_y = coordinates_y.data();
result.num_coordinates = numSmallFlowEdges;

errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);

// Cache has been deleted
errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, result);
ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);

// Re-cache values
errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);

// Get values with different set of options
errorCode = mkernel_mesh2d_get_small_flow_edge_centers(meshKernelId, 2.0 * smallFlowEdgesThreshold, result);
ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);

// Re-cache values
errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
ASSERT_EQ(meshkernel::ExitCode::Success, errorCode);
// Attempt at getting the size again will cause an error
errorCode = meshkernelapi::mkernel_mesh2d_count_small_flow_edge_centers(meshKernelId, smallFlowEdgesThreshold, numSmallFlowEdges);
ASSERT_EQ(meshkernel::ExitCode::ConstraintErrorCode, errorCode);
}

TEST_F(CartesianApiTestFixture, CountObtuseTriangles_OnMesh2DWithOneObtuseTriangle_ShouldCountObtuseTriangles)
{
// Prepare a mesh with one obtuse triangle
Expand Down

0 comments on commit 2f44c3e

Please sign in to comment.