//Source Transfer Preconditioner #include "ST.hpp" DofMap::DofMap(SesquilinearForm * bf_ , MeshPartition * partition_) : bf(bf_), partition(partition_) { int partition_kind = partition->partition_kind; MFEM_VERIFY(partition_kind == 1, "Check Partition kind"); fespace = bf->FESpace(); Mesh * mesh = fespace->GetMesh(); const FiniteElementCollection * fec = fespace->FEColl(); nrpatch = partition->nrpatch; fespaces.SetSize(nrpatch); Dof2GlobalDof.resize(nrpatch); for (int ip=0; ippatch_mesh[ip],fec); // construct the patch tdof to global tdof map int nrdof = fespaces[ip]->GetTrueVSize(); Dof2GlobalDof[ip].SetSize(2*nrdof); // loop through the elements in the patch for (int iel = 0; ielelement_map[ip].Size(); ++iel) { // index in the global mesh int iel_idx = partition->element_map[ip][iel]; // get the dofs of this element Array ElemDofs; Array GlobalElemDofs; fespaces[ip]->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; Dof2GlobalDof[ip][pdof] = gdof; Dof2GlobalDof[ip][pdof+nrdof] = gdof+fespace->GetTrueVSize(); } } } } DofMap::DofMap(SesquilinearForm * bf_ , MeshPartition * partition_, int nrlayers) : bf(bf_), partition(partition_) { int partition_kind = partition->partition_kind; fespace = bf->FESpace(); Mesh * mesh = fespace->GetMesh(); const FiniteElementCollection * fec = fespace->FEColl(); nrpatch = partition->nrpatch; fespaces.SetSize(nrpatch); PmlMeshes.SetSize(nrpatch); // Extend patch meshes to include pml for (int ip = 0; ip directions; if (ip > 0) { for (int i=0; ipatch_mesh[ip],directions); } // Save PML_meshes string meshpath; string solpath; if (partition_kind == 3) { meshpath = "output/mesh_ovlp_pml."; solpath = "output/sol_ovlp_pml."; } else if (partition_kind == 4) { meshpath = "output/mesh_novlp_pml."; solpath = "output/sol_novlp_pml."; } else { MFEM_ABORT("This partition kind not supported yet"); } // SaveMeshPartition(PmlMeshes, meshpath, solpath); PmlFespaces.SetSize(nrpatch); Dof2GlobalDof.resize(nrpatch); Dof2PmlDof.resize(nrpatch); for (int ip=0; ippatch_mesh[ip],fec); PmlFespaces[ip] = new FiniteElementSpace(PmlMeshes[ip],fec); // construct the patch tdof to global tdof map int nrdof = fespaces[ip]->GetTrueVSize(); Dof2GlobalDof[ip].SetSize(2*nrdof); Dof2PmlDof[ip].SetSize(2*nrdof); // build dof maps between patch and extended patch // loop through the patch elements and constract the dof map // The same elements in the extended mesh have the same ordering (but not the dofs) // loop through the elements in the patch for (int iel = 0; ielelement_map[ip].Size(); ++iel) { // index in the global mesh int iel_idx = partition->element_map[ip][iel]; // get the dofs of this element Array ElemDofs; Array PmlElemDofs; Array GlobalElemDofs; fespaces[ip]->GetElementDofs(iel,ElemDofs); PmlFespaces[ip]->GetElementDofs(iel,PmlElemDofs); fespace->GetElementDofs(iel_idx,GlobalElemDofs); // the sizes have to match MFEM_VERIFY(ElemDofs.Size() == GlobalElemDofs.Size(), "Size inconsistency"); MFEM_VERIFY(ElemDofs.Size() == PmlElemDofs.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; int pmldof = (pmldof_ >= 0) ? pmldof_ : abs(pmldof_) - 1; Dof2GlobalDof[ip][pdof] = gdof; Dof2GlobalDof[ip][pdof+nrdof] = gdof+fespace->GetTrueVSize(); Dof2PmlDof[ip][pdof] = pmldof; Dof2PmlDof[ip][pdof+nrdof] = pmldof+PmlFespaces[ip]->GetTrueVSize(); } } } } STP::STP(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 = 4; // Ovelapping partition for the halfspace problem pnovlp = new MeshPartition(mesh, partition_kind); // 2. Overlapping to the right partition_kind = 3; // Ovelapping partition for the full space povlp = new MeshPartition(mesh, partition_kind); nrpatch = pnovlp->nrpatch; // // ----------------- 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,nrlayers); ovlp_prob = new DofMap(bf,povlp,nrlayers); // ------------------Step 3 -------------------- // Assemble the PML Problem matrices and factor them PmlMat.SetSize(nrpatch); PmlMatInv.SetSize(nrpatch); for (int ip=0; ipSetOperator(*PmlMat[ip]); } HalfSpaceMat.SetSize(nrpatch); HalfSpaceMatInv.SetSize(nrpatch); HalfSpaceForms.SetSize(nrpatch); for (int ip=0; ipSetOperator(*HalfSpaceMat[ip]); } } SparseMatrix * STP::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; } SparseMatrix * STP::GetHalfSpaceSystemMatrix(int ip) { double h = GetUniformMeshElementSize(novlp_prob->PmlMeshes[ip]); Array2D length(dim,2); length = h*(nrlayers); if (ip == nrpatch-1 || ip == 0) { length[0][0] = Pmllength[0][0]; } length[1][0] = Pmllength[1][0]; length[1][1] = Pmllength[1][1]; length[0][1] = 0.0; CartesianPML pml(novlp_prob->PmlMeshes[ip], length); pml.SetOmega(omega); Array ess_tdof_list; if (novlp_prob->PmlMeshes[ip]->bdr_attributes.Size()) { Array ess_bdr(ovlp_prob->PmlMeshes[ip]->bdr_attributes.Max()); ess_bdr = 1; novlp_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); HalfSpaceForms[ip] = new SesquilinearForm(novlp_prob->PmlFespaces[ip], ComplexOperator::HERMITIAN); HalfSpaceForms[ip]->AddDomainIntegrator(new DiffusionIntegrator(c1_re), new DiffusionIntegrator(c1_im)); HalfSpaceForms[ip]->AddDomainIntegrator(new MassIntegrator(c2_re), new MassIntegrator(c2_im)); HalfSpaceForms[ip]->Assemble(); OperatorPtr Alocal; HalfSpaceForms[ip]->FormSystemMatrix(ess_tdof_list, Alocal); ComplexSparseMatrix * AZ_ext = Alocal.As(); SparseMatrix * Mat = AZ_ext->GetSystemMatrix(); Mat->Threshold(0.0); return Mat; } void STP::SolveHalfSpaceLinearSystem(int ip, Vector &x, Vector & load) const { Array ess_tdof_list; if (novlp_prob->PmlMeshes[ip]->bdr_attributes.Size()) { Array ess_bdr(ovlp_prob->PmlMeshes[ip]->bdr_attributes.Max()); ess_bdr = 1; novlp_prob->PmlFespaces[ip]->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); } OperatorHandle Ah; Vector X,Modload; HalfSpaceForms[ip]->FormLinearSystem(ess_tdof_list,x,load, Ah,X,Modload); HalfSpaceMatInv[ip]->Mult(Modload,X); HalfSpaceForms[ip]->RecoverFEMSolution(X,Modload,x); } void STP::Mult(const Vector &r, Vector &z) const { z = 0.0; res.SetSize(nrpatch); Vector rnew(r); Vector znew(z); Vector z1(z); Vector raux(znew.Size()); Vector res_local, sol_local; znew = 0.0; char vishost[] = "localhost"; int visport = 19916; // socketstream subsol_sock1(vishost, visport); // socketstream subsol_sock(vishost, visport); // source transfer algorithm 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); // store residuals for the non overlapping partition Array * nDof2GlobalDof; if (ip == nrpatch-1 ) { nDof2GlobalDof = &ovlp_prob->Dof2GlobalDof[ip]; } else { nDof2GlobalDof = &novlp_prob->Dof2GlobalDof[ip]; } int mdofs = nDof2GlobalDof->Size(); res[ip] = new Vector(mdofs); rnew.GetSubVector(*nDof2GlobalDof, *res[ip]); if (ip == nrpatch-1) continue; //----------------------------------------------- // 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); // PlotSolution(znew, subsol_sock,ip); cin.get(); // z.AddElementVector(*Dof2GlobalDof,sol_local); int direction = 1; GetCutOffSolution(znew, ip, direction); z1+=znew; // PlotSolution(z, subsol_sock,1); cin.get(); A->Mult(znew, raux); rnew -= raux; // PlotSolution(rnew, subsol_sock,ip); cin.get(); } // solution stage // First solve the nrpatch-1 problem (last subdomain) // extend residual to all around pml int nrdof_ext = PmlMat[nrpatch-1]->Height(); Vector res_ext(nrdof_ext); res_ext = 0.0; Vector sol_ext(nrdof_ext); sol_ext = 0.0; Array * Dof2GlobalDof = &ovlp_prob->Dof2GlobalDof[nrpatch-1]; Array * Dof2PmlDof = &ovlp_prob->Dof2PmlDof[nrpatch-1]; res_ext.SetSubVector(*Dof2PmlDof,*res[nrpatch-1]); PmlMatInv[nrpatch-1]->Mult(res_ext, sol_ext); int ndofs = Dof2GlobalDof->Size(); sol_local.SetSize(ndofs); sol_ext.GetSubVector(*Dof2PmlDof,sol_local); znew = 0.0; znew.SetSubVector(*Dof2GlobalDof,sol_local); z.SetSubVector(*Dof2GlobalDof,sol_local); z1+=znew; // z = z1; // PlotSolution(z1, subsol_sock1,0); cin.get(); // backward sweep for half space problems Vector z_loc(z.Size()); for (int ip = nrpatch-2; ip >= 0; ip--) { // Get solution from previous layer Array * Dof2GlobalDof = &novlp_prob->Dof2GlobalDof[ip]; Array * Dof2PmlDof = &novlp_prob->Dof2PmlDof[ip]; int ndof = Dof2GlobalDof->Size(); Vector sol_loc(ndof); znew.GetSubVector(* Dof2GlobalDof, sol_loc); // extend by zero to the halfspace pml problem FiniteElementSpace * subfespace = novlp_prob->PmlFespaces[ip]; int mdof = 2*subfespace->GetTrueVSize(); Vector sol_pml(mdof); sol_pml = 0.0; sol_pml.SetSubVector(* Dof2PmlDof, sol_loc); Mesh * submesh = subfespace->GetMesh(); // Set to zero the non boundary dofs Array ess_tdof_list; Array ess_bdr(submesh->bdr_attributes.Max()); ess_bdr = 1; subfespace->GetEssentialTrueDofs(ess_bdr, ess_tdof_list); int n = ess_tdof_list.Size(); for (int i=0; iFESpace(); Mesh * mesh = fespace->GetMesh(); GridFunction gf(fespace); double * data = sol.GetData(); gf.SetData(data); string keys; if (ip == 0) keys = "keys mrRljc\n"; sol_sock << "solution\n" << *mesh << gf << keys << flush; } void STP::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; } STP::~STP() { for (int ip = 0; ip & h_) { int dim = pmin.Size(); Vector h0(dim); Vector h1(dim); for (int i=0; i pmax(i) || x(i) < pmin(i)) { val = 0.0; } else if (x(i) <= pmax(i) && x(i) >= x0(i)) { if(x0(i)-pmax(i) != 0.0) val = (x(i)-pmax(i))/(x0(i)-pmax(i)); } else if (x(i) >= pmin(i) && x(i) <= x1(i)) { if (x1(i)-pmin(i) != 0.0) val = (x(i)-pmin(i))/(x1(i)-pmin(i)); } else { val = 1.0; } f *= val; } return f; }