From beb734416b2ba42269ae7e161fafe1ac475d620d Mon Sep 17 00:00:00 2001 From: BillSenior Date: Thu, 28 Nov 2024 13:19:03 +0100 Subject: [PATCH] GRIDEDIT-1546 Removed bathymetry from api function names, now called mkernel_mesh2d_set_property. Must also pass a propertyId to indicate which property is being defined --- .../include/MeshKernel/SampleInterpolator.hpp | 26 +++++++-------- .../tests/src/MeshPropertyTests.cpp | 23 +++++++------ .../include/MeshKernelApi/MeshKernel.hpp | 14 ++++++-- .../MeshKernelApi/PropertyCalculator.hpp | 17 ++++------ libs/MeshKernelApi/src/MeshKernel.cpp | 33 ++++++++++++++++--- libs/MeshKernelApi/src/PropertyCalculator.cpp | 30 +++++++++++------ .../tests/src/MeshPropertyTests.cpp | 18 +++++++--- 7 files changed, 106 insertions(+), 55 deletions(-) diff --git a/libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp b/libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp index c9e6e7794..d4a8dd4a0 100644 --- a/libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp +++ b/libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp @@ -65,14 +65,14 @@ namespace meshkernel /// @brief Set sample data template - void SetData(const std::string& name, const VectorType& sampleData); + void SetData(const int sampleId, const VectorType& sampleData); /// @brief Interpolate the sample data set at the interpolation nodes. template - void Interpolate(const std::string& name, const PointVectorType& iterpolationNodes, ScalarVectorType& result) const; + void Interpolate(const int sampleId, const PointVectorType& iterpolationNodes, ScalarVectorType& result) const; /// @brief Determine if the SampleInterpolator already has this sample set. - bool Contains(const std::string& name) const; + bool Contains(const int sampleId) const; private: /// @brief Interpolate the sample data on the element at the interpolation point. @@ -81,8 +81,8 @@ namespace meshkernel /// @brief Triangulation of the sample points MeshTriangulation m_triangulation; - /// @brief Map from sample name to sample data. - std::map> m_sampleData; + /// @brief Map from sample id (int) to sample data. + std::map> m_sampleData; }; } // namespace meshkernel @@ -92,13 +92,13 @@ inline meshkernel::UInt meshkernel::SampleInterpolator::Size() const return m_triangulation.NumberOfNodes(); } -inline bool meshkernel::SampleInterpolator::Contains(const std::string& name) const +inline bool meshkernel::SampleInterpolator::Contains(const int sampleId) const { - return m_sampleData.contains(name); + return m_sampleData.contains(sampleId); } template -void meshkernel::SampleInterpolator::SetData(const std::string& name, const VectorType& sampleData) +void meshkernel::SampleInterpolator::SetData(const int sampleId, const VectorType& sampleData) { if (m_triangulation.NumberOfNodes() != sampleData.size()) { @@ -106,15 +106,15 @@ void meshkernel::SampleInterpolator::SetData(const std::string& name, const Vect m_triangulation.NumberOfNodes(), sampleData.size()); } - m_sampleData[name].assign(sampleData.begin(), sampleData.end()); + m_sampleData[sampleId].assign(sampleData.begin(), sampleData.end()); } template -void meshkernel::SampleInterpolator::Interpolate(const std::string& name, const PointVectorType& iterpolationNodes, ScalarVectorType& result) const +void meshkernel::SampleInterpolator::Interpolate(const int sampleId, const PointVectorType& iterpolationNodes, ScalarVectorType& result) const { - if (!Contains(name)) + if (!Contains(sampleId)) { - throw ConstraintError("Sample interpolator does not contain the name: {}.", name); + throw ConstraintError("Sample interpolator does not contain the id: {}.", sampleId); } if (iterpolationNodes.size() != result.size()) @@ -123,7 +123,7 @@ void meshkernel::SampleInterpolator::Interpolate(const std::string& name, const iterpolationNodes.size(), result.size()); } - const std::vector& propertyValues = m_sampleData.at(name); + const std::vector& propertyValues = m_sampleData.at(sampleId); for (size_t i = 0; i < iterpolationNodes.size(); ++i) { diff --git a/libs/MeshKernel/tests/src/MeshPropertyTests.cpp b/libs/MeshKernel/tests/src/MeshPropertyTests.cpp index 8a812d02e..831cbe60b 100644 --- a/libs/MeshKernel/tests/src/MeshPropertyTests.cpp +++ b/libs/MeshKernel/tests/src/MeshPropertyTests.cpp @@ -95,6 +95,9 @@ TEST(MeshPropertyTests, SimpleSampleInterpolationTest) { const double tolerance = 1.0e-13; + const int xDepth = 1; + const int yDepth = 2; + std::vector xValues{0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0, 0.0, 1.0, 2.0, 3.0}; std::vector yValues{0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0}; @@ -106,17 +109,17 @@ TEST(MeshPropertyTests, SimpleSampleInterpolationTest) std::vector expectedXDepths{0.25, 1.25, 2.25, 0.25, 1.25, 2.25, 0.25, 1.25, 2.25}; std::vector expectedYDepths{0.25, 0.25, 0.25, 1.25, 1.25, 1.25, 2.25, 2.25, 2.25}; - properties.SetData("xdepth", std::vector{0.0, 1.0, 2.0, 3.0, - 0.0, 1.0, 2.0, 3.0, - 0.0, 1.0, 2.0, 3.0, - 0.0, 1.0, 2.0, 3.0}); + properties.SetData(xDepth, std::vector{0.0, 1.0, 2.0, 3.0, + 0.0, 1.0, 2.0, 3.0, + 0.0, 1.0, 2.0, 3.0, + 0.0, 1.0, 2.0, 3.0}); - properties.SetData("ydepth", std::vector{0.0, 0.0, 0.0, 0.0, - 1.0, 1.0, 1.0, 1.0, - 2.0, 2.0, 2.0, 2.0, - 3.0, 3.0, 3.0, 3.0}); + properties.SetData(yDepth, std::vector{0.0, 0.0, 0.0, 0.0, + 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, + 3.0, 3.0, 3.0, 3.0}); - properties.Interpolate("xdepth", nodes, interpolated); + properties.Interpolate(xDepth, nodes, interpolated); for (size_t i = 0; i < interpolated.size(); ++i) { @@ -125,7 +128,7 @@ TEST(MeshPropertyTests, SimpleSampleInterpolationTest) std::span interpolatedData(interpolated.data(), interpolated.size()); - properties.Interpolate("ydepth", nodes, interpolatedData); + properties.Interpolate(yDepth, nodes, interpolatedData); for (size_t i = 0; i < interpolated.size(); ++i) { diff --git a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp index ee65f4430..81ec6968f 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp @@ -1457,6 +1457,13 @@ namespace meshkernelapi int* faceNumEdges, int* faceEdgeIndex); + /// @brief Determine if the property data for the mesh can be computed + /// @param[in] meshKernelId The id of the mesh state + /// @param[in] propertyId The id of the property + /// @param[out] propertyIsAvailable Indicate (true or false) is the property can be calculated. + /// @returns Error code + MKERNEL_API int mkernel_mesh2d_is_valid_property(int meshKernelId, const int propertyId, bool& propertyIsAvailable); + /// @brief Compute the global mesh with a given number of points along the longitude and latitude directions. /// @param[in] meshKernelId The id of the mesh state /// @param [in] numLongitudeNodes The number of points along the longitude. @@ -1607,11 +1614,12 @@ namespace meshkernelapi /// @returns Error code MKERNEL_API int mkernel_mesh2d_set(int meshKernelId, const Mesh2D& mesh2d); - /// @brief Sets the bathymetry data for the mesh + /// @brief Sets the property data for the mesh, the sample data points do not have to match the mesh2d nodes. /// @param[in] meshKernelId The id of the mesh state - /// @param[in] sampleData The mesh2d bathymetry data + /// @param[in] propertyId The id of the property + /// @param[in] sampleData The sample data and associated sample data points. /// @returns Error code - MKERNEL_API int mkernel_mesh2d_set_bathymetry_data(int meshKernelId, const GeometryList& sampleData); + MKERNEL_API int mkernel_mesh2d_set_property(int meshKernelId, const int propertyId, const GeometryList& sampleData); /// @brief Snaps a mesh to a land boundary. /// @param[in] meshKernelId The id of the mesh state diff --git a/libs/MeshKernelApi/include/MeshKernelApi/PropertyCalculator.hpp b/libs/MeshKernelApi/include/MeshKernelApi/PropertyCalculator.hpp index d993ae8c9..543cc9001 100644 --- a/libs/MeshKernelApi/include/MeshKernelApi/PropertyCalculator.hpp +++ b/libs/MeshKernelApi/include/MeshKernelApi/PropertyCalculator.hpp @@ -42,11 +42,11 @@ namespace meshkernelapi /// @brief Determine is the calculator can compute the desired results correctly. /// - /// This has a default implementation returning true. - virtual bool IsValid(const MeshKernelState& state) const; + /// This has a default of checking that the mesh2d is not null and the number of nodes is greater than zero. + virtual bool IsValid(const MeshKernelState& state, const int propertyId) const; /// @brief Calculate the property - virtual void Calculate(const MeshKernelState& state, const GeometryList& geometryList) const = 0; + virtual void Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const = 0; /// @brief Determine the size of the vector required to store the calculated properties virtual int Size(const MeshKernelState& state) const = 0; @@ -57,7 +57,7 @@ namespace meshkernelapi { public: /// @brief Calculate the orthogonality for a mesh - void Calculate(const MeshKernelState& state, const GeometryList& geometryList) const override; + void Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const override; /// @brief Determine the size of the orthogonality vector required int Size(const MeshKernelState& state) const override; @@ -68,7 +68,7 @@ namespace meshkernelapi { public: /// @brief Calculate the edge-length for a mesh - void Calculate(const MeshKernelState& state, const GeometryList& geometryList) const override; + void Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const override; /// @brief Determine the size of the edge-length vector required int Size(const MeshKernelState& state) const override; @@ -78,14 +78,11 @@ namespace meshkernelapi class DepthSamplePropertyCalculator : public PropertyCalculator { public: - /// @brief The name of the sample data - static const std::string SampleName; - /// @brief Determine is the calculator can interpolate depth values correctly - bool IsValid(const MeshKernelState& state) const override; + bool IsValid(const MeshKernelState& state, const int propertyId) const override; /// @brief Calculate the edge-length for a mesh - void Calculate(const MeshKernelState& state, const GeometryList& geometryList) const override; + void Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const override; /// @brief Determine the size of the edge-length vector required int Size(const MeshKernelState& state) const override; diff --git a/libs/MeshKernelApi/src/MeshKernel.cpp b/libs/MeshKernelApi/src/MeshKernel.cpp index 9572c073b..c6d3d7228 100644 --- a/libs/MeshKernelApi/src/MeshKernel.cpp +++ b/libs/MeshKernelApi/src/MeshKernel.cpp @@ -505,7 +505,25 @@ namespace meshkernelapi return lastExitCode; } - MKERNEL_API int mkernel_mesh2d_set_bathymetry_data(int meshKernelId, const GeometryList& sampleData) + MKERNEL_API int mkernel_mesh2d_is_valid_property(int meshKernelId, const int propertyId, bool& propertyIsAvailable) + { + lastExitCode = meshkernel::ExitCode::Success; + propertyIsAvailable = false; + try + { + propertyIsAvailable = meshKernelState.contains(meshKernelId) && + propertyCalculators.contains(propertyId) && + propertyCalculators[propertyId] != nullptr && + propertyCalculators[propertyId]->IsValid(meshKernelState.at(meshKernelId), propertyId); + } + catch (...) + { + lastExitCode = HandleException(); + } + return lastExitCode; + } + + MKERNEL_API int mkernel_mesh2d_set_property(int meshKernelId, const int propertyId, const GeometryList& sampleData) { lastExitCode = meshkernel::ExitCode::Success; try @@ -520,12 +538,17 @@ namespace meshkernelapi throw meshkernel::MeshKernelError("The selected mesh not exist."); } + if (propertyCalculators[propertyId] != nullptr && propertyCalculators[propertyId]->IsValid(meshKernelState.at(meshKernelId), propertyId)) + { + throw meshkernel::MeshKernelError("The property, {}, has already been defined.", propertyId); + } + std::span xNodes(sampleData.coordinates_x, sampleData.num_coordinates); std::span yNodes(sampleData.coordinates_y, sampleData.num_coordinates); meshKernelState[meshKernelId].m_sampleInterpolator = std::make_shared(xNodes, yNodes, meshKernelState[meshKernelId].m_projection); - std::span bathymetryData(sampleData.values, sampleData.num_coordinates); - meshKernelState[meshKernelId].m_sampleInterpolator->SetData("depth", bathymetryData); + std::span dataSamples(sampleData.values, sampleData.num_coordinates); + meshKernelState[meshKernelId].m_sampleInterpolator->SetData(propertyId, dataSamples); } catch (...) { @@ -1562,9 +1585,9 @@ namespace meshkernelapi return lastExitCode; } - if (propertyCalculators.contains(propertyValue) && propertyCalculators[propertyValue] != nullptr && propertyCalculators[propertyValue]->IsValid(meshKernelState.at(meshKernelId))) + if (propertyCalculators.contains(propertyValue) && propertyCalculators[propertyValue] != nullptr && propertyCalculators[propertyValue]->IsValid(meshKernelState.at(meshKernelId), propertyValue)) { - propertyCalculators[propertyValue]->Calculate(meshKernelState.at(meshKernelId), geometryList); + propertyCalculators[propertyValue]->Calculate(meshKernelState.at(meshKernelId), propertyValue, geometryList); } else { diff --git a/libs/MeshKernelApi/src/PropertyCalculator.cpp b/libs/MeshKernelApi/src/PropertyCalculator.cpp index fc594ade4..6629bb49c 100644 --- a/libs/MeshKernelApi/src/PropertyCalculator.cpp +++ b/libs/MeshKernelApi/src/PropertyCalculator.cpp @@ -2,13 +2,19 @@ #include -bool meshkernelapi::PropertyCalculator::IsValid(const MeshKernelState& state [[maybe_unused]]) const +bool meshkernelapi::PropertyCalculator::IsValid(const MeshKernelState& state, const int propertyId [[maybe_unused]]) const { - return true; + return state.m_mesh2d != nullptr && state.m_mesh2d->GetNumNodes() > 0; } -void meshkernelapi::OrthogonalityPropertyCalculator::Calculate(const MeshKernelState& state, const GeometryList& geometryList) const +void meshkernelapi::OrthogonalityPropertyCalculator::Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const { + + if (propertyId != static_cast(meshkernel::Mesh2D::Property::Orthogonality)) + { + throw meshkernel::ConstraintError("Incorrect property id, expected = {}, actual = {}", static_cast(meshkernel::Mesh2D::Property::Orthogonality), propertyId); + } + std::vector values = state.m_mesh2d->GetOrthogonality(); if (static_cast(geometryList.num_coordinates) < values.size()) @@ -25,8 +31,14 @@ int meshkernelapi::OrthogonalityPropertyCalculator::Size(const MeshKernelState& return static_cast(state.m_mesh2d->GetNumEdges()); } -void meshkernelapi::EdgeLengthPropertyCalculator::Calculate(const MeshKernelState& state, const GeometryList& geometryList) const +void meshkernelapi::EdgeLengthPropertyCalculator::Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const { + + if (propertyId != static_cast(meshkernel::Mesh2D::Property::EdgeLength)) + { + throw meshkernel::ConstraintError("Incorrect property id, expected = {}, actual = {}", static_cast(meshkernel::Mesh2D::Property::EdgeLength), propertyId); + } + state.m_mesh2d->ComputeEdgesLengths(); std::vector values = state.m_mesh2d->m_edgeLengths; @@ -44,14 +56,12 @@ int meshkernelapi::EdgeLengthPropertyCalculator::Size(const MeshKernelState& sta return static_cast(state.m_mesh2d->GetNumEdges()); } -const std::string meshkernelapi::DepthSamplePropertyCalculator::SampleName = "depth"; - -bool meshkernelapi::DepthSamplePropertyCalculator::IsValid(const MeshKernelState& state) const +bool meshkernelapi::DepthSamplePropertyCalculator::IsValid(const MeshKernelState& state, const int propertyId) const { - return state.m_sampleInterpolator != nullptr; + return state.m_mesh2d != nullptr && state.m_mesh2d->GetNumNodes() > 0 && state.m_sampleInterpolator != nullptr && state.m_sampleInterpolator->Contains(propertyId); } -void meshkernelapi::DepthSamplePropertyCalculator::Calculate(const MeshKernelState& state, const GeometryList& geometryList) const +void meshkernelapi::DepthSamplePropertyCalculator::Calculate(const MeshKernelState& state, const int propertyId, const GeometryList& geometryList) const { if (geometryList.num_coordinates < Size(state)) @@ -61,7 +71,7 @@ void meshkernelapi::DepthSamplePropertyCalculator::Calculate(const MeshKernelSta } std::span interpolatedSampleData(geometryList.values, geometryList.num_coordinates); - state.m_sampleInterpolator->Interpolate(SampleName, state.m_mesh2d->Nodes(), interpolatedSampleData); + state.m_sampleInterpolator->Interpolate(propertyId, state.m_mesh2d->Nodes(), interpolatedSampleData); } int meshkernelapi::DepthSamplePropertyCalculator::Size(const MeshKernelState& state) const diff --git a/libs/MeshKernelApi/tests/src/MeshPropertyTests.cpp b/libs/MeshKernelApi/tests/src/MeshPropertyTests.cpp index d1c514dec..358457a34 100644 --- a/libs/MeshKernelApi/tests/src/MeshPropertyTests.cpp +++ b/libs/MeshKernelApi/tests/src/MeshPropertyTests.cpp @@ -27,7 +27,7 @@ TEST(MeshPropertyTests, BathymetryTest) const double origin = 0.0; const double delta = 1.0; - const int BathymetryPropertyId = 2; + const int BathymetryPropertyId = static_cast(meshkernel::Mesh2D::Property::Bathymetry); int meshKernelId = meshkernel::constants::missing::intValue; int errorCode; @@ -108,7 +108,7 @@ TEST(MeshPropertyTests, BathymetryTest) sampleData.coordinates_x = bathymetryXNodes.data(); sampleData.coordinates_y = bathymetryYNodes.data(); - errorCode = mkapi::mkernel_mesh2d_set_bathymetry_data(meshKernelId, sampleData); + errorCode = mkapi::mkernel_mesh2d_set_property(meshKernelId, BathymetryPropertyId, sampleData); ASSERT_EQ(mk::ExitCode::Success, errorCode); const double tolerance = 1.0e-13; @@ -153,7 +153,7 @@ TEST(MeshPropertyTests, PropertyFailureTest) const double origin = 0.0; const double delta = 1.0; - const int BathymetryPropertyId = 2; + const int BathymetryPropertyId = static_cast(meshkernel::Mesh2D::Property::Bathymetry); int meshKernelId = meshkernel::constants::missing::intValue; int errorCode; @@ -234,8 +234,18 @@ TEST(MeshPropertyTests, PropertyFailureTest) sampleData.coordinates_x = bathymetryXNodes.data(); sampleData.coordinates_y = bathymetryYNodes.data(); - errorCode = mkapi::mkernel_mesh2d_set_bathymetry_data(meshKernelId, sampleData); + bool hasBathymetryData = false; + + errorCode = mkapi::mkernel_mesh2d_is_valid_property(meshKernelId, BathymetryPropertyId, hasBathymetryData); + ASSERT_EQ(mk::ExitCode::Success, errorCode); + EXPECT_FALSE(hasBathymetryData); + + errorCode = mkapi::mkernel_mesh2d_set_property(meshKernelId, BathymetryPropertyId, sampleData); + ASSERT_EQ(mk::ExitCode::Success, errorCode); + + errorCode = mkapi::mkernel_mesh2d_is_valid_property(meshKernelId, BathymetryPropertyId, hasBathymetryData); ASSERT_EQ(mk::ExitCode::Success, errorCode); + EXPECT_TRUE(hasBathymetryData); //-------------------------------- // Start test