1456 lines
51 KiB
C++
1456 lines
51 KiB
C++
// 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.
|
||
//
|
||
// MFEM Ultraweak DPG Maxwell parallel example
|
||
//
|
||
// Compile with: make pmaxwell
|
||
//
|
||
// sample run
|
||
// mpirun -np 4 pmaxwell -m ../../data/star.mesh -o 2 -sref 0 -pref 3 -rnum 0.5 -prob 0
|
||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 0 -pref 3 -rnum 4.8 -sc -prob 0
|
||
// mpirun -np 4 pmaxwell -m ../../data/inline-hex.mesh -o 2 -sref 0 -pref 1 -rnum 0.8 -sc -prob 0
|
||
// mpirun -np 4 pmaxwell -m ../../data/inline-quad.mesh -o 3 -sref 1 -pref 3 -rnum 4.8 -sc -prob 2
|
||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 11.8 -sc -prob 3
|
||
// mpirun -np 4 pmaxwell -o 3 -sref 1 -pref 2 -rnum 9.8 -sc -prob 4
|
||
|
||
// AMR run. Note that this is a computationally intensive sample run.
|
||
// We recommend trying it on a large machine with more mpi ranks
|
||
// mpirun -np 4 pmaxwell -o 3 -sref 0 -pref 15 -prob 1 -theta 0.7 -sc
|
||
|
||
// Description:
|
||
// This example code demonstrates the use of MFEM to define and solve
|
||
// the "ultraweak" (UW) DPG formulation for the Maxwell problem
|
||
|
||
// ∇×(1/μ ∇×E) - ω² ϵ E = Ĵ , in Ω
|
||
// E×n = E₀ , on ∂Ω
|
||
|
||
// It solves the following kinds of problems
|
||
// 1) Known exact solutions with error convergence rates
|
||
// a) A manufactured solution problem where E is a plane beam
|
||
// 2) Fichera "microwave" problem
|
||
// 3) PML problems
|
||
// a) Generic PML problem with point source given by the load
|
||
// b) Plane wave scattering from a square
|
||
// c) PML problem with a point source prescribed on the boundary
|
||
|
||
// The DPG UW deals with the First Order System
|
||
// i ω μ H + ∇ × E = 0, in Ω
|
||
// -i ω ϵ E + ∇ × H = J, in Ω
|
||
// E × n = E_0, on ∂Ω
|
||
// Note: Ĵ = -iωJ
|
||
|
||
// The ultraweak-DPG formulation is obtained by integration by parts of both
|
||
// equations and the introduction of trace unknowns on the mesh skeleton
|
||
|
||
// in 2D
|
||
// E is vector valued and H is scalar.
|
||
// (∇ × E, F) = (E, ∇ × F) + < n × E , F>
|
||
// or (∇ ⋅ AE , F) = (AE, ∇ F) + < AE ⋅ n, F>
|
||
// where A = [0 1; -1 0];
|
||
|
||
// E ∈ (L²(Ω))² , H ∈ L²(Ω)
|
||
// Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ)
|
||
// i ω μ (H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹
|
||
// -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
|
||
// Ê = E₀ on ∂Ω
|
||
// -------------------------------------------------------------------------
|
||
// | | E | H | Ê | Ĥ | RHS |
|
||
// -------------------------------------------------------------------------
|
||
// | F | (E,∇ × F) | i ω μ (H,F) | < Ê, F > | | |
|
||
// | | | | | | |
|
||
// | G | -i ω ϵ (E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) |
|
||
// where (F,G) ∈ H¹ × H(curl,Ω)
|
||
|
||
// in 3D
|
||
// E,H ∈ (L^2(Ω))³
|
||
// Ê ∈ H_0^1/2(Ω)(curl, Γₕ), Ĥ ∈ H^-1/2(curl, Γₕ)
|
||
// i ω μ (H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω)
|
||
// -i ω ϵ (E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
|
||
// Ê × n = E₀ on ∂Ω
|
||
// -------------------------------------------------------------------------
|
||
// | | E | H | Ê | Ĥ | RHS |
|
||
// -------------------------------------------------------------------------
|
||
// | F | (E,∇ × F) | i ω μ (H,F) | < n × Ê, F > | | |
|
||
// | | | | | | |
|
||
// | G | -i ω ϵ (E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) |
|
||
// where (F,G) ∈ H(curl,Ω) × H(curl,Ω)
|
||
|
||
// Here we use the "Adjoint Graph" norm on the test space i.e.,
|
||
// ||(F,G)||²ᵥ = ||A^*(F,G)||² + ||(F,G)||² where A is the
|
||
// maxwell operator defined by (1)
|
||
|
||
// The PML formulation is
|
||
|
||
// ∇×(1/μ α ∇×E) - ω² ϵ β E = Ĵ , in Ω
|
||
// E×n = E₀ , on ∂Ω
|
||
|
||
// where α = |J|⁻¹ Jᵀ J (in 2D it's the scalar |J|⁻¹),
|
||
// β = |J| J⁻¹ J⁻ᵀ, J is the Jacobian of the stretching map
|
||
// and |J| its determinant.
|
||
|
||
// The first order system reads
|
||
// i ω μ α⁻¹ H + ∇ × E = 0, in Ω
|
||
// -i ω ϵ β E + ∇ × H = J, in Ω
|
||
// E × n = E₀, on ∂Ω
|
||
|
||
// and the ultraweak formulation is
|
||
|
||
// in 2D
|
||
// E ∈ (L²(Ω))² , H ∈ L²(Ω)
|
||
// Ê ∈ H^-1/2(Ω)(Γₕ), Ĥ ∈ H^1/2(Γₕ)
|
||
// i ω μ (α⁻¹ H,F) + (E, ∇ × F) + < AÊ, F > = 0, ∀ F ∈ H¹
|
||
// -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
|
||
// Ê = E₀ on ∂Ω
|
||
// ---------------------------------------------------------------------------------
|
||
// | | E | H | Ê | Ĥ | RHS |
|
||
// ---------------------------------------------------------------------------------
|
||
// | F | (E,∇ × F) | i ω μ (α⁻¹ H,F) | < Ê, F > | | |
|
||
// | | | | | | |
|
||
// | G | -i ω ϵ (β E,G) | (H,∇ × G) | | < Ĥ, G × n > | (J,G) |
|
||
|
||
// where (F,G) ∈ H¹ × H(curl,Ω)
|
||
|
||
//
|
||
// in 3D
|
||
// E,H ∈ (L^2(Ω))³
|
||
// Ê ∈ H_0^1/2(Ω)(curl, Γ_h), Ĥ ∈ H^-1/2(curl, Γₕ)
|
||
// i ω μ (α⁻¹ H,F) + (E,∇ × F) + < Ê, F × n > = 0, ∀ F ∈ H(curl,Ω)
|
||
// -i ω ϵ (β E,G) + (H,∇ × G) + < Ĥ, G × n > = (J,G) ∀ G ∈ H(curl,Ω)
|
||
// Ê × n = E_0 on ∂Ω
|
||
// -------------------------------------------------------------------------------
|
||
// | | E | H | Ê | Ĥ | RHS |
|
||
// -------------------------------------------------------------------------------
|
||
// | F | ( E,∇ × F) | i ω μ (α⁻¹ H,F) | < n × Ê, F > | | |
|
||
// | | | | | | |
|
||
// | G | -iωϵ (β E,G) | (H,∇ × G) | | < n × Ĥ, G > | (J,G) |
|
||
// where (F,G) ∈ H(curl,Ω) × H(curl,Ω)
|
||
|
||
// For more information see https://doi.org/10.1016/j.camwa.2021.01.017
|
||
|
||
#include "mfem.hpp"
|
||
#include "util/pcomplexweakform.hpp"
|
||
#include "util/pml.hpp"
|
||
#include "../common/mfem-common.hpp"
|
||
#include <fstream>
|
||
#include <iostream>
|
||
|
||
using namespace std;
|
||
using namespace mfem;
|
||
using namespace mfem::common;
|
||
|
||
void E_exact_r(const Vector &x, Vector & E_r);
|
||
void E_exact_i(const Vector &x, Vector & E_i);
|
||
|
||
void H_exact_r(const Vector &x, Vector & H_r);
|
||
void H_exact_i(const Vector &x, Vector & H_i);
|
||
|
||
|
||
void rhs_func_r(const Vector &x, Vector & J_r);
|
||
void rhs_func_i(const Vector &x, Vector & J_i);
|
||
|
||
void curlE_exact_r(const Vector &x, Vector &curlE_r);
|
||
void curlE_exact_i(const Vector &x, Vector &curlE_i);
|
||
void curlH_exact_r(const Vector &x,Vector &curlH_r);
|
||
void curlH_exact_i(const Vector &x,Vector &curlH_i);
|
||
|
||
void curlcurlE_exact_r(const Vector &x, Vector & curlcurlE_r);
|
||
void curlcurlE_exact_i(const Vector &x, Vector & curlcurlE_i);
|
||
|
||
void hatE_exact_r(const Vector & X, Vector & hatE_r);
|
||
void hatE_exact_i(const Vector & X, Vector & hatE_i);
|
||
|
||
void hatH_exact_r(const Vector & X, Vector & hatH_r);
|
||
void hatH_exact_i(const Vector & X, Vector & hatH_i);
|
||
|
||
real_t hatH_exact_scalar_r(const Vector & X);
|
||
real_t hatH_exact_scalar_i(const Vector & X);
|
||
|
||
void maxwell_solution(const Vector & X,
|
||
std::vector<complex<real_t>> &E);
|
||
|
||
void maxwell_solution_curl(const Vector & X,
|
||
std::vector<complex<real_t>> &curlE);
|
||
|
||
void maxwell_solution_curlcurl(const Vector & X,
|
||
std::vector<complex<real_t>> &curlcurlE);
|
||
|
||
void source_function(const Vector &x, Vector & f);
|
||
|
||
int dim;
|
||
int dimc;
|
||
real_t omega;
|
||
real_t mu = 1.0;
|
||
real_t epsilon = 1.0;
|
||
|
||
enum prob_type
|
||
{
|
||
plane_wave,
|
||
fichera_oven,
|
||
pml_general,
|
||
pml_plane_wave_scatter,
|
||
pml_pointsource
|
||
};
|
||
|
||
static const char *enum_str[] =
|
||
{
|
||
"plane_wave",
|
||
"fichera_oven",
|
||
"pml_general",
|
||
"pml_plane_wave_scatter",
|
||
"pml_pointsource"
|
||
};
|
||
|
||
prob_type prob;
|
||
|
||
int main(int argc, char *argv[])
|
||
{
|
||
Mpi::Init();
|
||
int myid = Mpi::WorldRank();
|
||
Hypre::Init();
|
||
|
||
const char *mesh_file = "../../data/inline-quad.mesh";
|
||
int order = 1;
|
||
int delta_order = 1;
|
||
real_t rnum=1.0;
|
||
real_t theta = 0.0;
|
||
bool static_cond = false;
|
||
int iprob = 0;
|
||
int sr = 0;
|
||
int pr = 1;
|
||
bool exact_known = false;
|
||
bool with_pml = false;
|
||
bool visualization = true;
|
||
int visport = 19916;
|
||
bool paraview = false;
|
||
|
||
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(&rnum, "-rnum", "--number-of-wavelengths",
|
||
"Number of wavelengths");
|
||
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(&iprob, "-prob", "--problem", "Problem case"
|
||
" 0: plane wave, 1: Fichera 'oven', "
|
||
" 2: Generic PML problem with point source given as a load "
|
||
" 3: Scattering of a plane wave, "
|
||
" 4: Point source given on the boundary");
|
||
args.AddOption(&delta_order, "-do", "--delta-order",
|
||
"Order enrichment for DPG test space.");
|
||
args.AddOption(&theta, "-theta", "--theta",
|
||
"Theta parameter for AMR");
|
||
args.AddOption(&sr, "-sref", "--serial-ref",
|
||
"Number of parallel refinements.");
|
||
args.AddOption(&pr, "-pref", "--parallel-ref",
|
||
"Number of parallel refinements.");
|
||
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
|
||
"--no-static-condensation", "Enable static condensation.");
|
||
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
|
||
"--no-visualization",
|
||
"Enable or disable GLVis visualization.");
|
||
args.AddOption(¶view, "-paraview", "--paraview", "-no-paraview",
|
||
"--no-paraview",
|
||
"Enable or disable ParaView visualization.");
|
||
args.AddOption(&visport, "-p", "--send-port", "Socket for GLVis.");
|
||
args.Parse();
|
||
if (!args.Good())
|
||
{
|
||
if (myid == 0)
|
||
{
|
||
args.PrintUsage(cout);
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
if (iprob > 4) { iprob = 0; }
|
||
prob = (prob_type)iprob;
|
||
omega = 2.*M_PI*rnum;
|
||
|
||
if (prob == 0)
|
||
{
|
||
exact_known = true;
|
||
}
|
||
else if (prob == 1)
|
||
{
|
||
mesh_file = "meshes/fichera-waveguide.mesh";
|
||
omega = 5.0;
|
||
rnum = omega/(2.*M_PI);
|
||
}
|
||
else if (prob == 2)
|
||
{
|
||
with_pml = true;
|
||
}
|
||
else
|
||
{
|
||
with_pml = true;
|
||
mesh_file = "meshes/scatter.mesh";
|
||
}
|
||
|
||
if (myid == 0)
|
||
{
|
||
args.PrintOptions(cout);
|
||
}
|
||
|
||
Mesh mesh(mesh_file, 1, 1);
|
||
dim = mesh.Dimension();
|
||
MFEM_VERIFY(dim > 1, "Dimension = 1 is not supported in this example");
|
||
|
||
dimc = (dim == 3) ? 3 : 1;
|
||
|
||
for (int i = 0; i<sr; i++)
|
||
{
|
||
mesh.UniformRefinement();
|
||
}
|
||
mesh.EnsureNCMesh(false);
|
||
|
||
CartesianPML * pml = nullptr;
|
||
if (with_pml)
|
||
{
|
||
Array2D<real_t> length(dim, 2); length = 0.25;
|
||
pml = new CartesianPML(&mesh,length);
|
||
pml->SetOmega(omega);
|
||
pml->SetEpsilonAndMu(epsilon,mu);
|
||
}
|
||
|
||
ParMesh pmesh(MPI_COMM_WORLD, mesh);
|
||
mesh.Clear();
|
||
|
||
// PML element attribute marker
|
||
Array<int> attr;
|
||
Array<int> attrPML;
|
||
if (pml) { pml->SetAttributes(&pmesh, &attr, &attrPML); }
|
||
|
||
// Define spaces
|
||
enum TrialSpace
|
||
{
|
||
E_space = 0,
|
||
H_space = 1,
|
||
hatE_space = 2,
|
||
hatH_space = 3
|
||
};
|
||
enum TestSpace
|
||
{
|
||
F_space = 0,
|
||
G_space = 1
|
||
};
|
||
// L2 space for E
|
||
FiniteElementCollection *E_fec = new L2_FECollection(order-1,dim);
|
||
ParFiniteElementSpace *E_fes = new ParFiniteElementSpace(&pmesh,E_fec,dim);
|
||
|
||
// Vector L2 space for H
|
||
FiniteElementCollection *H_fec = new L2_FECollection(order-1,dim);
|
||
ParFiniteElementSpace *H_fes = new ParFiniteElementSpace(&pmesh,H_fec, dimc);
|
||
|
||
// H^-1/2 (curl) space for Ê
|
||
FiniteElementCollection * hatE_fec = nullptr;
|
||
FiniteElementCollection * hatH_fec = nullptr;
|
||
FiniteElementCollection * F_fec = nullptr;
|
||
int test_order = order+delta_order;
|
||
if (dim == 3)
|
||
{
|
||
hatE_fec = new ND_Trace_FECollection(order,dim);
|
||
hatH_fec = new ND_Trace_FECollection(order,dim);
|
||
F_fec = new ND_FECollection(test_order, dim);
|
||
}
|
||
else
|
||
{
|
||
hatE_fec = new RT_Trace_FECollection(order-1,dim);
|
||
hatH_fec = new H1_Trace_FECollection(order,dim);
|
||
F_fec = new H1_FECollection(test_order, dim);
|
||
}
|
||
ParFiniteElementSpace *hatE_fes = new ParFiniteElementSpace(&pmesh,hatE_fec);
|
||
ParFiniteElementSpace *hatH_fes = new ParFiniteElementSpace(&pmesh,hatH_fec);
|
||
FiniteElementCollection * G_fec = new ND_FECollection(test_order, dim);
|
||
|
||
Array<ParFiniteElementSpace * > trial_fes;
|
||
Array<FiniteElementCollection * > test_fec;
|
||
trial_fes.Append(E_fes);
|
||
trial_fes.Append(H_fes);
|
||
trial_fes.Append(hatE_fes);
|
||
trial_fes.Append(hatH_fes);
|
||
test_fec.Append(F_fec);
|
||
test_fec.Append(G_fec);
|
||
|
||
// Bilinear form coefficients
|
||
ConstantCoefficient one(1.0);
|
||
ConstantCoefficient eps2omeg2(epsilon*epsilon*omega*omega);
|
||
ConstantCoefficient mu2omeg2(mu*mu*omega*omega);
|
||
ConstantCoefficient muomeg(mu*omega);
|
||
ConstantCoefficient negepsomeg(-epsilon*omega);
|
||
ConstantCoefficient epsomeg(epsilon*omega);
|
||
ConstantCoefficient negmuomeg(-mu*omega);
|
||
// for the 2D case
|
||
DenseMatrix rot_mat(2);
|
||
rot_mat(0,0) = 0.; rot_mat(0,1) = 1.;
|
||
rot_mat(1,0) = -1.; rot_mat(1,1) = 0.;
|
||
MatrixConstantCoefficient rot(rot_mat);
|
||
ScalarMatrixProductCoefficient epsrot(epsomeg,rot);
|
||
ScalarMatrixProductCoefficient negepsrot(negepsomeg,rot);
|
||
|
||
Coefficient * epsomeg_cf = nullptr;
|
||
Coefficient * negepsomeg_cf = nullptr;
|
||
Coefficient * eps2omeg2_cf = nullptr;
|
||
Coefficient * muomeg_cf = nullptr;
|
||
Coefficient * negmuomeg_cf = nullptr;
|
||
Coefficient * mu2omeg2_cf = nullptr;
|
||
MatrixCoefficient *epsrot_cf = nullptr;
|
||
MatrixCoefficient *negepsrot_cf = nullptr;
|
||
|
||
if (pml)
|
||
{
|
||
epsomeg_cf = new RestrictedCoefficient(epsomeg,attr);
|
||
negepsomeg_cf = new RestrictedCoefficient(negepsomeg,attr);
|
||
eps2omeg2_cf = new RestrictedCoefficient(eps2omeg2,attr);
|
||
muomeg_cf = new RestrictedCoefficient(muomeg,attr);
|
||
negmuomeg_cf = new RestrictedCoefficient(negmuomeg,attr);
|
||
mu2omeg2_cf = new RestrictedCoefficient(mu2omeg2,attr);
|
||
epsrot_cf = new MatrixRestrictedCoefficient(epsrot,attr);
|
||
negepsrot_cf = new MatrixRestrictedCoefficient(negepsrot,attr);
|
||
}
|
||
else
|
||
{
|
||
epsomeg_cf = &epsomeg;
|
||
negepsomeg_cf = &negepsomeg;
|
||
eps2omeg2_cf = &eps2omeg2;
|
||
muomeg_cf = &muomeg;
|
||
negmuomeg_cf = &negmuomeg;
|
||
mu2omeg2_cf = &mu2omeg2;
|
||
epsrot_cf = &epsrot;
|
||
negepsrot_cf = &negepsrot;
|
||
}
|
||
|
||
// PML coefficients;
|
||
PmlCoefficient detJ_r(detJ_r_function,pml);
|
||
PmlCoefficient detJ_i(detJ_i_function,pml);
|
||
PmlCoefficient abs_detJ_2(abs_detJ_2_function,pml);
|
||
PmlMatrixCoefficient detJ_Jt_J_inv_r(dim,detJ_Jt_J_inv_r_function,pml);
|
||
PmlMatrixCoefficient detJ_Jt_J_inv_i(dim,detJ_Jt_J_inv_i_function,pml);
|
||
PmlMatrixCoefficient abs_detJ_Jt_J_inv_2(dim,abs_detJ_Jt_J_inv_2_function,pml);
|
||
|
||
ProductCoefficient negmuomeg_detJ_r(negmuomeg,detJ_r);
|
||
ProductCoefficient negmuomeg_detJ_i(negmuomeg,detJ_i);
|
||
ProductCoefficient muomeg_detJ_r(muomeg,detJ_r);
|
||
ProductCoefficient mu2omeg2_detJ_2(mu2omeg2,abs_detJ_2);
|
||
ScalarMatrixProductCoefficient epsomeg_detJ_Jt_J_inv_i(epsomeg,
|
||
detJ_Jt_J_inv_i);
|
||
ScalarMatrixProductCoefficient epsomeg_detJ_Jt_J_inv_r(epsomeg,
|
||
detJ_Jt_J_inv_r);
|
||
ScalarMatrixProductCoefficient negepsomeg_detJ_Jt_J_inv_r(negepsomeg,
|
||
detJ_Jt_J_inv_r);
|
||
ScalarMatrixProductCoefficient muomeg_detJ_Jt_J_inv_r(muomeg,detJ_Jt_J_inv_r);
|
||
ScalarMatrixProductCoefficient negmuomeg_detJ_Jt_J_inv_i(negmuomeg,
|
||
detJ_Jt_J_inv_i);
|
||
ScalarMatrixProductCoefficient negmuomeg_detJ_Jt_J_inv_r(negmuomeg,
|
||
detJ_Jt_J_inv_r);
|
||
ScalarMatrixProductCoefficient mu2omeg2_detJ_Jt_J_inv_2(mu2omeg2,
|
||
abs_detJ_Jt_J_inv_2);
|
||
ScalarMatrixProductCoefficient eps2omeg2_detJ_Jt_J_inv_2(eps2omeg2,
|
||
abs_detJ_Jt_J_inv_2);
|
||
|
||
RestrictedCoefficient negmuomeg_detJ_r_restr(negmuomeg_detJ_r,attrPML);
|
||
RestrictedCoefficient negmuomeg_detJ_i_restr(negmuomeg_detJ_i,attrPML);
|
||
RestrictedCoefficient muomeg_detJ_r_restr(muomeg_detJ_r,attrPML);
|
||
RestrictedCoefficient mu2omeg2_detJ_2_restr(mu2omeg2_detJ_2,attrPML);
|
||
MatrixRestrictedCoefficient epsomeg_detJ_Jt_J_inv_i_restr(
|
||
epsomeg_detJ_Jt_J_inv_i,attrPML);
|
||
MatrixRestrictedCoefficient epsomeg_detJ_Jt_J_inv_r_restr(
|
||
epsomeg_detJ_Jt_J_inv_r,attrPML);
|
||
MatrixRestrictedCoefficient negepsomeg_detJ_Jt_J_inv_r_restr(
|
||
negepsomeg_detJ_Jt_J_inv_r,attrPML);
|
||
MatrixRestrictedCoefficient muomeg_detJ_Jt_J_inv_r_restr(muomeg_detJ_Jt_J_inv_r,
|
||
attrPML);
|
||
MatrixRestrictedCoefficient negmuomeg_detJ_Jt_J_inv_i_restr(
|
||
negmuomeg_detJ_Jt_J_inv_i,attrPML);
|
||
MatrixRestrictedCoefficient negmuomeg_detJ_Jt_J_inv_r_restr(
|
||
negmuomeg_detJ_Jt_J_inv_r,attrPML);
|
||
MatrixRestrictedCoefficient mu2omeg2_detJ_Jt_J_inv_2_restr(
|
||
mu2omeg2_detJ_Jt_J_inv_2,attrPML);
|
||
MatrixRestrictedCoefficient eps2omeg2_detJ_Jt_J_inv_2_restr(
|
||
eps2omeg2_detJ_Jt_J_inv_2,attrPML);
|
||
|
||
MatrixProductCoefficient * epsomeg_detJ_Jt_J_inv_i_rot = nullptr;
|
||
MatrixProductCoefficient * epsomeg_detJ_Jt_J_inv_r_rot = nullptr;
|
||
MatrixProductCoefficient * negepsomeg_detJ_Jt_J_inv_r_rot = nullptr;
|
||
MatrixRestrictedCoefficient * epsomeg_detJ_Jt_J_inv_i_rot_restr = nullptr;
|
||
MatrixRestrictedCoefficient * epsomeg_detJ_Jt_J_inv_r_rot_restr = nullptr;
|
||
MatrixRestrictedCoefficient * negepsomeg_detJ_Jt_J_inv_r_rot_restr = nullptr;
|
||
|
||
if (pml && dim == 2)
|
||
{
|
||
epsomeg_detJ_Jt_J_inv_i_rot = new MatrixProductCoefficient(
|
||
epsomeg_detJ_Jt_J_inv_i, rot);
|
||
epsomeg_detJ_Jt_J_inv_r_rot = new MatrixProductCoefficient(
|
||
epsomeg_detJ_Jt_J_inv_r, rot);
|
||
negepsomeg_detJ_Jt_J_inv_r_rot = new MatrixProductCoefficient(
|
||
negepsomeg_detJ_Jt_J_inv_r, rot);
|
||
epsomeg_detJ_Jt_J_inv_i_rot_restr = new MatrixRestrictedCoefficient(
|
||
*epsomeg_detJ_Jt_J_inv_i_rot, attrPML);
|
||
epsomeg_detJ_Jt_J_inv_r_rot_restr = new MatrixRestrictedCoefficient(
|
||
*epsomeg_detJ_Jt_J_inv_r_rot, attrPML);
|
||
negepsomeg_detJ_Jt_J_inv_r_rot_restr = new MatrixRestrictedCoefficient(
|
||
*negepsomeg_detJ_Jt_J_inv_r_rot, attrPML);
|
||
}
|
||
|
||
ParComplexDPGWeakForm * a = new ParComplexDPGWeakForm(trial_fes,test_fec);
|
||
a->StoreMatrices(); // needed for AMR
|
||
|
||
// (E,∇ × F)
|
||
a->AddTrialIntegrator(new TransposeIntegrator(new MixedCurlIntegrator(one)),
|
||
nullptr,TrialSpace::E_space, TestSpace::F_space);
|
||
// -i ω ϵ (E , G) = i (- ω ϵ E, G)
|
||
a->AddTrialIntegrator(nullptr,
|
||
new TransposeIntegrator(new VectorFEMassIntegrator(*negepsomeg_cf)),
|
||
TrialSpace::E_space,TestSpace::G_space);
|
||
// (H,∇ × G)
|
||
a->AddTrialIntegrator(new TransposeIntegrator(new MixedCurlIntegrator(one)),
|
||
nullptr,TrialSpace::H_space, TestSpace::G_space);
|
||
// < n×Ĥ ,G>
|
||
a->AddTrialIntegrator(new TangentTraceIntegrator,nullptr,
|
||
TrialSpace::hatH_space, TestSpace::G_space);
|
||
// test integrators
|
||
// (∇×G ,∇× δG)
|
||
a->AddTestIntegrator(new CurlCurlIntegrator(one),nullptr,
|
||
TestSpace::G_space,TestSpace::G_space);
|
||
// (G,δG)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(one),nullptr,
|
||
TestSpace::G_space,TestSpace::G_space);
|
||
|
||
if (dim == 3)
|
||
{
|
||
// i ω μ (H, F)
|
||
a->AddTrialIntegrator(nullptr, new TransposeIntegrator(
|
||
new VectorFEMassIntegrator(*muomeg_cf)),
|
||
TrialSpace::H_space,TestSpace::F_space);
|
||
// < n×Ê,F>
|
||
a->AddTrialIntegrator(new TangentTraceIntegrator,nullptr,
|
||
TrialSpace::hatE_space, TestSpace::F_space);
|
||
|
||
// test integrators
|
||
// (∇×F,∇×δF)
|
||
a->AddTestIntegrator(new CurlCurlIntegrator(one),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// (F,δF)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(one),nullptr,
|
||
TestSpace::F_space,TestSpace::F_space);
|
||
// μ^2 ω^2 (F,δF)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(*mu2omeg2_cf),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G)
|
||
a->AddTestIntegrator(nullptr,new MixedVectorWeakCurlIntegrator(*negmuomeg_cf),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// -i ω ϵ (∇ × F, δG)
|
||
a->AddTestIntegrator(nullptr,new MixedVectorCurlIntegrator(*negepsomeg_cf),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// i ω μ (∇ × G,δF)
|
||
a->AddTestIntegrator(nullptr,new MixedVectorCurlIntegrator(*muomeg_cf),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// i ω ϵ (G, ∇ × δF )
|
||
a->AddTestIntegrator(nullptr,new MixedVectorWeakCurlIntegrator(*epsomeg_cf),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// ϵ^2 ω^2 (G,δG)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(*eps2omeg2_cf),nullptr,
|
||
TestSpace::G_space, TestSpace::G_space);
|
||
}
|
||
else
|
||
{
|
||
// i ω μ (H, F)
|
||
a->AddTrialIntegrator(nullptr,new MixedScalarMassIntegrator(*muomeg_cf),
|
||
TrialSpace::H_space, TestSpace::F_space);
|
||
// < n×Ê,F>
|
||
a->AddTrialIntegrator(new TraceIntegrator,nullptr,
|
||
TrialSpace::hatE_space, TestSpace::F_space);
|
||
// test integrators
|
||
// (∇F,∇δF)
|
||
a->AddTestIntegrator(new DiffusionIntegrator(one),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// (F,δF)
|
||
a->AddTestIntegrator(new MassIntegrator(one),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// μ^2 ω^2 (F,δF)
|
||
a->AddTestIntegrator(new MassIntegrator(*mu2omeg2_cf),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// -i ω μ (F,∇ × δG) = i (F, -ω μ ∇ × δ G)
|
||
a->AddTestIntegrator(nullptr,
|
||
new TransposeIntegrator(new MixedCurlIntegrator(*negmuomeg_cf)),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// -i ω ϵ (∇ × F, δG) = i (- ω ϵ A ∇ F,δG), A = [0 1; -1; 0]
|
||
a->AddTestIntegrator(nullptr,new MixedVectorGradientIntegrator(*negepsrot_cf),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// i ω μ (∇ × G,δF) = i (ω μ ∇ × G, δF )
|
||
a->AddTestIntegrator(nullptr,new MixedCurlIntegrator(*muomeg_cf),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// i ω ϵ (G, ∇ × δF ) = i (ω ϵ G, A ∇ δF) = i ( G , ω ϵ A ∇ δF)
|
||
a->AddTestIntegrator(nullptr,
|
||
new TransposeIntegrator(
|
||
new MixedVectorGradientIntegrator(*epsrot_cf)),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// ϵ^2 ω^2 (G, δG)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(*eps2omeg2_cf),nullptr,
|
||
TestSpace::G_space, TestSpace::G_space);
|
||
}
|
||
if (pml)
|
||
{
|
||
//trial integrators
|
||
// -i ω ϵ (β E , G) = -i ω ϵ ((β_re + i β_im) E, G)
|
||
// = (ω ϵ β_im E, G) + i (- ω ϵ β_re E, G)
|
||
a->AddTrialIntegrator(
|
||
new TransposeIntegrator(new VectorFEMassIntegrator(
|
||
epsomeg_detJ_Jt_J_inv_i_restr)),
|
||
new TransposeIntegrator(new VectorFEMassIntegrator(
|
||
negepsomeg_detJ_Jt_J_inv_r_restr)),
|
||
TrialSpace::E_space,TestSpace::G_space);
|
||
if (dim == 3)
|
||
{
|
||
//trial integrators
|
||
// i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F)
|
||
// = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F)
|
||
a->AddTrialIntegrator(
|
||
new TransposeIntegrator(new VectorFEMassIntegrator(
|
||
negmuomeg_detJ_Jt_J_inv_i_restr)),
|
||
new TransposeIntegrator(new VectorFEMassIntegrator(
|
||
muomeg_detJ_Jt_J_inv_r_restr)),
|
||
TrialSpace::H_space, TestSpace::F_space);
|
||
// test integrators
|
||
// μ^2 ω^2 (|α|^-2 F,δF)
|
||
a->AddTestIntegrator(
|
||
new VectorFEMassIntegrator(mu2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// -i ω μ (α^-* F,∇ × δG) = i (F, - ω μ α^-1 ∇ × δ G)
|
||
// = i (F, - ω μ (α^-1_re + i α^-1_im) ∇ × δ G)
|
||
// = (F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG)
|
||
a->AddTestIntegrator(new MixedVectorWeakCurlIntegrator(
|
||
negmuomeg_detJ_Jt_J_inv_i_restr),
|
||
new MixedVectorWeakCurlIntegrator(negmuomeg_detJ_Jt_J_inv_r_restr),
|
||
TestSpace::F_space,TestSpace::G_space);
|
||
// -i ω ϵ (β ∇ × F, δG) = -i ω ϵ ((β_re + i β_im) ∇ × F, δG)
|
||
// = (ω ϵ β_im ∇ × F, δG) + i (- ω ϵ β_re ∇ × F, δG)
|
||
a->AddTestIntegrator(new MixedVectorCurlIntegrator(
|
||
epsomeg_detJ_Jt_J_inv_i_restr),
|
||
new MixedVectorCurlIntegrator(negepsomeg_detJ_Jt_J_inv_r_restr),
|
||
TestSpace::F_space,TestSpace::G_space);
|
||
// i ω μ (α^-1 ∇ × G,δF) = i ω μ ((α^-1_re + i α^-1_im) ∇ × G,δF)
|
||
// = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF)
|
||
a->AddTestIntegrator(new MixedVectorCurlIntegrator(
|
||
negmuomeg_detJ_Jt_J_inv_i_restr),
|
||
new MixedVectorCurlIntegrator(muomeg_detJ_Jt_J_inv_r_restr),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// i ω ϵ (β^* G, ∇×δF) = i ω ϵ ( (β_re - i β_im) G, ∇×δF)
|
||
// = (ω ϵ β_im G, ∇×δF) + i ( ω ϵ β_re G, ∇×δF)
|
||
a->AddTestIntegrator(new MixedVectorWeakCurlIntegrator(
|
||
epsomeg_detJ_Jt_J_inv_i_restr),
|
||
new MixedVectorWeakCurlIntegrator(epsomeg_detJ_Jt_J_inv_r_restr),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// ϵ^2 ω^2 (|β|^2 G,δG)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(
|
||
eps2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
|
||
TestSpace::G_space, TestSpace::G_space);
|
||
}
|
||
else
|
||
{
|
||
//trial integrators
|
||
// i ω μ (α^-1 H, F) = i ω μ ( (α^-1_re + i α^-1_im) H, F)
|
||
// = (- ω μ α^-1_im, H,F) + i *(ω μ α^-1_re H, F)
|
||
a->AddTrialIntegrator(
|
||
new MixedScalarMassIntegrator(negmuomeg_detJ_i_restr),
|
||
new MixedScalarMassIntegrator(muomeg_detJ_r_restr),
|
||
TrialSpace::H_space, TestSpace::F_space);
|
||
// test integrators
|
||
// μ^2 ω^2 (|α|^-2 F,δF)
|
||
a->AddTestIntegrator(new MassIntegrator(mu2omeg2_detJ_2_restr),nullptr,
|
||
TestSpace::F_space, TestSpace::F_space);
|
||
// -i ω μ (α^-* F,∇ × δG) = (F, ω μ α^-1 ∇ × δ G)
|
||
// =(F, - ω μ α^-1_im ∇ × δ G) + i (F, - ω μ α^-1_re ∇×δG)
|
||
a->AddTestIntegrator(
|
||
new TransposeIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_i_restr)),
|
||
new TransposeIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_r_restr)),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// -i ω ϵ (β ∇ × F, δG) = i (- ω ϵ β A ∇ F,δG), A = [0 1; -1; 0]
|
||
// = (ω ϵ β_im A ∇ F, δG) + i (- ω ϵ β_re A ∇ F, δG)
|
||
a->AddTestIntegrator(new MixedVectorGradientIntegrator(
|
||
*epsomeg_detJ_Jt_J_inv_i_rot_restr),
|
||
new MixedVectorGradientIntegrator(*negepsomeg_detJ_Jt_J_inv_r_rot_restr),
|
||
TestSpace::F_space, TestSpace::G_space);
|
||
// i ω μ (α^-1 ∇ × G,δF) = i (ω μ α^-1 ∇ × G, δF )
|
||
// = (- ω μ α^-1_im ∇ × G,δF) + i (ω μ α^-1_re ∇ × G,δF)
|
||
a->AddTestIntegrator(new MixedCurlIntegrator(negmuomeg_detJ_i_restr),
|
||
new MixedCurlIntegrator(muomeg_detJ_r_restr),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// i ω ϵ (β^* G, ∇ × δF ) = i ( G , ω ϵ β A ∇ δF)
|
||
// = ( G , ω ϵ β_im A ∇ δF) + i ( G , ω ϵ β_re A ∇ δF)
|
||
a->AddTestIntegrator(
|
||
new TransposeIntegrator(new MixedVectorGradientIntegrator(
|
||
*epsomeg_detJ_Jt_J_inv_i_rot_restr)),
|
||
new TransposeIntegrator(new MixedVectorGradientIntegrator(
|
||
*epsomeg_detJ_Jt_J_inv_r_rot_restr)),
|
||
TestSpace::G_space, TestSpace::F_space);
|
||
// ϵ^2 ω^2 (|β|^2 G,δG)
|
||
a->AddTestIntegrator(new VectorFEMassIntegrator(
|
||
eps2omeg2_detJ_Jt_J_inv_2_restr),nullptr,
|
||
TestSpace::G_space, TestSpace::G_space);
|
||
}
|
||
}
|
||
// RHS
|
||
VectorFunctionCoefficient f_rhs_r(dim,rhs_func_r);
|
||
VectorFunctionCoefficient f_rhs_i(dim,rhs_func_i);
|
||
VectorFunctionCoefficient f_source(dim,source_function);
|
||
if (prob == 0)
|
||
{
|
||
a->AddDomainLFIntegrator(new VectorFEDomainLFIntegrator(f_rhs_r),
|
||
new VectorFEDomainLFIntegrator(f_rhs_i),
|
||
TestSpace::G_space);
|
||
}
|
||
else if (prob == 2)
|
||
{
|
||
a->AddDomainLFIntegrator(new VectorFEDomainLFIntegrator(f_source),nullptr,
|
||
TestSpace::G_space);
|
||
}
|
||
|
||
VectorFunctionCoefficient hatEex_r(dim,hatE_exact_r);
|
||
VectorFunctionCoefficient hatEex_i(dim,hatE_exact_i);
|
||
|
||
socketstream E_out_r;
|
||
socketstream H_out_r;
|
||
if (myid == 0)
|
||
{
|
||
std::cout << "\n Ref |"
|
||
<< " Dofs |"
|
||
<< " ω |" ;
|
||
if (exact_known)
|
||
{
|
||
std::cout << " L2 Error |"
|
||
<< " Rate |" ;
|
||
}
|
||
std::cout << " Residual |"
|
||
<< " Rate |"
|
||
<< " PCG it |" << endl;
|
||
std::cout << std::string((exact_known) ? 82 : 60,'-')
|
||
<< endl;
|
||
}
|
||
|
||
real_t res0 = 0.;
|
||
real_t err0 = 0.;
|
||
int dof0 = 0; // init to suppress gcc warning
|
||
|
||
Array<int> elements_to_refine;
|
||
|
||
ParGridFunction E_r, E_i, H_r, H_i;
|
||
|
||
ParaViewDataCollection * paraview_dc = nullptr;
|
||
|
||
if (paraview)
|
||
{
|
||
paraview_dc = new ParaViewDataCollection(enum_str[prob], &pmesh);
|
||
paraview_dc->SetPrefixPath("ParaView/Maxwell");
|
||
paraview_dc->SetLevelsOfDetail(order);
|
||
paraview_dc->SetCycle(0);
|
||
paraview_dc->SetDataFormat(VTKFormat::BINARY);
|
||
paraview_dc->SetHighOrderOutput(true);
|
||
paraview_dc->SetTime(0.0); // set the time
|
||
paraview_dc->RegisterField("E_r",&E_r);
|
||
paraview_dc->RegisterField("E_i",&E_i);
|
||
paraview_dc->RegisterField("H_r",&H_r);
|
||
paraview_dc->RegisterField("H_i",&H_i);
|
||
}
|
||
|
||
if (static_cond) { a->EnableStaticCondensation(); }
|
||
for (int it = 0; it<=pr; it++)
|
||
{
|
||
a->Assemble();
|
||
|
||
Array<int> ess_tdof_list;
|
||
Array<int> ess_bdr;
|
||
if (pmesh.bdr_attributes.Size())
|
||
{
|
||
ess_bdr.SetSize(pmesh.bdr_attributes.Max());
|
||
ess_bdr = 1;
|
||
hatE_fes->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
||
if (pml)
|
||
{
|
||
ess_bdr = 0;
|
||
ess_bdr[1] = 1;
|
||
}
|
||
}
|
||
|
||
// shift the ess_tdofs
|
||
for (int j = 0; j < ess_tdof_list.Size(); j++)
|
||
{
|
||
ess_tdof_list[j] += E_fes->GetTrueVSize() + H_fes->GetTrueVSize();
|
||
}
|
||
|
||
Array<int> offsets(5);
|
||
offsets[0] = 0;
|
||
offsets[1] = E_fes->GetVSize();
|
||
offsets[2] = H_fes->GetVSize();
|
||
offsets[3] = hatE_fes->GetVSize();
|
||
offsets[4] = hatH_fes->GetVSize();
|
||
offsets.PartialSum();
|
||
|
||
Vector x(2*offsets.Last());
|
||
x = 0.;
|
||
|
||
if (prob != 2)
|
||
{
|
||
ParGridFunction hatE_gf_r(hatE_fes, x, offsets[2]);
|
||
ParGridFunction hatE_gf_i(hatE_fes, x, offsets.Last() + offsets[2]);
|
||
if (dim == 3)
|
||
{
|
||
hatE_gf_r.ProjectBdrCoefficientTangent(hatEex_r, ess_bdr);
|
||
hatE_gf_i.ProjectBdrCoefficientTangent(hatEex_i, ess_bdr);
|
||
}
|
||
else
|
||
{
|
||
hatE_gf_r.ProjectBdrCoefficientNormal(hatEex_r, ess_bdr);
|
||
hatE_gf_i.ProjectBdrCoefficientNormal(hatEex_i, ess_bdr);
|
||
}
|
||
}
|
||
|
||
OperatorPtr Ah;
|
||
Vector X,B;
|
||
a->FormLinearSystem(ess_tdof_list,x,Ah, X,B);
|
||
|
||
ComplexOperator * Ahc = Ah.As<ComplexOperator>();
|
||
|
||
BlockOperator * BlockA_r = dynamic_cast<BlockOperator *>(&Ahc->real());
|
||
BlockOperator * BlockA_i = dynamic_cast<BlockOperator *>(&Ahc->imag());
|
||
|
||
int num_blocks = BlockA_r->NumRowBlocks();
|
||
Array<int> tdof_offsets(2*num_blocks+1);
|
||
|
||
tdof_offsets[0] = 0;
|
||
int skip = (static_cond) ? 0 : 2;
|
||
int k = (static_cond) ? 2 : 0;
|
||
for (int i=0; i<num_blocks; i++)
|
||
{
|
||
tdof_offsets[i+1] = trial_fes[i+k]->GetTrueVSize();
|
||
tdof_offsets[num_blocks+i+1] = trial_fes[i+k]->GetTrueVSize();
|
||
}
|
||
tdof_offsets.PartialSum();
|
||
|
||
BlockOperator blockA(tdof_offsets);
|
||
for (int i = 0; i<num_blocks; i++)
|
||
{
|
||
for (int j = 0; j<num_blocks; j++)
|
||
{
|
||
blockA.SetBlock(i,j,&BlockA_r->GetBlock(i,j));
|
||
blockA.SetBlock(i,j+num_blocks,&BlockA_i->GetBlock(i,j), -1.0);
|
||
blockA.SetBlock(i+num_blocks,j+num_blocks,&BlockA_r->GetBlock(i,j));
|
||
blockA.SetBlock(i+num_blocks,j,&BlockA_i->GetBlock(i,j));
|
||
}
|
||
}
|
||
|
||
X = 0.;
|
||
BlockDiagonalPreconditioner M(tdof_offsets);
|
||
|
||
if (!static_cond)
|
||
{
|
||
HypreBoomerAMG * solver_E = new HypreBoomerAMG((HypreParMatrix &)
|
||
BlockA_r->GetBlock(0,0));
|
||
solver_E->SetPrintLevel(0);
|
||
solver_E->SetSystemsOptions(dim);
|
||
HypreBoomerAMG * solver_H = new HypreBoomerAMG((HypreParMatrix &)
|
||
BlockA_r->GetBlock(1,1));
|
||
solver_H->SetPrintLevel(0);
|
||
solver_H->SetSystemsOptions(dim);
|
||
M.SetDiagonalBlock(0,solver_E);
|
||
M.SetDiagonalBlock(1,solver_H);
|
||
M.SetDiagonalBlock(num_blocks,solver_E);
|
||
M.SetDiagonalBlock(num_blocks+1,solver_H);
|
||
}
|
||
|
||
HypreSolver * solver_hatH = nullptr;
|
||
HypreAMS * solver_hatE = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip,
|
||
skip),
|
||
hatE_fes);
|
||
solver_hatE->SetPrintLevel(0);
|
||
if (dim == 2)
|
||
{
|
||
solver_hatH = new HypreBoomerAMG((HypreParMatrix &)BlockA_r->GetBlock(skip+1,
|
||
skip+1));
|
||
dynamic_cast<HypreBoomerAMG*>(solver_hatH)->SetPrintLevel(0);
|
||
}
|
||
else
|
||
{
|
||
solver_hatH = new HypreAMS((HypreParMatrix &)BlockA_r->GetBlock(skip+1,skip+1),
|
||
hatH_fes);
|
||
dynamic_cast<HypreAMS*>(solver_hatH)->SetPrintLevel(0);
|
||
}
|
||
|
||
M.SetDiagonalBlock(skip,solver_hatE);
|
||
M.SetDiagonalBlock(skip+1,solver_hatH);
|
||
M.SetDiagonalBlock(skip+num_blocks,solver_hatE);
|
||
M.SetDiagonalBlock(skip+num_blocks+1,solver_hatH);
|
||
|
||
CGSolver cg(MPI_COMM_WORLD);
|
||
cg.SetRelTol(1e-6);
|
||
cg.SetMaxIter(10000);
|
||
cg.SetPrintLevel(0);
|
||
cg.SetPreconditioner(M);
|
||
cg.SetOperator(blockA);
|
||
cg.Mult(B, X);
|
||
|
||
for (int i = 0; i<num_blocks; i++)
|
||
{
|
||
delete &M.GetDiagonalBlock(i);
|
||
}
|
||
|
||
int num_iter = cg.GetNumIterations();
|
||
|
||
a->RecoverFEMSolution(X,x);
|
||
|
||
Vector & residuals = a->ComputeResidual(x);
|
||
|
||
real_t residual = residuals.Norml2();
|
||
real_t maxresidual = residuals.Max();
|
||
real_t globalresidual = residual * residual;
|
||
MPI_Allreduce(MPI_IN_PLACE, &maxresidual, 1, MPITypeMap<real_t>::mpi_type,
|
||
MPI_MAX, MPI_COMM_WORLD);
|
||
MPI_Allreduce(MPI_IN_PLACE, &globalresidual, 1,
|
||
MPITypeMap<real_t>::mpi_type, MPI_SUM, MPI_COMM_WORLD);
|
||
|
||
globalresidual = sqrt(globalresidual);
|
||
|
||
E_r.MakeRef(E_fes,x, 0);
|
||
E_i.MakeRef(E_fes,x, offsets.Last());
|
||
|
||
H_r.MakeRef(H_fes,x, offsets[1]);
|
||
H_i.MakeRef(H_fes,x, offsets.Last()+offsets[1]);
|
||
|
||
int dofs = 0;
|
||
for (int i = 0; i<trial_fes.Size(); i++)
|
||
{
|
||
dofs += trial_fes[i]->GlobalTrueVSize();
|
||
}
|
||
|
||
real_t L2Error = 0.0;
|
||
real_t rate_err = 0.0;
|
||
|
||
if (exact_known)
|
||
{
|
||
VectorFunctionCoefficient E_ex_r(dim,E_exact_r);
|
||
VectorFunctionCoefficient E_ex_i(dim,E_exact_i);
|
||
VectorFunctionCoefficient H_ex_r(dim,H_exact_r);
|
||
VectorFunctionCoefficient H_ex_i(dim,H_exact_i);
|
||
real_t E_err_r = E_r.ComputeL2Error(E_ex_r);
|
||
real_t E_err_i = E_i.ComputeL2Error(E_ex_i);
|
||
real_t H_err_r = H_r.ComputeL2Error(H_ex_r);
|
||
real_t H_err_i = H_i.ComputeL2Error(H_ex_i);
|
||
L2Error = sqrt( E_err_r*E_err_r + E_err_i*E_err_i
|
||
+ H_err_r*H_err_r + H_err_i*H_err_i );
|
||
rate_err = (it) ? dim*log(err0/L2Error)/log((real_t)dof0/dofs) : 0.0;
|
||
err0 = L2Error;
|
||
}
|
||
|
||
real_t rate_res = (it) ? dim*log(res0/globalresidual)/log((
|
||
real_t)dof0/dofs) : 0.0;
|
||
|
||
res0 = globalresidual;
|
||
dof0 = dofs;
|
||
|
||
if (myid == 0)
|
||
{
|
||
std::ios oldState(nullptr);
|
||
oldState.copyfmt(std::cout);
|
||
std::cout << std::right << std::setw(5) << it << " | "
|
||
<< std::setw(10) << dof0 << " | "
|
||
<< std::setprecision(1) << std::fixed
|
||
<< std::setw(4) << 2.0*rnum << " π | "
|
||
<< std::setprecision(3);
|
||
if (exact_known)
|
||
{
|
||
std::cout << std::setw(10) << std::scientific << err0 << " | "
|
||
<< std::setprecision(2)
|
||
<< std::setw(6) << std::fixed << rate_err << " | " ;
|
||
}
|
||
std::cout << std::setprecision(3)
|
||
<< std::setw(10) << std::scientific << res0 << " | "
|
||
<< std::setprecision(2)
|
||
<< std::setw(6) << std::fixed << rate_res << " | "
|
||
<< std::setw(6) << std::fixed << num_iter << " | "
|
||
<< std::endl;
|
||
std::cout.copyfmt(oldState);
|
||
}
|
||
|
||
if (visualization)
|
||
{
|
||
const char * keys = (it == 0 && dim == 2) ? "jRcml\n" : nullptr;
|
||
char vishost[] = "localhost";
|
||
VisualizeField(E_out_r,vishost, visport, E_r,
|
||
"Numerical Electric field (real part)", 0, 0, 500, 500, keys);
|
||
VisualizeField(H_out_r,vishost, visport, H_r,
|
||
"Numerical Magnetic field (real part)", 501, 0, 500, 500, keys);
|
||
}
|
||
|
||
if (paraview)
|
||
{
|
||
paraview_dc->SetCycle(it);
|
||
paraview_dc->SetTime((real_t)it);
|
||
paraview_dc->Save();
|
||
}
|
||
|
||
if (it == pr)
|
||
{
|
||
break;
|
||
}
|
||
|
||
if (theta > 0.0)
|
||
{
|
||
elements_to_refine.SetSize(0);
|
||
for (int iel = 0; iel<pmesh.GetNE(); iel++)
|
||
{
|
||
if (residuals[iel] > theta * maxresidual)
|
||
{
|
||
elements_to_refine.Append(iel);
|
||
}
|
||
}
|
||
pmesh.GeneralRefinement(elements_to_refine,1,1);
|
||
}
|
||
else
|
||
{
|
||
pmesh.UniformRefinement();
|
||
}
|
||
if (pml) { pml->SetAttributes(&pmesh); }
|
||
for (int i =0; i<trial_fes.Size(); i++)
|
||
{
|
||
trial_fes[i]->Update(false);
|
||
}
|
||
a->Update();
|
||
}
|
||
|
||
if (pml && dim == 2)
|
||
{
|
||
delete epsomeg_detJ_Jt_J_inv_i_rot;
|
||
delete epsomeg_detJ_Jt_J_inv_r_rot;
|
||
delete negepsomeg_detJ_Jt_J_inv_r_rot;
|
||
delete epsomeg_detJ_Jt_J_inv_i_rot_restr;
|
||
delete epsomeg_detJ_Jt_J_inv_r_rot_restr;
|
||
delete negepsomeg_detJ_Jt_J_inv_r_rot_restr;
|
||
}
|
||
|
||
if (paraview)
|
||
{
|
||
delete paraview_dc;
|
||
}
|
||
|
||
delete a;
|
||
delete F_fec;
|
||
delete G_fec;
|
||
delete hatH_fes;
|
||
delete hatH_fec;
|
||
delete hatE_fes;
|
||
delete hatE_fec;
|
||
delete H_fec;
|
||
delete E_fec;
|
||
delete H_fes;
|
||
delete E_fes;
|
||
|
||
return 0;
|
||
}
|
||
|
||
void E_exact_r(const Vector &x, Vector & E_r)
|
||
{
|
||
std::vector<std::complex<real_t>> E;
|
||
maxwell_solution(x,E);
|
||
E_r.SetSize(E.size());
|
||
for (unsigned i = 0; i < E.size(); i++)
|
||
{
|
||
E_r[i]= E[i].real();
|
||
}
|
||
}
|
||
|
||
void E_exact_i(const Vector &x, Vector & E_i)
|
||
{
|
||
std::vector<std::complex<real_t>> E;
|
||
maxwell_solution(x, E);
|
||
E_i.SetSize(E.size());
|
||
for (unsigned i = 0; i < E.size(); i++)
|
||
{
|
||
E_i[i]= E[i].imag();
|
||
}
|
||
}
|
||
|
||
void curlE_exact_r(const Vector &x, Vector &curlE_r)
|
||
{
|
||
std::vector<std::complex<real_t>> curlE;
|
||
maxwell_solution_curl(x, curlE);
|
||
curlE_r.SetSize(curlE.size());
|
||
for (unsigned i = 0; i < curlE.size(); i++)
|
||
{
|
||
curlE_r[i]= curlE[i].real();
|
||
}
|
||
}
|
||
|
||
void curlE_exact_i(const Vector &x, Vector &curlE_i)
|
||
{
|
||
std::vector<std::complex<real_t>> curlE;
|
||
maxwell_solution_curl(x, curlE);
|
||
curlE_i.SetSize(curlE.size());
|
||
for (unsigned i = 0; i < curlE.size(); i++)
|
||
{
|
||
curlE_i[i]= curlE[i].imag();
|
||
}
|
||
}
|
||
|
||
void curlcurlE_exact_r(const Vector &x, Vector & curlcurlE_r)
|
||
{
|
||
std::vector<std::complex<real_t>> curlcurlE;
|
||
maxwell_solution_curlcurl(x, curlcurlE);
|
||
curlcurlE_r.SetSize(curlcurlE.size());
|
||
for (unsigned i = 0; i < curlcurlE.size(); i++)
|
||
{
|
||
curlcurlE_r[i]= curlcurlE[i].real();
|
||
}
|
||
}
|
||
|
||
void curlcurlE_exact_i(const Vector &x, Vector & curlcurlE_i)
|
||
{
|
||
std::vector<std::complex<real_t>> curlcurlE;
|
||
maxwell_solution_curlcurl(x, curlcurlE);
|
||
curlcurlE_i.SetSize(curlcurlE.size());
|
||
for (unsigned i = 0; i < curlcurlE.size(); i++)
|
||
{
|
||
curlcurlE_i[i]= curlcurlE[i].imag();
|
||
}
|
||
}
|
||
|
||
|
||
void H_exact_r(const Vector &x, Vector & H_r)
|
||
{
|
||
// H = i ∇ × E / ω μ
|
||
// H_r = - ∇ × E_i / ω μ
|
||
Vector curlE_i;
|
||
curlE_exact_i(x,curlE_i);
|
||
H_r.SetSize(dimc);
|
||
for (int i = 0; i<dimc; i++)
|
||
{
|
||
H_r(i) = - curlE_i(i) / (omega * mu);
|
||
}
|
||
}
|
||
|
||
void H_exact_i(const Vector &x, Vector & H_i)
|
||
{
|
||
// H = i ∇ × E / ω μ
|
||
// H_i = ∇ × E_r / ω μ
|
||
Vector curlE_r;
|
||
curlE_exact_r(x,curlE_r);
|
||
H_i.SetSize(dimc);
|
||
for (int i = 0; i<dimc; i++)
|
||
{
|
||
H_i(i) = curlE_r(i) / (omega * mu);
|
||
}
|
||
}
|
||
|
||
void curlH_exact_r(const Vector &x,Vector &curlH_r)
|
||
{
|
||
// ∇ × H_r = - ∇ × ∇ × E_i / ω μ
|
||
Vector curlcurlE_i;
|
||
curlcurlE_exact_i(x,curlcurlE_i);
|
||
curlH_r.SetSize(dim);
|
||
for (int i = 0; i<dim; i++)
|
||
{
|
||
curlH_r(i) = -curlcurlE_i(i) / (omega * mu);
|
||
}
|
||
}
|
||
|
||
void curlH_exact_i(const Vector &x,Vector &curlH_i)
|
||
{
|
||
// ∇ × H_i = ∇ × ∇ × E_r / ω μ
|
||
Vector curlcurlE_r;
|
||
curlcurlE_exact_r(x,curlcurlE_r);
|
||
curlH_i.SetSize(dim);
|
||
for (int i = 0; i<dim; i++)
|
||
{
|
||
curlH_i(i) = curlcurlE_r(i) / (omega * mu);
|
||
}
|
||
}
|
||
|
||
void hatE_exact_r(const Vector & x, Vector & hatE_r)
|
||
{
|
||
if (dim == 3)
|
||
{
|
||
E_exact_r(x,hatE_r);
|
||
}
|
||
else
|
||
{
|
||
Vector E_r;
|
||
E_exact_r(x,E_r);
|
||
hatE_r.SetSize(hatE_r.Size());
|
||
// rotate E_hat
|
||
hatE_r[0] = E_r[1];
|
||
hatE_r[1] = -E_r[0];
|
||
}
|
||
}
|
||
|
||
void hatE_exact_i(const Vector & x, Vector & hatE_i)
|
||
{
|
||
if (dim == 3)
|
||
{
|
||
E_exact_i(x,hatE_i);
|
||
}
|
||
else
|
||
{
|
||
Vector E_i;
|
||
E_exact_i(x,E_i);
|
||
hatE_i.SetSize(hatE_i.Size());
|
||
// rotate E_hat
|
||
hatE_i[0] = E_i[1];
|
||
hatE_i[1] = -E_i[0];
|
||
}
|
||
}
|
||
|
||
void hatH_exact_r(const Vector & x, Vector & hatH_r)
|
||
{
|
||
H_exact_r(x,hatH_r);
|
||
}
|
||
|
||
void hatH_exact_i(const Vector & x, Vector & hatH_i)
|
||
{
|
||
H_exact_i(x,hatH_i);
|
||
}
|
||
|
||
real_t hatH_exact_scalar_r(const Vector & x)
|
||
{
|
||
Vector hatH_r;
|
||
H_exact_r(x,hatH_r);
|
||
return hatH_r[0];
|
||
}
|
||
|
||
real_t hatH_exact_scalar_i(const Vector & x)
|
||
{
|
||
Vector hatH_i;
|
||
H_exact_i(x,hatH_i);
|
||
return hatH_i[0];
|
||
}
|
||
|
||
// J = -i ω ϵ E + ∇ × H
|
||
// J_r + iJ_i = -i ω ϵ (E_r + i E_i) + ∇ × (H_r + i H_i)
|
||
void rhs_func_r(const Vector &x, Vector & J_r)
|
||
{
|
||
// J_r = ω ϵ E_i + ∇ × H_r
|
||
Vector E_i, curlH_r;
|
||
E_exact_i(x,E_i);
|
||
curlH_exact_r(x,curlH_r);
|
||
J_r.SetSize(dim);
|
||
for (int i = 0; i<dim; i++)
|
||
{
|
||
J_r(i) = omega * epsilon * E_i(i) + curlH_r(i);
|
||
}
|
||
}
|
||
|
||
void rhs_func_i(const Vector &x, Vector & J_i)
|
||
{
|
||
// J_i = - ω ϵ E_r + ∇ × H_i
|
||
Vector E_r, curlH_i;
|
||
E_exact_r(x,E_r);
|
||
curlH_exact_i(x,curlH_i);
|
||
J_i.SetSize(dim);
|
||
for (int i = 0; i<dim; i++)
|
||
{
|
||
J_i(i) = -omega * epsilon * E_r(i) + curlH_i(i);
|
||
}
|
||
}
|
||
|
||
void maxwell_solution(const Vector & X, std::vector<complex<real_t>> &E)
|
||
{
|
||
complex<real_t> zi = complex<real_t>(0., 1.);
|
||
E.resize(dim);
|
||
for (int i = 0; i < dim; ++i)
|
||
{
|
||
E[i] = 0.0;
|
||
}
|
||
switch (prob)
|
||
{
|
||
case plane_wave:
|
||
{
|
||
E[0] = exp(zi * omega * (X.Sum()));
|
||
}
|
||
break;
|
||
case pml_plane_wave_scatter:
|
||
{
|
||
E[1] = exp(zi * omega * (X(0)));
|
||
}
|
||
break;
|
||
case fichera_oven:
|
||
{
|
||
if (abs(X(2) - 3.0) < 1e-10)
|
||
{
|
||
E[0] = sin(M_PI*X(1));
|
||
}
|
||
}
|
||
break;
|
||
case pml_pointsource:
|
||
{
|
||
Vector shift(dim);
|
||
real_t k = omega * sqrt(epsilon * mu);
|
||
shift = -0.5;
|
||
|
||
if (dim == 2)
|
||
{
|
||
real_t x0 = X(0) + shift(0);
|
||
real_t x1 = X(1) + shift(1);
|
||
real_t r = sqrt(x0 * x0 + x1 * x1);
|
||
real_t beta = k * r;
|
||
|
||
// Bessel functions
|
||
complex<real_t> Ho, Ho_r, Ho_rr;
|
||
Ho = real_t(jn(0, beta)) + zi * real_t(yn(0, beta));
|
||
Ho_r = -k * real_t(jn(1, beta)) + zi * real_t(yn(1, beta));
|
||
Ho_rr = -k * k * (1_r / beta *
|
||
(real_t(jn(1, beta)) + zi * real_t(yn(1, beta))) -
|
||
(real_t(jn(2, beta)) + zi * real_t(yn(2, beta))));
|
||
|
||
// First derivatives
|
||
real_t r_x = x0 / r;
|
||
real_t r_y = x1 / r;
|
||
real_t r_xy = -(r_x / r) * r_y;
|
||
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
|
||
|
||
complex<real_t> val, val_xx, val_xy;
|
||
val = 0.25_r * zi * Ho;
|
||
val_xx = 0.25_r * zi * (r_xx * Ho_r + r_x * r_x * Ho_rr);
|
||
val_xy = 0.25_r * zi * (r_xy * Ho_r + r_x * r_y * Ho_rr);
|
||
E[0] = zi / k * (k * k * val + val_xx);
|
||
E[1] = zi / k * val_xy;
|
||
}
|
||
else
|
||
{
|
||
real_t x0 = X(0) + shift(0);
|
||
real_t x1 = X(1) + shift(1);
|
||
real_t x2 = X(2) + shift(2);
|
||
real_t r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
|
||
|
||
real_t r_x = x0 / r;
|
||
real_t r_y = x1 / r;
|
||
real_t r_z = x2 / r;
|
||
real_t r_xx = (1.0 / r) * (1.0 - r_x * r_x);
|
||
real_t r_yx = -(r_y / r) * r_x;
|
||
real_t r_zx = -(r_z / r) * r_x;
|
||
|
||
complex<real_t> val, val_r, val_rr;
|
||
val = exp(zi * k * r) / r;
|
||
val_r = val / r * (zi * k * r - 1_r);
|
||
val_rr = val / (r * r) * (-k * k * r * r
|
||
- 2_r * zi * k * r + 2_r);
|
||
|
||
complex<real_t> val_xx, val_yx, val_zx;
|
||
val_xx = val_rr * r_x * r_x + val_r * r_xx;
|
||
val_yx = val_rr * r_x * r_y + val_r * r_yx;
|
||
val_zx = val_rr * r_x * r_z + val_r * r_zx;
|
||
complex<real_t> alpha = zi * k / 4_r / real_t(M_PI) / k / k;
|
||
E[0] = alpha * (k * k * val + val_xx);
|
||
E[1] = alpha * val_yx;
|
||
E[2] = alpha * val_zx;
|
||
}
|
||
}
|
||
break;
|
||
|
||
default:
|
||
MFEM_ABORT("Should be unreachable");
|
||
break;
|
||
}
|
||
}
|
||
|
||
void maxwell_solution_curl(const Vector & X,
|
||
std::vector<complex<real_t>> &curlE)
|
||
{
|
||
complex<real_t> zi = complex<real_t>(0., 1.);
|
||
curlE.resize(dimc);
|
||
for (int i = 0; i < dimc; ++i)
|
||
{
|
||
curlE[i] = 0.0;
|
||
}
|
||
switch (prob)
|
||
{
|
||
case plane_wave:
|
||
{
|
||
std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
|
||
if (dim == 3)
|
||
{
|
||
curlE[0] = 0.0;
|
||
curlE[1] = zi * omega * pw;
|
||
curlE[2] = -zi * omega * pw;
|
||
}
|
||
else
|
||
{
|
||
curlE[0] = -zi * omega * pw;
|
||
}
|
||
}
|
||
break;
|
||
case pml_plane_wave_scatter:
|
||
{
|
||
std::complex<real_t> pw = exp(zi * omega * (X(0)));
|
||
curlE[0] = zi * omega * pw;
|
||
}
|
||
break;
|
||
default:
|
||
MFEM_ABORT("Should be unreachable");
|
||
break;
|
||
}
|
||
}
|
||
|
||
void maxwell_solution_curlcurl(const Vector & X,
|
||
std::vector<complex<real_t>> &curlcurlE)
|
||
{
|
||
complex<real_t> zi = complex<real_t>(0., 1.);
|
||
curlcurlE.resize(dim);
|
||
for (int i = 0; i < dim; ++i)
|
||
{
|
||
curlcurlE[i] = 0.0;
|
||
}
|
||
switch (prob)
|
||
{
|
||
case plane_wave:
|
||
{
|
||
std::complex<real_t> pw = exp(zi * omega * (X.Sum()));
|
||
if (dim == 3)
|
||
{
|
||
curlcurlE[0] = 2_r * omega * omega * pw;
|
||
curlcurlE[1] = - omega * omega * pw;
|
||
curlcurlE[2] = - omega * omega * pw;
|
||
}
|
||
else
|
||
{
|
||
curlcurlE[0] = omega * omega * pw;
|
||
curlcurlE[1] = -omega * omega * pw;
|
||
}
|
||
}
|
||
break;
|
||
case pml_plane_wave_scatter:
|
||
{
|
||
std::complex<real_t> pw = exp(zi * omega * (X(0)));
|
||
curlcurlE[1] = omega * omega * pw;
|
||
}
|
||
break;
|
||
default:
|
||
MFEM_ABORT("Should be unreachable");
|
||
break;
|
||
}
|
||
}
|
||
|
||
void source_function(const Vector &x, Vector &f)
|
||
{
|
||
Vector center(dim);
|
||
center = 0.5;
|
||
real_t r = 0.0;
|
||
for (int i = 0; i < dim; ++i)
|
||
{
|
||
r += pow(x[i] - center[i], 2.);
|
||
}
|
||
real_t n = 5.0 * omega * sqrt(epsilon * mu) / M_PI;
|
||
real_t coeff = pow(n, 2) / M_PI;
|
||
real_t alpha = -pow(n, 2) * r;
|
||
f = 0.0;
|
||
f[0] = -omega * coeff * exp(alpha)/omega;
|
||
}
|