diff --git a/.github/workflows/continuous.yml b/.github/workflows/continuous.yml index 5f5f5244..493bdc01 100644 --- a/.github/workflows/continuous.yml +++ b/.github/workflows/continuous.yml @@ -42,13 +42,14 @@ jobs: libglu1-mesa-dev \ xorg-dev \ mpi \ - ccache + ccache \ + libsuitesparse-dev echo 'CACHE_PATH=~/.ccache' >> "$GITHUB_ENV" - name: Dependencies (macOS) if: runner.os == 'macOS' run: | - brew install ccache open-mpi + brew install ccache open-mpi suitesparse echo 'CACHE_PATH=~/Library/Caches/ccache' >> "$GITHUB_ENV" - name: Cache Build diff --git a/CMakeLists.txt b/CMakeLists.txt index 474ef9ba..f5bd5435 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -74,6 +74,7 @@ option(POLYSOLVE_WITH_ACCELERATE "Enable Apple Accelerate" ${POLYSOLVE_ON_APP option(POLYSOLVE_WITH_CHOLMOD "Enable Cholmod library" ON) option(POLYSOLVE_WITH_UMFPACK "Enable UmfPack library" ON) option(POLYSOLVE_WITH_SUPERLU "Enable SuperLU library" ON) +option(POLYSOLVE_WITH_SPQR "Enable SPQR library" ON) option(POLYSOLVE_WITH_MKL "Enable MKL library" ${POLYSOLVE_NOT_ON_APPLE_SILICON}) option(POLYSOLVE_WITH_CUSOLVER "Enable cuSOLVER library" OFF) option(POLYSOLVE_WITH_PARDISO "Enable Pardiso library" OFF) @@ -269,6 +270,17 @@ if(POLYSOLVE_WITH_SUPERLU) endif() endif() +# SuperLU solver +if(POLYSOLVE_WITH_SPQR) + include(spqr) + if(TARGET SuiteSparse::SPQR) + target_link_libraries(polysolve_linear PRIVATE SuiteSparse::SPQR) + target_compile_definitions(polysolve_linear PUBLIC POLYSOLVE_WITH_SPQR) + else() + message(WARNING "SPQR Not found, solver will not be available.") + endif() +endif() + # AMGCL solver if(POLYSOLVE_WITH_AMGCL) include(amgcl) diff --git a/cmake/recipes/boost.cmake b/cmake/recipes/boost.cmake index 5c5cd09c..07a9154e 100644 --- a/cmake/recipes/boost.cmake +++ b/cmake/recipes/boost.cmake @@ -20,7 +20,9 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(OLD_CMAKE_POSITION_INDEPENDENT_CODE ${CMAKE_POSITION_INDEPENDENT_CODE}) set(CMAKE_POSITION_INDEPENDENT_CODE ON) -set(BOOST_URL "https://boostorg.jfrog.io/artifactory/main/release/1.83.0/source/boost_1_83_0.tar.bz2" CACHE STRING "Boost download URL") +set(BOOST_URL + "https://archives.boost.io/release/1.83.0/source/boost_1_83_0.tar.bz2" + CACHE STRING "Boost download URL") set(BOOST_URL_SHA256 "6478edfe2f3305127cffe8caf73ea0176c53769f4bf1585be237eb30798c3b8e" CACHE STRING "Boost download URL SHA256 checksum") include(CPM) diff --git a/cmake/recipes/spqr.cmake b/cmake/recipes/spqr.cmake new file mode 100644 index 00000000..05cb74de --- /dev/null +++ b/cmake/recipes/spqr.cmake @@ -0,0 +1,11 @@ +# SPQR solver + +if(TARGET SparseSuite::SPQR) + return() +endif() + +message(STATUS "Third-party: creating targets 'SuiteSparse::SPQR'") + +# We do not have a build recipe for this, so find it as a system installed library. +find_package(SPQR) + diff --git a/src/polysolve/linear/Solver.cpp b/src/polysolve/linear/Solver.cpp index 25595bea..e7c0c259 100644 --- a/src/polysolve/linear/Solver.cpp +++ b/src/polysolve/linear/Solver.cpp @@ -11,6 +11,12 @@ #include // ----------------------------------------------------------------------------- +// +// Subsequent macros assume a single template parameter and SparseQR fails due to requiring 2 parameters. this is because the OrderingType is not filled in. +// SparseLU has a default declaration of _OrderingType to use COLAMDOrdering but SparseQR doesn't - so this just mimics that behavior. If Eigen adds such a default in the future this line will need to be guarded to avoid multiple defaults +namespace Eigen { +template > class SparseQR; +} #include #ifdef POLYSOLVE_WITH_ACCELERATE #include @@ -21,6 +27,24 @@ #ifdef POLYSOLVE_WITH_UMFPACK #include #endif +#ifdef POLYSOLVE_WITH_SPQR +#include +namespace polysolve::linear { + template <> + void EigenDirect>::analyze_pattern(const StiffnessMatrix& A, const int precond_num) { + m_Solver.compute(A); + } + template <> + void EigenDirect>::factorize(const StiffnessMatrix &A) + { + m_Solver.compute(A); + if (m_Solver.info() == Eigen::NumericalIssue) + { + throw std::runtime_error("[EigenDirect] NumericalIssue encountered."); + } + } +} +#endif #ifdef POLYSOLVE_WITH_SUPERLU #include #endif @@ -293,6 +317,10 @@ namespace polysolve::linear else if (solver == "Eigen::SparseLU") { RETURN_DIRECT_SOLVER_PTR(SparseLU, "Eigen::SparseLU"); + } + else if (solver == "Eigen::SparseQR") + { + RETURN_DIRECT_SOLVER_PTR(SparseQR, "Eigen::SparseQR"); #ifdef POLYSOLVE_WITH_ACCELERATE } else if (solver == "Eigen::AccelerateLLT") @@ -335,6 +363,12 @@ namespace polysolve::linear { RETURN_DIRECT_SOLVER_PTR(SuperLU, "Eigen::SuperLU"); #endif +#ifdef POLYSOLVE_WITH_SPQR + } + else if (solver == "Eigen::SPQR") + { + RETURN_DIRECT_SOLVER_PTR(SPQR, "Eigen::SPQR"); +#endif #ifdef POLYSOLVE_WITH_MKL } else if (solver == "Eigen::PardisoLLT") @@ -465,6 +499,7 @@ namespace polysolve::linear return {{ "Eigen::SimplicialLDLT", "Eigen::SparseLU", + "Eigen::SparseQR", #ifdef POLYSOLVE_WITH_ACCELERATE "Eigen::AccelerateLLT", "Eigen::AccelerateLDLT", @@ -481,6 +516,9 @@ namespace polysolve::linear #ifdef POLYSOLVE_WITH_SUPERLU "Eigen::SuperLU", #endif +#ifdef POLYSOLVE_WITH_SPQR + "Eigen::SPQR", +#endif #ifdef POLYSOLVE_WITH_MKL "Eigen::PardisoLLT", "Eigen::PardisoLDLT",