#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "../Math/Vector.h" #include "GridTypes.h" class vtkMPIController; namespace VofFlow { class DomainInfo { public: struct NeighborInfo { int processId = 0; std::bitset<6> flags; extent_t zeroExtent{}; bounds_t zeroBounds{}; }; explicit DomainInfo(vtkRectilinearGrid* grid, vtkMPIController* mpiController = nullptr); [[nodiscard]] inline vtkRectilinearGrid* grid() const { return grid_; } [[nodiscard]] inline const extent_t& localExtent() const { return localExtent_; } [[nodiscard]] inline const extent_t& localZeroExtent() const { return localZeroExtent_; } [[nodiscard]] inline const extent_t& globalExtent() const { return globalExtent_; } [[nodiscard]] inline const bounds_t& localBounds() const { return localBounds_; } [[nodiscard]] inline const bounds_t& localZeroBounds() const { return localZeroBounds_; } [[nodiscard]] inline const bounds_t& globalBounds() const { return globalBounds_; } [[nodiscard]] inline const dim_t& cellDims() const { return dims_; } [[nodiscard]] inline bool isUniform() const { return isUniform_; } [[nodiscard]] inline bool isParallel() const { return isParallel_; } [[nodiscard]] inline const vtkSmartPointer& ghostArray() const { return ghostArray_; } [[nodiscard]] inline const std::vector& coordsX() const { return coordsX_; } [[nodiscard]] inline const std::vector& coordsY() const { return coordsY_; } [[nodiscard]] inline const std::vector& coordsZ() const { return coordsZ_; } [[nodiscard]] inline const std::vector& cellSizesX() const { return cellSizesX_; } [[nodiscard]] inline const std::vector& cellSizesY() const { return cellSizesY_; } [[nodiscard]] inline const std::vector& cellSizesZ() const { return cellSizesZ_; } [[nodiscard]] inline const std::vector& cellCentersX() const { return cellCentersX_; } [[nodiscard]] inline const std::vector& cellCentersY() const { return cellCentersY_; } [[nodiscard]] inline const std::vector& cellCentersZ() const { return cellCentersZ_; } [[nodiscard]] inline const std::vector& neighbors() const { return neighbors_; } [[nodiscard]] inline const std::array, 6>& neighborsByDirection() const { return neighborsByDirection_; } [[nodiscard]] inline vtkIdType numCells() const { return static_cast(dims_[0]) * static_cast(dims_[1]) * static_cast(dims_[2]); } [[nodiscard]] inline posCoords_t coords(int x, int y, int z) const { return {coordsX_[x], coordsY_[y], coordsZ_[z]}; } [[nodiscard]] inline posCoords_t coords(gridCoords_t g_coords) const { return coords(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline vec3 coordsVec3(int x, int y, int z) const { return { static_cast(coordsX_[x]), static_cast(coordsY_[y]), static_cast(coordsZ_[z]), }; } [[nodiscard]] inline vec3 coordsVec3(gridCoords_t g_coords) const { return coordsVec3(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline posCoords_t cellSize(int g_x, int g_y, int g_z) const { return {cellSizesX_[g_x], cellSizesY_[g_y], cellSizesZ_[g_z]}; } [[nodiscard]] inline posCoords_t cellSize(gridCoords_t g_coords) const { return cellSize(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline vec3 cellSizeVec3(int g_x, int g_y, int g_z) const { return { static_cast(cellSizesX_[g_x]), static_cast(cellSizesY_[g_y]), static_cast(cellSizesZ_[g_z]), }; } [[nodiscard]] inline vec3 cellSizeVec3(gridCoords_t g_coords) const { return cellSizeVec3(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline posCoords_t cellCenter(int g_x, int g_y, int g_z) const { return {cellCentersX_[g_x], cellCentersY_[g_y], cellCentersZ_[g_z]}; } [[nodiscard]] inline posCoords_t cellCenter(gridCoords_t g_coords) const { return cellCenter(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline vec3 cellCenterVec3(int g_x, int g_y, int g_z) const { return { static_cast(cellCentersX_[g_x]), static_cast(cellCentersY_[g_y]), static_cast(cellCentersZ_[g_z]), }; } [[nodiscard]] inline vec3 cellCenterVec3(gridCoords_t g_coords) const { return cellCenterVec3(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline bool isInLocalExtent(const gridCoords_t& e_coords) const { return Grid::isInExtent(localExtent_, e_coords); } [[nodiscard]] inline bool isInLocalExtent(int e_x, int e_y, int e_z) const { return isInLocalExtent(gridCoords_t{e_x, e_y, e_z}); } [[nodiscard]] inline bool isInZeroExtent(const gridCoords_t& e_coords) const { return Grid::isInExtent(localZeroExtent_, e_coords); } [[nodiscard]] inline bool isInZeroExtent(int e_x, int e_y, int e_z) const { return isInZeroExtent(gridCoords_t{e_x, e_y, e_z}); } [[nodiscard]] inline bool isInZeroExtent(vtkIdType idx) const { return isInZeroExtent(idxToExtentCoord(idx)); } [[nodiscard]] inline vtkIdType gridCoordToIdx(int g_x, int g_y, int g_z) const { return static_cast(g_x) + static_cast(g_y) * static_cast(dims_[0]) + static_cast(g_z) * static_cast(dims_[0]) * static_cast(dims_[1]); } [[nodiscard]] inline vtkIdType gridCoordToIdx(const gridCoords_t& g_coords) const { return gridCoordToIdx(g_coords[0], g_coords[1], g_coords[2]); } [[nodiscard]] inline gridCoords_t idxToGridCoord(vtkIdType idx) const { const int g_x = static_cast(idx % dims_[0]); const int g_y = static_cast((idx / dims_[0]) % dims_[1]); const int g_z = static_cast(idx / (dims_[0] * dims_[1])); return {g_x, g_y, g_z}; } [[nodiscard]] inline vtkIdType localExtentCoordToIdx(int e_x, int e_y, int e_z) const { if (!isInLocalExtent(e_x, e_y, e_z)) { throw std::runtime_error("Extent coord out of bounds!"); } return (e_x - localExtent_[0]) + (e_y - localExtent_[2]) * dims_[0] + (e_z - localExtent_[4]) * dims_[0] * dims_[1]; } [[nodiscard]] inline vtkIdType localExtentCoordToIdx(const gridCoords_t& e_coords) const { return localExtentCoordToIdx(e_coords[0], e_coords[1], e_coords[2]); } [[nodiscard]] inline gridCoords_t idxToExtentCoord(vtkIdType idx) const { const auto [g_x, g_y, g_z] = idxToGridCoord(idx); return {localExtent_[0] + g_x, localExtent_[2] + g_y, localExtent_[4] + g_z}; } [[nodiscard]] inline gridCoords_t localExtentCoordToGridCoord(int e_x, int e_y, int e_z) const { if (!isInLocalExtent(e_x, e_y, e_z)) { throw std::runtime_error("Extent coord out of bounds!"); } return {e_x - localExtent_[0], e_y - localExtent_[2], e_z - localExtent_[4]}; } [[nodiscard]] inline gridCoords_t localExtentCoordToGridCoord(const gridCoords_t& e_coords) const { return localExtentCoordToGridCoord(e_coords[0], e_coords[1], e_coords[2]); } [[nodiscard]] inline bool isInLocalBounds(const posCoords_t& pos) const { return Grid::isInBounds(localBounds_, pos); } [[nodiscard]] inline bool isInLocalBounds(double x, double y, double z) const { return isInLocalBounds(posCoords_t{x, y, z}); } [[nodiscard]] inline bool isInLocalBounds(const vec3& p) const { return isInLocalBounds(p.x, p.y, p.z); } [[nodiscard]] inline bool isInZeroBounds(const posCoords_t& pos) const { return Grid::isInBounds(localZeroBounds_, pos); } [[nodiscard]] inline bool isInZeroBounds(double x, double y, double z) const { return isInZeroBounds(posCoords_t{x, y, z}); } [[nodiscard]] inline bool isInZeroBounds(const vec3& p) const { return isInZeroBounds(p.x, p.y, p.z); } [[nodiscard]] inline bool isInGlobalBounds(const posCoords_t& pos) const { return Grid::isInBounds(globalBounds_, pos); } [[nodiscard]] inline bool isInGlobalBounds(double x, double y, double z) const { return isInGlobalBounds(posCoords_t{x, y, z}); } [[nodiscard]] inline bool isInGlobalBounds(const vec3& p) const { return isInGlobalBounds(p.x, p.y, p.z); } [[nodiscard]] inline int isOutOfZeroBoundsDirection(const vec3& p) const { return Grid::isOutOfBoundsDirection(localZeroBounds_, posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline std::optional computeStructuredCoordinates( const posCoords_t& p) const { StructuredCoordinates sc; if (computeStructuredCoordinates(coordsX_, p[0], sc.cellCoords[0], sc.relativeCoords[0]) && computeStructuredCoordinates(coordsY_, p[1], sc.cellCoords[1], sc.relativeCoords[1]) && computeStructuredCoordinates(coordsZ_, p[2], sc.cellCoords[2], sc.relativeCoords[2])) { return sc; } return std::nullopt; } [[nodiscard]] inline std::optional computeStructuredCoordinates(const vec3& p) const { return computeStructuredCoordinates(posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline StructuredCoordinates computeNearestStructuredCoordinates(const posCoords_t& p) const { StructuredCoordinates sc; computeStructuredCoordinates(coordsX_, p[0], sc.cellCoords[0], sc.relativeCoords[0]); computeStructuredCoordinates(coordsY_, p[1], sc.cellCoords[1], sc.relativeCoords[1]); computeStructuredCoordinates(coordsZ_, p[2], sc.cellCoords[2], sc.relativeCoords[2]); return sc; } [[nodiscard]] inline StructuredCoordinates computeNearestStructuredCoordinates(const vec3& p) const { return computeNearestStructuredCoordinates(posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline std::optional posToGridCoord(const posCoords_t& p) const { auto coords = computeStructuredCoordinates(p); if (coords.has_value()) { return coords.value().cellCoords; } return std::nullopt; } [[nodiscard]] inline std::optional posToGridCoord(const vec3& p) const { return posToGridCoord(posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline gridCoords_t posToGridCoordEx(const posCoords_t& p) const { const auto cell = posToGridCoord(p); if (cell.has_value()) { return cell.value(); } throw std::runtime_error("Position is outside of grid bounds!"); } [[nodiscard]] inline gridCoords_t posToGridCoordEx(const vec3& p) const { return posToGridCoordEx(posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline std::optional posToIdx(const posCoords_t& p) const { const auto g_coords = posToGridCoord(p); if (g_coords.has_value()) { return gridCoordToIdx(g_coords.value()); } return std::nullopt; } [[nodiscard]] inline std::optional posToIdx(const vec3& p) const { return posToIdx(posCoords_t{p.x, p.y, p.z}); } [[nodiscard]] inline vtkIdType posToIdxEx(const posCoords_t& p) const { return gridCoordToIdx(posToGridCoordEx(p)); } [[nodiscard]] inline vtkIdType posToIdxEx(const vec3& p) const { return gridCoordToIdx(posToGridCoordEx(p)); } private: /** * VTK's `ComputeStructuredCoordinates()` is very slow. The two major points are the linear search and the * overhead from the GetComponent interface of the arrays. Here, we implement binary search and directly use * the std::vector coords. * Assumptions: coords is sorted and size >= 2. (Both checked in constructor.) */ inline bool computeStructuredCoordinates(const std::vector& coords, double pos, int& cell, double& pcoord) const { // If out of bounds return closest point. if (pos < coords.front()) { cell = 0; pcoord = 0.0; return false; } else if (pos >= coords.back()) { cell = static_cast(coords.size()) - 2; pcoord = 1.0; return false; } // Shortcut for uniform grids if (isUniform_) { double relative_pos = (pos - coords.front()) / (coords.back() - coords.front()); // [0, 1) relative_pos *= static_cast(coords.size() - 1); // [0, num_cells) double iptr = 0.0; pcoord = std::clamp(std::modf(relative_pos, &iptr), 0.0, 1.0); cell = std::clamp(static_cast(iptr), 0, static_cast(coords.size() - 1)); return true; } std::size_t left = 0; std::size_t right = coords.size() - 1; while (left + 1 < right) { const std::size_t mid = left + (right - left) / 2; if (pos < coords[mid]) { right = mid; } else { left = mid; } } cell = static_cast(left); pcoord = (pos - coords[left]) / (coords[right] - coords[left]); return true; } vtkSmartPointer grid_; extent_t localExtent_; // Extent of thread local grid. extent_t localZeroExtent_; // Extent of the thread local grid without ghost cells. extent_t globalExtent_; // Extent of the global grid across all threads. bounds_t localBounds_; // Bounds of the thread local grid domain. bounds_t localZeroBounds_; // Bounds of the thread local grid domain without ghost cells. bounds_t globalBounds_; // Bounds of the global grid domain across all threads. dim_t dims_; bool isUniform_; bool isParallel_; vtkSmartPointer ghostArray_; std::vector coordsX_; std::vector coordsY_; std::vector coordsZ_; std::vector cellSizesX_; std::vector cellSizesY_; std::vector cellSizesZ_; std::vector cellCentersX_; std::vector cellCentersY_; std::vector cellCentersZ_; std::vector neighbors_; std::array, 6> neighborsByDirection_; // list neighbors by direction }; } // namespace VofFlow