Files
mfem/examples/maxwell-solver/maxwell.cpp
T

339 lines
9.7 KiB
C++

//
// Compile with: make maxwell
//
// maxwell -o 2 -f 8.0 -ref 3 -prob 4 -m ../data/inline-quad.mesh
//
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include "DST/DST.hpp"
using namespace std;
using namespace mfem;
void source_re(const Vector &x, Vector & f);
void source_im(const Vector &x, Vector & f);
double wavespeed(const Vector &x);
double mu = 1.0;
double epsilon = 1.0;
double omega;
int dim;
double length = 1.0;
Array2D<double> comp_bdr;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
const char *mesh_file = "../../data/inline-quad.mesh";
int order = 1;
int ref_levels = 3;
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(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
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(&ref_levels, "-ref", "--refinements",
"Number of refinements");
args.AddOption(&mu, "-mu", "--permeability",
"Permeability of free space (or 1/(spring constant)).");
args.AddOption(&epsilon, "-eps", "--permittivity",
"Permittivity of free space (or mass constant).");
args.AddOption(&freq, "-f", "--frequency",
"Frequency (in Hz).");
args.AddOption(&herm_conv, "-herm", "--hermitian", "-no-herm",
"--no-hermitian", "Use convention for Hermitian operators.");
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);
Mesh *mesh;
if (nd == 2)
{
mesh = new Mesh(4, 4, Element::QUADRILATERAL, true, length, length, false);
}
else
{
mesh = new Mesh(1, 1, 1, Element::HEXAHEDRON, true, length, length, length,false);
}
dim = mesh->Dimension();
// Angular frequency
omega = 2.0 * M_PI * freq;
// 4. Refine the mesh to increase the resolution.
for (int l = 0; l < ref_levels; l++)
{
mesh->UniformRefinement();
}
// char vishost[] = "localhost";
// int visport = 19916;
// socketstream mesh_sock(vishost, visport);
// mesh_sock.precision(8);
// mesh_sock << "mesh\n"
// << *mesh << "window_title 'Global mesh'" << flush;
// Setup PML length
int nrlayers = 2;
double hl = GetUniformMeshElementSize(mesh);
Array2D<double> lengths(dim, 2);
lengths = hl*nrlayers;
CartesianPML * pml = new CartesianPML(mesh,lengths);
pml->SetOmega(omega);
comp_bdr.SetSize(dim,2);
comp_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);
FiniteElementSpace *fespace = new FiniteElementSpace(mesh, fec);
int size = fespace->GetTrueVSize();
cout << "Number of finite element unknowns: " << size << endl;
// 7. Determine the list of true essential boundary dofs. In this example,
// the boundary conditions are defined based on the specific mesh and the
// problem type.
Array<int> ess_tdof_list;
if (mesh->bdr_attributes.Size())
{
Array<int> ess_bdr(mesh->bdr_attributes.Max());
ess_bdr = 1;
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
// 8. Setup Complex Operator convention
ComplexOperator::Convention conv =
herm_conv ? ComplexOperator::HERMITIAN : ComplexOperator::BLOCK_SYMMETRIC;
// 9. Set up the linear form b(.) which corresponds to the right-hand side of
// the FEM linear system.
VectorFunctionCoefficient f_re(dim, source_re);
VectorFunctionCoefficient f_im(dim, source_re);
ComplexLinearForm b(fespace, conv);
b.AddDomainIntegrator(new VectorFEDomainLFIntegrator(f_re),
new VectorFEDomainLFIntegrator(f_im));
b.Vector::operator=(0.0);
b.Assemble();
// 10. Define the solution vector x as a complex finite element grid function
// corresponding to fespace.
ComplexGridFunction x(fespace);
x = 0.0;
// 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)
//
FunctionCoefficient ws(wavespeed);
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_Re0(omeg,pml_c2_Re);
ScalarMatrixProductCoefficient c2_Im0(omeg,pml_c2_Im);
ScalarMatrixProductCoefficient c2_Re(ws,c2_Re0);
ScalarMatrixProductCoefficient c2_Im(ws,c2_Im0);
SesquilinearForm a(fespace, conv);
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);
OperatorHandle Ah;
Vector B, X;
a.FormLinearSystem(ess_tdof_list, x, b, Ah, X, B);
ComplexSparseMatrix * Ac = Ah.As<ComplexSparseMatrix>();
StopWatch chrono;
// chrono.Clear();
// chrono.Start();
// {
// ComplexUMFPackSolver csolver;
// csolver.Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
// csolver.SetOperator(*Ac);
// // csolver.SetPrintLevel(2);
// csolver.Mult(B,X);
// }
// chrono.Stop();
// cout << "Time 1 = " << chrono.RealTime() << endl;
chrono.Clear();
chrono.Start();
DST S(&a,lengths, omega, &ws, nrlayers, nx, ny, nz);
chrono.Stop();
cout << "Time 2 = " << chrono.RealTime() << endl;
chrono.Clear();
chrono.Start();
X = 0.0;
GMRESSolver gmres;
// gmres.iterative_mode = true;
gmres.SetPreconditioner(S);
gmres.SetOperator(*Ac);
gmres.SetRelTol(1e-8);
gmres.SetMaxIter(50);
gmres.SetPrintLevel(1);
gmres.Mult(B, X);
chrono.Stop();
cout << "Time 3 = " << chrono.RealTime() << endl;
// 14. Solve using a direct or an iterative solver
// Vector Y(X);
// chrono.Stop();
// cout << "Time 3 = " << chrono.RealTime() << endl;
// cout << endl;
// cout << "X norm = " << X.Norml2() << endl;
// cout << "Y norm = " << Y.Norml2() << endl;
// Y-=X;
// cout << "diff norm = " << Y.Norml2() << endl;
a.RecoverFEMSolution(X, b, x);
// 17. Send the solution by socket to a GLVis server.
if (visualization)
{
// Define visualization keys for GLVis (see GLVis documentation)
string keys;
keys = (dim == 3) ? "keys acF\n" : keys = "keys amrRljcUUuu\n";
char vishost[] = "localhost";
int visport = 19916;
socketstream sol_sock_re(vishost, visport);
sol_sock_re.precision(8);
sol_sock_re << "solution\n"
<< *mesh << x.real() << keys
<< "window_title 'Solution real part'" << flush;
socketstream sol_sock_im(vishost, visport);
sol_sock_im.precision(8);
sol_sock_im << "solution\n"
<< *mesh << x.imag() << keys
<< "window_title 'Solution imag part'" << flush;
GridFunction x_t(fespace);
x_t = x.real();
socketstream sol_sock(vishost, visport);
sol_sock.precision(8);
sol_sock << "solution\n"
<< *mesh << x_t << keys << "autoscale off\n"
<< "window_title 'Harmonic Solution (t = 0.0 T)'"
<< "pause\n" << flush;
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 << "solution\n"
<< *mesh << x_t
<< "window_title '" << oss.str() << "'" << flush;
i++;
}
}
// 18. Free the used memory.
delete pml;
delete fespace;
delete fec;
delete mesh;
return 0;
}
void source_re(const Vector &x, Vector &f)
{
f = 0.0;
double x0 = length/2.0;
double x1 = length/2.0;
double x2 = length/2.0;
x0 = 0.45;
x1 = 0.35;
x2 = 0.25;
double alpha,beta;
double n = 4.0*omega/M_PI;
beta = pow(x0-x(0),2) + pow(x1-x(1),2);
if (dim == 3) { beta += pow(x2-x(2),2); }
double coeff = 16.0*omega*omega/M_PI/M_PI/M_PI;
alpha = -pow(n,2) * beta;
f[0] = coeff*exp(alpha);
// f[1] = coeff*exp(alpha);
x0 = 0.8;
x1 = 0.8;
beta = pow(x0-x(0),2) + pow(x1-x(1),2);
if (dim == 3) { beta += pow(x2-x(2),2); }
alpha = -pow(n,2) * beta;
// f[0] += coeff*exp(alpha);
bool in_pml = false;
for (int i = 0; i<dim; i++)
{
if (x(i)<=comp_bdr(i,0) || x(i)>=comp_bdr(i,1))
{
in_pml = true;
break;
}
}
if (in_pml) f = 0.0;
}
void source_im(const Vector &x, Vector &f)
{
f = 0.0;
}
double wavespeed(const Vector &x)
{
double ws;
ws = 1.0;
return ws;
}