// Pure Source Transfer Preconditioner #include "PST.hpp" PSTP::PSTP(SesquilinearForm * bf_, Array2D & 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(); // ----------------- Step 1 -------------------- // Introduce 2 layered partitios of the domain // int partition_kind; // 1. Non ovelapping partition_kind = 1; // Non Ovelapping partition pnovlp = new MeshPartition(mesh, partition_kind); // 2. Overlapping to the right partition_kind = 3; // Overlapping partition for the full space povlp = new MeshPartition(mesh, partition_kind); nrpatch = povlp->nrpatch; MFEM_VERIFY(povlp->nrpatch+1 == pnovlp->nrpatch,"Check nrpatch"); lmap = new LocalDofMap(bf->FESpace()->FEColl(),pnovlp,povlp); // Given the two partitions create a dof map between the non-ovelapping // subdomain dofs and the overlapping ones // // ----------------- Step 1a ------------------- // Save the partition for visualization // SaveMeshPartition(povlp->patch_mesh, "output/mesh_ovlp.", "output/sol_ovlp."); // SaveMeshPartition(pnovlp->patch_mesh, "output/mesh_novlp.", "output/sol_novlp."); // ------------------Step 2 -------------------- // Construct the dof maps from subdomains to global (for the extended and not) // The non ovelapping is extended on the left by pml (halfspace problem) // The overlapping is extended left and right by pml (unbounded domain problem) novlp_prob = new DofMap(bf,pnovlp); ovlp_prob = new DofMap(bf,povlp,nrlayers); // Given // ------------------Step 3 -------------------- // Assemble the PML Problem matrices and factor them PmlMat.SetSize(nrpatch); PmlMatInv.SetSize(nrpatch); for (int ip=0; ipSetOperator(*PmlMat[ip]); } } SparseMatrix * PSTP::GetPmlSystemMatrix(int ip) { double h = GetUniformMeshElementSize(ovlp_prob->PmlMeshes[ip]); Array2D length(dim,2); length = h*(nrlayers); if (ip == nrpatch-1 || ip == 0) { length[0][0] = Pmllength[0][0]; length[0][1] = Pmllength[0][1]; } length[1][0] = Pmllength[1][0]; length[1][1] = Pmllength[1][1]; CartesianPML pml(ovlp_prob->PmlMeshes[ip], length); pml.SetOmega(omega); Array ess_tdof_list; if (ovlp_prob->PmlMeshes[ip]->bdr_attributes.Size()) { Array ess_bdr(ovlp_prob->PmlMeshes[ip]->bdr_attributes.Max()); ess_bdr = 1; ovlp_prob->PmlFespaces[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->PmlFespaces[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(); SparseMatrix * Mat = AZ_ext->GetSystemMatrix(); Mat->Threshold(0.0); return Mat; } void PSTP::Mult(const Vector &r, Vector &z) const { z = 0.0; res.SetSize(nrpatch); Vector rnew(r); Vector znew(z); Vector z1(z); Vector z2(z); Vector raux(znew.Size()); Vector res_local, sol_local; znew = 0.0; char vishost[] = "localhost"; int visport = 19916; Array fsol(nrpatch+1); Array bsol(nrpatch+1); // source transfer algorithm for (int ip = 0; ip < nrpatch; ip++) { // cout << "ip = " << ip << endl; Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; int ndofs = Dof2GlobalDof->Size(); res_local.SetSize(ndofs); sol_local.SetSize(ndofs); rnew.GetSubVector(*Dof2GlobalDof, res_local); int nrdof_ext = PmlMat[ip]->Height(); Vector res_ext(nrdof_ext); res_ext = 0.0; Vector sol_ext(nrdof_ext); sol_ext = 0.0; res_ext.SetSubVector(*Dof2PmlDof,res_local.GetData()); PmlMatInv[ip]->Mult(res_ext, sol_ext); sol_ext.GetSubVector(*Dof2PmlDof,sol_local); znew = 0.0; znew.SetSubVector(*Dof2GlobalDof,sol_local); // cout << "ip+1 = " << ip+1 << endl; Array * nDof2GlobalDof = &novlp_prob->Dof2GlobalDof[ip+1]; fsol[ip+1].SetSize(nDof2GlobalDof->Size()); znew.GetSubVector(*nDof2GlobalDof,fsol[ip+1]); socketstream subsol_sock(vishost, visport); // PlotSolution(znew, subsol_sock,ip); cin.get(); // z.AddElementVector(*Dof2GlobalDof,sol_local); int direction = 1; if (ip Mult(znew, raux); rnew -= raux; // PlotSolution(rnew, subsol_sock,ip); cin.get(); } // socketstream subsol1_sock(vishost, visport); // PlotSolution(z1, subsol1_sock,0); rnew = r; for (int ip = nrpatch-1; ip >=0; ip--) { Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; int ndofs = Dof2GlobalDof->Size(); res_local.SetSize(ndofs); sol_local.SetSize(ndofs); rnew.GetSubVector(*Dof2GlobalDof, res_local); //----------------------------------------------- // Extend by zero to the extended mesh int nrdof_ext = PmlMat[ip]->Height(); Vector res_ext(nrdof_ext); res_ext = 0.0; Vector sol_ext(nrdof_ext); sol_ext = 0.0; res_ext.SetSubVector(*Dof2PmlDof,res_local.GetData()); PmlMatInv[ip]->Mult(res_ext, sol_ext); sol_ext.GetSubVector(*Dof2PmlDof,sol_local); znew = 0.0; znew.SetSubVector(*Dof2GlobalDof,sol_local); Array * nDof2GlobalDof = &novlp_prob->Dof2GlobalDof[ip]; bsol[ip].SetSize(nDof2GlobalDof->Size()); znew.GetSubVector(*nDof2GlobalDof,bsol[ip]); // cout << "ip = " << ip << endl; // PlotSolution(znew, subsol_sock,ip); cin.get(); // z.AddElementVector(*Dof2GlobalDof,sol_local); int direction = -1; if (ip>0) GetCutOffSolution(znew, ip-1, direction); if (ip != nrpatch-1) z2+=znew; // PlotSolution(z, subsol_sock,1); cin.get(); A->Mult(znew, raux); rnew -= raux; // PlotSolution(rnew, subsol_sock,ip); cin.get(); } // socketstream subsol2_sock(vishost, visport); // PlotSolution(z2, subsol2_sock,0); cin.get(); // construct solution z by z1 and z2 // vizualize solutions // Forward solutions // socketstream subsol3_sock(vishost, visport); for (int ip = 0; ip fn(nrpatch+1); // Array ftransf(nrpatch+1); // for (int ip=0; ip<=nrpatch; ip++) // { // Array *Dof2GDof = &novlp_prob->Dof2GlobalDof[ip]; // fn[ip].SetSize(Dof2GDof->Size()); // ftransf[ip].SetSize(Dof2GDof->Size()); // r.GetSubVector(*Dof2GDof,fn[ip]); // } // // source transfer algorithm 1 (forward sweep) // Vector f; // for (int ip = 0; ip < nrpatch; ip++) // { // // construct the source in the overlapping PML problem // if (ip == 0) ftransf[ip] = fn[ip]; // int ndof = ovlp_prob->Dof2GlobalDof[ip].Size(); // f.SetSize(ndof); f = 0.0; // f.SetSubVector(lmap->map1[ip],ftransf[ip]); // f.SetSubVector(lmap->map2[ip],fn[ip+1]); // // Extend to the pml problem and solve for the local pml solution // Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; // int ndof_pml = PmlMat[ip]->Height(); // fpml.SetSize(ndof_pml); fpml=0.0; // zpml.SetSize(ndof_pml); zpml=0.0; // fpml.SetSubVector(*Dof2PmlDof,f); // // Solve the pml problem // PmlMatInv[ip]->Mult(fpml, zpml); // // PlotLocalSolution(zpml,subsol_sock,ip); cin.get(); // //-------------------------------------------------- // // Save the solution to the global solution // // restrict to non-pml problem // Vector sol(ndof); // zpml.GetSubVector(*Dof2PmlDof, sol); // // restrict to the non-ovlp subdomain // // z1.AddElementVector(ovlp_prob->Dof2GlobalDof[ip],sol); // int m = lmap->map2[ip].Size(); // Vector soll(m); // sol.GetSubVector(lmap->map2[ip],soll); // // prolong to the global solution // z.SetSubVector(novlp_prob->Dof2GlobalDof[ip+1],soll); // // PlotSolution(z,subsol1_sock,0); // // PlotSolution(z1,subsol2_sock,0); // //-------------------------------------------------- // if (ip == nrpatch-1) continue; // int direction = 1; // GetCutOffSol(zpml, ip, direction); // // PlotLocalSolution(zpml,subsol3_sock,ip); cin.get(); // // Calculate source to be trasfered to the pml mesh // Vector respml(zpml.Size()); // PmlMat[ip]->Mult(zpml,respml); // // PlotLocalSolution(respml,subsol_sock,ip); cin.get(); // // restrict to non-pml problem // Vector res(ndof); // respml.GetSubVector(*Dof2PmlDof, res); // // source to be transfered // res.GetSubVector(lmap->map2[ip],ftransf[ip+1]); // // restrict to nonpml problem // // restrict to non-pml problem // // Vector sol1(ndof); // // zpml.GetSubVector(*Dof2PmlDof, sol1); // // // prolong to global sol // // z1 = 0.0; // // Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; // // z1.SetSubVector(*Dof2GlobalDof, sol1); // // // calculate new source // // A->Mult(z1,res); // // //restrict to subdomain ip+1 // // Array * nDof2GlobalDof = &novlp_prob->Dof2GlobalDof[ip+1]; // // res.GetSubVector(*nDof2GlobalDof,ftransf[ip+1]); // } // // source transfer algorithm 2 (backward sweep) // for (int ip = nrpatch-1; ip >= 0; ip--) // { // // construct the source in the overlapping PML problem // if (ip == nrpatch-1) ftransf[ip+1] = fn[ip+1]; // int ndof = ovlp_prob->Dof2GlobalDof[ip].Size(); // f.SetSize(ndof); f = 0.0; // f.SetSubVector(lmap->map1[ip],fn[ip]); // f.SetSubVector(lmap->map2[ip],ftransf[ip+1]); // // Extend to the pml problem and solve for the local pml solution // Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; // int ndof_pml = PmlMat[ip]->Height(); // fpml.SetSize(ndof_pml); fpml=0.0; // zpml.SetSize(ndof_pml); zpml=0.0; // fpml.SetSubVector(*Dof2PmlDof,f); // // Solve the pml problem // PmlMatInv[ip]->Mult(fpml, zpml); // PlotLocalSolution(zpml,subsol_sock,ip); cin.get(); // //-------------------------------------------------- // // Save the solution to the global solution // // restrict to non-pml problem // Vector sol(ndof); // zpml.GetSubVector(*Dof2PmlDof, sol); // // restrict to the non-ovlp subdomain // int m = lmap->map1[ip].Size(); // Vector soll(m); // sol.GetSubVector(lmap->map1[ip],soll); // // prolong to the global solution // z.AddElementVector(novlp_prob->Dof2GlobalDof[ip],soll); // // PlotSolution(z,subsol_sock,0); cin.get(); // //-------------------------------------------------- // if (ip == 0) continue; // int direction = -1; // GetCutOffSol(zpml, ip-1, direction); // PlotLocalSolution(zpml,subsol_sock,ip); cin.get(); // // Calculate source to be trasfered to the pml mesh // Vector respml(zpml.Size()); // PmlMat[ip]->Mult(zpml,respml); // // PlotLocalSolution(respml,subsol_sock,ip); cin.get(); // // restrict to non-pml problem // Vector res(ndof); // respml.GetSubVector(*Dof2PmlDof, res); // // source to be transfered // res.GetSubVector(lmap->map2[ip],ftransf[ip]); // } // PlotSolution(z,subsol_sock,0); cin.get(); // res.SetSize(nrpatch); // Vector rnew(r); // Vector rnew2(r); // Vector znew(z); // Vector znew1(z); // Vector znew2(z); // Vector raux(znew.Size()); // Vector res_local, sol_local; // znew = 0.0; // znew1= 0.0; // znew2= 0.0; // char vishost[] = "localhost"; // int visport = 19916; // socketstream subsol_sock(vishost, visport); // std::vector zloc; // zloc.resize(nrpatch+1); // // allocate memory and initialize // for (int ip = 0; ip <= nrpatch; ip++) // { // int n = novlp_prob->Dof2GlobalDof[ip].Size(); // zloc[ip] = new Vector(n); *zloc[ip]=0.0; // } // // source transfer algorithm 1 (forward sweep) // for (int ip = 0; ip < nrpatch; ip++) // { // Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; // Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; // int ndofs = Dof2GlobalDof->Size(); // res_local.SetSize(ndofs); // sol_local.SetSize(ndofs); // rnew.GetSubVector(*Dof2GlobalDof, res_local); // //----------------------------------------------- // // Extend by zero to the extended mesh // int nrdof_ext = PmlMat[ip]->Height(); // Vector res_ext(nrdof_ext); res_ext = 0.0; // Vector sol_ext(nrdof_ext); sol_ext = 0.0; // res_ext.SetSubVector(*Dof2PmlDof,res_local.GetData()); // PmlMatInv[ip]->Mult(res_ext, sol_ext); // sol_ext.GetSubVector(*Dof2PmlDof,sol_local); // znew = 0.0; // znew.SetSubVector(*Dof2GlobalDof,sol_local); // Array * Dof2GDof = &novlp_prob->Dof2GlobalDof[ip+1]; // int n = Dof2GDof->Size(); // Vector nsol(n); // znew.GetSubVector(*Dof2GDof, nsol); // *zloc[ip+1] += nsol; // int direction = 1; // if (ip < nrpatch-1) GetCutOffSolution(znew, ip, direction); // A->Mult(znew, raux); // rnew -= raux; // znew1 += znew; // } // PlotSolution(znew1, subsol_sock,0); cin.get(); // // source transfer algorithm 2 (backward sweep) // for (int ip = nrpatch-1; ip >=0; ip--) // { // Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; // Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[ip]; // int ndofs = Dof2GlobalDof->Size(); // res_local.SetSize(ndofs); // sol_local.SetSize(ndofs); // rnew2.GetSubVector(*Dof2GlobalDof, res_local); // //----------------------------------------------- // // Extend by zero to the extended mesh // int nrdof_ext = PmlMat[ip]->Height(); // Vector res_ext(nrdof_ext); res_ext = 0.0; // Vector sol_ext(nrdof_ext); sol_ext = 0.0; // res_ext.SetSubVector(*Dof2PmlDof,res_local.GetData()); // PmlMatInv[ip]->Mult(res_ext, sol_ext); // sol_ext.GetSubVector(*Dof2PmlDof,sol_local); // znew = 0.0; // znew.SetSubVector(*Dof2GlobalDof,sol_local); // Array * Dof2GDof = &novlp_prob->Dof2GlobalDof[ip]; // int n = Dof2GDof->Size(); // Vector nsol(n); // znew.GetSubVector(*Dof2GDof, nsol); // *zloc[ip] += nsol; // int direction = -1; // if (ip > 0) GetCutOffSolution(znew, ip-1, direction); // A->Mult(znew, raux); // rnew2 -= raux; // znew2 += znew; // } // // PlotSolution(znew2, subsol_sock,0); cin.get(); // // propagate to global dofs // z = 0.0; // for (int ip = 0; ip <= nrpatch; ip++) // { // Array Dof2GDof = novlp_prob->Dof2GlobalDof[ip]; // z.AddElementVector(Dof2GDof,*zloc[ip]); // } // PlotSolution(z, subsol_sock,0); cin.get(); } void PSTP::PlotSolution(Vector & sol, socketstream & sol_sock, int ip) const { FiniteElementSpace * fespace = bf->FESpace(); Mesh * mesh = fespace->GetMesh(); GridFunction gf(fespace); double * data = sol.GetData(); gf.SetData(data); string keys = "keys z\n"; if (ip ==0) keys = "keys rRljc\n"; sol_sock << "solution\n" << *mesh << gf << flush; } void PSTP::PlotLocalSolution(Vector & sol, socketstream & sol_sock, int ip) const { FiniteElementSpace * fespace = ovlp_prob->PmlFespaces[ip]; Mesh * mesh = fespace->GetMesh(); GridFunction gf(fespace); double * data = sol.GetData(); gf.SetData(data); string keys = "keys z\n"; if (ip ==0) keys = "keys rRljc\n"; sol_sock << "solution\n" << *mesh << gf << flush; } void PSTP::GetCutOffSolution(Vector & sol, int ip, int direction) const { int l,k; l=(direction == 1)? ip+1: ip; k=(direction == 1)? ip: ip+1; Mesh * mesh1 = ovlp_prob->fespaces[l]->GetMesh(); Mesh * mesh2 = ovlp_prob->fespaces[k]->GetMesh(); Vector pmin1, pmax1; Vector pmin2, pmax2; mesh1->GetBoundingBox(pmin1, pmax1); mesh2->GetBoundingBox(pmin2, pmax2); Array2D h(dim,2); h[0][0] = pmin2[0] - pmin1[0]; h[0][1] = pmax2[0] - pmin1[0]; h[1][0] = pmin2[1] - pmin1[1]; h[1][1] = pmax2[1] - pmax1[1]; if (direction == 1) { h[0][0] = 0.0; } else if (direction == -1) { h[0][1] = 0.0; } CutOffFnCoefficient cf(CutOffFncn, pmin2, pmax2, h); double * data = sol.GetData(); FiniteElementSpace * fespace = bf->FESpace(); 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); sol = gf; } PSTP::~PSTP() { for (int ip = 0; ipfespaces[l]->GetMesh(); Mesh * mesh2 = ovlp_prob->fespaces[k]->GetMesh(); Vector pmin1, pmax1; Vector pmin2, pmax2; mesh1->GetBoundingBox(pmin1, pmax1); mesh2->GetBoundingBox(pmin2, pmax2); Array2D h(dim,2); h[0][0] = pmin2[0] - pmin1[0]; h[0][1] = pmax2[0] - pmin1[0]; h[1][0] = pmin2[1] - pmin1[1]; h[1][1] = pmax2[1] - pmax1[1]; if (direction == 1) { h[0][0] = 0.0; } else if (direction == -1) { h[0][1] = 0.0; } CutOffFnCoefficient cf(CutOffFncn, pmin2, pmax2, h); double * data = sol.GetData(); int m = (direction == 1) ? ip : ip+1; FiniteElementSpace * fespace = ovlp_prob->PmlFespaces[m]; 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); sol = gf; } LocalDofMap::LocalDofMap(const FiniteElementCollection * fec_, MeshPartition * part1_, MeshPartition * part2_):fec(fec_), part1(part1_), part2(part2_) { // Each overlapping patch has 2 non-overlapping subdomains // Thre are n non-overlapping and and n-1 overlapping subdomains int nrpatch = part2->nrpatch; MFEM_VERIFY(part1->nrpatch-1 == part2->nrpatch, "Check number of subdomains"); cout << "Constructing local dof maps" << endl; map1.resize(nrpatch); map2.resize(nrpatch); for (int ip=0; ippatch_mesh[ip]; Mesh * mesh1 = part1->patch_mesh[ip]; Mesh * mesh2 = part1->patch_mesh[ip+1]; // Define the fespaces FiniteElementSpace fespace(mesh, fec); FiniteElementSpace fespace1(mesh1, fec); FiniteElementSpace fespace2(mesh2, fec); int ndof1 = fespace1.GetTrueVSize(); int ndof2 = fespace2.GetTrueVSize(); map1[ip].SetSize(2*ndof1); // times 2 because it's complex map2[ip].SetSize(2*ndof2); // times 2 because it's complex // loop through the elements in the patches // map 1 is constructed by the first half of elements // map 2 is constructed by the second half of elements for (int iel = 0; ielelement_map[ip].Size(); ++iel) { // index in the overlapping mesh int iel_idx = iel; Array ElemDofs; Array GlobalElemDofs; fespace1.GetElementDofs(iel,ElemDofs); fespace.GetElementDofs(iel_idx,GlobalElemDofs); // the sizes have to match MFEM_VERIFY(ElemDofs.Size() == GlobalElemDofs.Size(), "Size inconsistency"); // loop through the dofs and take into account the signs; int ndof = ElemDofs.Size(); for (int i = 0; i= 0) ? pdof_ : abs(pdof_) - 1; int gdof = (gdof_ >= 0) ? gdof_ : abs(gdof_) - 1; map1[ip][pdof] = gdof; map1[ip][pdof+ndof1] = gdof+fespace.GetTrueVSize(); } } for (int iel = 0; ielelement_map[ip+1].Size(); ++iel) { // index in the overlapping mesh int k = part1->element_map[ip].Size(); int iel_idx = iel+k; Array ElemDofs; Array GlobalElemDofs; fespace2.GetElementDofs(iel,ElemDofs); fespace.GetElementDofs(iel_idx,GlobalElemDofs); // the sizes have to match MFEM_VERIFY(ElemDofs.Size() == GlobalElemDofs.Size(), "Size inconsistency"); // loop through the dofs and take into account the signs; int ndof = ElemDofs.Size(); for (int i = 0; i= 0) ? pdof_ : abs(pdof_) - 1; int gdof = (gdof_ >= 0) ? gdof_ : abs(gdof_) - 1; map2[ip][pdof] = gdof; map2[ip][pdof+ndof2] = gdof+fespace.GetTrueVSize(); } } } }