Files
mfem/linalg/superlu.cpp
T

785 lines
23 KiB
C++

// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#include "../config/config.hpp"
#ifdef MFEM_USE_SUPERLU
#ifdef MFEM_USE_MPI
#include "superlu.hpp"
// SuperLU header
#include "superlu_ddefs.h"
#if XSDK_INDEX_SIZE == 64 && !(defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT))
#error "Mismatch between HYPRE (32bit) and SuperLU (64bit) integer types"
#endif
#if XSDK_INDEX_SIZE == 32 && (defined(HYPRE_BIGINT) || defined(HYPRE_MIXEDINT))
#error "Mismatch between HYPRE (64bit) and SuperLU (32bit) integer types"
#endif
#if SUPERLU_DIST_MAJOR_VERSION > 6 || \
(SUPERLU_DIST_MAJOR_VERSION == 6 && SUPERLU_DIST_MINOR_VERSION >= 3)
#define ScalePermstruct_t dScalePermstruct_t
#define LUstruct_t dLUstruct_t
#define SOLVEstruct_t dSOLVEstruct_t
#define ZeroLblocks dZeroLblocks
#define ZeroUblocks dZeroUblocks
#define Destroy_LU dDestroy_LU
#define SolveFinalize dSolveFinalize
#define ScalePermstructInit dScalePermstructInit
#define ScalePermstructFree dScalePermstructFree
#define LUstructFree dLUstructFree
#define LUstructInit dLUstructInit
#endif
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
#define DeAllocLlu_3d dDeAllocLlu_3d
#define DeAllocGlu_3d dDeAllocGlu_3d
#define Destroy_A3d_gathered_on_2d dDestroy_A3d_gathered_on_2d
#endif
unsigned int sqrti(unsigned int a)
{
unsigned int rem = 0;
unsigned int root = 0;
unsigned short len = sizeof(int); len <<= 2;
unsigned short shift = (unsigned short)((len << 1) - 2);
for (int i = 0; i < len; i++)
{
root <<= 1;
rem = ((rem << 2) + (a >> shift));
a <<= 2;
root ++;
if (root <= rem)
{
rem -= root;
root++;
}
else
{
root--;
}
}
return (root >> 1);
}
int GetGridRows(MPI_Comm comm, int npdep)
{
int np;
MPI_Comm_size(comm, &np);
MFEM_VERIFY(npdep > 0 && np % npdep == 0 && !(npdep & (npdep - 1)),
"SuperLUSolver: 3D partition depth must be a power of two "
"and evenly divide the number of processors!");
int nr = (int)sqrti((unsigned int)(np / npdep));
while (np % nr != 0 && nr > 0)
{
nr--;
}
MFEM_VERIFY(nr > 0,
"SuperLUSolver: Unable to determine processor grid for np = " << np);
return nr;
}
int GetGridCols(MPI_Comm comm, int npdep, int nr)
{
int np;
MPI_Comm_size(comm, &np);
int nc = np / (nr * npdep);
MFEM_VERIFY(nr * nc * npdep == np,
"SuperLUSolver: Impossible processor partition!");
return nc;
}
namespace mfem
{
SuperLURowLocMatrix::SuperLURowLocMatrix(MPI_Comm comm,
int num_loc_rows,
HYPRE_BigInt first_loc_row,
HYPRE_BigInt glob_nrows,
HYPRE_BigInt glob_ncols,
int *I, HYPRE_BigInt *J,
double *data)
: comm_(comm)
{
// Set mfem::Operator member data
height = num_loc_rows;
width = num_loc_rows;
// Allocate SuperLU's SuperMatrix struct
rowLocPtr_ = new SuperMatrix;
SuperMatrix *A = (SuperMatrix *)rowLocPtr_;
A->Store = NULL;
int_t m = glob_nrows;
int_t n = glob_ncols;
int_t nnz_loc = I[num_loc_rows];
int_t m_loc = num_loc_rows;
int_t fst_row = first_loc_row;
double *nzval = NULL;
int_t *colind = NULL;
int_t *rowptr = NULL;
if (!(nzval = doubleMalloc_dist(nnz_loc)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for nzval!");
}
for (int_t i = 0; i < nnz_loc; i++)
{
nzval[i] = data[i];
}
if (!(colind = intMalloc_dist(nnz_loc)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for colind!")
}
for (int_t i = 0; i < nnz_loc; i++)
{
colind[i] = J[i];
}
if (!(rowptr = intMalloc_dist(m_loc+1)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for rowptr!")
}
for (int_t i = 0; i <= m_loc; i++)
{
rowptr[i] = I[i];
}
// Assign the matrix data to SuperLU's SuperMatrix structure
dCreate_CompRowLoc_Matrix_dist(A, m, n, nnz_loc, m_loc, fst_row,
nzval, colind, rowptr,
SLU_NR_loc, SLU_D, SLU_GE);
// Save global number of rows and columns of the matrix
num_global_rows_ = m;
num_global_cols_ = n;
}
SuperLURowLocMatrix::SuperLURowLocMatrix(const Operator &op)
{
const HypreParMatrix *APtr = dynamic_cast<const HypreParMatrix *>(&op);
MFEM_VERIFY(APtr, "Not a compatible matrix type");
comm_ = APtr->GetComm();
// Set mfem::Operator member data
height = op.Height();
width = op.Width();
// Allocate SuperLU's SuperMatrix struct
rowLocPtr_ = new SuperMatrix;
SuperMatrix *A = (SuperMatrix *)rowLocPtr_;
A->Store = NULL;
// First cast the parameter to a hypre_ParCSRMatrix
hypre_ParCSRMatrix *parcsr_op =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix &>(*APtr);
// Create the SuperMatrix A by taking the internal data from a
// hypre_CSRMatrix
APtr->HostRead();
hypre_CSRMatrix *csr_op = hypre_MergeDiagAndOffd(parcsr_op);
APtr->HypreRead();
HYPRE_Int *Iptr = csr_op->i;
#if MFEM_HYPRE_VERSION >= 21600
HYPRE_BigInt *Jptr = csr_op->big_j;
#else
HYPRE_Int *Jptr = csr_op->j;
#endif
int_t m = parcsr_op->global_num_rows;
int_t n = parcsr_op->global_num_cols;
int_t fst_row = parcsr_op->first_row_index;
int_t nnz_loc = csr_op->num_nonzeros;
int_t m_loc = csr_op->num_rows;
// We copy the data from the hypre_CSRMatrix because SuperLU_DIST will
// free the memory assuming it has been allocated with its *Malloc_dist
// wrappers
double *nzval = NULL;
int_t *colind = NULL;
int_t *rowptr = NULL;
if (!(nzval = doubleMalloc_dist(nnz_loc)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for nzval!");
}
for (int_t i = 0; i < nnz_loc; i++)
{
nzval[i] = csr_op->data[i];
}
if (!(colind = intMalloc_dist(nnz_loc)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for colind!")
}
for (int_t i = 0; i < nnz_loc; i++)
{
colind[i] = Jptr[i];
}
if (!(rowptr = intMalloc_dist(m_loc+1)))
{
MFEM_ABORT("SuperLURowLocMatrix: Malloc failed for rowptr!")
}
for (int_t i = 0; i <= m_loc; i++)
{
rowptr[i] = Iptr[i];
}
// Assign the matrix data to SuperLU's SuperMatrix structure
dCreate_CompRowLoc_Matrix_dist(A, m, n, nnz_loc, m_loc, fst_row,
nzval, colind, rowptr,
SLU_NR_loc, SLU_D, SLU_GE);
// Everything has been copied so delete the structure
hypre_CSRMatrixDestroy(csr_op);
// Save global number of rows and columns of the matrix
num_global_rows_ = m;
num_global_cols_ = n;
}
SuperLURowLocMatrix::~SuperLURowLocMatrix()
{
SuperMatrix *A = (SuperMatrix *)rowLocPtr_;
Destroy_CompRowLoc_Matrix_dist(A);
delete A;
}
SuperLUSolver::SuperLUSolver(MPI_Comm comm, int npdep)
: nprow_(GetGridRows(comm, npdep)),
npcol_(GetGridCols(comm, npdep, nprow_)),
npdep_(npdep),
APtr_(NULL),
nrhs_(0)
{
Init(comm);
}
SuperLUSolver::SuperLUSolver(SuperLURowLocMatrix &A, int npdep)
: SuperLUSolver(A.GetComm(), npdep)
{
SetOperator(A);
}
SuperLUSolver::~SuperLUSolver()
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
ScalePermstruct_t *ScalePermstruct = (ScalePermstruct_t *)ScalePermstructPtr_;
LUstruct_t *LUstruct = (LUstruct_t *)LUstructPtr_;
SOLVEstruct_t *SOLVEstruct = (SOLVEstruct_t *)SOLVEstructPtr_;
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
gridinfo3d_t *grid3d = (gridinfo3d_t *)gridPtr_;
if (APtr_)
{
if (grid3d->zscp.Iam == 0)
{
// Process layer 0
Destroy_LU(APtr_->GetGlobalNumColumns(), &(grid3d->grid2d),
LUstruct);
SolveFinalize(options, SOLVEstruct);
}
else
{
// Process layers not equal 0
DeAllocLlu_3d(APtr_->GetGlobalNumColumns(), LUstruct, grid3d);
DeAllocGlu_3d(LUstruct);
}
Destroy_A3d_gathered_on_2d(SOLVEstruct, grid3d);
ScalePermstructFree(ScalePermstruct);
LUstructFree(LUstruct);
}
superlu_gridexit3d(grid3d);
delete grid3d;
}
else
#endif
{
gridinfo_t *grid = (gridinfo_t *)gridPtr_;
if (APtr_)
{
Destroy_LU(APtr_->GetGlobalNumColumns(), grid, LUstruct);
SolveFinalize(options, SOLVEstruct);
ScalePermstructFree(ScalePermstruct);
LUstructFree(LUstruct);
}
superlu_gridexit(grid);
delete grid;
}
delete options;
delete ScalePermstruct;
delete LUstruct;
delete SOLVEstruct;
}
void SuperLUSolver::Init(MPI_Comm comm)
{
optionsPtr_ = new superlu_dist_options_t;
ScalePermstructPtr_ = new ScalePermstruct_t;
LUstructPtr_ = new LUstruct_t;
SOLVEstructPtr_ = new SOLVEstruct_t;
// Initialize process grid
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
gridPtr_ = new gridinfo3d_t;
superlu_gridinit3d(comm, nprow_, npcol_, npdep_, (gridinfo3d_t *)gridPtr_);
}
else
#endif
{
gridPtr_ = new gridinfo_t;
MFEM_VERIFY(npdep_ == 1,
"SuperLUSolver: 3D partitioning is only available for "
"SuperLU_DIST version >= 7.2.0!");
superlu_gridinit(comm, nprow_, npcol_, (gridinfo_t *)gridPtr_);
}
// Set default options:
// options.Fact = DOFACT;
// options.Equil = YES;
// options.ParSymbFact = NO;
// options.ColPerm = METIS_AT_PLUS_A;
// options.RowPerm = LargeDiag_MC64;
// options.ReplaceTinyPivot = NO;
// options.IterRefine = SLU_DOUBLE;
// options.Trans = NOTRANS;
// options.SolveInitialized = NO;
// options.RefineInitialized = NO;
// options.PrintStat = YES;
// options.lookahead_etree = NO;
// options.num_lookaheads = 10;
// options.superlu_acc_offload = 1;
// options.SymPattern = NO;
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
set_default_options_dist(options);
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
options->Algo3d = YES;
}
#endif
}
void SuperLUSolver::SetPrintStatistics(bool print_stat)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = print_stat ? YES : NO;
options->PrintStat = opt;
}
void SuperLUSolver::SetEquilibriate(bool equil)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = equil ? YES : NO;
options->Equil = opt;
}
void SuperLUSolver::SetColumnPermutation(superlu::ColPerm col_perm)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
colperm_t opt = (colperm_t)col_perm;
if (opt == MY_PERMC)
{
MFEM_ABORT("SuperLUSolver::SetColumnPermutation does not yet support "
"MY_PERMC!");
}
else if (opt == PARMETIS)
{
options->ParSymbFact = YES;
}
options->ColPerm = opt;
}
void SuperLUSolver::SetRowPermutation(superlu::RowPerm row_perm)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
rowperm_t opt = (rowperm_t)row_perm;
if (opt == MY_PERMR)
{
MFEM_ABORT("SuperLUSolver::SetRowPermutation does not yet support "
"MY_PERMR!");
}
options->RowPerm = opt;
}
void SuperLUSolver::SetIterativeRefine(superlu::IterRefine iter_ref)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
IterRefine_t opt = (IterRefine_t)iter_ref;
options->IterRefine = opt;
}
void SuperLUSolver::SetReplaceTinyPivot(bool rtp)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = rtp ? YES : NO;
options->ReplaceTinyPivot = opt;
}
void SuperLUSolver::SetNumLookAheads(int num_lookaheads)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
options->num_lookaheads = num_lookaheads;
}
void SuperLUSolver::SetLookAheadElimTree(bool etree)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = etree ? YES : NO;
options->lookahead_etree = opt;
}
void SuperLUSolver::SetSymmetricPattern(bool sym)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = sym ? YES : NO;
options->SymPattern = opt;
}
void SuperLUSolver::SetParSymbFact(bool par)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
yes_no_t opt = par ? YES : NO;
options->ParSymbFact = opt;
}
void SuperLUSolver::SetFact(superlu::Fact fact)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
fact_t opt = (fact_t)fact;
options->Fact = opt;
}
void SuperLUSolver::SetDeviceOffload(bool offload)
{
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
options->superlu_acc_offload = offload;
}
void SuperLUSolver::SetOperator(const Operator &op)
{
// Verify that we have a compatible operator
bool LUStructInitialized = (APtr_ != NULL);
APtr_ = dynamic_cast<const SuperLURowLocMatrix *>(&op);
MFEM_VERIFY(APtr_, "SuperLUSolver::SetOperator: Not a SuperLURowLocMatrix!");
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
ScalePermstruct_t *ScalePermstruct = (ScalePermstruct_t *)ScalePermstructPtr_;
LUstruct_t *LUstruct = (LUstruct_t *)LUstructPtr_;
gridinfo_t *grid;
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
gridinfo3d_t *grid3d = NULL;
if (npdep_ > 1)
{
grid3d = (gridinfo3d_t *)gridPtr_;
grid = NULL;
}
else
#endif
{
grid = (gridinfo_t *)gridPtr_;
}
// Set mfem::Operator member data
MFEM_VERIFY(!LUStructInitialized ||
(height == op.Height() && width == op.Width()),
"SuperLUSolver::SetOperator: Inconsistent new matrix size!");
height = op.Height();
width = op.Width();
if (!LUStructInitialized)
{
// Initialize ScalePermstruct and LUstruct once for all operators (must
// have same dimensions)
ScalePermstructInit(APtr_->GetGlobalNumRows(),
APtr_->GetGlobalNumColumns(), ScalePermstruct);
LUstructInit(APtr_->GetGlobalNumColumns(), LUstruct);
options->Fact = DOFACT;
}
else
{
// A previous matrix has already been set and factored
switch (options->Fact)
{
case DOFACT:
MFEM_ABORT("SuperLUSolver::SetOperator: Previous matrix was never used!");
break;
case SamePattern_SameRowPerm:
{
// Just zero the LU factors
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
if (grid3d->zscp.Iam == 0)
{
ZeroLblocks(grid3d->iam, APtr_->GetGlobalNumColumns(),
&(grid3d->grid2d), LUstruct);
ZeroUblocks(grid3d->iam, APtr_->GetGlobalNumColumns(),
&(grid3d->grid2d), LUstruct);
}
}
else
#endif
{
ZeroLblocks(grid->iam, APtr_->GetGlobalNumColumns(),
grid, LUstruct);
ZeroUblocks(grid->iam, APtr_->GetGlobalNumColumns(),
grid, LUstruct);
}
}
break;
case SamePattern:
case FACTORED:
{
// Delete factors from the prior factorization
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
if (grid3d->zscp.Iam == 0)
{
Destroy_LU(APtr_->GetGlobalNumColumns(), &(grid3d->grid2d),
LUstruct);
}
else
{
DeAllocLlu_3d(APtr_->GetGlobalNumColumns(), LUstruct,
grid3d);
DeAllocGlu_3d(LUstruct);
}
}
else
#endif
{
Destroy_LU(APtr_->GetGlobalNumColumns(), grid, LUstruct);
}
}
break;
default:
MFEM_ABORT("SuperLUSolver::SetOperator: Unexpected value for "
"options->Fact!");
break;
}
if (options->Fact == FACTORED) { options->Fact = DOFACT; }
}
}
void SuperLUSolver::Mult(const Vector &x, Vector &y) const
{
Array<const Vector *> X(1);
Array<Vector *> Y(1);
X[0] = &x;
Y[0] = &y;
ArrayMult(X, Y);
}
void SuperLUSolver::ArrayMult(const Array<const Vector *> &X,
Array<Vector *> &Y) const
{
MFEM_ASSERT(APtr_ != NULL,
"SuperLU Error: The operator must be set before"
" the system can be solved.");
SuperMatrix *A = (SuperMatrix *)APtr_->InternalData();
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
ScalePermstruct_t *ScalePermstruct = (ScalePermstruct_t *)ScalePermstructPtr_;
LUstruct_t *LUstruct = (LUstruct_t *)LUstructPtr_;
SOLVEstruct_t *SOLVEstruct = (SOLVEstruct_t *)SOLVEstructPtr_;
gridinfo_t *grid;
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
gridinfo3d_t *grid3d = NULL;
if (npdep_ > 1)
{
grid3d = (gridinfo3d_t *)gridPtr_;
grid = NULL;
}
else
#endif
{
grid = (gridinfo_t *)gridPtr_;
}
// SuperLU overwrites x with y, so copy x to y and pass that to the solve
// routine. Due to issues with repeated solves and changes in the number
// of RHS vectors, this is not supported.
MFEM_ASSERT(X.Size() == Y.Size(),
"Number of columns mismatch in SuperLUSolver::Mult!");
MFEM_VERIFY(nrhs_ < 1 || nrhs_ == X.Size(),
"SuperLUSolver does not support multiple solves with different "
"numbers of RHS vectors!");
int ldx = Height();
if (X.Size() == 1)
{
MFEM_ASSERT(X[0] && Y[0], "Missing Vector in SuperLUSolver::Mult!");
sol_.MakeRef(*Y[0], 0, Y[0]->Size());
sol_ = *X[0];
nrhs_ = 1;
}
else
{
if (nrhs_ < 1)
{
MFEM_ASSERT(X[0], "Missing Vector in SuperLUSolver::Mult!");
sol_.SetSize(X.Size() * ldx, *X[0]);
nrhs_ = X.Size();
}
for (int i = 0; i < nrhs_; i++)
{
MFEM_ASSERT(X[i], "Missing Vector in SuperLUSolver::Mult!");
Vector s(sol_, i * ldx, ldx);
s = *X[i];
sol_.SyncMemory(s); // Update flags for sol_ if updated on device
}
}
// Solve the system
double *B = sol_.HostReadWrite(), *berr;
if (!(berr = doubleMalloc_dist(nrhs_)))
{
MFEM_ABORT("SuperLUSolver::Mult: Malloc failed for berr!");
}
SuperLUStat_t stat;
PStatInit(&stat);
int info = -1;
#if SUPERLU_DIST_MAJOR_VERSION > 7 || \
(SUPERLU_DIST_MAJOR_VERSION == 7 && SUPERLU_DIST_MINOR_VERSION >= 2)
if (npdep_ > 1)
{
pdgssvx3d(options, A, ScalePermstruct, B, ldx, nrhs_,
grid3d, LUstruct, SOLVEstruct, berr, &stat, &info);
}
else
#endif
{
pdgssvx(options, A, ScalePermstruct, B, ldx, nrhs_,
grid, LUstruct, SOLVEstruct, berr, &stat, &info);
}
HandleError(info);
SUPERLU_FREE(berr);
PStatFree(&stat);
options->Fact = FACTORED;
// Copy solution into output (no need to do anything for single RHS since
// solution is written directly into output Vector)
if (nrhs_ == 1)
{
sol_.SyncAliasMemory(*Y[0]);
}
else
{
for (int i = 0; i < nrhs_; i++)
{
MFEM_ASSERT(Y[i], "Missing Vector in SuperLUSolver::Mult!");
Vector s(sol_, i * ldx, ldx);
*Y[i] = s;
}
}
}
void SuperLUSolver::MultTranspose(const Vector &x, Vector &y) const
{
// Set flag for transpose solve
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
options->Trans = TRANS;
Mult(x, y);
// Reset the flag
options->Trans = NOTRANS;
}
void SuperLUSolver::ArrayMultTranspose(const Array<const Vector *> &X,
Array<Vector *> &Y) const
{
// Set flag for transpose solve
superlu_dist_options_t *options = (superlu_dist_options_t *)optionsPtr_;
options->Trans = TRANS;
ArrayMult(X, Y);
// Reset the flag
options->Trans = NOTRANS;
}
void SuperLUSolver::HandleError(int info) const
{
if (info != 0)
{
SuperMatrix *A = (SuperMatrix *)APtr_->InternalData();
if (info < 0)
{
switch (-info)
{
case 1:
MFEM_ABORT("SuperLUSolver: SuperLU options are invalid!");
break;
case 2:
MFEM_ABORT("SuperLUSolver: Matrix A (in Ax=b) is invalid!");
break;
case 5:
MFEM_ABORT("SuperLUSolver: Vector b dimension (in Ax=b) is "
"invalid!");
break;
case 6:
MFEM_ABORT("SuperLUSolver: Number of right-hand sides is "
"invalid!");
break;
default:
MFEM_ABORT("SuperLUSolver: Parameter with index "
<< -info << "invalid (1-indexed)!");
break;
}
}
else if (info <= A->ncol)
{
MFEM_ABORT("SuperLUSolver: Found a singular matrix, U("
<< info << "," << info << ") is exactly zero!");
}
else if (info > A->ncol)
{
MFEM_ABORT("SuperLUSolver: Memory allocation error with "
<< info - A->ncol << " bytes already allocated!");
}
else
{
MFEM_ABORT("Unknown SuperLU error: info = " << info << "!");
}
}
}
} // namespace mfem
#endif // MFEM_USE_MPI
#endif // MFEM_USE_SUPERLU