#include "convergence.hpp" using namespace std; namespace mfem { void ConvergenceStudy::Reset() { counter=0; dcounter=0; fcounter=0; cont_type=-1; print_flag=1; L2Errors.SetSize(0); L2Rates.SetSize(0); DErrors.SetSize(0); DRates.SetSize(0); EnErrors.SetSize(0); EnRates.SetSize(0); DGFaceErrors.SetSize(0); DGFaceRates.SetSize(0); ndofs.SetSize(0); } double ConvergenceStudy::GetNorm(GridFunction *gf, Coefficient *scalar_u, VectorCoefficient *vector_u) { bool norm_set = false; double norm=0.0; int order = gf->FESpace()->GetMaxElementOrder(); int order_quad = std::max(2, 2*order+1); const IntegrationRule *irs[Geometry::NumGeom]; for (int i=0; i < Geometry::NumGeom; ++i) { irs[i] = &(IntRules.Get(i, order_quad)); } #ifdef MFEM_USE_MPI ParGridFunction *pgf = dynamic_cast(gf); if (pgf) { ParMesh *pmesh = pgf->ParFESpace()->GetParMesh(); if (scalar_u) { norm = ComputeGlobalLpNorm(2.0,*scalar_u,*pmesh,irs); } else if (vector_u) { norm = ComputeGlobalLpNorm(2.0,*vector_u,*pmesh,irs); } norm_set = true; } #endif if (!norm_set) { Mesh *mesh = gf->FESpace()->GetMesh(); if (scalar_u) { norm = ComputeLpNorm(2.0,*scalar_u,*mesh,irs); } else if (vector_u) { norm = ComputeLpNorm(2.0,*vector_u,*mesh,irs); } } return norm; } void ConvergenceStudy::AddL2Error(GridFunction *gf, Coefficient *scalar_u, VectorCoefficient *vector_u) { int tdofs=0; int dim = gf->FESpace()->GetMesh()->Dimension(); #ifdef MFEM_USE_MPI ParGridFunction *pgf = dynamic_cast(gf); if (pgf) { MPI_Comm comm = pgf->ParFESpace()->GetComm(); int rank; MPI_Comm_rank(comm, &rank); print_flag = 0; if (rank==0) { print_flag = 1; } tdofs = pgf->ParFESpace()->GlobalTrueVSize(); } #endif if (!tdofs) { tdofs = gf->FESpace()->GetTrueVSize(); } ndofs.Append(tdofs); double L2Err = 1.; if (scalar_u) { L2Err = gf->ComputeL2Error(*scalar_u); CoeffNorm = GetNorm(gf,scalar_u,nullptr); } else if (vector_u) { L2Err = gf->ComputeL2Error(*vector_u); CoeffNorm = GetNorm(gf,nullptr,vector_u); } else { MFEM_ABORT("Exact Solution Coefficient pointer is NULL"); } L2Errors.Append(L2Err); // Compute the rate of convergence by: // rate = log (||u - u_h|| / ||u - u_{h/2}||)/(1/dim * log(N_{h/2}/N_{h})) double val=0.; if (counter) { double num = log(L2Errors[counter-1]/L2Err); double den = log((double)ndofs[counter]/ndofs[counter-1]); val = dim * num/den; } L2Rates.Append(val); counter++; } void ConvergenceStudy::AddGf(GridFunction *gf, Coefficient *scalar_u, VectorCoefficient *grad, Coefficient *ell_coeff, JumpScaling jump_scaling) { cont_type = gf->FESpace()->FEColl()->GetContType(); MFEM_VERIFY((cont_type == mfem::FiniteElementCollection::CONTINUOUS) || (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS), "This constructor is intended for H1 or L2 Elements") AddL2Error(gf,scalar_u, nullptr); int dim = gf->FESpace()->GetMesh()->Dimension(); if (grad) { double GradErr = gf->ComputeGradError(grad); DErrors.Append(GradErr); double error = sqrt(L2Errors[counter-1]*L2Errors[counter-1]+GradErr*GradErr); EnErrors.Append(error); // Compute the rate of convergence by: // rate = log (||u - u_h|| / ||u - u_{h/2}||)/(1/dim * log(N_{h/2}/N_{h})) double val = 0.; double eval = 0.; if (dcounter) { double num = log(DErrors[dcounter-1]/GradErr); double den = log((double)ndofs[dcounter]/ndofs[dcounter-1]); val = dim * num/den; num = log(EnErrors[dcounter-1]/error); eval = dim * num/den; } DRates.Append(val); EnRates.Append(eval); CoeffDNorm = GetNorm(gf,nullptr,grad); dcounter++; MFEM_VERIFY(counter == dcounter, "Number of added solutions and derivatives do not match") } if (cont_type == mfem::FiniteElementCollection::DISCONTINUOUS && ell_coeff) { double DGErr = gf->ComputeDGFaceJumpError(scalar_u,ell_coeff,jump_scaling); DGFaceErrors.Append(DGErr); // Compute the rate of convergence by: // rate = log (||u - u_h|| / ||u - u_{h/2}||)/(1/dim * log(N_{h/2}/N_{h})) double val = 0.; if (fcounter) { double num = log(DGFaceErrors[fcounter-1]/DGErr); double den = log((double)ndofs[fcounter]/ndofs[fcounter-1]); val = dim * num/den; } DGFaceRates.Append(val); fcounter++; MFEM_VERIFY(fcounter == counter, "Number of added solutions mismatch"); } } void ConvergenceStudy::AddGf(GridFunction *gf, VectorCoefficient *vector_u, VectorCoefficient *curl, Coefficient *div) { cont_type = gf->FESpace()->FEColl()->GetContType(); AddL2Error(gf,nullptr,vector_u); int dim = gf->FESpace()->GetMesh()->Dimension(); double DErr = 0.0; bool derivative = false; if (curl) { DErr = gf->ComputeCurlError(curl); CoeffDNorm = GetNorm(gf,nullptr,curl); derivative = true; } else if (div) { DErr = gf->ComputeDivError(div); // update coefficient norm CoeffDNorm = GetNorm(gf,div,nullptr); derivative = true; } if (derivative) { double error = sqrt(L2Errors[counter-1]*L2Errors[counter-1] + DErr*DErr); DErrors.Append(DErr); EnErrors.Append(error); // Compute the rate of convergence by: // rate = log (||u - u_h|| / ||u - u_{h/2}||)/(1/dim * log(N_{h/2}/N_{h})) double val = 0.; double eval = 0.; if (dcounter) { double num = log(DErrors[dcounter-1]/DErr); double den = log((double)ndofs[dcounter]/ndofs[dcounter-1]); val = dim * num/den; num = log(EnErrors[dcounter-1]/error); eval = dim * num/den; } DRates.Append(val); EnRates.Append(eval); dcounter++; MFEM_VERIFY(counter == dcounter, "Number of added solutions and derivatives do not match") } } void ConvergenceStudy::Print(bool relative, std::ostream &os) { if (print_flag) { std::string title = (relative) ? "Relative " : "Absolute "; os << "\n"; os << " -------------------------------------------" << "\n"; os << std::setw(21) << title << "L2 Error " << "\n"; os << " -------------------------------------------" << "\n"; os << std::right<< std::setw(11)<< "DOFs "<< std::setw(13) << "Error "; os << std::setw(15) << "Rate " << "\n"; os << " -------------------------------------------" << "\n"; os << std::setprecision(4); double d = (relative) ? CoeffNorm : 1.0; for (int i =0; i