Files
mfem/examples/maxwell-solver/DST2D/AdditiveST2D.cpp
T

546 lines
15 KiB
C++

//Additive Source Transfer Preconditioner
#include "AdditiveST2D.hpp"
AdditiveST2D::AdditiveST2D(SesquilinearForm * bf_, Array2D<double> & Pmllength_,
double omega_, Coefficient * ws_, int nrlayers_)
: Solver(2*bf_->FESpace()->GetTrueVSize(), 2*bf_->FESpace()->GetTrueVSize()),
bf(bf_), Pmllength(Pmllength_), omega(omega_), ws(ws_), nrlayers(nrlayers_)
{
Mesh * mesh = bf->FESpace()->GetMesh();
dim = mesh->Dimension();
int partition_kind;
// 1. Ovelapping partition with overlap = 2h
partition_kind = 2; // Non Overlapping partition
int nx=2;
int ny=2;
int nz=1;
ovlpnrlayers = nrlayers+2;
povlp = new MeshPartition(mesh, partition_kind,nx,ny,nz, ovlpnrlayers);
partition_kind = 1;
novlp = new MeshPartition(mesh, partition_kind,nx,ny,nz);
nxyz[0] = povlp->nxyz[0];
nxyz[1] = povlp->nxyz[1];
nxyz[2] = povlp->nxyz[2];
nrpatch = povlp->nrpatch;
subdomains = povlp->subdomains;
ovlp_prob = new DofMap(bf,povlp);
nvlp_prob = new DofMap(bf,novlp);
PmlMat.SetSize(nrpatch);
PmlMatInv.SetSize(nrpatch);
for (int ip=0; ip<nrpatch; ip++)
{
PmlMat[ip] = GetPmlSystemMatrix(ip);
PmlMatInv[ip] = new KLUSolver;
PmlMatInv[ip]->SetOperator(*PmlMat[ip]);
}
int nsteps = nx + ny - 1;
f_orig.SetSize(nrpatch);
usol.SetSize(nrpatch);
f_s.SetSize(nrpatch);
f_diag.SetSize(nrpatch);
// Construct a simple map used for directions of transfer
for (int ip=0; ip<nrpatch; ip++)
{
int n = 2*ovlp_prob->fespaces[ip]->GetTrueVSize(); // (x 2 for complex )
f_orig[ip] = new Vector(n); *f_orig[ip] = 0.0;
usol[ip] = new Vector(n); *usol[ip] = 0.0;
f_s[ip].SetSize(nsteps);
f_diag[ip].SetSize(nsteps);
for (int i=0;i<nsteps; i++)
{
f_s[ip][i] = new Vector(n);
f_diag[ip][i] = new Vector(n);
}
}
}
void AdditiveST2D::Mult(const Vector &r, Vector &z) const
{
char vishost[] = "localhost";
int visport = 19916;
for (int ip=0; ip<nrpatch; ip++)
{
*f_orig[ip] = 0.0;
*usol[ip] = 0.0;
for (int i=0;i< f_s[ip].Size(); i++)
{
*f_s[ip][i] = 0.0;
*f_diag[ip][i] = 0.0;
}
}
socketstream res_sock(vishost, visport);
Vector res(r);
PlotSolution(res,res_sock,0,false);
// for (int ip=0; ip<nrpatch; ip++)
for (int ip=nrpatch-1; ip>=0; ip--)
{
Array<int> * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip];
r.GetSubVector(*Dof2GlobalDof,*f_orig[ip]);
// make sure that f_ij is compactly supported in \Omega_ij (non overlapping)
int i,j,k;
Getijk(ip,i,j,k);
Array<int> directions(2); directions = 0;
int nx = nxyz[0];
int ny = nxyz[1];
if (i+1<nx) directions[0] = 1;
if (j+1<ny) directions[1] = 1;
Vector faux(f_orig[ip]->Size());
GetChiRes(*f_orig[ip],faux,ip,directions,ovlpnrlayers);
directions = 0.0;
if (i>0) directions[0] = -1;
if (j>0) directions[1] = -1;
*f_orig[ip] = 0.0;
GetChiRes(faux,*f_orig[ip],ip,directions,ovlpnrlayers);
// Array<int> * nDof2GlobalDof = &nvlp_prob->Dof2GlobalDof[ip];
// Vector faux(nDof2GlobalDof->Size());
// r.GetSubVector(*nDof2GlobalDof,faux);
// res = 0.0;
// res.SetSubVector(*nDof2GlobalDof,faux);
// res.GetSubVector(*Dof2GlobalDof,*f_orig[ip]);
}
z = 0.0;
Vector znew(z);
// --------------------------------------------
// Sweep in the direction (1,1)
// --------------------------------------------
int nx = nxyz[0];
int ny = nxyz[1];
int nsteps = (nx + ny - 1);
for (int s = 0; s<nsteps; s++)
{
for (int ip = 0; ip<nrpatch; ip++)
{
Array<int> * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip];
int ndofs = Dof2GlobalDof->Size();
Vector sol_local(ndofs); sol_local = 0.0;
Vector res_local(ndofs); res_local = 0.0;
if (s==0)
{
res_local = *f_orig[ip];
}
else if (s == 1)
{
res_local = *f_s[ip][s-1];
}
else
{
res_local = *f_s[ip][s-1];
res_local += *f_diag[ip][s-2];
}
// cout << "reslocal norm = " << res_local.Norml2() << endl;
if (res_local.Norml2() < 1e-12) continue;
PmlMatInv[ip]->Mult(res_local, sol_local);
AdditiveTransferSources(s, ip, sol_local);
*usol[ip] += sol_local;
// Array<int>directions(2); directions = 0;
// int i,j,k;
// Getijk(ip,i,j,k);
// if (i+1<nx) directions[0] = 1;
// if (j+1<ny) directions[1] = 1;
// Vector cfsol_local;
// GetCutOffSolution(sol_local,cfsol_local,ip,directions,ovlpnrlayers,true);
// sol_local = cfsol_local;
// directions = 0.0;
// if (i>0) directions[0] = -1;
// if (j>0) directions[1] = -1;
// GetCutOffSolution(sol_local,cfsol_local,ip,directions,ovlpnrlayers,true);
// znew = 0.0;
// znew.SetSubVector(*Dof2GlobalDof, cfsol_local);
// z+=znew;
}
// socketstream sol1_sock(vishost, visport);
// PlotSolution(z,sol1_sock,0,false); cin.get();
}
for (int ip = 0; ip<nrpatch; ip++)
{
Array<int> * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip];
Array<int>directions(2); directions = 0;
int i,j,k;
Getijk(ip,i,j,k);
if (i+1<nx) directions[0] = 1;
if (j+1<ny) directions[1] = 1;
Vector cfsol_local;
GetCutOffSolution(*usol[ip],cfsol_local,ip,directions,ovlpnrlayers,true);
*usol[ip] = cfsol_local;
directions = 0.0;
if (i>0) directions[0] = -1;
if (j>0) directions[1] = -1;
GetCutOffSolution(*usol[ip],cfsol_local,ip,directions,ovlpnrlayers,true);
znew = 0.0;
znew.SetSubVector(*Dof2GlobalDof, cfsol_local);
z+=znew;
}
}
void AdditiveST2D::GetCutOffSolution(const Vector & sol, Vector & cfsol,
int ip, Array<int> directions, int nlayers, bool local) const
{
// int d = directions.Size();
// int directx = directions[0]; // 1,0,-1
// int directy = directions[1]; // 1,0,-1
// int directz;
// if (d ==3) directz = directions[2];
Mesh * mesh = ovlp_prob->fespaces[ip]->GetMesh();
Vector pmin, pmax;
mesh->GetBoundingBox(pmin, pmax);
double h = GetUniformMeshElementSize(povlp->patch_mesh[ip]);
int i, j, k;
Getijk(ip,i,j,k);
// int nx = nxyz[0];
// int ny = nxyz[1];
if (directions[0]==1) pmax[0] -= h*nrlayers;
if (directions[1]==1) pmax[1] -= h*nrlayers;
if (directions[0]==-1) pmin[0] += h*nrlayers;
if (directions[1]==-1) pmin[1] += h*nrlayers;
Array2D<double> pmlh(dim,2); pmlh = 0.0;
if (directions[0]==1)
{
pmlh[0][1] = h*(nlayers-nrlayers-1);
}
if (directions[0]==-1)
{
pmlh[0][0] = h*(nlayers-nrlayers-1);
}
if (directions[1]==1)
{
pmlh[1][1] = h*(nlayers-nrlayers-1);
}
if (directions[1]==-1)
{
pmlh[1][0] = h*(nlayers-nrlayers-1);
}
CutOffFnCoefficient cf(CutOffFncn, pmin, pmax, pmlh);
double * data = sol.GetData();
FiniteElementSpace * fes;
if (!local)
{
fes = bf->FESpace();
}
else
{
fes = ovlp_prob->fespaces[ip];
}
int n = fes->GetTrueVSize();
GridFunction solgf_re(fes, data);
GridFunction solgf_im(fes, &data[n]);
GridFunctionCoefficient coeff1_re(&solgf_re);
GridFunctionCoefficient coeff1_im(&solgf_im);
ProductCoefficient prod_re(coeff1_re, cf);
ProductCoefficient prod_im(coeff1_im, cf);
ComplexGridFunction gf(fes);
gf.ProjectCoefficient(prod_re,prod_im);
cfsol.SetSize(sol.Size());
cfsol = gf;
}
AdditiveST2D::~AdditiveST2D()
{
}
void AdditiveST2D::Getijk(int ip, int & i, int & j, int & k) const
{
k = ip/(nxyz[0]*nxyz[1]);
j = (ip-k*nxyz[0]*nxyz[1])/nxyz[0];
i = (ip-k*nxyz[0]*nxyz[1])%nxyz[0];
}
int AdditiveST2D::GetPatchId(const Array<int> & ijk) const
{
int d=ijk.Size();
int z = (d==2)? 0 : ijk[2];
return subdomains(ijk[0],ijk[1],z);
}
void AdditiveST2D::AdditiveTransferSources(int s, int ip0, Vector & sol0) const
{
// Find all neighbors of patch ip0
int nx = nxyz[0];
int ny = nxyz[1];
int i0, j0, k0;
Getijk(ip0, i0,j0,k0);
for (int i=-1; i<2; i++)
{
int i1 = i0 + i;
if (i1 <0 || i1>=nx) continue;
for (int j=-1; j<2; j++)
{
if (i==0 && j==0) continue;
int j1 = j0 + j;
if (j1 <0 || j1>=ny) continue;
Array<int> ij1(2); ij1[0] = i1; ij1[1]=j1;
int ip1 = GetPatchId(ij1);
Array<int> directions(2);
directions[0] = i;
directions[1] = j;
Vector cfsol0;
GetCutOffSolution(sol0,cfsol0,ip0,directions,ovlpnrlayers,true);
Vector raux;
SourceTransfer(cfsol0,directions,ip0,raux);
if (abs(i)+abs(j) == 2)
{
*f_diag[ip1][s]+=raux;
}
else
{
*f_s[ip1][s]+=raux;
}
}
}
}
SparseMatrix * AdditiveST2D::GetPmlSystemMatrix(int ip)
{
double h = GetUniformMeshElementSize(povlp->patch_mesh[ip]);
Array2D<double> length(dim,2);
length = h*(nrlayers);
int i,j,k;
int nx = nxyz[0];
int ny = nxyz[1];
Getijk(ip,i,j,k);
if (i == 0 ) length[0][0] = Pmllength[0][0];
if (j == 0 ) length[1][0] = Pmllength[1][0];
if (i == nx-1 ) length[0][1] = Pmllength[0][1];
if (j == ny-1 ) length[1][1] = Pmllength[1][1];
CartesianPML pml(povlp->patch_mesh[ip], length);
pml.SetOmega(omega);
Array <int> ess_tdof_list;
if (povlp->patch_mesh[ip]->bdr_attributes.Size())
{
Array<int> ess_bdr(povlp->patch_mesh[ip]->bdr_attributes.Max());
ess_bdr = 1;
ovlp_prob->fespaces[ip]->GetEssentialTrueDofs(ess_bdr, ess_tdof_list);
}
ConstantCoefficient one(1.0);
ConstantCoefficient sigma(-pow(omega, 2));
PmlMatrixCoefficient c1_re(dim,pml_detJ_JT_J_inv_Re,&pml);
PmlMatrixCoefficient c1_im(dim,pml_detJ_JT_J_inv_Im,&pml);
PmlCoefficient detJ_re(pml_detJ_Re,&pml);
PmlCoefficient detJ_im(pml_detJ_Im,&pml);
ProductCoefficient c2_re0(sigma, detJ_re);
ProductCoefficient c2_im0(sigma, detJ_im);
ProductCoefficient c2_re(c2_re0, *ws);
ProductCoefficient c2_im(c2_im0, *ws);
SesquilinearForm a(ovlp_prob->fespaces[ip],ComplexOperator::HERMITIAN);
a.AddDomainIntegrator(new DiffusionIntegrator(c1_re),
new DiffusionIntegrator(c1_im));
a.AddDomainIntegrator(new MassIntegrator(c2_re),
new MassIntegrator(c2_im));
a.Assemble();
OperatorPtr Alocal;
a.FormSystemMatrix(ess_tdof_list,Alocal);
ComplexSparseMatrix * AZ_ext = Alocal.As<ComplexSparseMatrix>();
SparseMatrix * Mat = AZ_ext->GetSystemMatrix();
Mat->Threshold(1e-13);
return Mat;
}
void AdditiveST2D::PlotSolution(Vector & sol, socketstream & sol_sock, int ip,
bool localdomain) const
{
FiniteElementSpace * fes;
if (!localdomain)
{
fes = bf->FESpace();
}
else
{
fes = ovlp_prob->fespaces[ip];
}
Mesh * mesh = fes->GetMesh();
GridFunction gf(fes);
double * data = sol.GetData();
gf.SetData(data);
string keys;
keys = "keys mrRljc\n";
sol_sock << "solution\n" << *mesh << gf << keys << flush;
}
void AdditiveST2D::PlotMesh(socketstream & mesh_sock, int ip) const
{
FiniteElementSpace * fes = ovlp_prob->fespaces[ip];
Mesh * mesh = fes->GetMesh();
mesh_sock << "mesh\n" << *mesh << flush;
}
void AdditiveST2D::SaveSolution(Vector & sol, int ip, bool localdomain) const
{
FiniteElementSpace * fes;
if (!localdomain)
{
fes = bf->FESpace();
}
else
{
// fes = ovlp_prob->fespaces[ip];
fes = nvlp_prob->fespaces[ip];
}
Mesh * mesh = fes->GetMesh();
int n = fes->GetTrueVSize();
GridFunction gf_re(fes);
GridFunction gf_im(fes);
double * data = sol.GetData();
gf_re.SetData(data);
gf_im.SetData(&data[n]);
cout << "saving mesh no " << ip << endl;
string mfilename = "output/mesh_nvlp.";
ostringstream mesh_name;
mesh_name << mfilename << setfill('0') << setw(6) << ip;
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(8);
mesh->Print(mesh_ofs);
string sfilename_re = "output/sol_nvlp.";
ostringstream solre_name;
solre_name << sfilename_re << setfill('0') << setw(6) << ip;
ofstream solre_ofs(solre_name.str().c_str());
gf_re.Save(solre_ofs);
}
int AdditiveST2D::SourceTransfer(const Vector & Psi0, Array<int> direction, int ip0, Vector & Psi1) const
{
int i0,j0,k0;
Getijk(ip0,i0,j0,k0);
int i1 = i0+direction[0];
int j1 = j0+direction[1];
Array<int> ij(2); ij[0]=i1; ij[1]=j1;
int ip1 = GetPatchId(ij);
MFEM_VERIFY(i1 < nxyz[0] && i1>=0, "SourceTransfer: i1 out of bounds");
MFEM_VERIFY(j1 < nxyz[1] && j1>=0, "SourceTransfer: j1 out of bounds");
Array<int> * Dof2GlobalDof0 = &ovlp_prob->Dof2GlobalDof[ip0];
Array<int> * Dof2GlobalDof1 = &ovlp_prob->Dof2GlobalDof[ip1];
Psi1.SetSize(Dof2GlobalDof1->Size()); Psi1=0.0;
Vector r(2*bf->FESpace()->GetTrueVSize());
r = 0.0;
r.SetSubVector(*Dof2GlobalDof0,Psi0);
Vector zloc(Psi1.Size()); zloc = 0.0;
r.GetSubVector(*Dof2GlobalDof1,zloc);
Vector Psi(Dof2GlobalDof1->Size()); Psi=0.0;
PmlMat[ip1]->Mult(zloc,Psi);
Psi *=-1.0;
Array<int> direct(2); direct = 0;
direct[0] = -direction[0];
direct[1] = -direction[1];
GetChiRes(Psi, Psi1,ip1,direct, ovlpnrlayers);
return ip1;
}
void AdditiveST2D::GetChiRes(const Vector & res, Vector & cfres,
int ip, Array<int> directions, int nlayers) const
{
// int l,k;
// int d = directions.Size();
// int directx = directions[0]; // 1,0,-1
// int directy = directions[1]; // 1,0,-1
// int directz;
// if (d ==3) directz = directions[2];
Mesh * mesh = ovlp_prob->fespaces[ip]->GetMesh();
double h = GetUniformMeshElementSize(mesh);
Vector pmin, pmax;
mesh->GetBoundingBox(pmin, pmax);
Array2D<double> pmlh(dim,2); pmlh = 0.0;
int i,j,k;
Getijk(ip,i,j,k);
if (directions[0]==-1)
{
pmlh[0][0] = h;
pmin[0] += h*(nlayers-1);
}
if (directions[0]==1)
{
pmlh[0][1] = h;
pmax[0] -= h*(nlayers-1);
}
if (directions[1]==-1)
{
pmlh[1][0] = h;
pmin[1] += h*(nlayers-1);
}
if (directions[1]==1)
{
pmlh[1][1] = h;
pmax[1] -= h*(nlayers-1);
}
CutOffFnCoefficient cf(ChiFncn, pmin, pmax, pmlh);
double * data = res.GetData();
FiniteElementSpace * fespace;
fespace = ovlp_prob->fespaces[ip];
int n = fespace->GetTrueVSize();
GridFunction solgf_re(fespace, data);
GridFunction solgf_im(fespace, &data[n]);
GridFunctionCoefficient coeff1_re(&solgf_re);
GridFunctionCoefficient coeff1_im(&solgf_im);
ProductCoefficient prod_re(coeff1_re, cf);
ProductCoefficient prod_im(coeff1_im, cf);
ComplexGridFunction gf(fespace);
gf.ProjectCoefficient(prod_re,prod_im);
cfres.SetSize(res.Size());
cfres = gf;
}