Compare commits
56
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2d68264e6 | ||
|
|
8bf2b3f061 | ||
|
|
933ddce17a | ||
|
|
085557f02b | ||
|
|
2544bab0aa | ||
|
|
bea4a8bae0 | ||
|
|
31dc0b5322 | ||
|
|
18ca696093 | ||
|
|
c441b28b01 | ||
|
|
125e182a05 | ||
|
|
3dc8e4d98e | ||
|
|
b947d34583 | ||
|
|
862e527539 | ||
|
|
297d7eabd6 | ||
|
|
86f214bdc6 | ||
|
|
8420384555 | ||
|
|
f158717ae5 | ||
|
|
3a645d61b2 | ||
|
|
ac86240cd8 | ||
|
|
8c7f47ee71 | ||
|
|
8a9d4e94cf | ||
|
|
224345b00c | ||
|
|
6ee0947d03 | ||
|
|
b82f870350 | ||
|
|
819a262bd3 | ||
|
|
10a017a62d | ||
|
|
b82ec338c5 | ||
|
|
90ebbb469c | ||
|
|
32318eaf75 | ||
|
|
98d80620bf | ||
|
|
cec5a119d1 | ||
|
|
8744958c2f | ||
|
|
65b1e0addb | ||
|
|
a0b8427774 | ||
|
|
bd3897a7ec | ||
|
|
98039728a7 | ||
|
|
537f9ad677 | ||
|
|
6081e24e78 | ||
|
|
9779145f1a | ||
|
|
e1576f336e | ||
|
|
673f0364de | ||
|
|
90c4e55c40 | ||
|
|
2f610e0170 | ||
|
|
35598cb6fb | ||
|
|
af5003aee2 | ||
|
|
0e3223dd83 | ||
|
|
b1ac354f59 | ||
|
|
0147180a8b | ||
|
|
2d0a0b6c63 | ||
|
|
044ac04693 | ||
|
|
019a983732 | ||
|
|
8ff51b993c | ||
|
|
5d20efdbbd | ||
|
|
eed944d75f | ||
|
|
826f041d7f | ||
|
|
97d4558da0 |
@@ -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
|
||||
|
||||
@@ -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@
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user