Compare commits

...
56 Commits
Author SHA1 Message Date
Stowell, Mark L. e2d68264e6 Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev 2026-04-29 12:12:31 -07:00
Mark L. Stowell 8bf2b3f061 Merge branch 'master' into eigensolvers-dev 2026-04-29 12:03:54 -07:00
Stowell, Mark L. 933ddce17a Removing ex11 and ex13 from cmake build when ARPACK is not available 2026-04-29 00:22:35 -07:00
Stowell, Mark L. 085557f02b Modifying ex11p to new API 2026-04-28 17:22:36 -07:00
Stowell, Mark L. 2544bab0aa Adapting serial examples to modified API 2026-04-28 17:18:57 -07:00
Stowell, Mark L. bea4a8bae0 Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev 2026-04-28 15:59:48 -07:00
Stowell, Mark L. 31dc0b5322 Simplifying inheritance hierarchy 2026-04-28 15:18:12 -07:00
Stowell, Mark L. 18ca696093 Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev
# Conflicts:
#	linalg/eigensolvers.hpp
2026-04-24 13:52:49 -07:00
Stowell, Mark L. c441b28b01 Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev 2026-04-24 13:48:10 -07:00
Stowell, Mark L. 125e182a05 Merge remote-tracking branch 'origin/master' into eigensolvers-dev 2026-04-24 13:47:04 -07:00
Stowell, Mark L. 3dc8e4d98e Provide eight variants of eigensolver for easier inheritance 2026-04-24 13:46:38 -07:00
Stowell, Mark L. b947d34583 Make it stop! 2026-04-24 11:05:08 -07:00
Stowell, Mark L. 862e527539 Disabling ex11 and ex13 builds when ARPACK is not available 2026-04-24 11:01:25 -07:00
Stowell, Mark L. 297d7eabd6 Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev 2026-04-24 10:03:41 -07:00
Stowell, Mark L. 86f214bdc6 When will it end? 2026-04-24 10:02:03 -07:00
Stowell, Mark L. 8420384555 Disabling ex13 when ARPACK is unavailable 2026-04-24 09:48:24 -07:00
Stowell, Mark L. f158717ae5 Disabling ex11 if ARPACK is not available 2026-04-24 07:27:25 -07:00
Stowell, Mark L. 3a645d61b2 Yet another explicit Distribute 2026-04-24 07:17:08 -07:00
Stowell, Mark L. ac86240cd8 Tweaking ex11p 2026-04-23 17:41:55 -07:00
Stowell, Mark L. 8c7f47ee71 Cleanup 2026-04-23 16:13:57 -07:00
Stowell, Mark L. 8a9d4e94cf Merge remote-tracking branch 'origin/eigensolvers-dev' into arpack-dev
# Conflicts:
#	examples/ex11p.cpp
#	linalg/eigensolvers.hpp
#	linalg/hypre.cpp
#	linalg/hypre.hpp
2026-04-23 16:09:06 -07:00
Stowell, Mark L. 224345b00c One more explicit Distribute 2026-04-23 15:59:16 -07:00
Stowell, Mark L. 6ee0947d03 Adding explicit Distribute 2026-04-23 15:14:40 -07:00
Stowell, Mark L. b82f870350 Adding missing overrides 2026-04-23 12:56:05 -07:00
Stowell, Mark L. 819a262bd3 make style 2026-04-23 11:20:13 -07:00
Stowell, Mark L. 10a017a62d Modifying hypre eigensolvers to fit the proposed interface 2026-04-23 11:19:53 -07:00
Stowell, Mark L. b82ec338c5 Adding references to new header 2026-04-23 10:44:25 -07:00
Stowell, Mark L. 90ebbb469c Suggestion for eigensolver base classes 2026-04-23 10:42:55 -07:00
Stowell, Mark L. 32318eaf75 One more file header 2026-04-19 14:47:30 -07:00
Stowell, Mark L. 98d80620bf Updating file headers 2026-04-19 14:42:28 -07:00
Stowell, Mark L. cec5a119d1 Merge remote-tracking branch 'origin/master' into arpack-dev 2026-04-19 14:39:37 -07:00
Stowell, Mark L. 8744958c2f Attempting to standardize arguments 2026-04-19 14:38:15 -07:00
Stowell, Mark L. 65b1e0addb Merge remote-tracking branch 'origin/master' into arpack-dev
# Conflicts:
#	config/config.hpp.in
#	config/defaults.mk
#	examples/ex11p.cpp
#	examples/makefile
#	linalg/CMakeLists.txt
#	linalg/hypre.cpp
#	linalg/hypre.hpp
#	linalg/linalg.hpp
#	makefile
2026-04-18 11:38:43 -07:00
Stowell, Mark L a0b8427774 Changing more license headers 2020-09-01 16:42:50 -07:00
Stowell, Mark L bd3897a7ec Changing cout to mfem::out 2020-09-01 16:41:12 -07:00
Stowell, Mark L 98039728a7 Changing license header 2020-09-01 16:40:50 -07:00
Stowell, Mark L 537f9ad677 Adding ARPACK option to ex11p 2020-09-01 16:30:27 -07:00
Stowell, Mark L 6081e24e78 make style 2020-09-01 16:03:57 -07:00
Stowell, Mark L 9779145f1a Merge remote-tracking branch 'origin/master' into arpack-dev 2020-09-01 10:43:44 -07:00
Stowell, Mark L e1576f336e Removing old initializations 2020-09-01 10:41:40 -07:00
Stowell, Mark L 673f0364de make style 2020-09-01 10:41:05 -07:00
Stowell, Mark L 90c4e55c40 Adding arpack.?pp files to CMakeLists 2020-09-01 10:34:35 -07:00
Stowell, Mark L 2f610e0170 Small improvements to ARPACK examples 2020-09-01 10:29:06 -07:00
Stowell, Mark L 35598cb6fb Adding SetOperator(Operator) methods 2020-09-01 10:28:02 -07:00
Stowell, Mark L af5003aee2 Adding new examples to make system 2020-09-01 10:27:19 -07:00
Stowell, Mark L 0e3223dd83 Changes suggested in issue #114 2020-09-01 10:23:43 -07:00
Veselin Dobrev b1ac354f59 Merge branch 'master' into arpack-dev 2020-08-27 11:12:48 -07:00
Stowell, Mark L 0147180a8b A possible replacement for ex11p 2017-02-24 01:57:30 -08:00
Stowell, Mark L 2d0a0b6c63 Adding an abstract base class for eigenvalue solvers 2017-02-24 01:56:41 -08:00
Stowell, Mark L 044ac04693 Fixed the parallel example
This needs to be cleaned up a bit or merged with ex11p.
2017-02-22 18:52:38 -08:00
Stowell, Mark L 019a983732 Run through astyle 2017-02-22 18:51:41 -08:00
Stowell, Mark L 8ff51b993c Fixing bugs in parallel implementation
Method overloading was not functioning because various methods were not
declared as ‘virtual’.

The partiitioning was computed incorrectly which lead to incorrectly
sized eigenvectors.
2017-02-22 18:51:09 -08:00
Stowell, Mark L 5d20efdbbd Adding an ARPACK version of ex11p for parallel testing
This version compares well to both ex11 and ex11p when run in serial.
However there is a bug which produces very poor solutions in parallel.
2017-02-22 02:35:08 -08:00
Stowell, Mark L eed944d75f Adding serial ARPACK examples 2017-02-21 17:22:33 -08:00
Stowell, Mark L 826f041d7f Adding ARPACK wrapper 2017-02-21 17:22:12 -08:00
Stowell, Mark L 97d4558da0 Adding ARPACK to config files 2017-02-21 17:20:55 -08:00
24 changed files with 3004 additions and 92 deletions
+3
View File
@@ -97,6 +97,9 @@
// Enable MFEM functionality based on the SuiteSparse library.
// #define MFEM_USE_SUITESPARSE
// Enable MFEM functionality based on the ARPACK library.
// #define MFEM_USE_ARPACK
// Enable MFEM functionality based on the SuperLU_DIST library.
// #define MFEM_USE_SUPERLU
// #define MFEM_USE_SUPERLU5
+1
View File
@@ -32,6 +32,7 @@ MFEM_USE_MEMALLOC = @MFEM_USE_MEMALLOC@
MFEM_TIMER_TYPE = @MFEM_TIMER_TYPE@
MFEM_USE_SUNDIALS = @MFEM_USE_SUNDIALS@
MFEM_USE_SUITESPARSE = @MFEM_USE_SUITESPARSE@
MFEM_USE_ARPACK = @MFEM_USE_ARPACK@
MFEM_USE_SUPERLU = @MFEM_USE_SUPERLU@
MFEM_USE_SUPERLU5 = @MFEM_USE_SUPERLU5@
MFEM_USE_MUMPS = @MFEM_USE_MUMPS@
+9
View File
@@ -178,6 +178,7 @@ MFEM_USE_ALGOIM = NO
MFEM_USE_UMPIRE = NO
MFEM_USE_SIMD = NO
MFEM_USE_ADIOS2 = NO
MFEM_USE_ARPACK = NO
MFEM_USE_MKL_CPARDISO = NO
MFEM_USE_MKL_PARDISO = NO
MFEM_USE_MOONOLITH = NO
@@ -427,6 +428,14 @@ NETCDF_LIB = $(XLINKER)-rpath,$(NETCDF_DIR)/lib -L$(NETCDF_DIR)/lib\
$(XLINKER)-rpath,$(HDF5_DIR)/lib -L$(HDF5_DIR)/lib\
-lnetcdf -lhdf5_hl -lhdf5 $(ZLIB_LIB)
# ARPACK library configuration
ARPACK_DIR = @MFEM_DIR@/../ARPACK
ifeq ($(MFEM_USE_MPI),YES)
ARPACK_LIB = -L$(ARPACK_DIR) -lparpack -larpack
else
ARPACK_LIB = -L$(ARPACK_DIR) -larpack
endif
# PETSc library configuration (version greater or equal to 3.8 or the dev branch)
PETSC_ARCH := arch-linux2-c-debug
PETSC_DIR := $(MFEM_DIR)/../petsc/$(PETSC_ARCH)
+7
View File
@@ -49,6 +49,13 @@ list(APPEND ALL_EXE_SRCS
ex41.cpp
)
if (MFEM_USE_ARPACK)
list(APPEND ALL_EXE_SRCS
ex11.pp
ex13.pp
)
endif()
if (MFEM_USE_MPI)
list(APPEND ALL_EXE_SRCS
ex0p.cpp
+298
View File
@@ -0,0 +1,298 @@
// MFEM Example 11 - Serial Version
//
// Compile with: make ex11
//
// Sample runs: ex11 -m ../data/square-disc.mesh
// ex11 -m ../data/star.mesh
// ex11 -m ../data/star-mixed.mesh
// ex11 -m ../data/periodic-annulus-sector.msh
// ex11 -m ../data/square-disc-p2.vtk -o 2
// ex11 -m ../data/square-disc-p3.mesh -o 3
// ex11 -m ../data/square-disc-nurbs.mesh -o -1
// ex11 -m ../data/disc-nurbs.mesh -o -1 -n 20
// ex11 -m ../data/star-surf.mesh
// ex11 -m ../data/square-disc-surf.mesh
// ex11 -m ../data/inline-segment.mesh
// ex11 -m ../data/inline-quad.mesh
// ex11 -m ../data/inline-tri.mesh
// ex11 -m ../data/amr-quad.mesh
// ex11 -m ../data/amr-hex.mesh
// ex11 -m ../data/mobius-strip.mesh -n 8
//
// Description: This example code demonstrates the use of MFEM to solve the
// eigenvalue problem -Delta u = lambda u with homogeneous
// Dirichlet boundary conditions.
//
// We compute a number of the lowest eigenmodes by discretizing
// the Laplacian and Mass operators using a FE space of the
// specified order, or an isoparametric/isogeometric space if
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of the ARPACK eigenvalue solver
// (regular inverse mode). Reusing a single GLVis visualization
// window for multiple eigenfunctions is also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
#ifdef MFEM_USE_ARPACK
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ser_ref_levels = 3;
int order = 1;
int nev = 5;
double dbc_eig = 1e3;
bool visualization = 1;
bool arp_solver = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&dbc_eig, "-d", "--dbc-eig",
"Eigenvalues associated with Dirichlet BC "
"(should be larger than the maximum desired eigenvalue).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh;
ifstream imesh(mesh_file);
if (!imesh)
{
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
return 2;
}
mesh = new Mesh(imesh, 1, 1);
imesh.close();
int dim = mesh->Dimension();
// 3. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
// specified on the command line with -rs).
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 4. Define a finite element space on the mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (mesh->GetNodes())
{
fec = mesh->GetNodes()->OwnFEC();
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
int size = fespace->GetVSize();
cout << "Number of unknowns: " << size << endl;
// 5. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
// element space. The first corresponds to the Laplacian operator -Delta,
// while the second is a simple mass matrix needed on the right hand side
// of the generalized eigenvalue problem below. The boundary conditions
// are implemented by elimination with special values on the diagonal to
// shift the Dirichlet eigenvalues out of the computational range. After
// serial and parallel assembly we extract the corresponding parallel
// matrices A and M.
ConstantCoefficient one(1.0);
Array<int> ess_bdr;
if (mesh->bdr_attributes.Size())
{
ess_bdr.SetSize(mesh->bdr_attributes.Max());
ess_bdr = 1;
}
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
if (mesh->bdr_attributes.Size() == 0)
{
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
// closed surface.
a->AddDomainIntegrator(new MassIntegrator(one));
}
a->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
a->EliminateEssentialBCDiag(ess_bdr, dbc_eig);
}
a->Finalize();
BilinearForm *m = new BilinearForm(fespace);
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
if (mesh->bdr_attributes.Size() != 0)
{
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, 1.0);
}
m->Finalize();
Solver * solver = NULL;
#ifndef MFEM_USE_SUITESPARSE
// 6. Define a simple symmetric Gauss-Seidel preconditioner and use it to
// solve the system A X = B with PCG.
cout << "Building CGSolver" << endl;
GSSmoother M(m->SpMat());
CGSolver * cg_solver = new CGSolver;
cg_solver->SetPreconditioner(M);
cg_solver->SetRelTol(1.0e-12);
solver = cg_solver;
#else
// 7. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
cout << "Building UMFPackSolver" << endl;
UMFPackSolver * umf_solver = new UMFPackSolver;
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
solver = umf_solver;
#endif
solver->SetOperator(m->SpMat());
// 7. Define and configure the ARPACK eigensolver
SymGenEigensolver * eig_solver = NULL;
if (arp_solver)
{
// ArPackSymGen * arpack = new ArPackSymGen();
ArPackSAUPD * arpack = new ArPackSAUPD();
arpack->SetMode(2);
arpack->SetNumModes(nev);
arpack->SetMaxIter(400);
arpack->SetTol(1e-8);
arpack->SetPrintLevel(2);
arpack->SetSolver(*solver);
eig_solver = arpack;
}
eig_solver->SetOperators(*a, *m);
// 8. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<double> eigenvalues;
eig_solver->Solve();
eig_solver->GetEigenvalues(eigenvalues);
cout << endl;
std::ios::fmtflags old_fmt = cout.flags();
cout.setf(std::ios::scientific);
std::streamsize old_prec = cout.precision(14);
for (int i=0; i<nev; i++)
{
cout << "Eigenvalue lambda " << eigenvalues[i] << endl;
}
cout.precision(old_prec);
cout.flags(old_fmt);
cout << endl;
GridFunction x(fespace);
// 9. Save the refined mesh and the modes in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g mode".
{
ostringstream mesh_name, mode_name;
mesh_name << "ex11.mesh";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
for (int i=0; i<nev; i++)
{
// convert eigenvector from Vector to GridFunction
x = eig_solver->GetEigenvector(i);
mode_name << "mode_" << setfill('0') << setw(2) << i;
ofstream mode_ofs(mode_name.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
mode_name.str("");
}
}
// 10. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<nev; i++)
{
cout << "Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << endl;
// convert eigenvector from Vector to GridFunction
x = eig_solver->GetEigenvector(i);
mode_sock << "solution\n" << *mesh << x << flush
<< "window_title 'Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
char c;
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 11. Free the used memory.
delete eig_solver;
delete solver;
delete m;
delete a;
delete fespace;
if (order > 0)
{
delete fec;
}
delete mesh;
return 0;
}
#endif // MFEM_USE_ARPACK
+104 -43
View File
@@ -72,6 +72,8 @@ int main(int argc, char *argv[])
int seed = 75;
bool slu_solver = false;
bool sp_solver = false;
bool lob_solver = true;
bool arp_solver = false;
bool cpardiso_solver = false;
bool visualization = 1;
@@ -97,6 +99,10 @@ int main(int argc, char *argv[])
args.AddOption(&sp_solver, "-sp", "--strumpack", "-no-sp",
"--no-strumpack", "Use the STRUMPACK Solver.");
#endif
#ifdef MFEM_USE_ARPACK
args.AddOption(&arp_solver, "-arp", "--arpack", "-no-arp",
"--no-arpack", "Use the Parallel ARPACK Solver.");
#endif
#ifdef MFEM_USE_MKL_CPARDISO
args.AddOption(&cpardiso_solver, "-cpardiso", "--cpardiso", "-no-cpardiso",
"--no-cpardiso", "Use the MKL CPardiso Solver.");
@@ -113,6 +119,11 @@ int main(int argc, char *argv[])
<< " Defaulting to SuperLU." << endl;
sp_solver = false;
}
if (arp_solver)
{
lob_solver = false;
}
// The command line options are also passed to the STRUMPACK
// solver. So do not exit if some options are not recognized.
if (!sp_solver)
@@ -243,70 +254,119 @@ int main(int argc, char *argv[])
// 8. Define and configure the LOBPCG eigensolver and the BoomerAMG
// preconditioner for A to be used within the solver. Set the matrices
// which define the generalized eigenproblem A x = lambda M x.
Solver * solver = NULL;
Solver * precond = NULL;
if (!slu_solver && !sp_solver && !cpardiso_solver)
{
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
amg->SetPrintLevel(0);
precond = amg;
}
else
{
#ifdef MFEM_USE_SUPERLU
if (slu_solver)
if (arp_solver)
{
HyprePCG * pcg = new HyprePCG(*A);
pcg->SetTol(1e-12);
pcg->SetPreconditioner(*amg);
solver = pcg;
}
}
#ifdef MFEM_USE_SUPERLU
else if (slu_solver)
{
SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD);
superlu->SetPrintStatistics(false);
superlu->SetSymmetricPattern(true);
superlu->SetColumnPermutation(superlu::PARMETIS);
superlu->SetOperator(*Arow);
if (arp_solver)
{
solver = superlu;
}
else
{
SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD);
superlu->SetPrintStatistics(false);
superlu->SetSymmetricPattern(true);
superlu->SetColumnPermutation(superlu::PARMETIS);
superlu->SetOperator(*Arow);
precond = superlu;
}
}
#endif
#ifdef MFEM_USE_STRUMPACK
if (sp_solver)
else if (sp_solver)
{
STRUMPACKSolver * strumpack = new STRUMPACKSolver(argc, argv,
MPI_COMM_WORLD);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetMatching(strumpack::MatchingJob::NONE);
strumpack->SetCompression(strumpack::CompressionType::NONE);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
if (arp_solver)
{
solver = strumpack;
}
else
{
STRUMPACKSolver * strumpack = new STRUMPACKSolver(MPI_COMM_WORLD, argc, argv);
strumpack->SetPrintFactorStatistics(true);
strumpack->SetPrintSolveStatistics(false);
strumpack->SetKrylovSolver(strumpack::KrylovSolver::DIRECT);
strumpack->SetReorderingStrategy(strumpack::ReorderingStrategy::METIS);
strumpack->SetMatching(strumpack::MatchingJob::NONE);
strumpack->SetCompression(strumpack::CompressionType::NONE);
strumpack->SetOperator(*Arow);
strumpack->SetFromCommandLine();
precond = strumpack;
}
}
#endif
#ifdef MFEM_USE_MKL_CPARDISO
if (cpardiso_solver)
else if (cpardiso_solver)
{
auto cpardiso = new CPardisoSolver(A->GetComm());
cpardiso->SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
cpardiso->SetPrintLevel(1);
cpardiso->SetOperator(*A);
if (arp_solver)
{
solver = cpardiso;
}
else
{
auto cpardiso = new CPardisoSolver(A->GetComm());
cpardiso->SetMatrixType(CPardisoSolver::MatType::REAL_STRUCTURE_SYMMETRIC);
cpardiso->SetPrintLevel(1);
cpardiso->SetOperator(*A);
precond = cpardiso;
}
#endif
}
#endif
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
lobpcg->SetNumModes(nev);
lobpcg->SetRandomSeed(seed);
lobpcg->SetPreconditioner(*precond);
lobpcg->SetMaxIter(200);
lobpcg->SetTol(1e-8);
lobpcg->SetPrecondUsageMode(1);
lobpcg->SetPrintLevel(1);
lobpcg->SetMassMatrix(*M);
lobpcg->SetOperator(*A);
SymGenEigensolver * eig_solver = NULL;
if (lob_solver)
{
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
lobpcg->SetNumModes(nev);
lobpcg->SetRandomSeed(seed);
lobpcg->SetPreconditioner(*precond);
lobpcg->SetMaxIter(200);
lobpcg->SetTol(1e-8);
lobpcg->SetPrecondUsageMode(1);
lobpcg->SetPrintLevel(1);
eig_solver = lobpcg;
}
#ifdef MFEM_USE_ARPACK
else if (arp_solver)
{
ArPackPSAUPD * arpack = new ArPackPSAUPD(MPI_COMM_WORLD);
arpack->SetNumModes(nev);
arpack->SetMaxIter(400);
arpack->SetTol(1e-8);
arpack->SetMode(3);
arpack->SetPrintLevel(2);
arpack->SetSolver(*solver);
eig_solver = arpack;
}
#endif
eig_solver->SetOperators(*A, *M);
// 9. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<real_t> eigenvalues;
lobpcg->Solve();
lobpcg->GetEigenvalues(eigenvalues);
eig_solver->Solve();
eig_solver->GetEigenvalues(eigenvalues);
ParGridFunction x(fespace);
// 10. Save the refined mesh and the modes in parallel. This output can be
@@ -321,8 +381,8 @@ int main(int argc, char *argv[])
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(eig_solver->GetEigenvector(i));
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
@@ -350,8 +410,8 @@ int main(int argc, char *argv[])
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(eig_solver->GetEigenvector(i));
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush
@@ -375,7 +435,8 @@ int main(int argc, char *argv[])
}
// 12. Free the used memory.
delete lobpcg;
delete eig_solver;
delete solver;
delete precond;
delete M;
delete A;
+381
View File
@@ -0,0 +1,381 @@
// MFEM Example 11 - Parallel Version
//
// Compile with: make ex11p
//
// Sample runs: mpirun -np 4 ex11p -m ../data/square-disc.mesh
// mpirun -np 4 ex11p -m ../data/star.mesh
// mpirun -np 4 ex11p -m ../data/escher.mesh
// mpirun -np 4 ex11p -m ../data/fichera.mesh
// mpirun -np 4 ex11p -m ../data/square-disc-p2.vtk -o 2
// mpirun -np 4 ex11p -m ../data/square-disc-p3.mesh -o 3
// mpirun -np 4 ex11p -m ../data/square-disc-nurbs.mesh -o -1
// mpirun -np 4 ex11p -m ../data/disc-nurbs.mesh -o -1 -n 20
// mpirun -np 4 ex11p -m ../data/pipe-nurbs.mesh -o -1
// mpirun -np 4 ex11p -m ../data/ball-nurbs.mesh -o 2
// mpirun -np 4 ex11p -m ../data/star-surf.mesh
// mpirun -np 4 ex11p -m ../data/square-disc-surf.mesh
// mpirun -np 4 ex11p -m ../data/inline-segment.mesh
// mpirun -np 4 ex11p -m ../data/amr-quad.mesh
// mpirun -np 4 ex11p -m ../data/amr-hex.mesh
// mpirun -np 4 ex11p -m ../data/mobius-strip.mesh -n 8
// mpirun -np 4 ex11p -m ../data/klein-bottle.mesh -n 10
//
// Description: This example code demonstrates the use of MFEM to solve the
// eigenvalue problem -Delta u = lambda u with homogeneous
// Dirichlet boundary conditions.
//
// We compute a number of the lowest eigenmodes by discretizing
// the Laplacian and Mass operators using a FE space of the
// specified order, or an isoparametric/isogeometric space if
// order < 1 (quadratic for quadratic curvilinear mesh, NURBS for
// NURBS mesh, etc.)
//
// The example highlights the use of the LOBPCG and ARPACK
// eigenvalue solvers together with the BoomerAMG preconditioner
// in HYPRE, as well as optionally the SuperLU parallel direct
// solver. Reusing a single GLVis visualization window for
// multiple eigenfunctions is also illustrated.
//
// We recommend viewing Example 1 before viewing this example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Initialize MPI.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
// 2. Parse command-line options.
const char *mesh_file = "../data/star.mesh";
int ser_ref_levels = 2;
int par_ref_levels = 1;
int order = 1;
int nev = 5;
bool slu_solver = false;
bool use_arpack = false;
bool visualization = 1;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&ser_ref_levels, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&par_ref_levels, "-rp", "--refine-parallel",
"Number of times to refine the mesh uniformly in parallel.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
#ifdef MFEM_USE_SUPERLU
args.AddOption(&slu_solver, "-slu", "--superlu", "-no-slu",
"--no-superlu", "Use the SuperLU Solver.");
#endif
#ifdef MFEM_USE_ARPACK
args.AddOption(&use_arpack, "-arpack", "--use-arpack", "-no-arpack",
"--no-arpack",
"Enable or disable the use of ARPACK.");
#endif
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// 3. Read the (serial) mesh from the given mesh file on all processors. We
// can handle triangular, quadrilateral, tetrahedral, hexahedral, surface
// and volume meshes with the same code.
Mesh *mesh;
ifstream imesh(mesh_file);
if (!imesh)
{
if (myid == 0)
{
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
}
MPI_Finalize();
return 2;
}
mesh = new Mesh(imesh, 1, 1);
imesh.close();
int dim = mesh->Dimension();
// 4. Refine the serial mesh on all processors to increase the resolution. In
// this example we do 'ref_levels' of uniform refinement (2 by default, or
// specified on the command line with -rs).
for (int lev = 0; lev < ser_ref_levels; lev++)
{
mesh->UniformRefinement();
}
// 5. Define a parallel mesh by a partitioning of the serial mesh. Refine
// this mesh further in parallel to increase the resolution (1 time by
// default, or specified on the command line with -rp). Once the parallel
// mesh is defined, the serial mesh can be deleted.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
for (int lev = 0; lev < par_ref_levels; lev++)
{
pmesh->UniformRefinement();
}
// 6. Define a parallel finite element space on the parallel mesh. Here we
// use continuous Lagrange finite elements of the specified order. If
// order < 1, we instead use an isoparametric/isogeometric space.
FiniteElementCollection *fec;
if (order > 0)
{
fec = new H1_FECollection(order, dim);
}
else if (pmesh->GetNodes())
{
fec = pmesh->GetNodes()->OwnFEC();
}
else
{
fec = new H1_FECollection(order = 1, dim);
}
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of unknowns: " << size << endl;
}
// 7. Set up the parallel bilinear forms a(.,.) and m(.,.) on the finite
// element space. The first corresponds to the Laplacian operator -Delta,
// while the second is a simple mass matrix needed on the right hand side
// of the generalized eigenvalue problem below. The boundary conditions
// are implemented by elimination with special values on the diagonal to
// shift the Dirichlet eigenvalues out of the computational range. After
// serial and parallel assembly we extract the corresponding parallel
// matrices A and M.
ConstantCoefficient one(1.0);
Array<int> ess_bdr;
if (pmesh->bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
ess_bdr = 1;
}
ParBilinearForm *a = new ParBilinearForm(fespace);
a->AddDomainIntegrator(new DiffusionIntegrator(one));
if (pmesh->bdr_attributes.Size() == 0)
{
// Add a mass term if the mesh has no boundary, e.g. periodic mesh or
// closed surface.
a->AddDomainIntegrator(new MassIntegrator(one));
}
a->Assemble();
a->EliminateEssentialBCDiag(ess_bdr, 1.0);
a->Finalize();
ParBilinearForm *m = new ParBilinearForm(fespace);
m->AddDomainIntegrator(new MassIntegrator(one));
m->Assemble();
// shift the eigenvalue corresponding to eliminated dofs to a large value
m->EliminateEssentialBCDiag(ess_bdr, numeric_limits<double>::min());
m->Finalize();
HypreParMatrix *A = a->ParallelAssemble();
HypreParMatrix *M = m->ParallelAssemble();
#ifdef MFEM_USE_SUPERLU
Operator * Arow = NULL;
if (slu_solver)
{
Arow = new SuperLURowLocMatrix(*A);
}
#endif
delete a;
delete m;
// 8. Define and configure the LOBPCG eigensolver and the BoomerAMG
// preconditioner for A to be used within the solver. Set the matrices
// which define the generalized eigenproblem A x = lambda M x.
Eigensolver * esolver = NULL;
Solver * solver = NULL;
Solver * precond = NULL;
if (!slu_solver)
{
HypreBoomerAMG * amg = new HypreBoomerAMG(*A);
amg->SetPrintLevel(0);
precond = amg;
#ifdef MFEM_USE_ARPACK
if ( use_arpack )
{
HyprePCG * pcg = new HyprePCG(*A);
pcg->SetTol(1e-12);
pcg->SetMaxIter(200);
pcg->SetPreconditioner(*amg);
pcg->SetPrintLevel(0);
solver = pcg;
}
#endif
}
#ifdef MFEM_USE_SUPERLU
else
{
SuperLUSolver * superlu = new SuperLUSolver(MPI_COMM_WORLD);
superlu->SetPrintStatistics(false);
superlu->SetSymmetricPattern(true);
superlu->SetColumnPermutation(superlu::PARMETIS);
superlu->SetOperator(*Arow);
solver = use_arpack?superlu:NULL;
precond = use_arpack?NULL:superlu;
}
#endif
if ( use_arpack )
{
ParArPackSym * arpack = new ParArPackSym(MPI_COMM_WORLD);
arpack->SetMode(3);
arpack->SetPrintLevel(2);
arpack->SetSolver(*solver);
esolver = arpack;
}
else
{
HypreLOBPCG * lobpcg = new HypreLOBPCG(MPI_COMM_WORLD);
lobpcg->SetPreconditioner(*precond);
lobpcg->SetPrecondUsageMode(1);
lobpcg->SetPrintLevel(1);
esolver = lobpcg;
}
esolver->SetNumModes(nev);
esolver->SetMaxIter(100);
esolver->SetTol(1e-8);
esolver->SetMassMatrix(*M);
esolver->SetOperator(*A);
// 9. Compute the eigenmodes and extract the array of eigenvalues. Define a
// parallel grid function to represent each of the eigenmodes returned by
// the solver.
Array<double> eigenvalues;
esolver->Solve();
esolver->GetEigenvalues(eigenvalues);
if ( myid == 0 && use_arpack )
{
cout << endl;
for (int i=0; i<eigenvalues.Size(); i++)
{
cout << "Eigenvalue lambda " << eigenvalues[i] << endl;
}
cout << endl;
}
ParGridFunction x(fespace);
// 10. Save the refined mesh and the modes in parallel. This output can be
// viewed later using GLVis: "glvis -np <np> -m mesh -g mode".
{
ostringstream mesh_name, mode_name;
mesh_name << "mesh." << setfill('0') << setw(6) << myid;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
pmesh->Print(mesh_ofs);
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x.Distribute(esolver->GetEigenvector(i));
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
ofstream mode_ofs(mode_name.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
mode_name.str("");
}
}
// 11. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<nev; i++)
{
if ( myid == 0 )
{
cout << "Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
x.Distribute(esolver->GetEigenvector(i));
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush
<< "window_title 'Eigenmode " << i+1 << '/' << nev
<< ", Lambda = " << eigenvalues[i] << "'" << endl;
char c;
if (myid == 0)
{
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
}
MPI_Bcast(&c, 1, MPI_CHAR, 0, MPI_COMM_WORLD);
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 12. Free the used memory.
delete esolver;
delete solver;
delete precond;
delete M;
delete A;
delete fespace;
if (order > 0)
{
delete fec;
}
delete pmesh;
MPI_Finalize();
return 0;
}
+5 -5
View File
@@ -276,8 +276,8 @@ int main(int argc, char *argv[])
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(lobpcg->GetEigenvector(i));
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
@@ -303,7 +303,7 @@ int main(int argc, char *argv[])
pmesh->Print(adios2output);
for (int i=0; i<nev; i++)
{
x = lobpcg->GetEigenvector(i);
x.Distribute(lobpcg->GetEigenvector(i));
// x is a temporary that must be saved immediately
x.Save(adios2output, "mode_" + std::to_string(i));
}
@@ -326,8 +326,8 @@ int main(int argc, char *argv[])
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(lobpcg->GetEigenvector(i));
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush
+282
View File
@@ -0,0 +1,282 @@
// MFEM Example 13
//
// Compile with: make ex3p
//
// Sample runs: ex13 -m ../data/star.mesh -s 5
// ex13 -m ../data/square-disc.mesh -o 2 -n 4 // minres fails to conv.
// ex13 -m ../data/beam-hex.mesh
// ex13 -m ../data/square-disc.mesh -rs 1 -s 26
// ex13 -m ../data/square-disc-nurbs.mesh -rs 3 -s 26
// ex13 -m ../data/amr-quad.mesh -o 2 // minres fails to conv.
// ex13 -m ../data/mobius-strip.mesh -n 8
//
// Description: This example code solves a simple 3D electromagnetic
// eigenmode problem corresponding to the second order
// Maxwell equation curl curl E = lambda E with boundary
// condition E x n = 0. We discretize with Nedelec finite
// elements.
//
// The example demonstrates the use of H(curl) finite element
// spaces with the curl-curl and the (vector finite element) mass
// bilinear form, as well as the use of the ARPACK eigenmode
// solver for symmetric matrices using the shift-invert mode.
//
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
#ifdef MFEM_USE_ARPACK
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../data/beam-tet.mesh";
int order = 1;
int nev = 5;
int sr = 2;
double sigma = 11.0;
bool visualization = 1;
bool arp_solver = true;
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&nev, "-n", "--num-eigs",
"Number of desired eigenmodes.");
args.AddOption(&sr, "-rs", "--refine-serial",
"Number of times to refine the mesh uniformly in serial.");
args.AddOption(&sigma, "-s", "--shift",
"Average of the desired eigenvalue range.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
if (!args.Good())
{
args.PrintUsage(cout);
return 1;
}
args.PrintOptions(cout);
// 2. Read the mesh from the given mesh file. We can handle triangular,
// quadrilateral, tetrahedral, hexahedral, surface and volume meshes
// with the same code.
Mesh *mesh;
ifstream imesh(mesh_file);
if (!imesh)
{
cerr << "\nCan not open mesh file: " << mesh_file << '\n' << endl;
return 2;
}
mesh = new Mesh(imesh, 1, 1);
imesh.close();
int dim = mesh->Dimension();
// 3. Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement.
{
int ref_levels = sr;
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
}
// 4. Define a finite element space on the mesh. Here we use the lowest
// order Nedelec finite elements, but we can easily switch
// to higher-order spaces by changing the value of p.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
int size = fespace->GetVSize();
cout << "Number of unknowns: " << size << endl;
cout << "Number of boundary attributes: " << mesh->bdr_attributes.Max()
<< endl;
// 5. Set up the parallel bilinear form corresponding to the EM diffusion
// operator curl muinv curl - sigma I, by adding the curl-curl and the
// mass domain integrators and finally imposing homogeneous Dirichlet
// boundary conditions. The boundary conditions are implemented by
// marking all the boundary attributes from the mesh as essential
// (Dirichlet). After serial and parallel assembly we extract the
// parallel matrices A and M.
Coefficient *muinv = new ConstantCoefficient(1.0);
Coefficient *negSigma = new ConstantCoefficient(-sigma);
BilinearForm *a = new BilinearForm(fespace);
a->AddDomainIntegrator(new CurlCurlIntegrator(*muinv));
a->AddDomainIntegrator(new VectorFEMassIntegrator(*negSigma));
a->Assemble();
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
a->EliminateEssentialBC(ess_bdr);
a->Finalize();
BilinearForm *m = new BilinearForm(fespace);
m->AddDomainIntegrator(new VectorFEMassIntegrator());
m->Assemble();
m->EliminateEssentialBCDiag(ess_bdr, sqrt(numeric_limits<double>::min()));
m->Finalize();
// 6. Define a parallel grid function to approximate each of the
// eigenmodes returned by the solver. Use this as a template to
// create a special multi-vector object needed by the eigensolver
// which is then initialized with random values.
GridFunction x(fespace);
x = 0.0;
// 7. Define and configure the GMRES
// solver to be used within the eigensolver.
Solver * solver = NULL;
if ( false )
{
GMRESSolver * gmres = new GMRESSolver();
gmres->SetOperator(*a);
gmres->SetRelTol(1e-8);
gmres->SetMaxIter(1000);
gmres->SetPrintLevel(0);
solver = gmres;
}
else
{
#ifndef MFEM_USE_SUITESPARSE
cout << "Building MINRESSolver" << endl;
MINRESSolver * minres = new MINRESSolver();
minres->SetRelTol(1e-12);
minres->SetMaxIter(1000);
minres->SetPrintLevel(0);
solver = minres;
#else
// 7. If MFEM was compiled with SuiteSparse, use UMFPACK to solve the system.
cout << "Building UMFPackSolver" << endl;
UMFPackSolver * umf_solver = new UMFPackSolver;
umf_solver->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
solver = umf_solver;
#endif
}
solver->SetOperator(a->SpMat());
// 7. Define and configure the ARPACK eigensolver
SymGenEigensolver * eig_solver = NULL;
if (arp_solver)
{
ArPackSAUPD * arpack = new ArPackSAUPD();
arpack->SetNumModes(nev);
arpack->SetMaxIter(400);
arpack->SetTol(1e-8);
arpack->SetShift(sigma);
arpack->SetMode(3);
arpack->SetPrintLevel(2);
arpack->SetSolver(*solver);
eig_solver = arpack;
}
eig_solver->SetOperators(*a, *m);
// Obtain the eigenvalues and eigenvectors
Array<double> eigenvalues(nev);
eigenvalues = -1.0;
// arpack->Solve(eigenvalues, *eigenvectors);
eig_solver->Solve();
eig_solver->GetEigenvalues(eigenvalues);
cout << endl;
std::ios::fmtflags old_fmt = cout.flags();
cout.setf(std::ios::scientific);
std::streamsize old_prec = cout.precision(14);
for (int i=0; i<min(nev,eigenvalues.Size()); i++)
{
cout << "Eigenvalue lambda " << eigenvalues[i] << endl;
}
cout.precision(old_prec);
cout.flags(old_fmt);
cout << endl;
VisItDataCollection visit_dc("Example13", mesh);
GridFunction ** mode = new GridFunction*[min(nev,eigenvalues.Size())];
for (int i=0; i<min(nev,eigenvalues.Size()); i++)
{
mode[i] = new GridFunction(fespace);
*mode[i] = eig_solver->GetEigenvector(i);
ostringstream modeName;
modeName << "mode_" << setfill('0') << setw(2) << i;
visit_dc.RegisterField(modeName.str().c_str(),mode[i]);
}
visit_dc.Save();
// 8. Save the refined mesh and the modes. This output can
// be viewed later using GLVis: "glvis -m mesh -g mode".
{
ofstream mesh_ofs("refined.mesh");
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
for (int i=0; i<min(nev,eigenvalues.Size()); i++)
{
x = eig_solver->GetEigenvector(i);
ostringstream modeName;
modeName << "mode_" << setfill('0') << setw(2) << i;
ofstream mode_ofs(modeName.str().c_str());
mode_ofs.precision(8);
x.Save(mode_ofs);
modeName.str("");
}
}
// 9. Send the solution by socket to a GLVis server.
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
socketstream mode_sock(vishost, visport);
mode_sock.precision(8);
for (int i=0; i<min(nev,eigenvalues.Size()); i++)
{
x = eig_solver->GetEigenvector(i);
mode_sock << "solution\n" << *mesh << x << flush;
char c;
cout << "press (q)uit or (c)ontinue --> " << flush;
cin >> c;
if (c != 'c')
{
break;
}
}
mode_sock.close();
}
// 10. Free the used memory.
delete a;
delete m;
delete negSigma;
delete muinv;
delete eig_solver;
delete solver;
// delete X;
delete fespace;
delete fec;
delete mesh;
return 0;
}
#endif // MFEM_USE_ARPACK
+4 -4
View File
@@ -215,8 +215,8 @@ int main(int argc, char *argv[])
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(ame->GetEigenvector(i));
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
@@ -244,8 +244,8 @@ int main(int argc, char *argv[])
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(ame->GetEigenvector(i));
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush
+4 -4
View File
@@ -228,7 +228,7 @@ int main(int argc, char *argv[])
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
x.Distribute(ame->GetEigenvector(i));
curl.Mult(x, dx);
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
@@ -295,7 +295,7 @@ int main(int argc, char *argv[])
}
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
x.Distribute(ame->GetEigenvector(i));
curl.Mult(x, dx);
{
@@ -469,7 +469,7 @@ int main(int argc, char *argv[])
}
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
x.Distribute(ame->GetEigenvector(i));
curl.Mult(x, dx);
{
@@ -599,7 +599,7 @@ int main(int argc, char *argv[])
}
// convert eigenvector from HypreParVector to ParGridFunction
x = ame->GetEigenvector(i);
x.Distribute(ame->GetEigenvector(i));
curl.Mult(x, dx);
mode_sock << "parallel " << num_procs << " " << myid << "\n"
+3 -3
View File
@@ -658,7 +658,7 @@ void ScalarWaveGuide(int mode, ParGridFunction &x)
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
x.Distribute(lobpcg.GetEigenvector(mode));
delete A;
delete M;
@@ -714,7 +714,7 @@ void VectorWaveGuide(int mode, ParGridFunction &x)
ame.SetOperator(*A);
ame.Solve();
x = ame.GetEigenvector(mode);
x.Distribute(ame.GetEigenvector(mode));
delete A;
delete M;
@@ -780,7 +780,7 @@ void PseudoScalarWaveGuide(int mode, ParGridFunction &x_l2)
lobpcg.SetOperator(*A);
lobpcg.Solve();
x = lobpcg.GetEigenvector(mode);
x.Distribute(lobpcg.GetEigenvector(mode));
x_l2.ProjectCoefficient(xCoef);
+3
View File
@@ -31,6 +31,9 @@ SEQ_DEVICE_EXAMPLES = ex1 ex3 ex4 ex5 ex6 ex9 ex14 ex22 ex24 ex25 ex26 ex34
PAR_DEVICE_EXAMPLES = ex1p ex2p ex3p ex4p ex5p ex6p ex7p ex9p ex13p ex14p \
ex22p ex24p ex25p ex26p ex34p ex35p
ifeq ($(MFEM_USE_ARPACK),YES)
SEQ_EXAMPLES += ex11 ex13
endif
ifeq ($(MFEM_USE_LAPACK),YES)
SEQ_EXAMPLES += ex38
endif
+7
View File
@@ -23,6 +23,7 @@ list(APPEND SRCS
complex_operator.cpp
constraints.cpp
densemat.cpp
eigensolvers.cpp
filteredsolver.cpp
handle.cpp
matrix.cpp
@@ -55,6 +56,7 @@ list(APPEND HDRS
dinvariants.hpp
dtensor.hpp
dual.hpp
eigensolvers.hpp
filteredsolver.hpp
handle.hpp
invariants.hpp
@@ -101,6 +103,11 @@ if (MFEM_USE_MPI)
endif()
endif()
if (MFEM_USE_ARPACK)
list(APPEND SRCS arpack.cpp)
list(APPEND HDRS arpack.hpp)
endif()
if (MFEM_USE_SUNDIALS)
list(APPEND SRCS sundials.cpp)
list(APPEND HDRS sundials.hpp)
+1122
View File
File diff suppressed because it is too large Load Diff
+271
View File
@@ -0,0 +1,271 @@
// 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.
#ifndef MFEM_ARPACK
#define MFEM_ARPACK
#include "../config/config.hpp"
#ifdef MFEM_USE_ARPACK
#include <string>
#ifdef MFEM_USE_MPI
#include <mpi.h>
#include "hypre.hpp"
#endif
#include "operator.hpp"
#define SSAUPD ssaupd_
#define SSEUPD sseupd_
#define DSAUPD dsaupd_
#define DSEUPD dseupd_
#ifdef MFEM_USE_MPI
#define PSSAUPD pssaupd_
#define PSSEUPD psseupd_
#define PDSAUPD pdsaupd_
#define PDSEUPD pdseupd_
#endif
extern "C" void SSAUPD(int *ido, char *bmat, int *n,
char *which, int *nev, float *tol, float *resid,
int *ncv, float *v, int *ldv,
int *iparam, int *ipntr,
float *workd, float *workl, int *lworkl, int *info);
extern "C" void SSEUPD(int *, char *, int *, float *,
float *, int *, float *, char *, int *, char *,
int *, float *, float *, int *, float *,
int *, int *, int *, float *,
float *, int *, int *);
extern "C" void DSAUPD(int *ido, char *bmat, int *n,
char *which, int *nev, double *tol, double *resid,
int *ncv, double *v, int *ldv,
int *iparam, int *ipntr,
double *workd, double *workl, int *lworkl, int *info);
extern "C" void DSEUPD(int *, char *, int *, double *,
double *, int *, double *, char *, int *, char *,
int *, double *, double *, int *, double *,
int *, int *, int *, double *,
double *, int *, int *);
#ifdef MFEM_USE_MPI
extern "C" void PSSAUPD(int *comm, int *ido, char *bmat, int *n,
char *which, int *nev, float *tol, float *resid,
int *ncv, float *v, int *ldv,
int *iparam, int *ipntr,
float *workd, float *workl, int *lworkl, int *info);
extern "C" void PSSEUPD(int *comm, int *, char *, int *, float *,
float *, int *, float *, char *, int *, char *,
int *, float *, float *, int *, float *,
int *, int *, int *, float *,
float *, int *, int *);
extern "C" void PDSAUPD(int *comm, int *ido, char *bmat, int *n,
char *which, int *nev, double *tol, double *resid,
int *ncv, double *v, int *ldv,
int *iparam, int *ipntr,
double *workd, double *workl, int *lworkl, int *info);
extern "C" void PDSEUPD(int *comm, int *, char *, int *, double *,
double *, int *, double *, char *, int *, char *,
int *, double *, double *, int *, double *,
int *, int *, int *, double *,
double *, int *, int *);
#endif
extern "C" {
void arpackgetcommdbg_(int *,int *,int *);
void arpacksetcommdbg_(int *,int *,int *);
void arpacksymdbg_(int *,int *,int *,int *,int *,int *,int *);
void arpacknonsymdbg_(int *,int *,int *,int *,int *,int *,int *);
void arpackcmplxdbg_(int *,int *,int *,int *,int *,int *,int *);
}
namespace mfem
{
/// Wrapper for the ARPACK routine SSAUPD or DSAUPD
class ArPackSAUPD : public SymEigensolver, public SymGenEigensolver
{
public:
ArPackSAUPD();
virtual ~ArPackSAUPD();
/** ARPACK modes are described in section 3.5 of the ARPACK manual.
Mode 1: regular mode to solve A x = lambda x
No solver and no mass matrix are needed.
Mode 2: regular inverse mode to solve A x = lambda M x
Both A and M are needed and the solver should compute M^{-1}.
Mode 3: shift-invert mode to solve either A x = lambda x
or A x = lambda M x
Mass matrix is optional. The solver should compute
(A-sigma I)^{-1} or (A-sigma M)^{-1}. The shift parameter,
sigma, also needs to be set with SetShift().
Mode 4: Buckling mode to solve K x = lambda K_G x
K is set using SetMassMatrix(), K_G is set using SetOperator(),
and the solver should compute (K-sigma K_G)^{-1}. The shift
parameter, sigma, also needs to be set with SetShift().
Mode 5: Cayley mode to solve A x = lambda M x
Both A and M are needed and the solver should compute
(A - sigma M)^{-1}. The shift parameter, sigma, also needs
to be set with SetShift().
*/
void SetMode(int mode);
inline void SetTol(real_t tol) override { tol_ = tol; }
inline void SetMaxIter(int max_iter) override { max_iter_ = max_iter; }
inline void SetPrintLevel(int logging) override { logging_ = logging; }
inline void SetShift(real_t sigma) { sigma_ = sigma; }
inline void SetNumModes(int num_eigs) override { nev_ = num_eigs; }
virtual void SetSolver(Solver & solver);
virtual void SetOperator(const Operator & A) override;
virtual void SetMassMatrix(const Operator & M);
virtual void SetOperators(const Operator & A, const Operator & B) override
{ SetOperator(A); SetMassMatrix(B); }
void Solve() override;
virtual int GetNumConverged() const override { return iparam_[4]; }
/// Collect the converged eigenvalues
virtual void GetEigenvalues(Array<real_t> & eigenvalues) const override;
/// Extract a single eigenvector
virtual const Vector & GetEigenvector(unsigned int i) const override;
/// Transfer ownership of the converged eigenvectors
Vector ** StealEigenvectors() override;
protected:
int myid_; // Index of this processor
int max_iter_;
int logging_;
// The following variables are for ARPACK
int nloc_; // number of items stored locally
int nev_; // number of requested eigenvalues
int ncv_; // number of ritz vectors
int rvec_; // boolean to return eigenvectors as well
int mode_; // 1 = standard, 2 = generalized, 3 = shift invert,
// 4 = buckling, 5 = Cayley
int lworkl_; // length of lworkl_ work array
int iparam_[12]; // arpack parameters
int ipntr_[12]; // arpack pointers
char bmat_; // I for standard problem, G for generalized
char which_[3]; // spectrum portion: LA, SA, LM, SM, BE
char hwmny_; // DSEUPD: A for all eigenvalues, S for some
real_t tol_; // relative accuracy bound for Ritz values
real_t sigma_; // eigenvalue shift parameter
int * select_;// workspace used during eigenvalue computation
real_t * dv_; // Ritz values
real_t * v_; // ncv Lanczos basis vectors
real_t * resid_; // residual vector
real_t * workd_; // work array for 3 vectors used in Arnoldi iteration
real_t * workl_; // work array
// Operators and Vectors needed outside of ARPACK
Solver * solver_;
const Operator * A_;
const Operator * B_;
Vector * w_;
Vector * x_;
Vector * y_;
Vector * z_;
mutable Vector ** eigenvectors_;
std::string solverName_;
void reverseComm();
int reverseCommMode1();
int reverseCommMode2();
int reverseCommMode3();
int reverseCommMode4();
int reverseCommMode5();
virtual void prepareEigenvectors() const;
void printErrors(const int & info, const int iparam[],
const char & bmat, const int & n,
const char which[],
const int & nev, const int & ncv,
const int & lworkl );
private:
virtual int computeNlocf() { return nloc_; }
virtual int computeIter(int & ido);
virtual int computeEigs();
};
#ifdef MFEM_USE_MPI
class ArPackPSAUPD : public ArPackSAUPD
{
public:
ArPackPSAUPD(MPI_Comm comm);
virtual ~ArPackPSAUPD() {}
void SetOperator(const Operator & A);
void SetMassMatrix(const Operator & M);
/// Collect the converged eigenvalues
void GetEigenvalues(Array<real_t> & eigenvalues) const;
/// Extract a single eigenvector
const Vector & GetEigenvector(unsigned int i) const;
/// Transfer ownership of the converged eigenvectors
// HypreParVector ** StealEigenvectors();
Vector ** StealEigenvectors();
protected:
void prepareEigenvectors() const;
private:
MPI_Comm comm_;
MPI_Fint commf_; // Fortran style MPI communicator
int numProcs_; // Number of processors
mutable HYPRE_Int * part_; // parallel partitioning for eigenvectors
int computeNlocf();
int computeIter(int & ido);
int computeEigs();
};
#endif // MFEM_USE_MPI
};
#endif // MFEM_USE_ARPACK
#endif // MFEM_ARPACK
+20
View File
@@ -0,0 +1,20 @@
// 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 "linalg.hpp"
#include "eigensolvers.hpp"
using namespace std;
namespace mfem
{
};
+396
View File
@@ -0,0 +1,396 @@
// 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.
#ifndef MFEM_EIGENSOLVERS
#define MFEM_EIGENSOLVERS
#include "vector.hpp"
namespace mfem
{
/// Abstract Eigenequation
/// Defines the operator of the linear eigenvalue equation
/// A x_i = lambda_i x_i
/// Where A is a real-valued operator, the lambda_i are the eigenvalues,
/// and x_i are the eigenvectors.
class Eigenequation
{
protected:
Eigenequation() = default;
public:
virtual ~Eigenequation() = default;
/// @brief Set the operator A of the eigenvalue equation
virtual void SetOperator(const Operator & A) = 0;
};
/// Abstract Complex-valued Eigenequation
/// Defines the operator of the linear eigenvalue equation
/// A x_i = lambda_i x_i
/// Where A is a complex-valued operator, the lambda_i are the eigenvalues,
/// and x_i are the eigenvectors.
class ComplexEigenequation
{
protected:
ComplexEigenequation() = default;
public:
virtual ~ComplexEigenequation() = default;
/// @brief Set the real and imaginary parts of the operator A
virtual void SetOperator(const Operator & Ar, const Operator & Ai) = 0;
};
/// Abstract Generalized Eigenequation
/// Defines the operator of the linear eigenvalue equation
/// A x_i = lambda_i B x_i
/// Where A and B are real-valued operators, the lambda_i are the eigenvalues,
/// and x_i are the eigenvectors.
class GenEigenequation
{
protected:
GenEigenequation() = default;
public:
virtual ~GenEigenequation() = default;
/// @brief Set the operators A and B of the generalized eigenvalue equation
virtual void SetOperators(const Operator & A, const Operator & B) = 0;
};
/// Abstract Complex-valued Generalized Eigenequation
/// Defines the operator of the linear eigenvalue equation
/// A x_i = lambda_i B x_i
/// Where A and B are complex-valued operators, the lambda_i are the
/// eigenvalues, and x_i are the eigenvectors.
class ComplexGenEigenequation
{
protected:
ComplexGenEigenequation() = default;
public:
virtual ~ComplexGenEigenequation() = default;
/// @brief Set the real and imaginary parts of the operators A and B
virtual void SetOperators(const Operator & Ar, const Operator & Ai,
const Operator & Br, const Operator & Bi) = 0;
};
/// Abstract Eigensolver
/// Computes eigenvalue/eigenvector pairs for the linear system
/// A x_i = lambda_i x_i
/// Where the lambda_i are the eigenvalues and x_i are the eigenvectors.
class EigensolverBase
{
protected:
EigensolverBase() = default;
public:
virtual ~EigensolverBase() = default;
/// @brief Stopping criteria based on numerical tolerance
///
/// @note This may be defined differently by different solvers.
virtual void SetTol(real_t tol) = 0;
/// @brief Stopping criteria based on number of iterations required to
/// reach convergence.
///
/// @note This may also be defined differently in different solvers.
virtual void SetMaxIter(int max_iter) = 0;
/// @brief Controls the type and amount of information printed to
/// standard output.
virtual void SetPrintLevel(int logging) = 0;
/// @brief Set the number of desired eigenmodes to compute
virtual void SetNumModes(int num_eigs) = 0;
/// @brief Get the number of converged eigenmodes
virtual int GetNumConverged() const = 0;
/// @brief Perform the eigenvalue solve
virtual void Solve() = 0;
};
/// Symmetric Eigensolver
/// If A^T = A the linear system must have real-valued eigenvalues
/// and eigenvectors.
class SymEigensolver : public EigensolverBase, public Eigenequation
{
protected:
SymEigensolver() = default;
public:
virtual ~SymEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should equal the number of converged eigenvalues.
virtual void GetEigenvalues(Array<real_t> & eigenvalues) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, numConverged). The
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain numConverged vectors.
virtual Vector ** StealEigenvectors() = 0;
};
/// Symmetric Generalized Eigensolver
/// If A^T = A and M^T = M the linear system must have real-valued eigenvalues
/// and eigenvectors.
class SymGenEigensolver : public EigensolverBase, public GenEigenequation
{
protected:
SymGenEigensolver() = default;
public:
virtual ~SymGenEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should equal the number of converged eigenvalues.
virtual void GetEigenvalues(Array<real_t> & eigenvalues) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, numConverged). The
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain numConverged vectors.
virtual Vector ** StealEigenvectors() = 0;
};
/// Hermetian Eigensolver
/// If A^H = A the linear system must have real-valued eigenvalues
/// but may have complex-valued eigenvectors.
class HermEigensolver : public EigensolverBase, public ComplexEigenequation
{
protected:
HermEigensolver() = default;
public:
virtual ~HermEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should equal the number of converged eigenvalues.
virtual void GetEigenvalues(Array<real_t> & eigenvalues) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, 2*numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain 2*numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
/// Hermetian Generalized Eigensolver
/// If A^H = A and M^H = M the linear system must have real-valued eigenvalues
/// but may have complex-valued eigenvectors.
class HermGenEigensolver :
public EigensolverBase, public ComplexGenEigenequation
{
protected:
HermGenEigensolver() = default;
public:
virtual ~HermGenEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should equal the number of converged eigenvalues.
virtual void GetEigenvalues(Array<real_t> & eigenvalues) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, 2*numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain 2*numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
/// Non-Symmetric Eigensolver
/// For general real-valued operators A the linear system must have
/// eigenvalues and eigenvectors which form complex conjugate pairs.
class NonSymEigensolver : public EigensolverBase, public Eigenequation
{
protected:
NonSymEigensolver() = default;
public:
virtual ~NonSymEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should be the number of converged
/// eigenvalues. The complex-valued eigenvalues can be constructed
/// as: lambda_{2*j} = eig[2*j]+i*eig[2*j+1] and
/// lambda_{2*j+1} = eig[2*j]-i*eig[2*j+1]
/// With j in the range [0, numConverged/2)
virtual void GetEigenvalues(Array<real_t> & eig) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts. If needed, the complex conjugate pairs of
/// eigenvectors can be constructed in the same manner described
/// for the eigenvalues.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
/// Non-Symmetric Eigensolver
/// For general real-valued operators A and M the linear system must have
/// eigenvalues and eigenvectors which form complex conjugate pairs.
class NonSymGenEigensolver : public EigensolverBase, public GenEigenequation
{
protected:
NonSymGenEigensolver() = default;
public:
virtual ~NonSymGenEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should be the number of converged
/// eigenvalues. The complex-valued eigenvalues can be constructed
/// as: lambda_{2*j} = eig[2*j]+i*eig[2*j+1] and
/// lambda_{2*j+1} = eig[2*j]-i*eig[2*j+1]
/// With j in the range [0, numConverged/2)
virtual void GetEigenvalues(Array<real_t> & eig) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts. If needed, the complex conjugate pairs of
/// eigenvectors can be constructed in the same manner described
/// for the eigenvalues.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
/// Complex Eigensolver
/// Can have arbitrary complex-valued eigenvalues and eigenvectors
class ComplexEigensolver : public EigensolverBase, public ComplexEigenequation
{
protected:
ComplexEigensolver() = default;
public:
virtual ~ComplexEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should be twice the number of converged
/// eigenvalues. The complex-valued eigenvalues can be constructed
/// as: lambda_j = eig[2*j]+i*eig[2*j+1]
virtual void GetEigenvalues(Array<real_t> & eig) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, 2*numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain 2*numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
/// Complex Generalized Eigensolver
/// Can have arbitrary complex-valued eigenvalues and eigenvectors
class ComplexGenEigensolver :
public EigensolverBase, public ComplexGenEigenequation
{
protected:
ComplexGenEigensolver() = default;
public:
virtual ~ComplexGenEigensolver() = default;
/// @brief Collect the converged eigenvalues
///
/// The length of the array should be twice the number of converged
/// eigenvalues. The complex-valued eigenvalues can be constructed
/// as: lambda_j = eig[2*j]+i*eig[2*j+1]
virtual void GetEigenvalues(Array<real_t> & eig) const = 0;
/// @brief Extract a single eigenvector
///
/// The index i should be in the range [0, 2*numConverged). The
/// vectors corresponding to even indices are the real parts of the
/// converged eigenvectors and the odd indices correspond to the
/// imaginary parts.
virtual const Vector & GetEigenvector(unsigned int i) const = 0;
/// @brief Transfer ownership of the converged eigenvectors
///
/// The array should contain 2*numConverged vectors with the even
/// indices corresponding to the real parts of the converged
/// eigenvectors and the odd indices corresponding to the imaginary
/// parts.
virtual Vector ** StealEigenvectors() = 0;
};
}
#endif
+25 -7
View File
@@ -6556,7 +6556,7 @@ HypreLOBPCG::SetPreconditioner(Solver & precond)
}
void
HypreLOBPCG::SetOperator(Operator & A)
HypreLOBPCG::SetOperator(const Operator & A)
{
HYPRE_BigInt locSize = A.Width();
@@ -6603,7 +6603,7 @@ HypreLOBPCG::SetOperator(Operator & A)
}
void
HypreLOBPCG::SetMassMatrix(Operator & M)
HypreLOBPCG::SetMassMatrix(const Operator & M)
{
matvec_fn.MatvecCreate = this->OperatorMatvecCreate;
matvec_fn.Matvec = this->OperatorMatvec;
@@ -6624,7 +6624,7 @@ HypreLOBPCG::GetEigenvalues(Array<real_t> & eigs) const
}
}
const HypreParVector &
const Vector &
HypreLOBPCG::GetEigenvector(unsigned int i) const
{
return multi_vec->GetVector(i);
@@ -6866,6 +6866,24 @@ HypreAME::SetPreconditioner(HypreSolver & precond)
ams_precond = &precond;
}
void
HypreAME::SetOperators(const Operator & opA, const Operator & opB)
{
const HypreParMatrix * A = dynamic_cast<const HypreParMatrix *>(&opA);
if (A == NULL)
{
mfem_error("HypreAME::SetOperator : first operator not HypreParMatrix!");
}
SetOperator(*A);
const HypreParMatrix * B = dynamic_cast<const HypreParMatrix *>(&opB);
if (B == NULL)
{
mfem_error("HypreAME::SetOperator : second operator not HypreParMatrix!");
}
SetMassMatrix(*B);
}
void
HypreAME::SetOperator(const HypreParMatrix & A)
{
@@ -6924,7 +6942,7 @@ HypreAME::createDummyVectors() const
}
}
const HypreParVector &
const Vector &
HypreAME::GetEigenvector(unsigned int i) const
{
if ( eigenvectors == NULL )
@@ -6935,7 +6953,7 @@ HypreAME::GetEigenvector(unsigned int i) const
return *eigenvectors[i];
}
HypreParVector **
Vector **
HypreAME::StealEigenvectors()
{
if ( eigenvectors == NULL )
@@ -6944,11 +6962,11 @@ HypreAME::StealEigenvectors()
}
// Set the local pointers to NULL so that they won't be deleted later
HypreParVector ** vecs = eigenvectors;
Vector ** vecs = (Vector**)eigenvectors;
eigenvectors = NULL;
multi_vec = NULL;
return vecs;
return (Vector**)vecs;
}
}
+30 -20
View File
@@ -18,7 +18,9 @@
#include "../general/globals.hpp"
#include "sparsemat.hpp"
#include "eigensolvers.hpp"
#include "hypre_parcsr.hpp"
#include "eigensolvers.hpp"
#include <mpi.h>
// Enable internal hypre timing routines
@@ -2146,7 +2148,7 @@ public:
A. Knyazev, M. Argentati, I. Lashuk, and E. Ovtchinnikov, SISC, 29(5),
2224-2239, 2007.
*/
class HypreLOBPCG
class HypreLOBPCG : public SymGenEigensolver
{
private:
MPI_Comm comm;
@@ -2236,38 +2238,43 @@ public:
HypreLOBPCG(MPI_Comm comm);
~HypreLOBPCG();
void SetTol(real_t tol);
void SetTol(real_t tol) override;
// not implemented in HYPRE
// real_t GetTol() const;
void SetRelTol(real_t rel_tol);
// not implemented in HYPRE
// real_t GetRelTol() const;
void SetMaxIter(int max_iter);
void SetMaxIter(int max_iter) override;
// not implemented in HYPRE
// int GetMaxIter() const;
void SetPrintLevel(int logging);
void SetNumModes(int num_eigs) { nev = num_eigs; }
void SetPrintLevel(int logging) override;
void SetNumModes(int num_eigs) override { nev = num_eigs; }
void SetPrecondUsageMode(int pcg_mode);
void SetRandomSeed(int s) { seed = s; }
void SetInitialVectors(int num_vecs, HypreParVector ** vecs);
// The following four methods support general operators
void SetPreconditioner(Solver & precond);
void SetOperator(Operator & A);
void SetMassMatrix(Operator & M);
void SetOperators(const Operator & A, const Operator & B) override
{ SetOperator(A); SetMassMatrix(B); }
void SetOperator(const Operator & A);
void SetMassMatrix(const Operator & M);
void SetSubSpaceProjector(Operator & proj) { subSpaceProj = &proj; }
/// Solve the eigenproblem
void Solve();
void Solve() override;
int GetNumConverged() const override { return nev; }
/// Collect the converged eigenvalues
void GetEigenvalues(Array<real_t> & eigenvalues) const;
void GetEigenvalues(Array<real_t> & eigenvalues) const override;
/// Extract a single eigenvector
const HypreParVector & GetEigenvector(unsigned int i) const;
const Vector & GetEigenvector(unsigned int i) const override;
/// Transfer ownership of the converged eigenvectors
HypreParVector ** StealEigenvectors() { return multi_vec->StealVectors(); }
Vector ** StealEigenvectors() override
{ return (Vector**)multi_vec->StealVectors(); }
};
/** AME eigenvalue solver in hypre
@@ -2292,7 +2299,7 @@ public:
mass matrix but it seems unlikely that this would be useful so it is not the
default behavior.
*/
class HypreAME
class HypreAME : public SymGenEigensolver
{
private:
int myid;
@@ -2321,28 +2328,31 @@ public:
HypreAME(MPI_Comm comm);
~HypreAME();
void SetTol(real_t tol);
void SetTol(real_t tol) override;
void SetRelTol(real_t rel_tol);
void SetMaxIter(int max_iter);
void SetPrintLevel(int logging);
void SetNumModes(int num_eigs);
void SetMaxIter(int max_iter) override;
void SetPrintLevel(int logging) override;
void SetNumModes(int num_eigs) override;
// The following four methods support operators of type HypreParMatrix.
void SetPreconditioner(HypreSolver & precond);
void SetOperators(const Operator & opA, const Operator & opB) override;
void SetOperator(const HypreParMatrix & A);
void SetMassMatrix(const HypreParMatrix & M);
/// Solve the eigenproblem
void Solve();
void Solve() override;
int GetNumConverged() const override { return nev; }
/// Collect the converged eigenvalues
void GetEigenvalues(Array<real_t> & eigenvalues) const;
void GetEigenvalues(Array<real_t> & eigenvalues) const override;
/// Extract a single eigenvector
const HypreParVector & GetEigenvector(unsigned int i) const;
const Vector & GetEigenvector(unsigned int i) const override;
/// Transfer ownership of the converged eigenvectors
HypreParVector ** StealEigenvectors();
Vector ** StealEigenvectors() override;
};
}
+5
View File
@@ -28,6 +28,7 @@
#include "symmat.hpp"
#include "ode.hpp"
#include "solvers.hpp"
#include "eigensolvers.hpp"
#include "handle.hpp"
#include "invariants.hpp"
#include "constraints.hpp"
@@ -57,6 +58,10 @@
#include "ginkgo.hpp"
#endif
#ifdef MFEM_USE_ARPACK
#include "arpack.hpp"
#endif
#ifdef MFEM_USE_MKL_PARDISO
#include "pardiso.hpp"
#endif
+16
View File
@@ -844,6 +844,22 @@ public:
};
/// Zero Operator N: x -> 0.
class ZeroOperator : public Operator
{
public:
/// Create an zero operator of size @a n.
explicit ZeroOperator(int n) : Operator(n) { }
/// Operator application
void Mult(const Vector &x, Vector &y) const override
{ y.SetSize(width); y = 0_r; }
/// Application of the transpose
void MultTranspose(const Vector &x, Vector &y) const override
{ y.SetSize(width); y = 0_r; }
};
/// Identity Operator I: x -> x.
class IdentityOperator : public Operator
{
+4 -2
View File
@@ -302,7 +302,7 @@ endif
MFEM_REQ_LIB_DEPS = SUPERLU MUMPS METIS FMS CONDUIT SIDRE LAPACK SUNDIALS\
SUITESPARSE STRUMPACK GINKGO GNUTLS HDF5 NETCDF SLEPC PETSC MPFR PUMI HIOP\
GSLIB OCCA CEED RAJA UMPIRE MKL_CPARDISO MKL_PARDISO AMGX MAGMA CALIPER PARELAG\
TRIBOL BENCHMARK MOONOLITH ALGOIM
TRIBOL BENCHMARK MOONOLITH ALGOIM ARPACK
PETSC_ERROR_MSG = $(if $(PETSC_FOUND),,. PETSC config not found: $(PETSC_VARS))
@@ -371,7 +371,8 @@ MFEM_DEFINES = MFEM_VERSION MFEM_VERSION_STRING MFEM_GIT_STRING MFEM_USE_MPI\
MFEM_USE_SIMD MFEM_USE_ADIOS2 MFEM_USE_MKL_CPARDISO MFEM_USE_MKL_PARDISO MFEM_USE_AMGX\
MFEM_USE_MAGMA MFEM_USE_MUMPS MFEM_USE_ADFORWARD MFEM_USE_CODIPACK MFEM_USE_CALIPER\
MFEM_USE_BENCHMARK MFEM_USE_PARELAG MFEM_USE_TRIBOL MFEM_USE_ALGOIM MFEM_USE_ENZYME\
MFEM_SOURCE_DIR MFEM_INSTALL_DIR MFEM_SHARED_BUILD MFEM_USE_DOUBLE MFEM_USE_SINGLE
MFEM_SOURCE_DIR MFEM_INSTALL_DIR MFEM_SHARED_BUILD MFEM_USE_DOUBLE MFEM_USE_SINGLE\
MFEM_USE_ARPACK
# List of makefile variables that will be written to config.mk:
MFEM_CONFIG_VARS = MFEM_CXX MFEM_HOST_CXX MFEM_CPPFLAGS MFEM_CXXFLAGS\
@@ -733,6 +734,7 @@ status info:
$(info MFEM_TIMER_TYPE = $(MFEM_TIMER_TYPE))
$(info MFEM_USE_SUNDIALS = $(MFEM_USE_SUNDIALS))
$(info MFEM_USE_SUITESPARSE = $(MFEM_USE_SUITESPARSE))
$(info MFEM_USE_ARPACK = $(MFEM_USE_ARPACK))
$(info MFEM_USE_SUPERLU = $(MFEM_USE_SUPERLU))
$(info MFEM_USE_SUPERLU5 = $(MFEM_USE_SUPERLU5))
$(info MFEM_USE_MUMPS = $(MFEM_USE_MUMPS))
+4 -4
View File
@@ -329,8 +329,8 @@ int main(int argc, char *argv[])
for (int i=0; i<nev; i++)
{
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(lobpcg->GetEigenvector(i));
mode_name << "mode_" << setfill('0') << setw(2) << i << "."
<< setfill('0') << setw(6) << myid;
@@ -357,8 +357,8 @@ int main(int argc, char *argv[])
<< ", Lambda = " << eigenvalues[i] << endl;
}
// convert eigenvector from HypreParVector to ParGridFunction
x = lobpcg->GetEigenvector(i);
// convert eigenvector from Vector to ParGridFunction
x.Distribute(lobpcg->GetEigenvector(i));
mode_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x << flush