From 21bbdec20f80a7bde2229cb80a1956df5b09eff4 Mon Sep 17 00:00:00 2001
From: acrovato <39187559+acrovato@users.noreply.github.com>
Date: Tue, 1 Mar 2022 14:58:45 +0100
Subject: [PATCH] Add interface for Intel DSS

---
 tbox/_src/tboxw.h |   1 +
 tbox/_src/tboxw.i |   2 +
 tbox/src/tbox.h   |   1 +
 tbox/src/wDss.cpp | 100 ++++++++++++++++++++++++++++++++++++++++++++++
 tbox/src/wDss.h   |  61 ++++++++++++++++++++++++++++
 5 files changed, 165 insertions(+)
 create mode 100644 tbox/src/wDss.cpp
 create mode 100644 tbox/src/wDss.h

diff --git a/tbox/_src/tboxw.h b/tbox/_src/tboxw.h
index b9feacd..3da0640 100644
--- a/tbox/_src/tboxw.h
+++ b/tbox/_src/tboxw.h
@@ -25,6 +25,7 @@
 #include "wCacheQuad4.h"
 #include "wCacheTetra4.h"
 #include "wCacheTri3.h"
+#include "wDss.h"
 #include "wElement.h"
 #include "wFct0.h"
 #include "wFct1.h"
diff --git a/tbox/_src/tboxw.i b/tbox/_src/tboxw.i
index 36e9d5a..94acd7f 100644
--- a/tbox/_src/tboxw.i
+++ b/tbox/_src/tboxw.i
@@ -156,6 +156,8 @@ namespace std {
 %include "wLinearSolver.h"
 %shared_ptr(tbox::Pardiso);
 %include "wPardiso.h"
+%shared_ptr(tbox::Dss);
+%include "wDss.h"
 %shared_ptr(tbox::Mumps);
 %include "wMumps.h"
 %shared_ptr(tbox::SparseLu);
diff --git a/tbox/src/tbox.h b/tbox/src/tbox.h
index b6814d4..d136502 100644
--- a/tbox/src/tbox.h
+++ b/tbox/src/tbox.h
@@ -99,6 +99,7 @@ class Linesearch;
 // Linear solvers
 class LinearSolver;
 class Pardiso;
+class Dss;
 class Mumps;
 class SparseLu;
 class Gmres;
diff --git a/tbox/src/wDss.cpp b/tbox/src/wDss.cpp
new file mode 100644
index 0000000..c412f3c
--- /dev/null
+++ b/tbox/src/wDss.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2020 University of Liège
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wDss.h"
+#ifdef USE_MKL
+
+using namespace tbox;
+
+Dss::Dss() : LinearSolver()
+{
+    handle = NULL;
+    MKL_INT opt = MKL_DSS_MSG_LVL_INFO + MKL_DSS_TERM_LVL_FATAL + MKL_DSS_ZERO_BASED_INDEXING; // continue exec until non-recoverable (fatal) error
+    print(dss_create(handle, opt));
+}
+Dss::~Dss()
+{
+    if (handle)
+    {
+        MKL_INT opt = MKL_DSS_DEFAULTS;
+        print(dss_delete(handle, opt));
+        handle = NULL;
+    }
+}
+
+void Dss::analyze(Eigen::SparseMatrix<double> const &A)
+{
+    // Check that matrix A is square
+    if (A.rows() != A.cols())
+        throw std::runtime_error("tbox::Dss: Matrix A is not square!\n");
+    // Convert to CRS
+    Eigen::SparseMatrix<double, Eigen::RowMajor> AA = A;
+    if (!AA.isCompressed())
+        AA.makeCompressed();
+
+    // Build data structure
+    MKL_INT opt = MKL_DSS_NON_SYMMETRIC;        // consider MKL_DSS_SYMMETRIC and MKL_DSS_SYMMETRIC_STRUCTURE
+    MKL_INT n = AA.rows();                      // matrix size (number of rows and columns)
+    MKL_INT nz = AA.nonZeros();                 // number of non-zero entries
+    const MKL_INT *rStart = AA.outerIndexPtr(); // starting index of non-zero entry for a row
+    const MKL_INT *cIndex = AA.innerIndexPtr(); // index of column of non-zero entry
+    print(dss_define_structure(handle, opt, rStart, n, n, cIndex, nz));
+
+    // Define reordering
+    opt = MKL_DSS_AUTO_ORDER;
+    print(dss_reorder(handle, opt, 0));
+}
+void Dss::factorize(Eigen::SparseMatrix<double> const &A)
+{
+    Eigen::SparseMatrix<double, Eigen::RowMajor> AA = A;
+    MKL_INT opt = MKL_DSS_INDEFINITE;
+    const double *val = AA.valuePtr();
+    print(dss_factor_real(handle, opt, val));
+}
+void Dss::solve(Eigen::Map<Eigen::VectorXd> const &b, Eigen::Map<Eigen::VectorXd> &x)
+{
+    MKL_INT opt = MKL_DSS_DEFAULTS;
+    MKL_INT n = 1; // number of rhs
+    const double *rhs = b.data();
+    double *sol = x.data();
+    print(dss_solve_real(handle, opt, rhs, n, sol));
+}
+void Dss::compute(Eigen::SparseMatrix<double> const &A, Eigen::Map<Eigen::VectorXd> const &b, Eigen::Map<Eigen::VectorXd> &x)
+{
+    this->analyze(A);
+    this->factorize(A);
+    this->solve(b, x);
+}
+
+/**
+ * @brief Print status code
+ */
+void Dss::print(int cod)
+{
+    if (cod != MKL_DSS_SUCCESS)
+    {
+        std::stringstream err;
+        err << "tbox::Dss: DSS returned code " << cod << "\n";
+        throw std::runtime_error(err.str());
+    }
+}
+
+void Dss::write(std::ostream &out) const
+{
+    out << "DSS (MKL)" << std::endl;
+}
+
+#endif // USE_MKL
diff --git a/tbox/src/wDss.h b/tbox/src/wDss.h
new file mode 100644
index 0000000..a7e3d2d
--- /dev/null
+++ b/tbox/src/wDss.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2020 University of Liège
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WDSS_H
+#define WDSS_H
+
+#include "tbox.h"
+#ifdef USE_MKL
+
+#include "wLinearSolver.h"
+#include <mkl_dss.h>
+#include <Eigen/Sparse>
+#include <limits>
+
+namespace tbox
+{
+/**
+ * @brief Intel DSS (PARDISO) interface
+ * @authors Adrien Crovato
+ */
+class TBOX_API Dss : public LinearSolver
+{
+    void *handle; // DSS handle
+
+    void print(int cod);
+
+public:
+    Dss();
+    ~Dss();
+
+#ifndef SWIG
+    virtual void analyze(Eigen::SparseMatrix<double> const &A) override;
+    virtual void factorize(Eigen::SparseMatrix<double> const &A) override;
+    virtual void solve(Eigen::Map<Eigen::VectorXd> const &b, Eigen::Map<Eigen::VectorXd> &x) override;
+    virtual void compute(Eigen::SparseMatrix<double> const &A, Eigen::Map<Eigen::VectorXd> const &b, Eigen::Map<Eigen::VectorXd> &x) override;
+
+    virtual double getError() override { return std::numeric_limits<double>::epsilon(); }
+    virtual int getIterations() override { return 1; }
+
+    virtual void write(std::ostream &out) const override;
+#endif
+};
+
+} // namespace tbox
+
+#endif // USE_MKL
+
+#endif // WDSS_H
\ No newline at end of file
-- 
GitLab