Files
mfem/miniapps/dpg/util/pml.cpp
T

295 lines
7.8 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.
#include "pml.hpp"
namespace mfem
{
CartesianPML::CartesianPML(Mesh *mesh_, const Array2D<real_t> &length_)
: mesh(mesh_), length(length_)
{
dim = mesh->Dimension();
SetBoundaries();
}
void CartesianPML::SetBoundaries()
{
comp_dom_bdr.SetSize(dim, 2);
dom_bdr.SetSize(dim, 2);
// initialize
for (int i = 0; i < dim; i++)
{
dom_bdr(i, 0) = infinity();
dom_bdr(i, 1) = -infinity();
}
for (int i = 0; i < mesh->GetNBE(); i++)
{
Array<int> bdr_vertices;
mesh->GetBdrElementVertices(i, bdr_vertices);
for (int j = 0; j < bdr_vertices.Size(); j++)
{
for (int k = 0; k < dim; k++)
{
dom_bdr(k, 0) = std::min(dom_bdr(k, 0), mesh->GetVertex(bdr_vertices[j])[k]);
dom_bdr(k, 1) = std::max(dom_bdr(k, 1), mesh->GetVertex(bdr_vertices[j])[k]);
}
}
}
#ifdef MFEM_USE_MPI
ParMesh * pmesh = dynamic_cast<ParMesh *>(mesh);
if (pmesh)
{
for (int d=0; d<dim; d++)
{
MPI_Allreduce(MPI_IN_PLACE, &dom_bdr(d,0), 1,
MPITypeMap<real_t>::mpi_type, MPI_MIN,pmesh->GetComm());
MPI_Allreduce(MPI_IN_PLACE, &dom_bdr(d,1), 1,
MPITypeMap<real_t>::mpi_type, MPI_MAX, pmesh->GetComm());
}
}
#endif
for (int i = 0; i < dim; i++)
{
comp_dom_bdr(i, 0) = dom_bdr(i, 0) + length(i, 0);
comp_dom_bdr(i, 1) = dom_bdr(i, 1) - length(i, 1);
}
}
void CartesianPML::SetAttributes(Mesh *mesh_, Array<int> * attrNonPML,
Array<int> * attrPML)
{
int nrelem = mesh_->GetNE();
elems.SetSize(nrelem);
for (int i = 0; i < nrelem; ++i)
{
elems[i] = 1;
bool in_pml = false;
Element *el = mesh_->GetElement(i);
Array<int> vertices;
// Initialize Attribute
el->SetAttribute(1);
el->GetVertices(vertices);
int nrvert = vertices.Size();
// Check if any vertex is in the pml
for (int iv = 0; iv < nrvert; ++iv)
{
int vert_idx = vertices[iv];
real_t *coords = mesh_->GetVertex(vert_idx);
for (int comp = 0; comp < dim; ++comp)
{
if (coords[comp] > comp_dom_bdr(comp, 1) ||
coords[comp] < comp_dom_bdr(comp, 0))
{
in_pml = true;
break;
}
}
}
if (in_pml)
{
elems[i] = 0;
el->SetAttribute(2);
}
}
mesh_->SetAttributes();
if (mesh_->attributes.Size())
{
if (attrNonPML)
{
attrNonPML->SetSize(mesh_->attributes.Max());
*attrNonPML = 0; (*attrNonPML)[0] = 1;
}
if (attrPML)
{
attrPML->SetSize(mesh_->attributes.Max());
*attrPML = 0;
if (mesh_->attributes.Max()>1)
{
(*attrPML)[1]=1;
}
}
}
}
void CartesianPML::StretchFunction(const Vector &x,
std::vector<std::complex<real_t>> &dxs)
{
std::complex<real_t> zi = std::complex<real_t>(0., 1.);
real_t n = 2.0;
real_t c = 5.0;
real_t coeff;
real_t k = omega * sqrt(epsilon * mu);
// Stretch in each direction independently
for (int i = 0; i < dim; ++i)
{
dxs[i] = 1.0;
if (x(i) >= comp_dom_bdr(i, 1))
{
coeff = n * c / k / pow(length(i, 1), n);
dxs[i] = real_t(1.0) + zi * real_t(coeff * std::abs(pow(x(i) - comp_dom_bdr(i,
1), n - 1.0)));
}
if (x(i) <= comp_dom_bdr(i, 0))
{
coeff = n * c / k / pow(length(i, 0), n);
dxs[i] = real_t(1.0) + zi * real_t(coeff * std::abs(pow(x(i) - comp_dom_bdr(i,
0), n - 1.0)));
}
}
}
// acoustics UW PML coefficients functions
// |J|
real_t detJ_r_function(const Vector & x, CartesianPML * pml)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det(1.0,0.0);
pml->StretchFunction(x, dxs);
for (int i=0; i<dim; ++i) { det *= dxs[i]; }
return det.real();
}
real_t detJ_i_function(const Vector & x, CartesianPML * pml)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det(1.0,0.0);
pml->StretchFunction(x, dxs);
for (int i=0; i<dim; ++i) { det *= dxs[i]; }
return det.imag();
}
real_t abs_detJ_2_function(const Vector & x, CartesianPML * pml)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det(1.0,0.0);
pml->StretchFunction(x, dxs);
for (int i=0; i<dim; ++i) { det *= dxs[i]; }
return det.imag()*det.imag() + det.real()*det.real();
}
// J^T J / |J|
void Jt_J_detJinv_r_function(const Vector & x, CartesianPML * pml,
DenseMatrix & M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det(1.0,0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i<dim; ++i) { det *= dxs[i]; }
M=0.0;
for (int i = 0; i<dim; ++i)
{
M(i,i) = (pow(dxs[i], real_t(2))/det).real();
}
}
void Jt_J_detJinv_i_function(const Vector & x, CartesianPML * pml,
DenseMatrix & M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i<dim; ++i) { det *= dxs[i]; }
M=0.0;
for (int i = 0; i<dim; ++i)
{
M(i,i) = (pow(dxs[i], real_t(2))/det).imag();
}
}
void abs_Jt_J_detJinv_2_function(const Vector & x, CartesianPML * pml,
DenseMatrix & M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i<dim; ++i) { det *= dxs[i]; }
M=0.0;
for (int i = 0; i<dim; ++i)
{
std::complex<real_t> a = pow(dxs[i], real_t(2))/det;
M(i,i) = a.imag() * a.imag() + a.real() * a.real();
}
}
// Maxwell PML coefficients
void detJ_Jt_J_inv_r_function(const Vector &x, CartesianPML * pml,
DenseMatrix &M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det(1.0, 0.0);
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i) { det *= dxs[i]; }
M = 0.0;
for (int i = 0; i < dim; ++i)
{
M(i, i) = (det / pow(dxs[i], real_t(2))).real();
}
}
void detJ_Jt_J_inv_i_function(const Vector &x, CartesianPML * pml,
DenseMatrix &M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i) { det *= dxs[i]; }
M = 0.0;
for (int i = 0; i < dim; ++i)
{
M(i, i) = (det / pow(dxs[i], real_t(2))).imag();
}
}
void abs_detJ_Jt_J_inv_2_function(const Vector &x, CartesianPML * pml,
DenseMatrix &M)
{
int dim = pml->dim;
std::vector<std::complex<real_t>> dxs(dim);
std::complex<real_t> det = 1.0;
pml->StretchFunction(x, dxs);
for (int i = 0; i < dim; ++i) { det *= dxs[i]; }
M = 0.0;
for (int i = 0; i < dim; ++i)
{
std::complex<real_t> a = det / pow(dxs[i], real_t(2));
M(i, i) = a.real()*a.real() + a.imag()*a.imag();
}
}
} // namespace mfem