Research-Stack/2-Search-Space/simulations/heat-2D/heat2D/Mesh2D/StructuredMesh2D.cpp

132 lines
4 KiB
C++

#include <iostream>
#include <optional>
#include <stdexcept>
#include "StructuredMesh2D.hpp"
namespace spatial
{
StructuredMesh2D::StructuredMesh2D(double left, double right, double bottom, double top, int nx, int ny)
: Mesh2D(left, right, bottom, top)
{
if (nx <= 1 || ny <= 1) throw std::invalid_argument("Number of nodes must be positive and greater than 1.");
nx_ = nx;
ny_ = ny;
std::cout << "\nCreating StructuredMesh2D with domain [" << left << ", " << right << "] x [" << bottom << ", " << top << "] and " << nx_ << " x " << ny_ << " nodes...\n";
meshDomain();
std::cout << " -> StructuredMesh2D created with " << nodes_.size() << " nodes (" << inner_nodes_.size() << " inner, " << boundary_nodes_.size() << " boundary).\n";
};
StructuredMesh2D::StructuredMesh2D(const Domain2D& domain, int nx, int ny)
: StructuredMesh2D(domain.left_, domain.right_, domain.bottom_, domain.top_, nx, ny) {};
void StructuredMesh2D::meshDomain()
{
double dx = getDx(), dy = getDy();
nodes_.reserve(nx_ * ny_);
inner_nodes_.reserve((nx_ - 2) * (ny_ - 2));
boundary_nodes_.reserve(2 * (nx_ + ny_) - 4);
node_to_boundary_node_.resize(nx_ * ny_, -1);
boundaries_[sideToIndex(DomainSide::Left)].reserve(ny_);
boundaries_[sideToIndex(DomainSide::Right)].reserve(ny_);
boundaries_[sideToIndex(DomainSide::Bottom)].reserve(nx_);
boundaries_[sideToIndex(DomainSide::Top)].reserve(nx_);
int boundary_node = 0;
for (int row = 0; row < ny_; ++row)
{
for (int col = 0; col < nx_; ++col)
{
int nodeID = nx_ * row + col;
double x = domain_.left_ + col * dx;
double y = domain_.bottom_ + row * dy;
nodes_.push_back(Node2D{nodeID, x, y});
std::vector<DomainSide> sides;
if (col == 0)
{
boundaries_[sideToIndex(DomainSide::Left)].push_back(nodeID);
sides.push_back(DomainSide::Left);
}
if (col == nx_ - 1)
{
boundaries_[sideToIndex(DomainSide::Right)].push_back(nodeID);
sides.push_back(DomainSide::Right);
}
if (row == 0)
{
boundaries_[sideToIndex(DomainSide::Bottom)].push_back(nodeID);
sides.push_back(DomainSide::Bottom);
}
if (row == ny_ - 1)
{
boundaries_[sideToIndex(DomainSide::Top)].push_back(nodeID);
sides.push_back(DomainSide::Top);
}
if (sides.empty()) inner_nodes_.push_back(nodeID);
else
{
node_to_boundary_node_[nodeID] = boundary_node;
boundary_node++;
boundary_nodes_.push_back(BoundaryNode2D{nodeID, x, y, sides});
}
}
}
for (int i = 0; i < nodes_.size(); ++i)
{
if (nodes_[i].nodeID_ != i)
{
throw std::logic_error("Mesh2D invariant violated: nodeID_ must match nodes_ index.");
}
}
};
std::optional<int> StructuredMesh2D::getNodeID(int i, int j) const
{
if (i < 0 || i >= nx_ || j < 0 || j >= ny_) return std::nullopt;
return j * nx_ + i;
};
std::optional<int> StructuredMesh2D::getNeighbor(int nodeID, DomainSide side) const
{
switch (side)
{
case DomainSide::Left:
if (nodeID % nx_ == 0) return std::nullopt;
return nodeID - 1;
case DomainSide::Right:
if ((nodeID + 1) % nx_ == 0) return std::nullopt;
return nodeID + 1;
case DomainSide::Bottom:
if ((nodeID - nx_) < 0) return std::nullopt;
return nodeID - nx_;
case DomainSide::Top:
if ((nodeID + nx_) > nx_ * ny_ - 1) return std::nullopt;
return nodeID + nx_;
default:
return std::nullopt;
}
};
bool StructuredMesh2D::isCorner(int nodeID) const
{
return nodeID == 0 || nodeID == nx_ - 1 || nodeID == nx_ * (ny_ - 1) || nodeID == ny_ * nx_ - 1;
}
} // namespace