/* *************************************************************************/ /* File: pardisoinverse.cpp */ /* Author: Florian Bachinger */ /* Date: Feb. 2004 */ /* *************************************************************************/ #include #ifdef USE_PARDISO #define F77_FUNC(func) func ## _ extern "C" { /* PARDISO prototype. */ int F77_FUNC(pardisoinit) (void *, int *, int *); int F77_FUNC(pardiso) (void *, int *, int *, int *, int *, int *, double *, int *, int *, int *, int *, int *, int *, double *, double *, int *); } namespace ngla { using namespace ngla; using namespace ngstd; template int NumRows(TM entry) { return entry.Height(); } int NumRows(double entry) { return 1; } int NumRows(Complex entry) { return 1; } template int NumCols(TM entry) { return entry.Width(); } int NumCols(double entry) { return 1; } int NumCols(Complex entry) { return 1; } template typename TM::TSCAL Elem(TM entry, int i, int j) { return entry(i,j); } double Elem (double entry, int i, int j) { return entry; } Complex Elem (Complex entry, int i, int j) { return entry; } template int IsComplex(TM entry) { return ( sizeof( Elem(entry,0,0) ) == sizeof( Complex ) ); } template PardisoInverse :: PardisoInverse (const SparseMatrix & a, const BitArray * ainner, const ARRAY * acluster, int asymmetric) { // (*testout) << "matrix = " << a << endl; symmetric = asymmetric; inner = ainner; cluster = acluster; if ( inner && inner->Size() < a.Height() || cluster && cluster->Size() < a.Height() ) { cout << "PardisoInverse: Size of inner/cluster does not match matrix size!" << endl; throw Exception("Invalid parameters inner/cluster. Thrown by PardisoInverse."); } clock_t starttime, time1, time2; starttime = clock(); // prepare matrix and parameters for PARDISO TM entry = a(0,0); if ( NumRows(entry) != NumCols(entry) ) { cout << "PardisoInverse: Each entry in the square matrix has to be a square matrix!" << endl; throw Exception("No Square Matrix. Thrown by PardisoInverse."); } entrysize = NumRows(entry); SetMatrixType(entry); height = a.Height() * entrysize; rowstart = new int[height+1]; indices = new int[a.NZE() * entrysize * entrysize ]; matrix = new TSCAL[a.NZE() * entrysize * entrysize ]; int i, j, k, l, rowsize; int col; int maxfct = 1, mnum = 1, phase = 12, nrhs = 1, msglevel = 0, error; int params[64]; params[0] = 1; // no pardiso defaults params[2] = 1; // 1 processor params[1] = 2; params[3] = params[4] = params[5] = params[7] = params[8] = params[11] = params[12] = params[18] = 0; params[6] = 16; params[9] = 20; params[10] = 1; for (i = 0; i < 64; i++) pt[i] = 0; F77_FUNC(pardisoinit) (pt, &matrixtype, params); SetMatrixType(entry); if ( symmetric ) { // --- transform lower left to upper right triangular matrix --- // 1.) build array 'rowstart': // (a) get nr. of entries for each row for ( i=0; i<=height; i++ ) rowstart[i] = 0; for ( i=1; i<=a.Height(); i++ ) { for ( j=0; jTest(i-1) && inner->Test(col) ) ) || (!inner && cluster && ((*cluster)[i-1] == (*cluster)[col] && (*cluster)[i-1] )) ) { for ( k=0; kTest(i)) || (!inner && cluster && (*cluster)[i]) ) { for ( k=0; kTest(i) && inner->Test(col)) ) || (!inner && cluster && ((*cluster)[i] == (*cluster)[col] && (*cluster)[i] )) ) { entry = a(i,col); for ( k=0; kTest(i)) || (!inner && cluster && (*cluster)[i]) ) { entry = a(i,col); for ( l=0; lTest(i) && inner->Test(col))) || (!inner && cluster && ((*cluster)[i] == (*cluster)[col] && (*cluster)[i])) ) rowelems+=entrysize; else if ( i == col ) rowelems++; } } else rowelems = rowsize * entrysize; for ( k=0; kTest(i) && inner->Test(col) )) || (!inner && cluster && ((*cluster)[i] == (*cluster)[col] && (*cluster)[i] )) ) { entry = a(i,col); for ( k=0; k(matrix), rowstart, indices, NULL, &nrhs, params, &msglevel, NULL, NULL, &error ); time2 = clock(); if ( error != 0 ) { cout << "Setup and Factorization: PARDISO returned error " << error << "!" << endl; throw Exception("PardisoInverse: Setup and Factorization failed."); } (*testout) << endl << "Direct Solver: PARDISO by Schenk/Gaertner." << endl; (*testout) << "Matrix prepared for PARDISO in " << double(time1 - starttime)/CLOCKS_PER_SEC << " sec." << endl; (*testout) << "Factorization by PARDISO done in " << double(time2 - time1)/CLOCKS_PER_SEC << " sec." << endl << endl; } template PardisoInverse :: PardisoInverse (const ARRAY & aorder, const ARRAY & cliques, const ARRAY & vertices, int symmetric) { Allocate (aorder, cliques, vertices); } template void PardisoInverse :: Allocate (const ARRAY & aorder, const ARRAY & cliques, const ARRAY & vertices) { cout << "PardisoInverse::Allocate not implemented!" << endl; } template void PardisoInverse :: FactorNew (const SparseMatrix & a) { throw Exception ("PardisoInverse::FactorNew not implemented"); } template void PardisoInverse :: Factor (const int * blocknr) { cout << "PardisoInverse::Factor not implemented!" << endl; } template void PardisoInverse :: Mult (const BaseVector & x, BaseVector & y) const { FlatVector fx = dynamic_cast &> (const_cast (x)).FV(); FlatVector fy = dynamic_cast &> (y).FV(); int maxfct = 1, mnum = 1, phase = 33, nrhs = 1, msglevel = 0, error; int params[64]; params[0] = 1; // no pardiso defaults params[2] = 1; // 1 processor params[1] = 2; params[3] = params[4] = params[5] = params[7] = params[8] = params[11] = params[12] = params[18] = 0; params[6] = 16; params[9] = 20; params[10] = 1; F77_FUNC(pardiso) ( const_cast(pt), &maxfct, &mnum, const_cast(&matrixtype), &phase, const_cast(&height), reinterpret_cast(matrix), rowstart, indices, NULL, &nrhs, params, &msglevel, static_cast(fx.Data()), static_cast(fy.Data()), &error ); if ( error != 0 ) cout << "Apply Inverse: PARDISO returned error " << error << "!" << endl; if (inner) { for (int i=0; iTest(i)) for (int j=0; j void PardisoInverse :: Set (int i, int j, const TM & val) { cout << "PardisoInverse::Set not implemented!" << endl; } template const TM & PardisoInverse :: Get (int i, int j) const { cout << "PardisoInverse::Get not implemented!" << endl; } template ostream & PardisoInverse :: Print (ostream & ost) const { cout << "PardisoInverse::Print not implemented!" << endl; return ost; } template PardisoInverse :: ~PardisoInverse() { int maxfct = 1, mnum = 1, phase = -1, nrhs = 1, msglevel = 0, error; int params[64]; // cout << "call pardiso (clean up) ..." << endl; F77_FUNC(pardiso) ( pt, &maxfct, &mnum, &matrixtype, &phase, &height, NULL, rowstart, indices, NULL, &nrhs, params, &msglevel, NULL, NULL, &error ); if ( error != 0 ) cout << "Clean Up: PARDISO returned error " << error << "!" << endl; delete [] rowstart; delete [] indices; delete [] matrix; } template void PardisoInverse :: SetMatrixType(TM entry) { if ( IsComplex(entry) ) { if ( symmetric ) matrixtype = 6; else { matrixtype = 13; (*testout) << "PARDISO: Assume matrix type to be complex non-symmetric." << endl; (*testout) << "Warning: Works, but is not optimal for Hermitian matrices." << endl; } } else { if ( symmetric ) { matrixtype = 2; // +2 .. pos def., -2 .. symmetric indef (*testout) << "PARDISO: Assume matrix type to be symmetric positive definite." << endl; (*testout) << "Warning: This might cause errors for symmetric indefinite matrices!!" << endl; } else matrixtype = 11; } } template class PardisoInverse; template class PardisoInverse; #if MAX_SYS_DIM >= 1 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 2 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 3 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 4 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 5 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 6 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 7 template class PardisoInverse >; template class PardisoInverse >; #endif #if MAX_SYS_DIM >= 8 template class PardisoInverse >; template class PardisoInverse >; #endif } #endif