Skip to content

Commit

Permalink
CurvilinearGrid no longer inherits from Mesh
Browse files Browse the repository at this point in the history
* Access methods for node and edge vectors are added
* Access methods for node and edge counts are added
* Mutable members are used to lazily update the internal Mesh
  representation needed for node and edge lookup
  • Loading branch information
andreasbuykx committed Feb 8, 2024
1 parent 9f6df1e commit 2565db8
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
namespace meshkernel
{
/// @brief A class representing a curvilinear grid
class CurvilinearGrid final : public Mesh
class CurvilinearGrid final
{

public:
Expand Down Expand Up @@ -68,13 +68,13 @@ namespace meshkernel
Up
};

/// @brief Default destructor
~CurvilinearGrid() override = default;
/// @brief destructor
~CurvilinearGrid() = default;

/// @brief Default constructor
CurvilinearGrid() = default;

/// @brief Copy constructor taking only a curvilinear grid
/// @brief copy constructor
CurvilinearGrid(const CurvilinearGrid& grid);

/// @brief Constructor taking only a projection
Expand All @@ -100,6 +100,31 @@ namespace meshkernel
/// @return True if valid, false otherwise
[[nodiscard]] bool IsValid() const;

/// @brief get the projection type
Projection GetProjection() const { return m_projection; }

/// @brief the total number of nodes (including invalid nodes)
UInt GetNumNodes() const { return NumM() * NumN(); }

/// @brief the total number of edges (including invalid edges)
UInt GetNumEdges() const { return NumM() * (NumN() - 1) + NumN() * (NumM() - 1); }

/// @brief get a serialized representation of the nodes of the curvilinear grid.
/// @note the serialization is produced by ConvertCurvilinearToNodesAndEdges
std::vector<Point> GetNodeVector() const
{
BuildMesh();
return m_mesh->m_nodes;
}

/// @brief get a serialized representation of the edges of the curvilinear grid.
/// @note the serialization is produced by ConvertCurvilinearToNodesAndEdges
std::vector<Edge> GetEdgeVector() const
{
BuildMesh();
return m_mesh->m_edges;
}

/// @brief Converting a curvilinear mesh to a set of nodes, edges and returns the original mapping (gridtonet)
/// @details Nodes and grid indices from the matrix are serialized in row-major order (n runs fastest).
/// Edges are serialized as follows: first all m-oriented edges ((m,n)-(m+1,n)) in row-major order, then all
Expand All @@ -108,18 +133,19 @@ namespace meshkernel
/// @returns The nodes, the edges, and the original mapping (m and n indices for each node)
[[nodiscard]] std::tuple<std::vector<Point>, std::vector<Edge>, std::vector<CurvilinearGridNodeIndices>> ConvertCurvilinearToNodesAndEdges() const;

/// @brief Set internal flat copies of nodes and edges, so the pointer to the first entry is communicated with the front-end
/// @details The Mesh nodes and edges arrays, and the grid node indices array are populated by the result of ConvertCurvilinearToNodesAndEdges.
void SetFlatCopies();

/// @brief Get the m and n indices of the node closest to the point
/// @param[in] point The input grid points
[[nodiscard]] CurvilinearGridNodeIndices GetNodeIndices(Point point);

/// @brief Gets a reference to the grid node at the (m,n) location
/// @brief Gets a non-const reference to the grid node at the (m,n) location
/// @note a side effect is that the Mesh representation is cleared.
/// @param[in] m The m-dimension index
/// @param[in] n The n-dimension index
[[nodiscard]] meshkernel::Point& GetNode(const UInt m, const UInt n) { return m_gridNodes(m, n); }
[[nodiscard]] meshkernel::Point& GetNode(const UInt m, const UInt n)
{
ClearMesh();
return m_gridNodes(m, n);
}

/// @brief Gets a constant reference to the grid node at the (m,n) location
/// @param[in] m The m-dimension index
Expand Down Expand Up @@ -153,7 +179,7 @@ namespace meshkernel
/// @brief From a point gets the node indices of the closest edges
/// @param[in] point The input point
/// @return The curvilinear grid indices of the closest edge
[[nodiscard]] std::tuple<CurvilinearGridNodeIndices, CurvilinearGridNodeIndices> GetEdgeNodeIndices(Point const& point);
[[nodiscard]] std::tuple<CurvilinearGridNodeIndices, CurvilinearGridNodeIndices> GetEdgeNodeIndices(Point const& point) const;

/// @brief Computes the grid nodes types and the faces masks
void ComputeGridNodeTypes();
Expand Down Expand Up @@ -209,7 +235,7 @@ namespace meshkernel
/// @param[in] nodeIndex The current node index
/// @param[in] direction The direction, either m or n
/// @return The computed distance
[[nodiscard]] double ComputeAverageNodalDistance(CurvilinearGridNodeIndices const& nodeIndex, CurvilinearGridLine::GridLineDirection direction);
[[nodiscard]] double ComputeAverageNodalDistance(CurvilinearGridNodeIndices const& nodeIndex, CurvilinearGridLine::GridLineDirection direction) const;

/// @brief Transform the displacement around a node to local or global (TOLOCL)
/// @param[in] displacement The displacement to transform.
Expand Down Expand Up @@ -270,6 +296,22 @@ namespace meshkernel
std::vector<Point> GetNodeVectorAtN(UInt n) const { return lin_alg::MatrixColToSTLVector(m_gridNodes, n); }

private:
/// @brief clear the internal mesh representation
void ClearMesh();

/// @brief Build the internal mesh representation from the member data
void BuildMesh() const;

/// @brief Build the nodes lookup in the internal mesh representation
void BuildNodesTree() const;

/// @brief Build the edges lookup in the internal mesh representation
void BuildEdgesTree() const;

/// @brief Get the matrix indices for the node at serialization index.
/// @note the serialization index is determined by the ConvertCurvilinearToNodesAndEdges method.
CurvilinearGridNodeIndices GetNodeIndices(UInt index) const;

/// @brief Remove invalid nodes.
/// This function is recursive
/// @param[in] invalidNodesToRemove Whether there are still invalid nodes to remove
Expand All @@ -287,9 +329,13 @@ namespace meshkernel
void AddEdge(CurvilinearGridNodeIndices const& firstNode,
CurvilinearGridNodeIndices const& secondNode);

lin_alg::Matrix<Point> m_gridNodes; ///< Member variable storing the grid
lin_alg::Matrix<bool> m_gridFacesMask; ///< The mask of the grid faces (true/false)
lin_alg::Matrix<NodeType> m_gridNodesTypes; ///< The grid node types
std::vector<CurvilinearGridNodeIndices> m_gridIndices; ///< The original mapping of the flatten nodes in the curvilinear grid
Projection m_projection = Projection::cartesian; ///< type of projection (cartesian/spherical)
lin_alg::Matrix<Point> m_gridNodes; ///< Member variable storing the grid
lin_alg::Matrix<bool> m_gridFacesMask; ///< The mask of the grid faces (true/false)
lin_alg::Matrix<NodeType> m_gridNodesTypes; ///< The grid node types
mutable std::vector<CurvilinearGridNodeIndices> m_gridIndices; ///< The original mapping of the flatten nodes in the curvilinear grid
mutable std::unique_ptr<Mesh> m_mesh;
mutable bool m_nodeTreeBuilt = false;
mutable bool m_edgeTreeBuilt = false;
};
} // namespace meshkernel
106 changes: 72 additions & 34 deletions libs/MeshKernel/src/CurvilinearGrid/CurvilinearGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,29 @@
using meshkernel::CurvilinearGrid;
using meshkernel::CurvilinearGridNodeIndices;

CurvilinearGrid::CurvilinearGrid(const CurvilinearGrid& grid) : Mesh(grid.m_edges, grid.m_nodes, grid.m_projection),
CurvilinearGrid::CurvilinearGrid(const CurvilinearGrid& grid) : m_projection(grid.m_projection),
m_gridNodes(grid.m_gridNodes),
m_gridFacesMask(grid.m_gridFacesMask),
m_gridNodesTypes(grid.m_gridNodesTypes),
m_gridIndices(grid.m_gridIndices)
{
}

CurvilinearGrid::CurvilinearGrid(Projection projection) : Mesh(projection) {}
CurvilinearGrid::CurvilinearGrid(Projection projection) : m_projection(projection)
{
}

CurvilinearGrid::CurvilinearGrid(lin_alg::Matrix<Point> const& grid, Projection projection) : Mesh(projection)
CurvilinearGrid::CurvilinearGrid(lin_alg::Matrix<Point> const& grid, Projection projection) : m_projection(projection),
m_gridNodes(grid)
{
SetGridNodes(grid);
}

void CurvilinearGrid::ClearMesh()
{
m_mesh = nullptr;
m_nodeTreeBuilt = false;
m_edgeTreeBuilt = false;
m_gridIndices.clear();
}

void CurvilinearGrid::SetGridNodes(const lin_alg::Matrix<Point>& gridNodes)
Expand All @@ -57,12 +67,7 @@ void CurvilinearGrid::SetGridNodes(const lin_alg::Matrix<Point>& gridNodes)
{
throw std::invalid_argument("CurvilinearGrid::CurvilinearGrid: Invalid curvilinear grid");
}

m_nodesRTreeRequiresUpdate = true;
m_edgesRTreeRequiresUpdate = true;
m_facesRTreeRequiresUpdate = true;

SetFlatCopies();
ClearMesh();
}

void CurvilinearGrid::Delete(std::shared_ptr<Polygons> polygons, UInt polygonIndex)
Expand Down Expand Up @@ -132,6 +137,8 @@ void CurvilinearGrid::Delete(std::shared_ptr<Polygons> polygons, UInt polygonInd
}
}

bool changed = false;

// mark points inside a polygonIndex
for (UInt n = 0; n < numN; ++n)
{
Expand All @@ -141,22 +148,52 @@ void CurvilinearGrid::Delete(std::shared_ptr<Polygons> polygons, UInt polygonInd
{
m_gridNodes(n, m).x = constants::missing::doubleValue;
m_gridNodes(n, m).y = constants::missing::doubleValue;
changed = true;
}
}
}
if (changed)
{
ClearMesh();
}
}

void CurvilinearGrid::SetFlatCopies()
void CurvilinearGrid::BuildMesh() const
{
if (lin_alg::MatrixIsEmpty(m_gridNodes))
if (m_mesh)
{
return;
}

const auto [nodes, edges, gridIndices] = ConvertCurvilinearToNodesAndEdges();
m_nodes = nodes;
m_edges = edges;
m_gridIndices = gridIndices;
auto [nodes, edges, indices] = ConvertCurvilinearToNodesAndEdges();
m_mesh = std::make_unique<Mesh>(edges, nodes, m_projection);
m_gridIndices = indices;
}

void CurvilinearGrid::BuildNodesTree() const
{
if (m_nodeTreeBuilt)
return;

BuildMesh();
m_mesh->BuildTree(Location::Nodes);
m_nodeTreeBuilt = true;
}

void CurvilinearGrid::BuildEdgesTree() const
{
if (m_edgeTreeBuilt)
return;

BuildMesh();
m_mesh->BuildTree(Location::Edges);
m_edgeTreeBuilt = true;
}

CurvilinearGridNodeIndices CurvilinearGrid::GetNodeIndices(UInt index) const
{
BuildMesh();
return m_gridIndices[index];
}

std::tuple<std::vector<meshkernel::Point>,
Expand Down Expand Up @@ -235,31 +272,31 @@ bool CurvilinearGrid::IsValid() const

CurvilinearGridNodeIndices CurvilinearGrid::GetNodeIndices(Point point)
{
BuildTree(Location::Nodes);
SearchNearestLocation(point, Location::Nodes);
if (GetNumLocations(Location::Nodes) == 0)
BuildNodesTree();
m_mesh->SearchNearestLocation(point, Location::Nodes);
if (m_mesh->GetNumLocations(Location::Nodes) == 0)
{
return {constants::missing::uintValue, constants::missing::uintValue};
}

const auto nodeIndex = GetLocationsIndices(0, Location::Nodes);
return m_gridIndices[nodeIndex];
const auto nodeIndex = m_mesh->GetLocationsIndices(0, Location::Nodes);
return GetNodeIndices(nodeIndex);
}

std::tuple<CurvilinearGridNodeIndices, CurvilinearGridNodeIndices> CurvilinearGrid::GetEdgeNodeIndices(Point const& point)
std::tuple<CurvilinearGridNodeIndices, CurvilinearGridNodeIndices> CurvilinearGrid::GetEdgeNodeIndices(Point const& point) const
{
BuildTree(Location::Edges);
SearchNearestLocation(point, Location::Edges);
if (GetNumLocations(Location::Edges) == 0)
BuildEdgesTree();
m_mesh->SearchNearestLocation(point, Location::Edges);
if (m_mesh->GetNumLocations(Location::Edges) == 0)
{
return {{}, {}};
}

const auto nodeIndex = GetLocationsIndices(0, Location::Edges);
auto const firstNode = m_edges[nodeIndex].first;
auto const secondNode = m_edges[nodeIndex].second;
const auto nodeIndex = m_mesh->GetLocationsIndices(0, Location::Edges);
auto const firstNode = m_mesh->m_edges[nodeIndex].first;
auto const secondNode = m_mesh->m_edges[nodeIndex].second;

return {m_gridIndices[firstNode], m_gridIndices[secondNode]};
return {GetNodeIndices(firstNode), GetNodeIndices(secondNode)};
}

bool CurvilinearGrid::AreFaceNodesValid(UInt m, UInt n) const
Expand Down Expand Up @@ -622,7 +659,7 @@ void CurvilinearGrid::InsertFace(Point const& point)

// Re-compute quantities
ComputeGridNodeTypes();
SetFlatCopies();
ClearMesh();
}

bool CurvilinearGrid::AddGridLineAtBoundary(CurvilinearGridNodeIndices const& firstNode,
Expand Down Expand Up @@ -667,8 +704,8 @@ bool CurvilinearGrid::AddGridLineAtBoundary(CurvilinearGridNodeIndices const& fi
0);
gridSizeChanged = true;
}
ClearMesh();
}

return gridSizeChanged;
}

Expand Down Expand Up @@ -713,6 +750,7 @@ CurvilinearGrid::BoundaryGridLineType CurvilinearGrid::GetBoundaryGridLineType(C

void CurvilinearGrid::AddEdge(CurvilinearGridNodeIndices const& firstNode, CurvilinearGridNodeIndices const& secondNode)
{
ClearMesh();

// Allocate new grid line if needed
auto const gridLineType = GetBoundaryGridLineType(firstNode, secondNode);
Expand Down Expand Up @@ -740,7 +778,6 @@ void CurvilinearGrid::AddEdge(CurvilinearGridNodeIndices const& firstNode, Curvi
AddGridLineAtBoundary(firstNode, secondNode);
m_gridNodes(firstNode.m_m + 1, firstNode.m_n) = firstNewNodeCoordinates;
m_gridNodes(secondNode.m_m + 1, secondNode.m_n) = secondNewNodeCoordinates;

return;
}
if (gridLineType == BoundaryGridLineType::Bottom)
Expand Down Expand Up @@ -795,7 +832,7 @@ CurvilinearGrid::ComputeDirectionalSmoothingFactors(CurvilinearGridNodeIndices c
return {mSmoothingFactor, nSmoothingFactor, mixedSmoothingFactor};
}

double CurvilinearGrid::ComputeAverageNodalDistance(CurvilinearGridNodeIndices const& index, CurvilinearGridLine::GridLineDirection direction)
double CurvilinearGrid::ComputeAverageNodalDistance(CurvilinearGridNodeIndices const& index, CurvilinearGridLine::GridLineDirection direction) const
{
if (index.m_m > NumM() || index.m_n > NumN())
{
Expand Down Expand Up @@ -885,7 +922,7 @@ void CurvilinearGrid::DeleteNode(Point const& point)
m_gridNodes(nodeToDelete.m_m, nodeToDelete.m_n) = {constants::missing::doubleValue, constants::missing::doubleValue};
// Re-compute quantities
ComputeGridNodeTypes();
SetFlatCopies();
ClearMesh();
}
}

Expand All @@ -902,6 +939,7 @@ void CurvilinearGrid::MoveNode(Point const& fromPoint, Point const& toPoint)

// move fromPoint to toPoint
m_gridNodes(nodeIndex.m_m, nodeIndex.m_n) = toPoint;
ClearMesh();
}

meshkernel::BoundingBox CurvilinearGrid::GetBoundingBox() const
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,4 @@ void CurvilinearGridLineMirror::Compute()
m_grid.GetNode(i, 2) * b;
}
}

m_grid.SetFlatCopies();
}
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ void CurvilinearGridRefinement::Compute()
rightRefinement,
bottomRefinement,
topRefinement,
m_grid.m_projection,
m_grid.GetProjection(),
localMRefinement,
localNRefinement);
// Copy the local grid into the refined grid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void meshkernel::CurvilinearGridSnapping::Compute()
continue;
}

m_grid.GetNode(snappedNodeIndex) = m_landBoundary.FindNearestPoint(currentPoint, m_grid.m_projection);
m_grid.GetNode(snappedNodeIndex) = m_landBoundary.FindNearestPoint(currentPoint, m_grid.GetProjection());

// Only shift the line points in the grid line/region if the current grid point differs from the
// grid point (at the same index) snapped to the boundary.
Expand Down
2 changes: 1 addition & 1 deletion libs/MeshKernel/src/Splines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Splines::Splines(CurvilinearGrid const& grid)
AddSpline(grid.GetNodeVectorAtM(m));
}

m_projection = grid.m_projection;
m_projection = grid.GetProjection();
}

/// add a new spline, return the index
Expand Down
Loading

0 comments on commit 2565db8

Please sign in to comment.