Skip to content
Snippets Groups Projects
RecoveryEstimator.cc 5.93 KiB
#include "RecoveryEstimator.h"
#include "Parameters.h"

RecoveryEstimator::RecoveryEstimator(std::string name, DOFVector<double> *uh, int r) 
  : Estimator(name, r), 
    uh_(uh), 
    relative_(0), 
    C(1.0), 
    method(0),
    feSpace(NULL), 
    f_vec(NULL), 
    f_scal(NULL), 
    aux_vec(NULL), 
    rec_struct(NULL)
{
  FUNCNAME("RecoveryEstimator::constructor()");

  GET_PARAMETER(0, name + "->rec method", "%d", &method);
  GET_PARAMETER(0, name + "->rel error", "%d", &relative_);

  GET_PARAMETER(0, name + "->C", "%f", &C);
  C = C > 1e-25 ? sqr(C) : 1.0;

  if (norm == H1_NORM) {
    feSpace = uh->getFESpace();
    degree  = feSpace->getBasisFcts()->getDegree();

    if ((degree <= 2) && (C != 1.0)) {
      WARNING("Recovery estimators in the H1_NORM usually very good for linear and quadratic finite element; normally you do not need to overwrite the default value of C\n");
      WAIT;
    }
  }
  else {
    degree  = uh->getFESpace()->getBasisFcts()->getDegree() + 1;
    
    feSpace = FiniteElemSpace::provideFESpace(NULL,
					      Lagrange::getLagrange(uh->getFESpace()->getMesh()->getDim(), degree),
					      uh->getFESpace()->getMesh(),
					      name + "->feSpace");


    if (method == 2) {
      ERROR("Simple averaging only for the H1_NORM; using SPR instead\n");
      WAIT;
      method = 0;
    }
  }

  if ((method == 2) && (degree !=1)) {
    ERROR("Simple averaging only for linear elements; using SPR instead\n");
    WAIT;
    method = 0;
  }

  rec_struct = new Recovery(norm, method);
}

double RecoveryEstimator::estimate(double timestep)
{
  FUNCNAME("RecoveryEstimator::estimate()");

  const BasisFunction *basFcts = uh_->getFESpace()->getBasisFcts();
  Mesh                *mesh    = uh_->getFESpace()->getMesh();
  int                  dim     = mesh->getDim();
  int                  dow     = Global::getGeo(WORLD);
  double               h1Norm2 = 0.0;
  Flag                 flag    =
    Mesh::CALL_LEAF_EL | Mesh::FILL_COORDS | Mesh::FILL_DET | Mesh::FILL_GRD_LAMBDA;
  TraverseStack        stack;
  ElInfo              *elInfo  = NULL;

  int    i, j;
  double det, estEl, errEl, normEl;
  Element *el = NULL;

  if (norm == H1_NORM)     // sets recovery gradient.
    {
      if (method == 2)
	rec_grd   = rec_struct->recovery(uh_, f_vec, f_scal, aux_vec);
      else
	rec_grd   = rec_struct->recovery(uh_, feSpace, f_vec, f_scal, aux_vec);
      rec_basFcts = rec_grd->getFESpace()->getBasisFcts();
    }
  else                     // sets higher-order recovery solution.
    {
      rec_uh      = rec_struct->recoveryUh(uh_, feSpace);
      rec_basFcts = rec_uh->getFESpace()->getBasisFcts();
    }

  int          deg = 2 * std::max(basFcts->getDegree(),
				    rec_basFcts->getDegree());
  Quadrature *quad = Quadrature::provideQuadrature(dim, deg);
  int    numPoints = quad->getNumPoints();

  WorldVector<double> quad_pt;
  WorldVector<double> *grdAtQP = new WorldVector<double>[numPoints];
  WorldVector<double> *recoveryGrdAtQP = new WorldVector<double>[numPoints];

  double *uhAtQP = new double[numPoints];
  double *recoveryUhAtQP = new double[numPoints];

  FastQuadrature *quadFast =
    FastQuadrature::provideFastQuadrature(basFcts, *quad,
					  INIT_PHI | INIT_GRD_PHI);
  FastQuadrature *rec_quadFast =
    FastQuadrature::provideFastQuadrature(rec_basFcts, *quad,
					  INIT_PHI | INIT_GRD_PHI);

  // clear error indicators
  elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
  while (elInfo)
    {
      elInfo->getElement()->setEstimation(0.0, row);
      elInfo = stack.traverseNext(elInfo);
    }

  // traverse mesh
  est_sum = est_max = est_t_sum = 0.0;

  elInfo = stack.traverseFirst(mesh, -1, flag);
  while (elInfo)
    {
      el    = elInfo->getElement();
      det   = elInfo->getDet();
      errEl = 0.0;

      if (norm == H1_NORM)
	{
	  // get gradient and recovery gradient at quadrature points
	  uh_->getGrdAtQPs(elInfo, NULL, quadFast, grdAtQP);
	  rec_grd->getVecAtQPs(elInfo, NULL, rec_quadFast, recoveryGrdAtQP);
	  if (f_scal)
	    {
	      if (aux_vec)
		aux_vec->getVecAtQPs(elInfo, NULL, quadFast, uhAtQP);
	      else
		uh_->getVecAtQPs(elInfo, NULL, quadFast, uhAtQP);
	    }

	  // calc h1 error
	  for (i=0; i<numPoints; i++)
	    {
	      double  err2 = 0.0;
	      double fAtQP = 1.0;
	      if (f_scal)
		fAtQP = (*f_scal)(uhAtQP[i]);
	      if (f_vec)
		{
		  elInfo->coordToWorld(quad->getLambda(i), quad_pt);
		  fAtQP = (*f_vec)(quad_pt);
		}

	      for (j=0; j<dow; j++)
		err2 += sqr(recoveryGrdAtQP[i][j] - fAtQP * grdAtQP[i][j]);
	      errEl += quad->getWeight(i) * err2;
	    }
	}
      else
	{
	  // get vector and recovery vector at quadrature points
	  uh_->getVecAtQPs(elInfo, NULL, quadFast, uhAtQP);
	  rec_uh->getVecAtQPs(elInfo, NULL, rec_quadFast, recoveryUhAtQP);

	  // calc l2 error
	  for (i=0; i<numPoints; i++)
	    errEl += quad->getWeight(i) * sqr(recoveryUhAtQP[i] - uhAtQP[i]);
	}

      estEl = C * det * errEl;
      el->setEstimation(estEl, row);
      est_sum += estEl;
      est_max = std::max(est_max, estEl);

      if (relative_)
	{
	  normEl = 0.0;

	  if (norm == H1_NORM)
	    for (i=0; i<numPoints; i++)
	      {
		double norm2 = 0.0;
		for (j = 0; j < dow; j++)
		  norm2 += sqr(recoveryGrdAtQP[i][j]);
		normEl += quad->getWeight(i) * norm2;
	      }
	  else
	    for (i=0; i<numPoints; i++)
	      normEl += quad->getWeight(i) * sqr(recoveryUhAtQP[i]);

	  h1Norm2 += det * normEl;
	}

      elInfo = stack.traverseNext(elInfo);
    }

  // Computing relative errors
  if (relative_)
    {
      elInfo = stack.traverseFirst(mesh, -1, Mesh::CALL_LEAF_EL);
      while (elInfo)
	{
	  estEl  = elInfo->getElement()->getEstimation(row);
	  estEl /= h1Norm2;
	  elInfo->getElement()->setEstimation(estEl, row);
	  elInfo = stack.traverseNext(elInfo);
	}

      est_max /= h1Norm2;
      est_sum /= h1Norm2;
    }

  est_sum = sqrt(est_sum);

  MSG("estimate   = %.8e\n", est_sum);

  delete [] grdAtQP;
  delete [] recoveryGrdAtQP;
  delete [] uhAtQP;
  delete [] recoveryUhAtQP;

  return(est_sum);
}