-
Notifications
You must be signed in to change notification settings - Fork 10
Add LinearSolver interface #489
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
27fda8e
f32d829
4be022e
ca1e55d
1ed535d
ea84d17
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| add_subdirectory(SparseMatrix) | ||
| add_subdirectory(DenseMatrix) | ||
| add_subdirectory(Vector) | ||
| add_subdirectory(Solver) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| if(GRIDKIT_ENABLE_RESOLVE) | ||
| gridkit_add_library( | ||
| resolve_system_solver | ||
| SOURCES ResolveSystemSolver.cpp | ||
| HEADERS ResolveSystemSolver.hpp | ||
| LINK_LIBRARIES PRIVATE ReSolve::ReSolve) | ||
| endif() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| #pragma once | ||
|
|
||
| #include <GridKit/LinearAlgebra/SparseMatrix/CsrMatrix.hpp> | ||
| #include <GridKit/ScalarTraits.hpp> | ||
|
|
||
| #include "GridKit/LinearAlgebra/Vector/Vector.hpp" | ||
|
|
||
| namespace GridKit | ||
| { | ||
| namespace LinearAlgebra | ||
| { | ||
|
|
||
| /** | ||
| * @brief An interface for linear solvers to be used in GridKit, such as in \ref Integrator::Rosenbrock. | ||
| * | ||
| */ | ||
| template <class ScalarT, typename IdxT> | ||
| class LinearSolver | ||
| { | ||
| public: | ||
| using RealT = GridKit::ScalarTraits<ScalarT>::RealT; | ||
|
|
||
| /** | ||
| * @brief Configure the solver by analyzing the given matrix. The sparsity pattern of the given matrix must be set, and future calls | ||
| * to other methods will use this sparsity pattern, as well as the data pointer of the given matrix. | ||
| * | ||
| * @param matrix The matrix to configure the solver with. | ||
| * @return int An error code, or 0 if none. | ||
| */ | ||
| virtual int configureSolver(GridKit::LinearAlgebra::CsrMatrix<RealT, IdxT>& matrix) = 0; | ||
| /** | ||
| * @brief Setup the solver with matrix data. | ||
| * | ||
| * @param reuse_factors If true, factors from a previous call to `setupSolver()` are reused. | ||
| * @pre \ref configureSolver() must be called first and every time the sparsity pattern of the matrix changes. | ||
| * @pre If `reuse_factors` is true, then `setupSolver` must have been called once before with the same sparsity pattern. | ||
| * @return int An error code, or 0 if none. | ||
| */ | ||
| virtual int setupSolver(bool reuse_factors = false) = 0; | ||
| /** | ||
| * @brief Perform a linear solve using the configured matrix. | ||
| * | ||
| * @param rhs The right-hand-side vector (input). No data is changed. | ||
| * @param lhs The left-hand-side vector (output). | ||
| * @pre \ref setupSolver must be called first and every time the data of the matrix changes. | ||
| * @return int An error code, or 0 if none. | ||
| * | ||
| * @todo The data of the `rhs` parameter doesn't change, but we can't mark as cosntant because ReSolve currently requires | ||
| * a non-`const` pointer for vectors, even if it will only read from that vector. In the future this might change, so this | ||
| * can be updated to be `const`. | ||
| */ | ||
| virtual int solve(GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& rhs, GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& lhs) = 0; | ||
| }; | ||
| } // namespace LinearAlgebra | ||
| } // namespace GridKit |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,105 @@ | ||||||||||||||||||||||||||||||||||
| #include "ResolveSystemSolver.hpp" | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #include "GridKit/MemoryUtilities/MemoryUtils.hpp" | ||||||||||||||||||||||||||||||||||
| #include <resolve/vector/Vector.hpp> | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| namespace GridKit | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| namespace LinearAlgebra | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @brief Helper function to convert GridKit `MemorySpace` into ReSolve `MemorySpace`. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| ReSolve::memory::MemorySpace memorySpaceAsResolve(memory::MemorySpace memspace) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| switch (memspace) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| case memory::HOST: | ||||||||||||||||||||||||||||||||||
| return ReSolve::memory::HOST; | ||||||||||||||||||||||||||||||||||
| case memory::DEVICE: | ||||||||||||||||||||||||||||||||||
| return ReSolve::memory::DEVICE; | ||||||||||||||||||||||||||||||||||
| default: | ||||||||||||||||||||||||||||||||||
| throw "Memory space not supported"; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| template <class ScalarT, typename IdxT> | ||||||||||||||||||||||||||||||||||
| ResolveSystemSolver<ScalarT, IdxT>::ResolveSystemSolver(ReSolve::SystemSolver& lin_solver, GridKit::memory::MemorySpace memspace) | ||||||||||||||||||||||||||||||||||
| : lin_solver_(lin_solver), memspace_(memorySpaceAsResolve(memspace)) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @brief Creates a new ReSolve matrix with the dimensions of the given matrix, then sets its data pointers to those of the given matrix. | ||||||||||||||||||||||||||||||||||
| * Sets up the linear solver to use this new ReSolve matrix. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| * @todo Right now preconditioning doesn't work. There should be a ReSolve PR soon for this. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| template <class ScalarT, typename IdxT> | ||||||||||||||||||||||||||||||||||
| int ResolveSystemSolver<ScalarT, IdxT>::configureSolver(GridKit::LinearAlgebra::CsrMatrix<RealT, IdxT>& matrix) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| matrix_ = std::make_unique<ReSolve::matrix::Csr>(matrix.getNumRows(), matrix.getNumColumns(), matrix.getNnz()); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = matrix_->setDataPointers(matrix.getRowData(), matrix.getColData(), matrix.getValues(), memspace_)) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = lin_solver_.setMatrix(matrix_.get())) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = lin_solver_.analyze()) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| // TODO: This function needs to be called to properly use a preconditioner in ReSolve (if there is any), but currently will error | ||||||||||||||||||||||||||||||||||
| // if there is no preconditioner configured. Once we can detect if a preconditioner is configured, we can restore this functionality. | ||||||||||||||||||||||||||||||||||
| // Also, we will always want to use *right* preconditioning. | ||||||||||||||||||||||||||||||||||
| // BUBBLE_FAIL(lin_solver_.preconditionerSetup("right")); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| template <class ScalarT, typename IdxT> | ||||||||||||||||||||||||||||||||||
| int ResolveSystemSolver<ScalarT, IdxT>::setupSolver(bool reuse_factors) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| if (reuse_factors) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| if (int err = lin_solver_.refactorize()) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+69
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe there should be a third option
Suggested change
Might be a good idea to have an enum instead of multiple boolean flags. |
||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| if (int err = lin_solver_.factorize()) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||
| * @brief Perform the solver by creating two new ReSolve vectors and setting their data to point to their GridKit counterparts. | ||||||||||||||||||||||||||||||||||
| * Then ask ReSolve to perform the solve. Since the matrix should be pointing at the correct GridKit buffers and the vectors | ||||||||||||||||||||||||||||||||||
| * as well, this solve should correctly fill `lhs`'s data buffer. | ||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||
| template <class ScalarT, typename IdxT> | ||||||||||||||||||||||||||||||||||
| int ResolveSystemSolver<ScalarT, IdxT>::solve(GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& rhs, GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& lhs) | ||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||
| ReSolve::vector::Vector resolve_rhs(rhs.getSize()); | ||||||||||||||||||||||||||||||||||
| ReSolve::vector::Vector resolve_lhs(lhs.getSize()); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = resolve_rhs.setData(rhs.getData(), memspace_)) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = resolve_lhs.setData(lhs.getData(), memspace_)) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if (int err = lin_solver_.solve(&resolve_rhs, &resolve_lhs)) | ||||||||||||||||||||||||||||||||||
| return err; | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+88
to
+98
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really don't like
Suggested change
Even better would be if that constructor is made private and we implement method |
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| return 0; | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| template class ResolveSystemSolver<double, int>; | ||||||||||||||||||||||||||||||||||
| } // namespace LinearAlgebra | ||||||||||||||||||||||||||||||||||
| } // namespace GridKit | ||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| #pragma once | ||
|
|
||
| #include <memory> | ||
|
|
||
| #include <GridKit/LinearAlgebra/Solver/LinearSolver.hpp> | ||
|
|
||
| #include <resolve/MemoryUtils.hpp> | ||
| #include <resolve/SystemSolver.hpp> | ||
| #include <resolve/matrix/Csr.hpp> | ||
|
|
||
| namespace GridKit | ||
| { | ||
| namespace LinearAlgebra | ||
| { | ||
| template <class ScalarT, typename IdxT> | ||
| class ResolveSystemSolver : public LinearSolver<ScalarT, IdxT> | ||
| { | ||
| public: | ||
| using RealT = LinearSolver<ScalarT, IdxT>::RealT; | ||
|
|
||
| ResolveSystemSolver(ReSolve::SystemSolver& lin_solver, GridKit::memory::MemorySpace memspace = GridKit::memory::HOST); | ||
|
|
||
| int configureSolver(GridKit::LinearAlgebra::CsrMatrix<RealT, IdxT>& matrix) final; | ||
| int setupSolver(bool reuse_factors = false) final; | ||
| int solve(GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& rhs, GridKit::LinearAlgebra::Vector<ScalarT, IdxT>& lhs) final; | ||
|
|
||
| private: | ||
| /** | ||
| * @brief The ReSolve matrix used for the linear solve. Its data pointers should just point to a \ref GridKit::LinearAlgebra::CsrMatrix. | ||
| * | ||
| */ | ||
| std::unique_ptr<ReSolve::matrix::Csr> matrix_; | ||
| /** | ||
| * @brief The ReSolve linear solver to use. | ||
| * | ||
| */ | ||
| ReSolve::SystemSolver& lin_solver_; | ||
| /** | ||
| * @brief The memspace the data is stored in. | ||
| * | ||
| */ | ||
| ReSolve::memory::MemorySpace memspace_; | ||
| }; | ||
| } // namespace LinearAlgebra | ||
| } // namespace GridKit |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| #include "AdaptiveStep.hpp" | ||
|
|
||
| #include <algorithm> | ||
| #include <cmath> | ||
|
|
||
| #include <GridKit/Constants.hpp> | ||
|
|
||
| namespace AnalysisManager | ||
| { | ||
| namespace NativeDynamicSolver | ||
| { | ||
| /** | ||
| * @brief Standard textbook adaptive controller. Accept if `err <= 1` and use | ||
| * | ||
| * \f[h_{new} = h * \min \left\{fac_{max}, \max\left\{fac_{min}, fac_{scale} \cdot e ^{-1/p}\right\}\right\}.\f] | ||
| * | ||
| */ | ||
| template <typename RealT> | ||
| StepControl<RealT> AdaptiveStep<RealT>::nextStep(RealT err, StepControl<RealT> prev_step, uint8_t method_order) | ||
| { | ||
| StepControl<RealT> next_step = prev_step; | ||
|
|
||
| double h_mult = std::min(params_.fac_max_, std::max(params_.fac_scale_ * std::pow(err, GridKit::MINUS_ONE<RealT> / method_order), params_.fac_min_)); | ||
|
|
||
| next_step.accept_ = err <= 1; | ||
| next_step.step_size_ *= h_mult; | ||
|
|
||
| return next_step; | ||
| } | ||
|
|
||
| template class AdaptiveStep<double>; | ||
| } // namespace NativeDynamicSolver | ||
| } // namespace AnalysisManager |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You really don't need this. The
SystemSolverclass will manage host/device memory spaces under the hood.In the PR the
memspace_is used only to set vector/matrix views. I would just mark those places as@todoto remove them when we improve linear algebra support in GridKit. Better to merge this PR now and address these issues in the next PR.