#ifndef SPATIALDISCRETIZATION2D_HPP #define SPATIALDISCRETIZATION2D_HPP #include #include #include #include #include #include #include #include "BoundaryCondition.hpp" #include "Mesh2D.hpp" using SparseMatrixRM = Eigen::SparseMatrix; namespace spatial { // Pointer required for run-time polymorphism and to be used in different instances of the class using BoundaryConditions = std::unordered_map>; class SpatialDiscretization2D { private: // TODO: Study change from reference to mesh to using a shared_ptr or even removing mesh altogether. const Mesh2D& mesh_; protected: std::function source_; std::function alpha_; // Sparse matrix and tripletlist for assembly SparseMatrixRM matrix_; std::vector> tripletList; Eigen::VectorXd b_; // Mappings for nodes in the local, reduced space (Dirichlet nodes are removed) std::vector local_to_global_; std::vector global_to_local_; // Check if node has prescribed Dirichlet BCs std::vector is_dirichlet_; // Store boundary conditions std::array, 4> boundary_conditions_; bool hasNeumann = false; public: SpatialDiscretization2D(std::function alpha, const Mesh2D& mesh, BoundaryConditions boundary_conditions, std::function source) : alpha_(alpha), mesh_(mesh), source_(source), global_to_local_(mesh_.getNodes().size(), - 1), is_dirichlet_(mesh_.getNodes().size(), false) { // Convert boundary conditions from unordered_map to array for easier access. Check that all sides are present. const std::array all_sides = { DomainSide::Left, DomainSide::Right, DomainSide::Bottom, DomainSide::Top }; for (DomainSide side : all_sides) { const auto it = boundary_conditions.find(side); if (it == boundary_conditions.end()) { throw std::invalid_argument("Missing boundary condition for one or more domain sides."); } boundary_conditions_[sideToIndex(side)] = it->second; } }; virtual ~SpatialDiscretization2D() = default; // Discretize and build matrix A and vector b virtual void buildMappings() = 0; virtual void discretize() = 0; virtual void applyLaplacian() = 0; virtual void applyBoundaryConditions() = 0; virtual void updateRHS(double t) = 0; // Solves Au = b for steady-state problems. For time-dependent PDEs, this is unused. virtual Eigen::VectorXd solveSteadyState() = 0; virtual Eigen::VectorXd reduce(std::function) = 0; virtual Eigen::VectorXd fillDirichletNodes(const Eigen::Ref&, double) const = 0; // Getters inline const SparseMatrixRM& getMatrix() const {return matrix_;}; inline const Eigen::VectorXd& getVector() const {return b_;}; inline const BoundaryCondition& getBoundaryCondition(DomainSide side) const {return *boundary_conditions_[sideToIndex(side)];} inline bool isSPD() const {return !hasNeumann;}; }; }; // namespace #endif // ifndef SPATIALDISCRETIZATION2D_HPP