Skip to content

Commit

Permalink
GRIDEDIT-1546 Removed bathymetry from api function names, now called …
Browse files Browse the repository at this point in the history
…mkernel_mesh2d_set_property. Must also pass a propertyId to indicate which property is being defined
  • Loading branch information
BillSenior committed Nov 28, 2024
1 parent 47a4ccd commit beb7344
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 55 deletions.
26 changes: 13 additions & 13 deletions libs/MeshKernel/include/MeshKernel/SampleInterpolator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ namespace meshkernel

/// @brief Set sample data
template <ValidConstDoubleArray VectorType>
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 <ValidConstPointArray PointVectorType, ValidConstDoubleArray ScalarVectorType>
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.
Expand All @@ -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<std::string, std::vector<double>> m_sampleData;
/// @brief Map from sample id (int) to sample data.
std::map<int, std::vector<double>> m_sampleData;
};

} // namespace meshkernel
Expand All @@ -92,29 +92,29 @@ 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 <meshkernel::ValidConstDoubleArray VectorType>
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())
{
throw ConstraintError("The sample data array does not have the same number of elements as the number of nodes in the triangulation: {} /= {}",
m_triangulation.NumberOfNodes(), sampleData.size());
}

m_sampleData[name].assign(sampleData.begin(), sampleData.end());
m_sampleData[sampleId].assign(sampleData.begin(), sampleData.end());
}

template <meshkernel::ValidConstPointArray PointVectorType, meshkernel::ValidConstDoubleArray ScalarVectorType>
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())
Expand All @@ -123,7 +123,7 @@ void meshkernel::SampleInterpolator::Interpolate(const std::string& name, const
iterpolationNodes.size(), result.size());
}

const std::vector<double>& propertyValues = m_sampleData.at(name);
const std::vector<double>& propertyValues = m_sampleData.at(sampleId);

for (size_t i = 0; i < iterpolationNodes.size(); ++i)
{
Expand Down
23 changes: 13 additions & 10 deletions libs/MeshKernel/tests/src/MeshPropertyTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ TEST(MeshPropertyTests, SimpleSampleInterpolationTest)
{
const double tolerance = 1.0e-13;

const int xDepth = 1;
const int yDepth = 2;

std::vector<double> 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<double> 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};

Expand All @@ -106,17 +109,17 @@ TEST(MeshPropertyTests, SimpleSampleInterpolationTest)
std::vector<double> expectedXDepths{0.25, 1.25, 2.25, 0.25, 1.25, 2.25, 0.25, 1.25, 2.25};
std::vector<double> 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)
{
Expand All @@ -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)
{
Expand Down
14 changes: 11 additions & 3 deletions libs/MeshKernelApi/include/MeshKernelApi/MeshKernel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
17 changes: 7 additions & 10 deletions libs/MeshKernelApi/include/MeshKernelApi/PropertyCalculator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
33 changes: 28 additions & 5 deletions libs/MeshKernelApi/src/MeshKernel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<const double> xNodes(sampleData.coordinates_x, sampleData.num_coordinates);
std::span<const double> yNodes(sampleData.coordinates_y, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator = std::make_shared<meshkernel::SampleInterpolator>(xNodes, yNodes, meshKernelState[meshKernelId].m_projection);

std::span<const double> bathymetryData(sampleData.values, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator->SetData("depth", bathymetryData);
std::span<const double> dataSamples(sampleData.values, sampleData.num_coordinates);
meshKernelState[meshKernelId].m_sampleInterpolator->SetData(propertyId, dataSamples);
}
catch (...)
{
Expand Down Expand Up @@ -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
{
Expand Down
30 changes: 20 additions & 10 deletions libs/MeshKernelApi/src/PropertyCalculator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@

#include <algorithm>

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<int>(meshkernel::Mesh2D::Property::Orthogonality))
{
throw meshkernel::ConstraintError("Incorrect property id, expected = {}, actual = {}", static_cast<int>(meshkernel::Mesh2D::Property::Orthogonality), propertyId);
}

std::vector<double> values = state.m_mesh2d->GetOrthogonality();

if (static_cast<size_t>(geometryList.num_coordinates) < values.size())
Expand All @@ -25,8 +31,14 @@ int meshkernelapi::OrthogonalityPropertyCalculator::Size(const MeshKernelState&
return static_cast<int>(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<int>(meshkernel::Mesh2D::Property::EdgeLength))
{
throw meshkernel::ConstraintError("Incorrect property id, expected = {}, actual = {}", static_cast<int>(meshkernel::Mesh2D::Property::EdgeLength), propertyId);
}

state.m_mesh2d->ComputeEdgesLengths();
std::vector<double> values = state.m_mesh2d->m_edgeLengths;

Expand All @@ -44,14 +56,12 @@ int meshkernelapi::EdgeLengthPropertyCalculator::Size(const MeshKernelState& sta
return static_cast<int>(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))
Expand All @@ -61,7 +71,7 @@ void meshkernelapi::DepthSamplePropertyCalculator::Calculate(const MeshKernelSta
}

std::span<double> 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
Expand Down
18 changes: 14 additions & 4 deletions libs/MeshKernelApi/tests/src/MeshPropertyTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<int>(meshkernel::Mesh2D::Property::Bathymetry);

int meshKernelId = meshkernel::constants::missing::intValue;
int errorCode;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<int>(meshkernel::Mesh2D::Property::Bathymetry);

int meshKernelId = meshkernel::constants::missing::intValue;
int errorCode;
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit beb7344

Please sign in to comment.