Files
mfem/linalg/slepc.cpp
T

258 lines
7.1 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_MPI
#ifdef MFEM_USE_PETSC
#ifdef MFEM_USE_SLEPC
#include "linalg.hpp"
#include "petscinternals.hpp"
#include "slepc.h"
static PetscErrorCode ierr;
using namespace std;
namespace mfem
{
void MFEMInitializeSlepc()
{
MFEMInitializeSlepc(NULL,NULL,NULL,NULL);
}
void MFEMInitializeSlepc(int *argc,char*** argv)
{
MFEMInitializeSlepc(argc,argv,NULL,NULL);
}
void MFEMInitializeSlepc(int *argc,char ***argv,const char rc_file[],
const char help[])
{
if (mfem::Device::Allows(mfem::Backend::CUDA_MASK))
{
// Tell PETSc to use the same CUDA device as MFEM:
ierr = PetscOptionsSetValue(NULL,"-cuda_device",
to_string(mfem::Device::GetId()).c_str());
MFEM_VERIFY(!ierr,"Unable to set initial option value to PETSc");
}
ierr = SlepcInitialize(argc,argv,rc_file,help);
MFEM_VERIFY(!ierr,"Unable to initialize SLEPc");
}
void MFEMFinalizeSlepc()
{
ierr = SlepcFinalize();
MFEM_VERIFY(!ierr,"Unable to finalize SLEPc");
}
SlepcEigenSolver::SlepcEigenSolver(MPI_Comm comm, const std::string &prefix)
{
clcustom = false;
VR = NULL;
VC = NULL;
ierr = EPSCreate(comm,&eps); CCHKERRQ(comm,ierr);
ierr = EPSSetOptionsPrefix(eps, prefix.c_str()); PCHKERRQ(eps, ierr);
}
SlepcEigenSolver::~SlepcEigenSolver()
{
delete VR;
delete VC;
MPI_Comm comm;
ierr = PetscObjectGetComm((PetscObject)eps,&comm); PCHKERRQ(eps,ierr);
ierr = EPSDestroy(&eps); CCHKERRQ(comm,ierr);
}
void SlepcEigenSolver::SetOperator(const PetscParMatrix &op)
{
delete VR;
delete VC;
VR = VC = NULL;
ierr = EPSSetOperators(eps,op,NULL); PCHKERRQ(eps, ierr);
VR = new PetscParVector(op, true, false);
VC = new PetscParVector(op, true, false);
}
void SlepcEigenSolver::SetOperators(const PetscParMatrix &op,
const PetscParMatrix&opB)
{
delete VR;
delete VC;
VR = VC = NULL;
ierr = EPSSetOperators(eps,op,opB); PCHKERRQ(eps,ierr);
VR = new PetscParVector(op, true, false);
VC = new PetscParVector(op, true, false);
}
void SlepcEigenSolver::SetTol(real_t tol)
{
PetscInt max_its;
ierr = EPSGetTolerances(eps,NULL,&max_its); PCHKERRQ(eps,ierr);
// Work around uninitialized maximum iterations
if (max_its==0) { max_its = PETSC_DECIDE; }
ierr = EPSSetTolerances(eps,tol,max_its); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::SetMaxIter(int max_its)
{
real_t tol;
ierr = EPSGetTolerances(eps,&tol,NULL); PCHKERRQ(eps,ierr);
ierr = EPSSetTolerances(eps,tol,max_its); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::SetNumModes(int num_eigs)
{
ierr = EPSSetDimensions(eps,num_eigs,PETSC_DECIDE,PETSC_DECIDE);
PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::Solve()
{
Customize();
ierr = EPSSolve(eps); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::Customize(bool customize) const
{
if (!customize) {clcustom = true; }
if (!clcustom)
{
ierr = EPSSetFromOptions(eps); PCHKERRQ(eps,ierr);
}
clcustom = true;
}
void SlepcEigenSolver::GetEigenvalue(unsigned int i, real_t & lr) const
{
ierr = EPSGetEigenvalue(eps,i,&lr,NULL); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::GetEigenvalue(unsigned int i, real_t & lr,
real_t & lc) const
{
ierr = EPSGetEigenvalue(eps,i,&lr,&lc); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr) const
{
MFEM_VERIFY(VR,"Missing real vector");
MFEM_ASSERT(vr.Size() == VR->Size(), "invalid vr.Size() = " << vr.Size()
<< ", expected size = " << VR->Size());
VR->PlaceMemory(vr.GetMemory());
ierr = EPSGetEigenvector(eps,i,*VR,NULL); PCHKERRQ(eps,ierr);
VR->ResetMemory();
}
void SlepcEigenSolver::GetEigenvector(unsigned int i, Vector & vr,
Vector & vc) const
{
MFEM_VERIFY(VR,"Missing real vector");
MFEM_VERIFY(VC,"Missing imaginary vector");
MFEM_ASSERT(vr.Size() == VR->Size(), "invalid vr.Size() = " << vr.Size()
<< ", expected size = " << VR->Size());
MFEM_ASSERT(vc.Size() == VC->Size(), "invalid vc.Size() = " << vc.Size()
<< ", expected size = " << VC->Size());
VR->PlaceArray(vr.GetMemory());
VC->PlaceArray(vc.GetMemory());
ierr = EPSGetEigenvector(eps,i,*VR,*VC); PCHKERRQ(eps,ierr);
VR->ResetMemory();
VC->ResetMemory();
}
int SlepcEigenSolver::GetNumConverged()
{
PetscInt num_conv;
ierr = EPSGetConverged(eps,&num_conv); PCHKERRQ(eps,ierr);
return static_cast<int>(num_conv);
}
void SlepcEigenSolver::SetWhichEigenpairs(SlepcEigenSolver::Which which)
{
switch (which)
{
case SlepcEigenSolver::LARGEST_MAGNITUDE:
ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_MAGNITUDE); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::SMALLEST_MAGNITUDE:
ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_MAGNITUDE); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::LARGEST_REAL:
ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_REAL); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::SMALLEST_REAL:
ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_REAL); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::LARGEST_IMAGINARY:
ierr = EPSSetWhichEigenpairs(eps,EPS_LARGEST_IMAGINARY); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::SMALLEST_IMAGINARY:
ierr = EPSSetWhichEigenpairs(eps,EPS_SMALLEST_IMAGINARY); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::TARGET_MAGNITUDE:
ierr = EPSSetWhichEigenpairs(eps,EPS_TARGET_MAGNITUDE); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::TARGET_REAL:
ierr = EPSSetWhichEigenpairs(eps,EPS_TARGET_REAL); PCHKERRQ(eps,ierr);
break;
default:
MFEM_ABORT("Which eigenpair not implemented!");
break;
}
}
void SlepcEigenSolver::SetTarget(real_t target)
{
ierr = EPSSetTarget(eps,target); PCHKERRQ(eps,ierr);
}
void SlepcEigenSolver::SetSpectralTransformation(
SlepcEigenSolver::SpectralTransformation transformation)
{
ST st;
ierr = EPSGetST(eps,&st); PCHKERRQ(eps,ierr);
switch (transformation)
{
case SlepcEigenSolver::SHIFT:
ierr = STSetType(st,STSHIFT); PCHKERRQ(eps,ierr);
break;
case SlepcEigenSolver::SHIFT_INVERT:
ierr = STSetType(st,STSINVERT); PCHKERRQ(eps,ierr);
break;
default:
MFEM_ABORT("Spectral transformation not implemented!");
break;
}
}
}
#endif // MFEM_USE_SLEPC
#endif // MFEM_USE_PETSC
#endif // MFEM_USE_MPI