1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 // Authors: Dario Mangoni, Radu Serban
13 // =============================================================================
14 
15 
16 #include "chrono_pardisoproject/ChPardisoProjectEngine.h"
17 #include "chrono/parallel/ChOpenMP.h"
18 
19 
20 /* PARDISO prototype. */
21 extern "C" void pardisoinit (void   *, int    *,   int *, int *, double *, int *);
22 extern "C" void pardiso     (void   *, int    *,   int *, int *,    int *, int *,
23                   double *, int    *,    int *, int *,   int *, int *,
24                      int *, double *, double *, int *, double *);
25 extern "C" void pardiso_chkmatrix  (int *, int *, double *, int *, int *, int *);
26 extern "C" void pardiso_chkvec     (int *, int *, double *, int *);
27 extern "C" void pardiso_printstats (int *, int *, double *, int *, int *, int *, double *, int *);
28 extern "C" void pardiso_get_schur(void*, int*, int*, int*, double*, int*, int*);
29 
30 namespace chrono {
31 
ChPardisoProjectEngine(parproj_SYM symmetry)32 ChPardisoProjectEngine::ChPardisoProjectEngine(parproj_SYM symmetry) :symmetry(symmetry) {
33     Reinit();
34 }
35 
~ChPardisoProjectEngine()36 ChPardisoProjectEngine::~ChPardisoProjectEngine() {
37     PardisoProjectCall(parproj_PHASE::END);
38 }
39 
SetProblem(const ChSparseMatrix & Z,ChVectorRef rhs,ChVectorRef sol)40 void ChPardisoProjectEngine::SetProblem(const ChSparseMatrix& Z, ChVectorRef rhs, ChVectorRef sol) {
41     SetMatrix(Z);
42     SetRhsVector(rhs);
43     SetSolutionVector(sol);
44 }
45 
SetMatrix(const ChSparseMatrix & Z,bool isZeroIndexed)46 void ChPardisoProjectEngine::SetMatrix(const ChSparseMatrix& Z, bool isZeroIndexed) {
47     this->SetMatrix(
48         Z.rows(),
49         const_cast<int*>(Z.outerIndexPtr()),
50         const_cast<int*>(Z.innerIndexPtr()),
51         const_cast<double*>(Z.valuePtr()),
52         false
53     );
54     matOneIndexedFormat = !isZeroIndexed;
55 }
56 
SetMatrix(int n,int * ia,int * ja,double * a,bool isZeroIndexed)57 void ChPardisoProjectEngine::SetMatrix(int n, int *ia, int *ja, double *a, bool isZeroIndexed) {
58     this->n = n;
59     this->a = a;
60     this->ia = ia;
61     this->ja = ja;
62     matOneIndexedFormat = !isZeroIndexed;
63 }
64 
SetMatrixSymmetry(parproj_SYM symmetry)65 void ChPardisoProjectEngine::SetMatrixSymmetry(parproj_SYM symmetry) {
66     PardisoProjectCall(parproj_PHASE::END);
67     this->symmetry = symmetry;
68     Reinit();
69 }
70 
SetRhsVector(ChVectorRef b)71 void ChPardisoProjectEngine::SetRhsVector(ChVectorRef b) {
72     this->b = b.data();
73 }
74 
SetRhsVector(double * b)75 void ChPardisoProjectEngine::SetRhsVector(double* b) {
76     this->b = b;
77 }
78 
SetSolutionVector(ChVectorRef x)79 void ChPardisoProjectEngine::SetSolutionVector(ChVectorRef x) {
80     this->x = x.data();
81 }
82 
SetSolutionVector(double * x)83 void ChPardisoProjectEngine::SetSolutionVector(double* x) {
84     this->x = x;
85 }
86 
87 
PardisoProjectCall(parproj_PHASE phase)88 int ChPardisoProjectEngine::PardisoProjectCall(parproj_PHASE phase) {
89     int phase_int = phase;
90     int mtype_int = symmetry;
91 
92     SetOneIndexedFormat(); // make sure that is one-based format
93 
94     pardiso (pt, &maxfct, &mnum, &mtype_int, &phase_int, &n, a, ia, ja, &idum, &nrhs, iparm, &msglvl, b, x, &error,  dparm);
95 
96     return error;
97 }
98 
99 
CheckMatrix(bool print)100 int ChPardisoProjectEngine::CheckMatrix(bool print){
101     /* -------------------------------------------------------------------- */
102     /*  .. pardiso_chk_matrix(...)                                          */
103     /*     Checks the consistency of the given matrix.                      */
104     /*     Use this functionality only for debugging purposes               */
105     /* -------------------------------------------------------------------- */
106     bool matOneIndexedFormat_bkp = this->matOneIndexedFormat;
107     SetOneIndexedFormat();
108     int mtype_int = symmetry;
109     pardiso_chkmatrix(&mtype_int, &n, a, ia, ja, &error);
110     if (!matOneIndexedFormat_bkp) SetZeroIndexedFormat();
111 
112     if (error != 0) {
113         if (print)
114             printf("\nERROR in consistency of matrix: %d", error);
115         return error;
116     } else
117         printf("\nMatrix consistency check passed\n");
118     return error;
119 }
120 
CheckMatrixStats(bool print)121 int ChPardisoProjectEngine::CheckMatrixStats(bool print) {
122     /* -------------------------------------------------------------------- */
123     /* .. pardiso_printstats(...)                                           */
124     /*    prints information on the matrix to STDOUT.                       */
125     /*    Use this functionality only for debugging purposes                */
126     /* -------------------------------------------------------------------- */
127     bool matOneIndexedFormat_bkp = this->matOneIndexedFormat;
128     SetOneIndexedFormat();
129     int mtype_int = symmetry;
130     pardiso_printstats(&mtype_int, &n, a, ia, ja, &nrhs, b, &error);
131     if (!matOneIndexedFormat_bkp) SetZeroIndexedFormat();
132 
133     if (error != 0) {
134         if (print)
135             printf("\nERROR in matrix stats: %d", error);
136         return error;
137     } else
138         printf("\nMatrix stats passed\n");
139     return error;
140 }
141 
142 
CheckRhsVectors(bool print)143 int ChPardisoProjectEngine::CheckRhsVectors(bool print){
144     /* -------------------------------------------------------------------- */
145     /* ..  pardiso_chkvec(...)                                              */
146     /*     Checks the given vectors for infinite and NaN values             */
147     /*     Input parameters (see PARDISO user manual for a description):    */
148     /*     Use this functionality only for debugging purposes               */
149     /* -------------------------------------------------------------------- */
150     bool matOneIndexedFormat_bkp = this->matOneIndexedFormat;
151     SetOneIndexedFormat();
152     pardiso_chkvec (&n, &nrhs, b, &error);
153     if (!matOneIndexedFormat_bkp) SetZeroIndexedFormat();
154 
155     if (error != 0) {
156         if (print)
157             printf("\nERROR in right hand side: %d", error);
158         return error;
159     } else
160         printf("\nRhs check passed\n");
161     return error;
162 }
163 
GetSchurComplement(ChSparseMatrix & Z,int nrows)164 void ChPardisoProjectEngine::GetSchurComplement(ChSparseMatrix& Z, int nrows) {
165     SetIPARM(38-1, nrows);
166     PardisoProjectCall(ChPardisoProjectEngine::parproj_PHASE::ANALYZE_FACTORIZE);
167     int schurNNZ = GetIPARM(39-1);
168     Z.resize(nrows, nrows);
169     Z.reserve(schurNNZ);
170     int *iS, *jS;
171     double* S;
172     getMatrixInternalArrays(Z, &iS, &jS, &S);
173     int mtype_int = symmetry;
174     pardiso_get_schur(pt, &maxfct, &mnum, &mtype_int, S, iS, jS);
175 }
176 
shiftInternalMatrixIndices(int val)177 void ChPardisoProjectEngine::shiftInternalMatrixIndices(int val) {
178     shiftMatrixIndices(ia, ja, a, n, val, matOneIndexedFormat);
179 }
180 
shiftMatrixIndices(int * ext_ia,int * ext_ja,double * ext_a,int ext_n,int val,bool isOneIndexed)181 void ChPardisoProjectEngine::shiftMatrixIndices(int* ext_ia, int* ext_ja, double* ext_a, int ext_n, int val, bool isOneIndexed) {
182     int nnz = isOneIndexed ? ext_ia[ext_n]-1 : ext_ia[ext_n];
183     for (int i = 0; i < ext_n + 1; i++) {
184         ext_ia[i] += val;
185     }
186     for (int i = 0; i < nnz; i++) {
187         ext_ja[i] += val;
188     }
189 }
190 
getMatrixInternalArrays(ChSparseMatrix & sparseMat,int ** ext_ia,int ** ext_ja,double ** ext_a)191 bool ChPardisoProjectEngine::getMatrixInternalArrays(ChSparseMatrix& sparseMat, int** ext_ia, int** ext_ja, double** ext_a) {
192     *ext_ia = sparseMat.outerIndexPtr();
193     *ext_ja = sparseMat.innerIndexPtr();
194     *ext_a =  sparseMat.valuePtr();
195     return false;
196 }
197 
SetZeroIndexedFormat()198 inline void ChPardisoProjectEngine::SetZeroIndexedFormat() {
199     if (matOneIndexedFormat)
200         shiftInternalMatrixIndices(-1);
201     matOneIndexedFormat = false;
202 }
203 
SetOneIndexedFormat()204 inline void ChPardisoProjectEngine::SetOneIndexedFormat() {
205     if (!matOneIndexedFormat)
206         shiftInternalMatrixIndices(+1);
207     matOneIndexedFormat = true;
208 }
209 
210 /// Set the solver type. \p directsparse = true for direct sparse solver, false for multi-recursive iterative solver.
211 /// \warning{This function triggers a Reinit()}
212 
SetSolverType(bool directsparse)213 inline void ChPardisoProjectEngine::SetSolverType(bool directsparse) {
214     solver = directsparse ? 0 : 1;
215     //SetIPARM(32-1, directsparse ? 0 : 1);
216     Reinit();
217 }
218 
Reinit()219 void ChPardisoProjectEngine::Reinit() {
220     this->iparm[2]  = ChOMP::GetNumProcs();
221 
222     int mtype_int = symmetry;
223     pardisoinit(pt,  &mtype_int, &solver, iparm, dparm, &error);
224 
225     if (error != 0)
226     {
227         if (error == -10 )
228            printf("No license file found \n");
229         if (error == -11 )
230            printf("License is expired \n");
231         if (error == -12 )
232            printf("Wrong username or hostname \n");
233          //return 1;
234     }
235     else
236         printf("[PARDISO]: License check was successful ... \n");
237 }
238 
SetMessageLevel(int msglvl)239 void ChPardisoProjectEngine::SetMessageLevel(int msglvl) {
240     if (msglvl == 0 || msglvl == 1)
241         this->msglvl = msglvl;
242 }
243 
244 
245 }  // namespace chrono
246