// Copyright (c) 2010-2023, 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(double 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) { double 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, double & lr) const { ierr = EPSGetEigenvalue(eps,i,&lr,NULL); PCHKERRQ(eps,ierr); } void SlepcEigenSolver::GetEigenvalue(unsigned int i, double & lr, double & 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(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(double 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