615 lines
18 KiB
C++
615 lines
18 KiB
C++
//
|
|
// Compile with: make maxwellp
|
|
//
|
|
// mpirun -np 4 ./maxwellp -o 2 -f 8.0 -sr 3 -m ../../data/inline-quad.mesh
|
|
//
|
|
|
|
#include "mfem.hpp"
|
|
#include <fstream>
|
|
#include <iostream>
|
|
#include "ParDST/ParDST.hpp"
|
|
#include "common/PML.hpp"
|
|
|
|
using namespace std;
|
|
using namespace mfem;
|
|
|
|
void source_re(const Vector &x, Vector & f);
|
|
void source_im(const Vector &x, Vector & f);
|
|
void exact_re(const Vector & x, Vector & E);
|
|
void exact_im(const Vector & x, Vector & E);
|
|
void maxwell_solution(const Vector & x, double E[], double curl2E[]);
|
|
double wavespeed(const Vector &x);
|
|
void Mwavespeed(const Vector & x, DenseMatrix & M);
|
|
|
|
void ess_data_func(const Vector & x, Vector & E);
|
|
|
|
|
|
double mu = 1.0;
|
|
double epsilon = 1.0;
|
|
double omega;
|
|
int dim;
|
|
double length = 1.0;
|
|
double sigma_ = 0.0;
|
|
|
|
Array2D<double> comp_bdr;
|
|
Array2D<double> domain_bdr;
|
|
bool exact_known = false;
|
|
|
|
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);
|
|
const char *mesh_file = "../../data/inline-quad.mesh";
|
|
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;
|
|
int bc_type = 1;
|
|
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(&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(&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(&sigma_, "-sigma", "--damping-coef",
|
|
"Damping coefficient (or sigma).");
|
|
args.AddOption(&bc_type, "-bct", "--bc-type",
|
|
"BC type - 0:Neumann, 1: Dirichlet");
|
|
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();
|
|
|
|
// 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;
|
|
if (nd == 2)
|
|
{
|
|
mesh = new Mesh(nel, nel, Element::QUADRILATERAL, true, length, length, false);
|
|
}
|
|
else
|
|
{
|
|
mesh = new Mesh(nel, nel, nel, Element::HEXAHEDRON, true, length, length, length,false);
|
|
}
|
|
|
|
dim = mesh->Dimension();
|
|
|
|
// 4. Refine the mesh to increase the resolution.
|
|
for (int l = 0; l < ser_ref_levels; l++)
|
|
{
|
|
mesh->UniformRefinement();
|
|
}
|
|
|
|
// 4. Define a parallel mesh by a partitioning of the serial mesh.
|
|
// ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
|
|
int nprocs;
|
|
int nprocsx;
|
|
int nprocsy;
|
|
int nprocsz;
|
|
if (dim == 2)
|
|
{
|
|
nprocs = sqrt(num_procs);
|
|
nprocsx = nprocs;
|
|
nprocsy = nprocs;
|
|
nprocsz = 1;
|
|
}
|
|
else
|
|
{
|
|
nprocs = cbrt(num_procs);
|
|
nprocsx = nprocs;
|
|
nprocsy = nprocs;
|
|
nprocsz = nprocs;
|
|
}
|
|
int nxyz[3] = {nprocsx,nprocsy,nprocsz};
|
|
int * part = mesh->CartesianPartitioning(nxyz);
|
|
// ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD,*mesh,part);
|
|
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD,*mesh);
|
|
delete [] part;
|
|
|
|
|
|
delete mesh;
|
|
|
|
for (int l = 0; l < par_ref_levels; l++)
|
|
{
|
|
pmesh->UniformRefinement();
|
|
}
|
|
|
|
// char vishost[] = "localhost";
|
|
// int visport = 19916;
|
|
// socketstream mesh_sock1(vishost, visport);
|
|
// mesh_sock1.precision(8);
|
|
// mesh_sock1 << "parallel " << num_procs << " " << myid << "\n"
|
|
// << "mesh\n"
|
|
// << *pmesh << "window_title 'Global mesh'" << flush;
|
|
|
|
double hl = GetUniformMeshElementSize(pmesh);
|
|
int nrlayers = 3;
|
|
Array2D<double> lengths(dim,2);
|
|
lengths = hl*nrlayers;
|
|
// lengths[0][1] = 0.0;
|
|
// lengths[1][1] = 0.0;
|
|
// lengths[1][0] = 0.0;
|
|
// lengths[0][0] = 0.0;
|
|
if (exact_known) lengths = 0.0;
|
|
// CartesianPML pml(mesh,lengths);
|
|
CartesianPML pml(pmesh,lengths);
|
|
pml.SetAttributes(pmesh);
|
|
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);
|
|
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
|
|
HYPRE_Int size = fespace->GlobalTrueVSize();
|
|
|
|
if (myid == 0)
|
|
{
|
|
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 (pmesh->bdr_attributes.Size())
|
|
{
|
|
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
|
|
ess_bdr = bc_type;
|
|
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
|
}
|
|
|
|
|
|
Array<int> attr;
|
|
Array<int> attrPML;
|
|
if (pmesh->attributes.Size())
|
|
{
|
|
attr.SetSize(pmesh->attributes.Max());
|
|
attrPML.SetSize(pmesh->attributes.Max());
|
|
attr = 0; attr[0] = 1;
|
|
attrPML = 0;
|
|
if (pmesh->attributes.Max() > 1)
|
|
{
|
|
attrPML[1] = 1;
|
|
}
|
|
}
|
|
|
|
// 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);
|
|
ParComplexLinearForm 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.
|
|
ParComplexGridFunction x(fespace);
|
|
x = 0.0;
|
|
// VectorFunctionCoefficient done(dim,ess_data_func);
|
|
// x.ProjectCoefficient(done,done);
|
|
VectorFunctionCoefficient E_re(dim,exact_re);
|
|
VectorFunctionCoefficient E_im(dim,exact_re);
|
|
if (exact_known)
|
|
{
|
|
x.ProjectCoefficient(E_re,E_re);
|
|
}
|
|
// 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);
|
|
|
|
// MatrixFunctionCoefficient Mws(dim,Mwavespeed);
|
|
|
|
// DenseMatrix M(dim); M = 0.0;
|
|
// M(0,0) = -pow(omega, 2);
|
|
// M(1,1) = -pow(omega, 2);
|
|
// M(2,2) = -pow(omega, 2);
|
|
// MatrixConstantCoefficient Momeg(M);
|
|
MatrixFunctionCoefficient eps_func(dim,Mwavespeed);
|
|
|
|
ConstantCoefficient muinv(1.0/mu);
|
|
ConstantCoefficient omeg(-pow(omega, 2) * epsilon);
|
|
ConstantCoefficient lossCoef(-omega * sigma_);
|
|
RestrictedCoefficient restr_loss(lossCoef,attr);
|
|
RestrictedCoefficient restr_muinv(muinv,attr);
|
|
RestrictedCoefficient restr_omeg(omeg,attr);
|
|
|
|
// Integrators inside the computational domain (excluding the PML region)
|
|
ParSesquilinearForm a(fespace, conv);
|
|
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_muinv),NULL);
|
|
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
|
a.AddDomainIntegrator(NULL, new VectorFEMassIntegrator(lossCoef));
|
|
// a.AddDomainIntegrator(NULL, new VectorFEMassIntegrator(restr_loss));
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
// MatrixMatrixProductCoefficient c2_Re(c2_Re0,eps_func);
|
|
// MatrixMatrixProductCoefficient c2_Im(c2_Im0,eps_func);
|
|
|
|
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);
|
|
ScalarMatrixProductCoefficient c1_Re(muinv,pml_c1_Re);
|
|
ScalarMatrixProductCoefficient c1_Im(muinv,pml_c1_Im);
|
|
|
|
MatrixRestrictedCoefficient restr_c1_Re(c1_Re,attrPML);
|
|
MatrixRestrictedCoefficient restr_c1_Im(c1_Im,attrPML);
|
|
|
|
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);
|
|
MatrixRestrictedCoefficient restr_c2_Re(c2_Re,attrPML);
|
|
MatrixRestrictedCoefficient restr_c2_Im(c2_Im,attrPML);
|
|
|
|
// Integrators inside the PML region
|
|
a.AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
|
new CurlCurlIntegrator(restr_c1_Im));
|
|
a.AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re),
|
|
new VectorFEMassIntegrator(restr_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();
|
|
|
|
ParDST::BCType bct = (bc_type == 1)? ParDST::BCType::DIRICHLET : ParDST::BCType::NEUMANN;
|
|
ParDST * S = new ParDST(&a,lengths, omega, &ws, nrlayers, nx, ny, nz, bct, &lossCoef);
|
|
chrono.Stop();
|
|
double t1 = chrono.RealTime();
|
|
|
|
chrono.Clear();
|
|
chrono.Start();
|
|
// X = 0.0;
|
|
GMRESSolver gmres(MPI_COMM_WORLD);
|
|
// gmres.iterative_mode = true;
|
|
gmres.SetPreconditioner(*S);
|
|
gmres.SetOperator(*Ac);
|
|
gmres.SetRelTol(1e-8);
|
|
gmres.SetMaxIter(100);
|
|
gmres.SetPrintLevel(1);
|
|
gmres.Mult(B, X);
|
|
delete S;
|
|
chrono.Stop();
|
|
double t2 = chrono.RealTime();
|
|
|
|
MPI_Barrier(MPI_COMM_WORLD);
|
|
|
|
|
|
cout << " myid: " << myid
|
|
<< ", setup time: " << t1
|
|
<< ", solution time: " << t2 << endl;
|
|
|
|
// {
|
|
// HypreParMatrix *A = Ah.As<ComplexHypreParMatrix>()->GetSystemMatrix();
|
|
// SuperLURowLocMatrix SA(*A);
|
|
// SuperLUSolver superlu(MPI_COMM_WORLD);
|
|
// superlu.SetPrintStatistics(false);
|
|
// superlu.SetSymmetricPattern(false);
|
|
// superlu.SetColumnPermutation(superlu::PARMETIS);
|
|
// superlu.SetOperator(SA);
|
|
// superlu.Mult(B, X);
|
|
// delete A;
|
|
// }
|
|
|
|
a.RecoverFEMSolution(X, b, x);
|
|
|
|
|
|
if (visualization)
|
|
{
|
|
char vishost[] = "localhost";
|
|
int visport = 19916;
|
|
string keys;
|
|
if (dim ==2 )
|
|
{
|
|
keys = "keys mrRljcUUuuu\n";
|
|
}
|
|
else
|
|
{
|
|
keys = "keys mc\n";
|
|
}
|
|
// socketstream mesh_sock(vishost, visport);
|
|
// mesh_sock.precision(8);
|
|
// mesh_sock << "parallel " << num_procs << " " << myid << "\n"
|
|
// << "mesh\n" << *pmesh << flush;
|
|
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 source_re(const Vector &x, Vector &f)
|
|
{
|
|
f = 0.0;
|
|
if (exact_known)
|
|
{
|
|
double E[3], curl2E[3];
|
|
maxwell_solution(x, E, curl2E);
|
|
// curl ( curl E) +/- omega^2 E = f
|
|
double coeff = -omega * omega;
|
|
f(0) = curl2E[0] + coeff * E[0];
|
|
f(1) = curl2E[1] + coeff * E[1];
|
|
if (dim == 2)
|
|
{
|
|
if (x.Size() == 3) {f(2)=0.0;}
|
|
}
|
|
else
|
|
{
|
|
f(2) = curl2E[2] + coeff * E[2];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int nrsources = (dim == 2) ? 4 : 8;
|
|
Vector x0(nrsources);
|
|
Vector y0(nrsources);
|
|
Vector z0(nrsources);
|
|
x0(0) = 0.25; y0(0) = 0.25; z0(0) = 0.25;
|
|
x0(1) = 0.75; y0(1) = 0.25; z0(1) = 0.25;
|
|
x0(2) = 0.25; y0(2) = 0.75; z0(2) = 0.25;
|
|
x0(3) = 0.75; y0(3) = 0.75; z0(3) = 0.25;
|
|
if (dim == 3)
|
|
{
|
|
x0(4) = 0.25; y0(4) = 0.25; z0(4) = 0.75;
|
|
x0(5) = 0.75; y0(5) = 0.25; z0(5) = 0.75;
|
|
x0(6) = 0.25; y0(6) = 0.75; z0(6) = 0.75;
|
|
x0(7) = 0.75; y0(7) = 0.75; z0(7) = 0.75;
|
|
}
|
|
|
|
double n = 4.0*omega/M_PI;
|
|
double coeff = 16.0*omega*omega/M_PI/M_PI/M_PI;
|
|
|
|
// for (int i = 0; i<nrsources; i++)
|
|
x0(0) = 0.5; y0(0) = 0.5;
|
|
for (int i = 0; i<1; i++)
|
|
{
|
|
double beta = pow(x0(i)-x(0),2) + pow(y0(i)-x(1),2);
|
|
if (dim == 3) { beta += pow(z0(i)-x(2),2); }
|
|
double 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;
|
|
}
|
|
|
|
void Mwavespeed(const Vector & x, DenseMatrix & M)
|
|
{
|
|
M = 0.0;
|
|
M(0,0) = 1.0;
|
|
M(1,1) = 1.0;
|
|
// M(2,2) = 4.0*x(0)-1.0;
|
|
if (dim == 3) M(2,2) = 1.0;
|
|
}
|
|
|
|
|
|
void exact_re(const Vector & x, Vector & E)
|
|
{
|
|
double curl2E[3];
|
|
maxwell_solution(x, E, curl2E);
|
|
}
|
|
void exact_im(const Vector & x, Vector & E)
|
|
{
|
|
// double curl2E[3];
|
|
// maxwell_solution(x, E, curl2E);
|
|
E = 0.0;
|
|
}
|
|
void maxwell_solution(const Vector & x, double E[], double curl2E[])
|
|
{
|
|
// point source
|
|
if (dim == 2)
|
|
{
|
|
// shift to avoid singularity
|
|
double x0 = x(0) + 0.1;
|
|
double x1 = x(1) + 0.1;
|
|
//
|
|
double r = sqrt(x0 * x0 + x1 * x1);
|
|
|
|
E[0] = cos(omega * r);
|
|
E[1] = 0.0;
|
|
|
|
double r_x = x0 / r;
|
|
double r_y = x1 / r;
|
|
double r_xy = -(r_x / r) * r_y;
|
|
double r_yx = r_xy;
|
|
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
|
|
|
|
curl2E[0] = omega * ((r_yy ) * sin(omega * r) + (omega * r_y * r_y) * cos(omega * r));
|
|
curl2E[1] = -omega * (r_yx * sin(omega * r) + omega * r_y * r_x * cos(omega * r));
|
|
curl2E[2] = 0.0;
|
|
}
|
|
else
|
|
{
|
|
// shift to avoid singularity
|
|
double x0 = x(0) + 0.1;
|
|
double x1 = x(1) + 0.1;
|
|
double x2 = x(2) + 0.1;
|
|
//
|
|
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
|
|
|
|
E[0] = cos(omega * r);
|
|
E[1] = 0.0;
|
|
E[2] = 0.0;
|
|
|
|
double r_x = x0 / r;
|
|
double r_y = x1 / r;
|
|
double r_z = x2 / r;
|
|
double r_xy = -(r_x / r) * r_y;
|
|
double r_xz = -(r_x / r) * r_z;
|
|
double r_yx = r_xy;
|
|
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
|
|
double r_zx = r_xz;
|
|
double r_zz = (1.0 / r) * (1.0 - r_z * r_z);
|
|
|
|
curl2E[0] = omega * ((r_yy + r_zz) * sin(omega * r) +
|
|
(omega * r_y * r_y + omega * r_z * r_z) * cos(omega * r));
|
|
curl2E[1] = -omega * (r_yx * sin(omega * r) + omega * r_y * r_x * cos(omega * r));
|
|
curl2E[2] = -omega * (r_zx * sin(omega * r) + omega * r_z * r_x * cos(omega * r));
|
|
}
|
|
}
|
|
|
|
|
|
void ess_data_func(const Vector & x, Vector & E)
|
|
{
|
|
E = 0.0;
|
|
// if (x(0)==0.0) E[0] = sin(x(0)+x(1));
|
|
if (x(1)==0.0) E[0] = sin(x(0)+x(1));
|
|
|
|
|
|
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) E = 0.0;
|
|
|
|
}
|