Files
mfem/examples/maxwell-solver/waveguide.cpp
T
2020-12-21 09:48:20 -08:00

325 lines
9.3 KiB
C++

//
// Compile with: make maxwellp
//
// mpirun ./maxwellp -o 3 -f 8.0 -sr 2 -pr 2 -m ../../data/inline-quad.mesh -nx 4 -ny 4
//
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "ParDST/ParDST.hpp"
#include "common/PML.hpp"
using namespace std;
using namespace mfem;
void maxwell_solution(const Vector &x, vector<complex<double>> &Eval);
void ess_data_func_re(const Vector & x, Vector & E);
void ess_data_func_im(const Vector & x, Vector & E);
double mu = 1.0;
double epsilon = 1.0;
double omega;
int dim;
double length = 1.0;
Array2D<double> comp_domain_bdr;
Array2D<double> domain_bdr;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int num_procs, myid;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
int order = 1;
// number of serial refinements
int ser_ref_levels = 1;
// number of parallel refinements
int par_ref_levels = 2;
double freq = 5.0;
bool herm_conv = true;
bool visualization = 1;
int nd=2;
int nx=2;
int ny=2;
int nz=2;
OptionsParser args(argc, argv);
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree).");
args.AddOption(&nd, "-nd", "--dim",
"Problem space dimension");
args.AddOption(&nx, "-nx", "--nx","Number of subdomains in x direction");
args.AddOption(&ny, "-ny", "--ny","Number of subdomains in y direction");
args.AddOption(&nz, "-nz", "--nz","Number of subdomains in z direction");
args.AddOption(&ser_ref_levels, "-sr", "--ser_ref_levels",
"Number of Serial Refinements.");
args.AddOption(&par_ref_levels, "-pr", "--par_ref_levels",
"Number of Parallel Refinements.");
args.AddOption(&freq, "-f", "--frequency",
"Frequency (in Hz).");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.Parse();
// check if the inputs are correct
if (!args.Good())
{
if (myid == 0)
{
args.PrintUsage(cout);
}
MPI_Finalize();
return 1;
}
if (myid == 0)
{
args.PrintOptions(cout);
}
// Angular frequency
omega = 2.0 * M_PI * freq;
Mesh *mesh;
int nel = 1;
int nelx = 8;
double lengthx = 8*length;
if (nd == 3)
{
mesh = new Mesh(nelx, nel, nel, Element::HEXAHEDRON, true, lengthx, length, length,false);
}
else
{
mesh = new Mesh(nelx, nel, Element::QUADRILATERAL, true, lengthx, length,false);
}
dim = mesh->Dimension();
// 4. Refine the mesh to increase the resolution.
for (int l = 0; l < ser_ref_levels; l++) { mesh->UniformRefinement(); }
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
delete mesh;
for (int l = 0; l < par_ref_levels; l++) {pmesh->UniformRefinement(); }
double hl = GetUniformMeshElementSize(pmesh);
int nrlayers = 4;
Array2D<double> lengths(dim,2);
lengths = 0.0;
// lengths = hl*nrlayers;
lengths(0, 1) = hl*nrlayers;
CartesianPML pml(pmesh,lengths);
pml.SetOmega(omega);
comp_domain_bdr.SetSize(dim,2);
comp_domain_bdr = pml.GetCompDomainBdr();
// 6. Define a finite element space on the mesh. Here we use the Nedelec
// finite elements of the specified order.
FiniteElementCollection *fec = new ND_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
HYPRE_Int size = fespace->GlobalTrueVSize();
if (myid == 0)
{
cout << "Number of finite element unknowns: " << size << endl;
}
Array<int> ess_tdof_list;
Array<int> ess_bdr;
if (pmesh->bdr_attributes.Size())
{
ess_bdr.SetSize(pmesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
ParComplexLinearForm b(fespace);
b.Vector::operator=(0.0);
b.Assemble();
// 10. Define the solution vector x as a complex finite element grid function
// corresponding to fespace.
ParComplexGridFunction x(fespace);
x = 0.0;
VectorFunctionCoefficient E_re(dim,ess_data_func_re);
VectorFunctionCoefficient E_im(dim,ess_data_func_im);
x.ProjectBdrCoefficientTangent(E_re, E_im, ess_bdr);
// 11. Set up the sesquilinear form a(.,.)
//
// 1/mu (1/det(J) J^T J Curl E, Curl F)
// - omega^2 * epsilon (det(J) * (J^T J)^-1 * E, F)
//
ConstantCoefficient omeg(-pow(omega, 2));
int cdim = (dim == 2) ? 1 : dim;
PmlMatrixCoefficient pml_c1_Re(cdim,detJ_inv_JT_J_Re, &pml);
PmlMatrixCoefficient pml_c1_Im(cdim,detJ_inv_JT_J_Im, &pml);
PmlMatrixCoefficient pml_c2_Re(dim, detJ_JT_J_inv_Re,&pml);
PmlMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,&pml);
ScalarMatrixProductCoefficient c2_Re(omeg,pml_c2_Re);
ScalarMatrixProductCoefficient c2_Im(omeg,pml_c2_Im);
ParSesquilinearForm a(fespace);
a.AddDomainIntegrator(new CurlCurlIntegrator(pml_c1_Re),
new CurlCurlIntegrator(pml_c1_Im));
a.AddDomainIntegrator(new VectorFEMassIntegrator(c2_Re),
new VectorFEMassIntegrator(c2_Im));
a.Assemble(0);
OperatorPtr A;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, A, X, B);
ConstantCoefficient one(1.0);
ParDST * S = new ParDST(&a,lengths, omega, &one, nrlayers, nx, ny, nz);
X = 0.0;
GMRESSolver gmres(MPI_COMM_WORLD);
gmres.SetPreconditioner(*S);
gmres.SetOperator(*A);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(50);
gmres.SetPrintLevel(1);
gmres.Mult(B, X);
delete S;
// {
// ComplexMUMPSSolver mumps;
// mumps.SetOperator(*A.As<ComplexHypreParMatrix>());
// mumps.Mult(B,X);
// }
a.RecoverFEMSolution(X, b, x);
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
string keys;
// keys = "keys mc\n";
keys = "keys macFFiYYYYYYYYYYYYYYYYYY\n";
socketstream sol_sock_re(vishost, visport);
sol_sock_re.precision(8);
sol_sock_re << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x.real() << keys
<< "window_title 'E: Real Part' " << flush;
socketstream sol_sock_im(vishost, visport);
sol_sock_im.precision(8);
sol_sock_im << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x.imag() << keys
<< "window_title 'E: Imag Part' " << flush;
{
ParGridFunction x_t(fespace);
x_t = x.real();
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "parallel " << num_procs << " " << myid << "\n"
<< "solution\n" << *pmesh << x_t << keys << "autoscale off\n"
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
<< "pause\n" << flush;
if (myid == 0)
{
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
int num_frames = 32;
int i = 0;
while (sol_sock)
{
double t = (double)(i % num_frames) / num_frames;
ostringstream oss;
oss << "Harmonic Solution (t = " << t << " T)";
add(cos(2.0*M_PI*t), x.real(), sin(2.0*M_PI*t), x.imag(), x_t);
sol_sock << "parallel " << num_procs << " " << myid << "\n";
sol_sock << "solution\n" << *pmesh << x_t
<< "window_title '" << oss.str() << "'" << flush;
i++;
}
}
}
// 18. Free the used memory.
delete fespace;
delete fec;
delete pmesh;
MPI_Finalize();
return 0;
}
void maxwell_solution(const Vector &x, vector<complex<double>> &E)
{
complex<double> zi = complex<double>(0., 1.);
if (dim == 3)
{
double k10 = sqrt(omega * omega - M_PI * M_PI);
E[1] = -zi * omega / M_PI * sin(M_PI*x(2))*exp(zi * k10 * x(0));
}
else
{
E[1] = -zi * omega / M_PI * exp(zi * omega * x(0));
}
// E[1] = -zi * omega / M_PI * sin(M_PI*x(0))*exp(zi * k10 * x(2));
E[0] = 0.0;
if (dim == 3) E[2] = 0.0;
}
void ess_data_func_re(const Vector & x, Vector & E)
{
E = 0.0;
bool in_pml = false;
for (int i = 0; i < dim; ++i)
{
// check if in PML
if (x(i) - comp_domain_bdr(i, 0) < 0.0 ||
x(i) - comp_domain_bdr(i, 1) > 0.0)
{
in_pml = true;
break;
}
}
if (!in_pml)
{
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
E[i] = Eval[i].real();
}
}
}
void ess_data_func_im(const Vector & x, Vector & E)
{
E = 0.0;
bool in_pml = false;
for (int i = 0; i < dim; ++i)
{
// check if in PML
if (x(i) - comp_domain_bdr(i, 0) < 0.0 ||
x(i) - comp_domain_bdr(i, 1) > 0.0)
{
in_pml = true;
break;
}
}
if (!in_pml)
{
vector<complex<double>> Eval(E.Size());
maxwell_solution(x, Eval);
for (int i = 0; i < dim; ++i)
{
E[i] = Eval[i].imag();
}
}
}