void VoltaSolver::Solve() { if (myid_ == 0) { cout << "Running solver ... " << endl << flush; } // Initialize the electric potential with its boundary conditions *phi_ = 0.0; if ( dbcs_->Size() > 0 ) { if ( phiBCCoef_ ) { // Apply gradient boundary condition phi_->ProjectBdrCoefficient(*phiBCCoef_, ess_bdr_); } else { // Apply piecewise constant boundary condition Array<int> dbc_bdr_attr(pmesh_->bdr_attributes.Max()); for (int i=0; i<dbcs_->Size(); i++) { ConstantCoefficient voltage((*dbcv_)[i]); dbc_bdr_attr = 0; dbc_bdr_attr[(*dbcs_)[i]-1] = 1; phi_->ProjectBdrCoefficient(voltage, dbc_bdr_attr); } } } // Initialize the RHS vector HypreParVector *RHS = new HypreParVector(H1FESpace_); *RHS = 0.0; // Initialize the volumetric charge density if ( rho_ ) { rho_->ProjectCoefficient(*rhoCoef_); HypreParMatrix *MassH1 = h1Mass_->ParallelAssemble(); HypreParVector *Rho = rho_->ParallelProject(); MassH1->Mult(*Rho,*RHS); delete MassH1; delete Rho; } // Initialize the Polarization HypreParVector *P = NULL; if ( p_ ) { p_->ProjectCoefficient(*pCoef_); P = p_->ParallelProject(); HypreParMatrix *MassHCurl = hCurlMass_->ParallelAssemble(); HypreParVector *PD = new HypreParVector(HCurlFESpace_); MassHCurl->Mult(*P,*PD); Grad_->MultTranspose(*PD,*RHS,-1.0,1.0); delete MassHCurl; delete PD; } // Initialize the surface charge density if ( sigma_ ) { *sigma_ = 0.0; Array<int> nbc_bdr_attr(pmesh_->bdr_attributes.Max()); for (int i=0; i<nbcs_->Size(); i++) { ConstantCoefficient sigma_coef((*nbcv_)[i]); nbc_bdr_attr = 0; nbc_bdr_attr[(*nbcs_)[i]-1] = 1; sigma_->ProjectBdrCoefficient(sigma_coef, nbc_bdr_attr); } HypreParMatrix *MassS = h1SurfMass_->ParallelAssemble(); HypreParVector *Sigma = sigma_->ParallelProject(); MassS->Mult(*Sigma,*RHS,1.0,1.0); delete MassS; delete Sigma; } // Apply Dirichlet BCs to matrix and right hand side HypreParMatrix *DivEpsGrad = divEpsGrad_->ParallelAssemble(); HypreParVector *Phi = phi_->ParallelProject(); // Apply the boundary conditions to the assembled matrix and vectors if ( dbcs_->Size() > 0 ) { // According to the selected surfaces divEpsGrad_->ParallelEliminateEssentialBC(ess_bdr_, *DivEpsGrad, *Phi, *RHS); } else { // No surfaces were labeled as Dirichlet so eliminate one DoF Array<int> dof_list(0); if ( myid_ == 0 ) { dof_list.SetSize(1); dof_list[0] = 0; } DivEpsGrad->EliminateRowsCols(dof_list, *Phi, *RHS); } // Define and apply a parallel PCG solver for AX=B with the AMG // preconditioner from hypre. HypreSolver *amg = new HypreBoomerAMG(*DivEpsGrad); HyprePCG *pcg = new HyprePCG(*DivEpsGrad); pcg->SetTol(1e-12); pcg->SetMaxIter(500); pcg->SetPrintLevel(2); pcg->SetPreconditioner(*amg); pcg->Mult(*RHS, *Phi); delete amg; delete pcg; delete DivEpsGrad; delete RHS; // Extract the parallel grid function corresponding to the finite // element approximation Phi. This is the local solution on each // processor. *phi_ = *Phi; // Compute the negative Gradient of the solution vector. This is // the magnetic field corresponding to the scalar potential // represented by phi. HypreParVector *E = new HypreParVector(HCurlFESpace_); Grad_->Mult(*Phi,*E,-1.0); *e_ = *E; delete Phi; // Compute electric displacement (D) from E and P if (myid_ == 0) { cout << "Computing D ... " << flush; } HypreParMatrix *HCurlHDivEps = hCurlHDivEps_->ParallelAssemble(); HypreParVector *ED = new HypreParVector(HDivFESpace_); HypreParVector *D = new HypreParVector(HDivFESpace_); HCurlHDivEps->Mult(*E,*ED); if ( P ) { HypreParMatrix *HCurlHDiv = hCurlHDiv_->ParallelAssemble(); HCurlHDiv->Mult(*P,*ED,-1.0,1.0); delete HCurlHDiv; } HypreParMatrix * MassHDiv = hDivMass_->ParallelAssemble(); HyprePCG * pcgM = new HyprePCG(*MassHDiv); pcgM->SetTol(1e-12); pcgM->SetMaxIter(500); pcgM->SetPrintLevel(0); HypreDiagScale *diagM = new HypreDiagScale; pcgM->SetPreconditioner(*diagM); pcgM->Mult(*ED,*D); *d_ = *D; if (myid_ == 0) { cout << "done." << flush; } delete diagM; delete pcgM; delete HCurlHDivEps; delete MassHDiv; delete E; delete ED; delete D; delete P; if (myid_ == 0) { cout << " Solver done. " << flush; } }
void TeslaSolver::Solve() { if (myid_ == 0) { cout << "Running solver ... " << endl << flush; } // Initialize the magnetic vector potential with its boundary conditions *a_ = 0.0; // Apply surface currents if available if ( k_ ) { SurfCur_->ComputeSurfaceCurrent(*k_); *a_ = *k_; } // Apply uniform B boundary condition on remaining surfaces a_->ProjectBdrCoefficientTangent(*aBCCoef_, non_k_bdr_); // Initialize the RHS vector HypreParVector *RHS = new HypreParVector(HCurlFESpace_); *RHS = 0.0; HypreParMatrix *MassHCurl = hCurlMass_->ParallelAssemble(); // Initialize the volumetric current density if ( j_ ) { j_->ProjectCoefficient(*jCoef_); HypreParVector *J = j_->ParallelProject(); HypreParVector *JD = new HypreParVector(HCurlFESpace_); MassHCurl->Mult(*J,*JD); DivFreeProj_->Mult(*JD, *RHS); delete J; delete JD; } // Initialize the Magnetization HypreParVector *M = NULL; if ( m_ ) { m_->ProjectCoefficient(*mCoef_); M = m_->ParallelProject(); HypreParMatrix *MassHDiv = hDivMassMuInv_->ParallelAssemble(); HypreParVector *MD = new HypreParVector(HDivFESpace_); MassHDiv->Mult(*M,*MD); Curl_->MultTranspose(*MD,*RHS,mu0_,1.0); delete MassHDiv; delete MD; } // Apply Dirichlet BCs to matrix and right hand side HypreParMatrix *CurlMuInvCurl = curlMuInvCurl_->ParallelAssemble(); HypreParVector *A = a_->ParallelProject(); // Apply the boundary conditions to the assembled matrix and vectors curlMuInvCurl_->ParallelEliminateEssentialBC(ess_bdr_, *CurlMuInvCurl, *A, *RHS); // Define and apply a parallel PCG solver for AX=B with the AMS // preconditioner from hypre. HypreAMS *ams = new HypreAMS(*CurlMuInvCurl, HCurlFESpace_); ams->SetSingularProblem(); HyprePCG *pcg = new HyprePCG(*CurlMuInvCurl); pcg->SetTol(1e-12); pcg->SetMaxIter(500); pcg->SetPrintLevel(2); pcg->SetPreconditioner(*ams); pcg->Mult(*RHS, *A); delete ams; delete pcg; delete CurlMuInvCurl; delete RHS; // Extract the parallel grid function corresponding to the finite // element approximation Phi. This is the local solution on each // processor. *a_ = *A; // Compute the negative Gradient of the solution vector. This is // the magnetic field corresponding to the scalar potential // represented by phi. HypreParVector *B = new HypreParVector(HDivFESpace_); Curl_->Mult(*A,*B); *b_ = *B; // Compute magnetic field (H) from B and M if (myid_ == 0) { cout << "Computing H ... " << flush; } HypreParMatrix *HDivHCurlMuInv = hDivHCurlMuInv_->ParallelAssemble(); HypreParVector *BD = new HypreParVector(HCurlFESpace_); HypreParVector *H = new HypreParVector(HCurlFESpace_); HDivHCurlMuInv->Mult(*B,*BD); if ( M ) { HDivHCurlMuInv->Mult(*M,*BD,-1.0*mu0_,1.0); } HyprePCG * pcgM = new HyprePCG(*MassHCurl); pcgM->SetTol(1e-12); pcgM->SetMaxIter(500); pcgM->SetPrintLevel(0); HypreDiagScale *diagM = new HypreDiagScale; pcgM->SetPreconditioner(*diagM); pcgM->Mult(*BD,*H); *h_ = *H; if (myid_ == 0) { cout << "done." << flush; } delete diagM; delete pcgM; delete HDivHCurlMuInv; delete MassHCurl; delete A; delete B; delete BD; delete H; delete M; if (myid_ == 0) { cout << " Solver done. " << flush; } }