Files
mfem/linalg/strumpack.cpp
T
2020-03-09 15:36:41 -07:00

242 lines
6.5 KiB
C++

// Copyright (c) 2010-2020, 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_STRUMPACK
#ifdef MFEM_USE_MPI
#include "strumpack.hpp"
using namespace std;
using namespace strumpack;
namespace mfem
{
STRUMPACKRowLocMatrix::STRUMPACKRowLocMatrix(MPI_Comm comm,
int num_loc_rows, int first_loc_row,
int glob_nrows, int glob_ncols,
int *I, int *J, double *data)
: comm_(comm), A_(NULL)
{
// Set mfem::Operator member data
height = num_loc_rows;
width = num_loc_rows;
// Allocate STRUMPACK's CSRMatrixMPI
int nprocs, rank;
MPI_Comm_rank(comm_, &rank);
MPI_Comm_size(comm_, &nprocs);
int * dist = new int[nprocs + 1];
dist[rank + 1] = first_loc_row + num_loc_rows;
dist[0] = 0;
MPI_Allgather(MPI_IN_PLACE, 0, MPI_INT, dist + 1, 1, MPI_INT, comm_);
A_ = new CSRMatrixMPI<double,int>(num_loc_rows, I, J, data, dist, comm_, false);
delete[] dist;
}
STRUMPACKRowLocMatrix::STRUMPACKRowLocMatrix(const HypreParMatrix & hypParMat)
: comm_(hypParMat.GetComm()),
A_(NULL)
{
// First cast the parameter to a hypre_ParCSRMatrix
hypre_ParCSRMatrix * parcsr_op =
(hypre_ParCSRMatrix *)const_cast<HypreParMatrix&>(hypParMat);
MFEM_ASSERT(parcsr_op != NULL,"STRUMPACK: const_cast failed in SetOperator");
// Create the CSRMatrixMPI A_ by borrowing the internal data from a
// hypre_CSRMatrix.
hypre_CSRMatrix * csr_op = hypre_MergeDiagAndOffd(parcsr_op);
hypre_CSRMatrixSetDataOwner(csr_op,0);
height = csr_op->num_rows;
width = csr_op->num_rows;
int nprocs, rank;
MPI_Comm_rank(comm_, &rank);
MPI_Comm_size(comm_, &nprocs);
int * dist = new int[nprocs + 1];
dist[rank + 1] = parcsr_op->first_row_index + csr_op->num_rows;
dist[0] = 0;
MPI_Allgather(MPI_IN_PLACE, 0, MPI_INT, dist + 1, 1, MPI_INT, comm_);
A_ = new CSRMatrixMPI<double,int>(csr_op->num_rows, csr_op->i, csr_op->j,
csr_op->data, dist, comm_, false);
delete[] dist;
// Everything has been copied or abducted so delete the structure
hypre_CSRMatrixDestroy(csr_op);
}
STRUMPACKRowLocMatrix::~STRUMPACKRowLocMatrix()
{
// Delete the struct
if ( A_ != NULL ) { delete A_; }
}
STRUMPACKSolver::STRUMPACKSolver( int argc, char* argv[], MPI_Comm comm )
: comm_(comm),
APtr_(NULL),
solver_(NULL)
{
this->Init(argc, argv);
}
STRUMPACKSolver::STRUMPACKSolver( STRUMPACKRowLocMatrix & A )
: comm_(A.GetComm()),
APtr_(&A),
solver_(NULL)
{
height = A.Height();
width = A.Width();
this->Init(0, NULL);
}
STRUMPACKSolver::~STRUMPACKSolver()
{
if ( solver_ != NULL ) { delete solver_; }
}
void STRUMPACKSolver::Init( int argc, char* argv[] )
{
MPI_Comm_size(comm_, &numProcs_);
MPI_Comm_rank(comm_, &myid_);
factor_verbose_ = false;
solve_verbose_ = false;
solver_ = new StrumpackSparseSolverMPIDist<double,int>(comm_, argc, argv,
false);
}
void STRUMPACKSolver::SetFromCommandLine( )
{
solver_->options().set_from_command_line( );
}
void STRUMPACKSolver::SetPrintFactorStatistics( bool print_stat )
{
factor_verbose_ = print_stat;
}
void STRUMPACKSolver::SetPrintSolveStatistics( bool print_stat )
{
solve_verbose_ = print_stat;
}
void STRUMPACKSolver::SetKrylovSolver( strumpack::KrylovSolver method )
{
solver_->options().set_Krylov_solver( method );
}
void STRUMPACKSolver::SetReorderingStrategy( strumpack::ReorderingStrategy
method )
{
solver_->options().set_reordering_method( method );
}
void STRUMPACKSolver::DisableMatching( )
{
#if STRUMPACK_VERSION_MAJOR >= 3
solver_->options().set_matching( strumpack::MatchingJob::NONE );
#else
solver_->options().set_mc64job( strumpack::MC64Job::NONE );
#endif
}
void STRUMPACKSolver::EnableMatching( )
{
#if STRUMPACK_VERSION_MAJOR >= 3
solver_->options().set_matching
( strumpack::MatchingJob::MAX_DIAGONAL_PRODUCT_SCALING );
#else
solver_->options().set_mc64job
( strumpack::MC64Job::MAX_DIAGONAL_PRODUCT_SCALING );
#endif
}
#if STRUMPACK_VERSION_MAJOR >= 3
void STRUMPACKSolver::EnableParallelMatching( )
{
solver_->options().set_matching
( strumpack::MatchingJob::COMBBLAS );
}
#endif
void STRUMPACKSolver::SetRelTol( double rtol )
{
solver_->options().set_rel_tol( rtol );
}
void STRUMPACKSolver::SetAbsTol( double atol )
{
solver_->options().set_abs_tol( atol );
}
void STRUMPACKSolver::Mult( const Vector & x, Vector & y ) const
{
MFEM_ASSERT(APtr_ != NULL,
"STRUMPACK Error: The operator must be set before"
" the system can be solved.");
MFEM_ASSERT(x.Size() == Width(), "invalid x.Size() = " << x.Size()
<< ", expected size = " << Width());
MFEM_ASSERT(y.Size() == Height(), "invalid y.Size() = " << y.Size()
<< ", expected size = " << Height());
double* yPtr = (double*)y;
double* xPtr = (double*)(const_cast<Vector&>(x));
solver_->options().set_verbose( factor_verbose_ );
ReturnCode ret = solver_->factor();
switch (ret)
{
case ReturnCode::SUCCESS: break;
case ReturnCode::MATRIX_NOT_SET:
{
MFEM_ABORT("STRUMPACK: Matrix was not set!");
}
break;
case ReturnCode::REORDERING_ERROR:
{
MFEM_ABORT("STRUMPACK: Matrix reordering failed!");
}
break;
}
solver_->options().set_verbose( solve_verbose_ );
solver_->solve(xPtr, yPtr);
}
void STRUMPACKSolver::SetOperator( const Operator & op )
{
// Verify that we have a compatible operator
APtr_ = dynamic_cast<const STRUMPACKRowLocMatrix*>(&op);
if ( APtr_ == NULL )
{
mfem_error("STRUMPACKSolver::SetOperator : not STRUMPACKRowLocMatrix!");
}
solver_->set_matrix( *(APtr_->getA()) );
// Set mfem::Operator member data
height = op.Height();
width = op.Width();
}
} // mfem namespace
#endif // MFEM_USE_MPI
#endif // MFEM_USE_STRUMPACK