Exemple #1
0
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; }
}
Exemple #2
0
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; }
}