303 lines
9.6 KiB
C++
303 lines
9.6 KiB
C++
|
|
#include "ToroidST.hpp"
|
|
|
|
|
|
void ToroidST::SetupSubdomainProblems()
|
|
{
|
|
// Sesquilinear forms and Operator
|
|
sqf.SetSize(nrsubdomains);
|
|
Optr.SetSize(nrsubdomains);
|
|
// Subdomain Matrix and its LU factorization
|
|
PmlMat.SetSize(nrsubdomains);
|
|
PmlMatInv.SetSize(nrsubdomains);
|
|
// Right hand sides
|
|
f_orig.SetSize(nrsubdomains);
|
|
forward_transf.SetSize(nrsubdomains);
|
|
backward_transf.SetSize(nrsubdomains);
|
|
|
|
for (int ip=0; ip<nrsubdomains; ip++)
|
|
{
|
|
cout << "Ip = " << ip << endl;
|
|
SetMaxwellPmlSystemMatrix(ip);
|
|
PmlMat[ip] = Optr[ip]->As<ComplexSparseMatrix>();
|
|
// PmlMat[ip]->PrintMatlab(cout);
|
|
PmlMatInv[ip] = new ComplexUMFPackSolver;
|
|
PmlMatInv[ip]->Control[UMFPACK_ORDERING] = UMFPACK_ORDERING_METIS;
|
|
cout << "ComplexUMFPack: size = " << PmlMat[ip]->Height() << endl;
|
|
PmlMatInv[ip]->SetOperator(*PmlMat[ip]);
|
|
int ndofs = fespaces[ip]->GetTrueVSize();
|
|
f_orig[ip] = new Vector(2*ndofs);
|
|
forward_transf[ip] = new Vector(2*ndofs);
|
|
backward_transf[ip] = new Vector(2*ndofs);
|
|
}
|
|
}
|
|
|
|
void ToroidST::SetMaxwellPmlSystemMatrix(int ip)
|
|
{
|
|
Mesh * mesh = fespaces[ip]->GetMesh();
|
|
// Mesh * mesh = fes->GetMesh();
|
|
MFEM_VERIFY(mesh, "Null mesh pointer");
|
|
int dim = mesh->Dimension();
|
|
ToroidPML tpml(mesh);
|
|
Vector zlim, rlim, alim;
|
|
tpml.GetDomainBdrs(zlim,rlim,alim);
|
|
Vector zpml(2); zpml = 0.0;
|
|
Vector rpml(2); rpml = 0.0;
|
|
Vector apml(2); apml = 0.0;
|
|
bool zstretch = false;
|
|
bool astretch = true;
|
|
bool rstretch = false;
|
|
apml = aPmlThickness[1]; // just for this test (toroid waveguide)
|
|
if (ip == 0)
|
|
{
|
|
apml[0] = aPmlThickness[0];
|
|
}
|
|
if (ip == nrsubdomains-1)
|
|
{
|
|
apml[1] = aPmlThickness[1];
|
|
}
|
|
tpml.SetPmlAxes(zstretch,rstretch,astretch);
|
|
tpml.SetPmlWidth(zpml,rpml,apml);
|
|
tpml.SetOmega(omega);
|
|
|
|
|
|
|
|
ComplexOperator::Convention conv = bf->GetConvention();
|
|
tpml.SetAttributes(mesh);
|
|
Array<int> ess_tdof_list;
|
|
Array<int> ess_bdr;
|
|
if (mesh->bdr_attributes.Size())
|
|
{
|
|
ess_bdr.SetSize(mesh->bdr_attributes.Max());
|
|
ess_bdr = 1;
|
|
}
|
|
fespaces[ip]->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
|
// fes->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
|
|
Array<int> attr;
|
|
Array<int> attrPML;
|
|
if (mesh->attributes.Size())
|
|
{
|
|
attr.SetSize(mesh->attributes.Max());
|
|
attrPML.SetSize(mesh->attributes.Max());
|
|
attr = 0; attr[0] = 1;
|
|
attrPML = 0;
|
|
if (mesh->attributes.Max() > 1)
|
|
{
|
|
attrPML[1] = 1;
|
|
}
|
|
}
|
|
ConstantCoefficient one(1.0);
|
|
ConstantCoefficient omeg(-pow(omega, 2));
|
|
RestrictedCoefficient restr_one(one,attr);
|
|
RestrictedCoefficient restr_omeg(omeg,attr);
|
|
|
|
// Integrators inside the computational domain (excluding the PML region)
|
|
sqf[ip] = new SesquilinearForm(fespaces[ip], conv);
|
|
// sqf[ip] = new SesquilinearForm(fes, conv);
|
|
sqf[ip]->AddDomainIntegrator(new CurlCurlIntegrator(restr_one),NULL);
|
|
sqf[ip]->AddDomainIntegrator(new VectorFEMassIntegrator(restr_omeg),NULL);
|
|
|
|
PMLMatrixCoefficient pml_c1_Re(dim,detJ_inv_JT_J_Re, &tpml);
|
|
PMLMatrixCoefficient pml_c1_Im(dim,detJ_inv_JT_J_Im, &tpml);
|
|
ScalarMatrixProductCoefficient c1_Re(one,pml_c1_Re);
|
|
ScalarMatrixProductCoefficient c1_Im(one,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,&tpml);
|
|
PMLMatrixCoefficient pml_c2_Im(dim, detJ_JT_J_inv_Im,&tpml);
|
|
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
|
|
sqf[ip]->AddDomainIntegrator(new CurlCurlIntegrator(restr_c1_Re),
|
|
new CurlCurlIntegrator(restr_c1_Im));
|
|
sqf[ip]->AddDomainIntegrator(new VectorFEMassIntegrator(restr_c2_Re),
|
|
new VectorFEMassIntegrator(restr_c2_Im));
|
|
sqf[ip]->Assemble(0);
|
|
|
|
Optr[ip] = new OperatorPtr;
|
|
sqf[ip]->FormSystemMatrix(ess_tdof_list,*Optr[ip]);
|
|
// SparseMatrix * SpMat = (*Optr[ip]->As<ComplexSparseMatrix>()).GetSystemMatrix();
|
|
// SpMat->PrintMatlab(cout);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ToroidST::ToroidST(SesquilinearForm * bf_, const Vector & aPmlThickness_,
|
|
double omega_, int nrsubdomains_)
|
|
: bf(bf_), aPmlThickness(aPmlThickness_), omega(omega_), nrsubdomains(nrsubdomains_)
|
|
{
|
|
fes = bf->FESpace();
|
|
cout << "In ToroidST" << endl;
|
|
|
|
// overlap = 2.5;
|
|
overlap = 1.25;
|
|
ovlp = overlap + aPmlThickness[1]; // for now
|
|
//-------------------------------------------------------
|
|
// Step 0: Generate Mesh and FiniteElementSpace Partition
|
|
// ------------------------------------------------------
|
|
Array<Array<int> *> ElemMaps;
|
|
PartitionFE(fes,nrsubdomains,ovlp,fespaces, ElemMaps,
|
|
DofMaps0, DofMaps1, OvlpMaps0, OvlpMaps1);
|
|
for (int i = 0; i<nrsubdomains; i++) delete ElemMaps[i];
|
|
|
|
//-------------------------------------------------------
|
|
// Step 1: Setup local Maxwell Problems PML
|
|
// ------------------------------------------------------
|
|
cout << "Setting up local problems " << endl;
|
|
SetupSubdomainProblems();
|
|
cout << "Done "<< endl;
|
|
|
|
|
|
// Test local to global dof Maps
|
|
// cout << "Testing local to global maps " << endl;
|
|
// for (int i = 0; i<nrsubdomains; i++)
|
|
// {
|
|
// DofMapTests(*fespaces[i],*fes,*DofMaps0[i], *DofMaps1[i]);
|
|
// // DofMapTests(*fes,*fespaces[i], *DofMaps1[i], *DofMaps0[i]);
|
|
// }
|
|
|
|
// cout << "Testing local to neighbor maps " << endl;
|
|
// for (int i = 0; i<nrsubdomains-1; i++)
|
|
// {
|
|
// DofMapTests(*fespaces[i],*fespaces[i+1],*OvlpMaps0[i], *OvlpMaps1[i]);
|
|
// DofMapTests(*fespaces[i+1],*fespaces[i],*OvlpMaps1[i], *OvlpMaps0[i]);
|
|
// }
|
|
|
|
// cout << "Testing local to overlap maps " << endl;
|
|
// for (int i = 0; i<nrsubdomains; i++)
|
|
// {
|
|
// Array<int> rdofs;
|
|
// GetRestrictionDofs(*fespaces[i],1,ovlp,rdofs);
|
|
// GetRestrictionDofs(*fespaces[i],-1,ovlp,rdofs);
|
|
// DofMapOvlpTest(*fespaces[i],rdofs);
|
|
// }
|
|
}
|
|
|
|
|
|
void ToroidST::Mult(const Vector & r, Vector & z) const
|
|
{
|
|
cout << "ToroidST::Mult " << endl;
|
|
cout << "r norm = " << r.Norml2() << endl;
|
|
|
|
z = 0.0;
|
|
// Step 0;
|
|
// Initialize transfered residuals to 0.0 and
|
|
// restrict Source to subdomains
|
|
for (int ip=0; ip<nrsubdomains; ip++)
|
|
{
|
|
*forward_transf[ip] = 0.0;
|
|
*backward_transf[ip] = 0.0;
|
|
MapDofs(*DofMaps1[ip], *DofMaps0[ip],r,*f_orig[ip]);
|
|
// cout << "0:f_orig[ip] norm = " << f_orig[ip]->Norml2() << endl;
|
|
// cout << "ovlp = " << ovlp << endl;
|
|
int direction = 0;
|
|
if (ip == 0) direction = 1;
|
|
if (ip == nrsubdomains-1) direction = -1;
|
|
if (nrsubdomains == 1) continue;
|
|
Array<int> rdofs;
|
|
GetRestrictionDofs(*fespaces[ip],direction,ovlp,rdofs);
|
|
// cout << "direction = " << direction << endl;
|
|
// DofMapOvlpTest(*fespaces[ip],rdofs);
|
|
// cin.get();
|
|
// rdofs.Print(cout, 20);
|
|
RestrictDofs(rdofs,f_orig[ip]->Size()/2,*f_orig[ip]);
|
|
// cout << "1:f_orig[ip] norm = " << f_orig[ip]->Norml2() << endl;
|
|
// cin.get();
|
|
}
|
|
|
|
// Step 1; "forward sweep"
|
|
for (int ip=0; ip<nrsubdomains; ip++)
|
|
{
|
|
int n = fespaces[ip]->GetTrueVSize();
|
|
Vector res(2*n); res = 0.0;
|
|
res += *f_orig[ip];
|
|
res += *forward_transf[ip];
|
|
Vector sol(2*n);
|
|
PmlMatInv[ip]->Mult(res,sol);
|
|
// accumulate for the global correction;
|
|
// AddMapDofs(*DofMaps1[ip],*DofMaps0[ip],sol,z);
|
|
// Transfer source to (forward) neighbor
|
|
int sweep = 1;
|
|
SourceTransfer(ip,sol, sweep);
|
|
// cout << "res norm = " << res.Norml2() << endl;
|
|
// cout << "sol norm = " << sol.Norml2() << endl;
|
|
AddMapDofs(*DofMaps0[ip],*DofMaps1[ip],sol,z);
|
|
// cout << "z norm = " << z.Norml2() << endl;
|
|
}
|
|
// Step 2: "Backward Sweep"
|
|
for (int ip=nrsubdomains-1; ip>=0; ip--)
|
|
{
|
|
int n = fespaces[ip]->GetTrueVSize();
|
|
Vector res(2*n); res = 0.0;
|
|
res += *backward_transf[ip];
|
|
Vector sol(2*n);
|
|
PmlMatInv[ip]->Mult(res,sol);
|
|
int sweep = -1;
|
|
SourceTransfer(ip,sol,sweep);
|
|
AddMapDofs(*DofMaps0[ip],*DofMaps1[ip],sol,z);
|
|
}
|
|
}
|
|
|
|
void ToroidST::SourceTransfer(int ip, const Vector & sol, int sweep) const
|
|
{
|
|
// Transfer to ip+1 and ip-1
|
|
int ip0 = ip-1;
|
|
int ip1 = ip+1;
|
|
|
|
// sweep : 1 - forward
|
|
// sweep : -1 - forward
|
|
// direction : 0 - both
|
|
|
|
if (ip0 >= 0)
|
|
{ // map sol from ip to ip0
|
|
int n = fespaces[ip0]->GetTrueVSize();
|
|
Vector sol0(2*n); sol0 = 0.0;
|
|
Vector Psi0(2*n);
|
|
MapDofs(*OvlpMaps1[ip0], *OvlpMaps0[ip0],sol,sol0);
|
|
PmlMat[ip0]->Mult(sol0,Psi0);
|
|
int direction = 1;
|
|
Array<int> rdofs;
|
|
GetRestrictionDofs(*fespaces[ip0],direction,ovlp,rdofs);
|
|
RestrictDofs(rdofs,backward_transf[ip0]->Size()/2,Psi0);
|
|
*backward_transf[ip0]-= Psi0;
|
|
}
|
|
|
|
if (sweep == 1)
|
|
{
|
|
if (ip1 <= nrsubdomains-1)
|
|
{
|
|
int n = fespaces[ip1]->GetTrueVSize();
|
|
Vector sol1(2*n); sol1 = 0.0;
|
|
Vector Psi1(2*n);
|
|
MapDofs(*OvlpMaps0[ip], *OvlpMaps1[ip],sol,sol1);
|
|
PmlMat[ip1]->Mult(sol1,Psi1);
|
|
int direction = -1;
|
|
Array<int> rdofs;
|
|
GetRestrictionDofs(*fespaces[ip1],direction,ovlp,rdofs);
|
|
RestrictDofs(rdofs,forward_transf[ip1]->Size()/2,Psi1);
|
|
*forward_transf[ip1]-= Psi1;
|
|
}
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
ToroidST::~ToroidST()
|
|
{
|
|
for (int i = 0; i<nrsubdomains-1; i++)
|
|
{
|
|
delete DofMaps0[i];
|
|
delete DofMaps1[i];
|
|
delete OvlpMaps0[i];
|
|
delete OvlpMaps1[i];
|
|
}
|
|
delete DofMaps0[nrsubdomains-1];
|
|
delete DofMaps1[nrsubdomains-1];
|
|
} |