Files
mfem/examples/solvers-dev/helmholtzp.cpp
T

825 lines
23 KiB
C++

//
// Compile with: make helmholtz
//
// Sample runs: helmholtz -m ../data/one-hex.mesh
// helmholtz -m ../data/fichera.mesh
// helmholtz -m ../data/fichera-mixed.mesh
//
// Description: This example code demonstrates the use of MFEM to define a
// simple finite element discretization of the Helmholtz problem
// -Delta p - omega^2 p = 1 with impedance boundary conditiones.
//
#include "mfem.hpp"
#include <fstream>
#include <iostream>
using namespace std;
using namespace mfem;
// Exact solution and r.h.s., see below for implementation.
void get_helmholtz_solution_Re(const Vector &x, double & p, double dp[], double & d2p);
void get_helmholtz_solution_Im(const Vector &x, double & p, double dp[], double & d2p);
double p_exact_Re(const Vector &x);
double p_exact_Im(const Vector &x);
double f_exact_Re(const Vector &x);
double f_exact_Im(const Vector &x);
double g_exact_Re(const Vector &x);
double g_exact_Im(const Vector &x);
void grad_exact_Re(const Vector &x, Vector &grad_Re);
void grad_exact_Im(const Vector &x, Vector &grad_Im);
// pml
void pml_function(const Vector &x, std::vector<std::complex<double>> & dxs);
double pml_detJ_Re(const Vector &x);
double pml_detJ_Im(const Vector &x);
void pml_detJ_JT_J_inv_Re(const Vector &x, DenseMatrix &M);
void pml_detJ_JT_J_inv_Im(const Vector &x, DenseMatrix &M);
int dim;
double omega;
int sol = 1;
bool pml = false;
double length = 1.0;
double pml_length = 0.25;
bool scatter = false;
#ifndef MFEM_USE_PETSC
#error This example requires that MFEM is built with MFEM_USE_PETSC=YES
#endif
int main(int argc, char *argv[])
{
// 1. Initialise MPI
int num_procs, myid;
MPI_Init(&argc, &argv); // Initialise MPI
MPI_Comm_size(MPI_COMM_WORLD, &num_procs); //total number of processors available
MPI_Comm_rank(MPI_COMM_WORLD, &myid); // Determine process identifier
//-----------------------------------------------------------------------------
// 2. Parse command-line options.
// geometry file
const char *mesh_file = "../../data/one-hex.mesh";
// finite element order of approximation
int order = 1;
// static condensation flag
bool static_cond = false;
bool visualization = 1;
// number of wavelengths
double k = 0.5;
// number of mg levels
int ref = 1;
// number of initial ref
int initref = 1;
// dimension
int nd = 2;
// PETSC
// const char *petscrc_file = "";
const char *petscrc_file = "petscrc_mult_options";
// optional command line inputs
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use.");
args.AddOption(&order, "-o", "--order",
"Finite element order (polynomial degree) or -1 for"
" isoparametric space.");
args.AddOption(&nd, "-nd", "--dim","Problem space dimension");
args.AddOption(&sol, "-sol", "--exact",
"Exact solution flag - 0:polynomial, 1: plane wave, -1: unknown exact");
args.AddOption(&k, "-k", "--wavelengths",
"Number of wavelengths.");
args.AddOption(&pml, "-pml", "--pml", "-no-pml",
"--no-pml", "Enable PML.");
args.AddOption(&pml_length, "-pml_length", "--pml_length",
"Length of the PML region in each direction");
args.AddOption(&length, "-length", "--length",
"length of the domainin in each direction.");
args.AddOption(&ref, "-ref", "--ref",
"Number of Refinements.");
args.AddOption(&initref, "-initref", "--initref",
"Number of initial refinements.");
args.AddOption(&petscrc_file, "-petscopts", "--petscopts",
"PetscOptions file to use.");
args.AddOption(&static_cond, "-sc", "--static-condensation", "-no-sc",
"--no-static-condensation", "Enable static condensation.");
args.AddOption(&scatter, "-scat", "--scattering-prob", "-no-scat",
"--no-scattering", "Solve a scattering problem");
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 * k;
// omega = k;
// 2b. Initialize PETSc
MFEMInitializePetsc(NULL, NULL, petscrc_file, NULL);
//-----------------------------------------------------------------------------
// if (scatter) pml = true; // for now only scattering problems with pml
// 3. Read the mesh from the given mesh file.
Mesh *mesh;
if (nd == 2)
{
if (scatter)
{
mesh_file = "../../data/rectwhole7_2attr.e";
mesh = new Mesh(mesh_file, 1, 1);
}
else
{
mesh = new Mesh(1, 1, Element::QUADRILATERAL, true, length, length, false);
}
}
else
{
if (scatter)
{
// mesh_file = "../../data/hexwhole7.e";
// mesh_file = "../../data/hexwhole.e";
// mesh_file = "../../data/hexa728.mesh";
// mesh_file = "./hexa728.mesh";
mesh_file = "../../data/hexwhole7.e";
mesh = new Mesh(mesh_file, 1, 1);
}
else
{
mesh = new Mesh(1, 1, 1, Element::HEXAHEDRON, true, length, length, length, false);
}
}
// normalize mesh
mesh->EnsureNodes();
GridFunction * nodes = mesh->GetNodes();
// Assuming square/cubic domain
double min_coord = nodes->Min();
double max_coord = nodes->Max();
double domain_length = abs(max_coord-min_coord);
// shift to zero
*nodes -= min_coord;
// scale to one
*nodes *= 1./domain_length;
dim = mesh->Dimension();
int sdim = mesh->SpaceDimension();
// 3. Executing uniform h-refinement
for (int i = 0; i < initref; i++ )
{
mesh->UniformRefinement();
}
// 5. Define a parallel mesh and delete the serial mesh.
ParMesh *pmesh = new ParMesh(MPI_COMM_WORLD, *mesh);
delete mesh;
// ----------------------------------------------------------------------------
// 6. Define a finite element space on the mesh.
FiniteElementCollection *fec = new H1_FECollection(order, dim);
ParFiniteElementSpace *fespace = new ParFiniteElementSpace(pmesh, fec);
std::vector<HypreParMatrix*> P(ref);
for (int i = 0; i < ref; i++)
{
const ParFiniteElementSpace cfespace(*fespace);
pmesh->UniformRefinement();
fespace->Update();
OperatorHandle Tr(Operator::Hypre_ParCSR);
fespace->GetTrueTransferOperator(cfespace, Tr);
HypreParMatrix * Paux;
Tr.Get(Paux);
P[i] = new HypreParMatrix(*Paux);
}
// 6. Set up the linear form (Real and Imaginary part)
FunctionCoefficient f_Re(f_exact_Re);
FunctionCoefficient g_Re(g_exact_Re);
VectorFunctionCoefficient grad_Re(sdim, grad_exact_Re);
FunctionCoefficient f_Im(f_exact_Im);
FunctionCoefficient g_Im(g_exact_Im);
VectorFunctionCoefficient grad_Im(sdim, grad_exact_Im);
// ParLinearForm *b_Re(new ParLinearForm);
ParComplexLinearForm b(fespace, ComplexOperator::HERMITIAN);
if (!scatter) // if scattering problem the source is zero and is driven by bc
{
b.AddDomainIntegrator(new DomainLFIntegrator(f_Re),new DomainLFIntegrator(f_Im));
if (!pml && sol >=0) // if exact solution exists. Otherwise use homogeneous impedence (gradp . n + i omega p = 0)
{
b.AddBoundaryIntegrator(new BoundaryNormalLFIntegrator(grad_Re),
new BoundaryNormalLFIntegrator(grad_Im));
b.AddBoundaryIntegrator(new BoundaryLFIntegrator(g_Re),
new BoundaryLFIntegrator(g_Im));
}
}
b.real().Vector::operator=(0.0);
b.imag().Vector::operator=(0.0);
b.Assemble();
// 7. Set up the bilinear form (Real and Imaginary part)
ConstantCoefficient one(1.0);
ConstantCoefficient sigma(-pow(omega, 2));
ParSesquilinearForm a(fespace,ComplexOperator::HERMITIAN);
ConstantCoefficient impedance(omega);
MatrixFunctionCoefficient c1_Re(dim,pml_detJ_JT_J_inv_Re);
MatrixFunctionCoefficient c1_Im(dim,pml_detJ_JT_J_inv_Im);
FunctionCoefficient det_Re(pml_detJ_Re);
FunctionCoefficient det_Im(pml_detJ_Im);
ProductCoefficient c2_Re(det_Re,sigma);
ProductCoefficient c2_Im(det_Im,sigma);
Array<int> bdr_attr(pmesh->bdr_attributes.Max());
bdr_attr = 0;
bdr_attr[0] = 1;
if (!scatter) bdr_attr = 1;
RestrictedCoefficient imp_rest(impedance,bdr_attr);
a.AddDomainIntegrator(new DiffusionIntegrator(c1_Re),new DiffusionIntegrator(c1_Im));
a.AddDomainIntegrator(new MassIntegrator(c2_Re),new MassIntegrator(c2_Im));
if (!pml)
{
a.AddBoundaryIntegrator(NULL,new BoundaryMassIntegrator(imp_rest));
// a.AddBoundaryIntegrator(NULL,new BoundaryMassIntegrator(impedance));
}
a.Assemble();
a.Finalize();
Array<int> ess_tdof_list;
Array<int> ess_bdr(pmesh->bdr_attributes.Max());
ess_bdr = 0;
if (scatter)
{
if (pml)
{
ess_bdr = 1;
}
else
{
ess_bdr[1] = 1;
}
}
fespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
// Solution grid function
ParComplexGridFunction p_gf(fespace);
ParComplexGridFunction p_gf_ex(fespace);
FunctionCoefficient p_Re(p_exact_Re);
FunctionCoefficient p_Im(p_exact_Im);
p_gf = 0.0;
p_gf_ex.ProjectCoefficient(p_Re,p_Im);
if (!pml && sol >= 0 )
{
p_gf.ProjectBdrCoefficient(p_Re,p_Im,ess_bdr);
}
if (scatter)
{
p_gf.ProjectBdrCoefficient(p_Re,p_Im,ess_bdr);
}
OperatorHandle Ah;
Vector X, B;
a.FormLinearSystem(ess_tdof_list, p_gf, b, Ah, X, B);
ComplexHypreParMatrix * AZ = Ah.As<ComplexHypreParMatrix>();
HypreParMatrix * A = AZ->GetSystemMatrix();
if (myid == 0)
{
cout << "Size of fine grid system: "
<< A->GetGlobalNumRows() << " x " << A->GetGlobalNumCols() << endl;
}
PetscLinearSolver * petsc = new PetscLinearSolver(MPI_COMM_WORLD, "direct");
// Convert to PetscParMatrix
petsc->SetOperator(PetscParMatrix(A, Operator::PETSC_MATAIJ));
petsc->Mult(B,X);
a.RecoverFEMSolution(X,B,p_gf);
if (!scatter && sol >= 0 )
{
// int order_quad = max(2, 2*order+1);
// const IntegrationRule *irs[Geometry::NumGeom];
// for (int i=0; i < Geometry::NumGeom; ++i)
// {
// irs[i] = &(IntRules.Get(i, order_quad));
// }
const int h1_norm_type = 1;
double L2error;
double H1error;
double L2err_Re = p_gf.real().ComputeL2Error(p_Re);
double L2err_Im = p_gf.imag().ComputeL2Error(p_Im);
double loc_H1err_Re = p_gf.real().ComputeH1Error(&p_Re, &grad_Re, &one, 1.0, h1_norm_type);
double loc_H1err_Im = p_gf.imag().ComputeH1Error(&p_Im, &grad_Im, &one, 1.0, h1_norm_type);
double H1err_Re = GlobalLpNorm(2.0, loc_H1err_Re, MPI_COMM_WORLD);
double H1err_Im = GlobalLpNorm(2.0, loc_H1err_Im, MPI_COMM_WORLD);
// double norm_Re = ComputeGlobalLpNorm(2, p_Re, *pmesh, irs);
// double norm_Im = ComputeGlobalLpNorm(2, p_Im, *pmesh, irs);
L2error = sqrt(L2err_Re*L2err_Re + L2err_Im*L2err_Im);
H1error = sqrt(H1err_Re*H1err_Re + H1err_Im*H1err_Im);
// double L2norm = sqrt(norm_Re*norm_Re + norm_Im*norm_Im);
if (myid == 0)
{
cout << " || p_h - p ||_{H^1} = " << H1error << endl;
cout << " || p_h - p ||_{L^2} = " << L2error << endl;
}
}
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
string keys;
if(dim ==2 )
{
keys = "keys mrRljc\n";
}
else
{
keys = "keys mc\n";
}
socketstream sol_sock_re(vishost, visport);
sol_sock_re << "parallel " << num_procs << " " << myid << "\n";
sol_sock_re.precision(8);
sol_sock_re << "solution\n" << *pmesh << p_gf.real() << "window_title 'Numerical Pressure (real part)' "
<< keys << flush;
}
delete fespace;
delete fec;
delete pmesh;
MFEMFinalizePetsc();
MPI_Finalize();
return 0;
}
//define exact solutions
void get_helmholtz_solution_Re(const Vector &x, double & p, double dp[], double & d2p)
{
if (sol == 0) // polynomial
{
if (dim == 3)
{
p = x[0]*(1.0 - x[0]) * x[1]*(1.0 - x[1]) * x[2]*(1.0 - x[2]);
dp[0] = (1.0 - 2.0 *x[0]) * x[1]*(1.0 - x[1]) * x[2]*(1.0 - x[2]);
dp[1] = (1.0 - 2.0 *x[1]) * x[0]*(1.0 - x[0]) * x[2]*(1.0 - x[2]);
dp[2] = (1.0 - 2.0 *x[2]) * x[0]*(1.0 - x[0]) * x[1]*(1.0 - x[1]);
d2p = -2.0*(-1.0 + x[0]) * x[0] * (-1.0 + x[1]) * x[1]
-2.0*(-1.0 + x[0]) * x[0] * (-1.0 + x[2]) * x[2]
-2.0*(-1.0 + x[1]) * x[1] * (-1.0 + x[2]) * x[2];
}
else
{
p = x[1] * (1.0 - x[1])* x[0] * (1.0 - x[0]);
dp[0] = (1.0 - 2.0 *x[0]) * x[1]*(1.0 - x[1]);
dp[1] = (1.0 - 2.0 *x[1]) * x[0]*(1.0 - x[0]);
d2p = - 2.0 * x[1] * (1.0 - x[1])
- 2.0 * x[0] * (1.0 - x[0]);
}
}
else if(sol == 1) // Plane wave
{
double alpha;
if (dim == 2)
{
alpha = omega/sqrt(2);
p = cos(alpha * ( x(0) + x(1) ) );
dp[0] = -alpha * sin(alpha * ( x(0) + x(1) ) );
dp[1] = dp[0];
d2p = -2.0 * alpha * alpha * p;
}
else
{
alpha = omega/sqrt(3);
p = cos(alpha * ( x(0) + x(1) + x(2) ) );
dp[0] = -alpha * sin(alpha * ( x(0) + x(1) + x(2) ) );
dp[1] = dp[0];
dp[2] = dp[0];
d2p = -3.0 * alpha * alpha * p;
}
}
else if (sol == 2)
{
if (dim == 2 )
{
// shift to avoid singularity
double shift = 0.1;
if (scatter) shift = -0.5;
double x0 = x(0) + shift;
double x1 = x(1) + shift;
//
double r = sqrt(x0 * x0 + x1 * x1);
p = cos(omega * r);
double r_x = x0 / r;
double r_y = x1 / r;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
dp[0] = - omega * sin(omega * r) * r_x;
dp[1] = - omega * sin(omega * r) * r_y;
d2p = -omega*omega * cos(omega * r)*r_x * r_x - omega * sin(omega*r) * r_xx
-omega*omega * cos(omega * r)*r_y * r_y - omega * sin(omega*r) * r_yy;
}
else
{
// shift to avoid singularity
double shift = 0.1;
if (scatter) shift = -0.5;
double x0 = x(0) + shift;
double x1 = x(1) + shift;
double x2 = x(2) + shift;
//
double r = sqrt(x0 * x0 + x1 * x1 + x2 * x2);
p = cos(omega * r);
double r_x = x0 / r;
double r_y = x1 / r;
double r_z = x2 / r;
double r_xx = (1.0 / r) * (1.0 - r_x * r_x);
double r_yy = (1.0 / r) * (1.0 - r_y * r_y);
double r_zz = (1.0 / r) * (1.0 - r_z * r_z);
dp[0] = - omega * sin(omega * r) * r_x;
dp[1] = - omega * sin(omega * r) * r_y;
dp[2] = - omega * sin(omega * r) * r_z;
d2p = -omega*omega * cos(omega * r)*r_x * r_x - omega * sin(omega*r) * r_xx
-omega*omega * cos(omega * r)*r_y * r_y - omega * sin(omega*r) * r_yy
-omega*omega * cos(omega * r)*r_z * r_z - omega * sin(omega*r) * r_zz;
}
}
}
void get_helmholtz_solution_Im(const Vector &x, double & p, double dp[], double & d2p)
{
if (sol == 0) // polynomial
{
if (dim == 3)
{
p = x[0]*(1.0 - x[0]) * x[1]*(1.0 - x[1]) * x[2]*(1.0 - x[2]);
dp[0] = (1.0 - 2.0 *x[0]) * x[1]*(1.0 - x[1]) * x[2]*(1.0 - x[2]);
dp[1] = (1.0 - 2.0 *x[1]) * x[0]*(1.0 - x[0]) * x[2]*(1.0 - x[2]);
dp[2] = (1.0 - 2.0 *x[2]) * x[0]*(1.0 - x[0]) * x[1]*(1.0 - x[1]);
d2p = -2.0*(-1.0 + x[0]) * x[0] * (-1.0 + x[1]) * x[1]
-2.0*(-1.0 + x[0]) * x[0] * (-1.0 + x[2]) * x[2]
-2.0*(-1.0 + x[1]) * x[1] * (-1.0 + x[2]) * x[2];
}
else
{
p = x[1] * (1.0 - x[1])* x[0] * (1.0 - x[0]);
dp[0] = (1.0 - 2.0 *x[0]) * x[1]*(1.0 - x[1]);
dp[1] = (1.0 - 2.0 *x[1]) * x[0]*(1.0 - x[0]);
d2p = - 2.0 * x[1] * (1.0 - x[1])
- 2.0 * x[0] * (1.0 - x[0]);
}
}
else if (sol == 1)// plane wave
{
double alpha;
if (dim == 2)
{
alpha = omega/sqrt(2);
p = -sin(alpha * ( x(0) + x(1) ) );
dp[0] = -alpha * cos(alpha * ( x(0) + x(1) ) );
dp[1] = dp[0];
d2p = -2.0 * alpha * alpha * p;
}
else
{
alpha = omega/sqrt(3);
p = -sin(alpha * ( x(0) + x(1) + x(2) ) );
dp[0] = -alpha * cos(alpha * ( x(0) + x(1) + x(2) ) );
dp[1] = dp[0];
dp[2] = dp[0];
d2p = -3.0 * alpha * alpha * p;
}
}
}
double p_exact_Re(const Vector &x)
{
double p, d2p;
double dp[3];
get_helmholtz_solution_Re(x, p, dp, d2p);
if (scatter)
{
if (dim == 2)
{
if (abs(x(0)-1.) < 1e-13 || abs(x(1)-1.0) < 1e-13 ||
abs(x(0)) < 1e-13 || abs(x(1)) < 1e-13)
{
p = 0.0;
}
}
else
{
if (abs(x(0)-1.) < 1e-13 || abs(x(1)-1.0) < 1e-13 || abs(x(2)-1.0) < 1e-13 ||
abs(x(0)) < 1e-13 || abs(x(1)) < 1e-13 || abs(x(2)) < 1e-13)
{
p = 0.0;
}
}
}
return p;
}
double p_exact_Im(const Vector &x)
{
double p, d2p;
double dp[3];
get_helmholtz_solution_Im(x, p, dp, d2p);
if (scatter)
{
if (dim == 2)
{
if (abs(x(0)-1.) < 1e-13 || abs(x(1)-1.0) < 1e-13 ||
abs(x(0)) < 1e-13 || abs(x(1)) < 1e-13)
{
p = 0.0;
}
}
else
{
if (abs(x(0)-1.) < 1e-13 || abs(x(1)-1.0) < 1e-13 || abs(x(2)-1.0) < 1e-13 ||
abs(x(0)) < 1e-13 || abs(x(1)) < 1e-13 || abs(x(2)) < 1e-13)
{
p = 0.0;
}
}
}
// p *= -1.0;
return p;
}
//calculate RHS from exact solution f = - \Delta u
double f_exact_Re(const Vector &x)
{
double p_re, d2p_re, p_im, d2p_im;
double dp_re[3], dp_im[3];
double f_re;
f_re = 0.0;
if (sol < 0)
{
double x0 = length/2.0;
double x1 = length/2.0;
double x2 = length/2.0;
double alpha,beta;
double n = 5.0 * omega/M_PI;
double coeff = pow(n,2)/M_PI;
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_re = coeff*exp(alpha);
}
else
{
get_helmholtz_solution_Re(x, p_re, dp_re, d2p_re);
get_helmholtz_solution_Im(x, p_im, dp_im, d2p_im);
f_re = -d2p_re - omega * omega * p_re;
}
return f_re;
}
double f_exact_Im(const Vector &x)
{
double p_re, d2p_re, p_im, d2p_im;
double dp_re[3], dp_im[3];
double f_im;
f_im = 0.0;
if (sol < 0)
{
// double x0 = 0.6;
// double x1 = 0.6;
// double alpha;
// double n = 5.0 * omega/M_PI;
// double coeff = pow(n,2)/M_PI;
// alpha = -pow(n,2) * sqrt(pow(x0-x(0),2) + pow(x1-x(1),2));
// f_im = coeff*exp(alpha);
}
else
{
get_helmholtz_solution_Re(x, p_re, dp_re, d2p_re);
get_helmholtz_solution_Im(x, p_im, dp_im, d2p_im);
f_im = -d2p_im - omega * omega * p_im;
}
return f_im;
}
void grad_exact_Re(const Vector &x, Vector &dp)
{
double p, d2p;
get_helmholtz_solution_Re(x, p, dp, d2p);
}
void grad_exact_Im(const Vector &x, Vector &dp)
{
double p, d2p;
get_helmholtz_solution_Im(x, p, dp, d2p);
}
//define impedence coefficient: i omega p
double g_exact_Re(const Vector &x)
{
double p, d2p;
double dp[3];
get_helmholtz_solution_Im(x, p, dp, d2p);
return -omega * p;
}
double g_exact_Im(const Vector &x)
{
double p, d2p;
double dp[3];
get_helmholtz_solution_Re(x, p, dp, d2p);
return omega * p;
}
void pml_function(const Vector &x, std::vector<std::complex<double>> & dxs)
{
double L = length;
double n = 2.0;
double lbeg, lend;
double c = 50.0;
double c1 = pml_length;
double c2 = length-pml_length;
double coeff;
// initialize to one
for (int i = 0; i<dim; ++i) dxs[i] = complex<double>(1.0,0.0);
if (pml)
{
// Stretch in each direction independenly
for (int i = 0; i<dim; ++i)
{
if (x(i) >= c2)
{
lbeg = c2;
lend = L;
coeff = n * c / omega / pow(lend-lbeg,n);
dxs[i] = complex<double>(1.0,0.0) - complex<double>(0.0,coeff * pow(x(i)-lbeg, n-1.0));
}
if (x(i) <= c1)
{
lbeg = c1;
lend = 0.0;
coeff = n * c / omega / pow(lend-lbeg,n);
dxs[i] = complex<double>(1.0,0.0) + complex<double>(0.0, coeff * pow(x(i)-lbeg, n-1.0));
}
}
}
}
double pml_detJ_Re(const Vector &x)
{
std::vector<std::complex<double>> dxs(dim);
complex<double> det(1.0,0.0);
pml_function(x, dxs);
for (int i=0; i<dim; ++i) det *= dxs[i];
return det.real();
}
double pml_detJ_Im(const Vector &x)
{
std::vector<std::complex<double>> dxs(dim);
complex<double> det(1.0,0.0);
pml_function(x, dxs);
for (int i=0; i<dim; ++i) det *= dxs[i];
return det.imag();
}
void pml_detJ_JT_J_inv_Re(const Vector &x, DenseMatrix &M)
{
std::vector<complex<double>> diag(dim);
std::vector<std::complex<double>> dxs(dim);
complex<double> det(1.0,0.0);
pml_function(x, dxs);
for (int i = 0; i<dim; ++i)
{
diag[i] = complex<double>(1.0,0.0) / pow(dxs[i],2);
det *= dxs[i];
}
M.SetSize(dim);
M=0.0;
for (int i = 0; i<dim; ++i)
{
complex<double> temp = det * diag[i];
M(i,i) = temp.real();
}
}
void pml_detJ_JT_J_inv_Im(const Vector &x, DenseMatrix &M)
{
std::vector<std::complex<double>> diag(dim);
std::vector<std::complex<double>> dxs(dim);
complex<double> det = 1.0;
pml_function(x, dxs);
for (int i = 0; i<dim; ++i)
{
diag[i] = complex<double>(1.0,0.0) / pow(dxs[i],2);
det *= dxs[i];
}
M.SetSize(dim);
M=0.0;
for (int i = 0; i<dim; ++i)
{
complex<double> temp = det * diag[i];
M(i,i) = temp.imag();
}
}
// int ndofs = nodes->FESpace()->GetNDofs();
// Vector xcoords(ndofs), ycoords(ndofs), zcoords(ndofs);
// for (int comp = 0; comp < nodes->FESpace()->GetVDim(); comp++)
// {
// for (int i = 0; i < ndofs; i++)
// {
// if (comp == 0)
// {
// xcoords(i) = *nodes[nodes->FESpace()->DofToVDof(i, comp)];
// }
// else if (comp == 1)
// {
// ycoords(i) = *nodes[nodes->FESpace()->DofToVDof(i, comp)];
// }
// else if (comp == 2)
// {
// zcoords(i) = *nodes[nodes->FESpace()->DofToVDof(i, comp)];
// }
// }
// }