258 lines
7.1 KiB
C++
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
|