void HcurlOrthoHP::calc_projection_errors(Element* e, int order, Solution* rsln,
                                   double herr[8][11], double perr[11])
{
  int i, j, k, son, s;
  int m = e->get_mode();
  double error;
  scalar prod;

  if (!obase_ready) calc_ortho_base();

  // select quadrature, obtain integration points and weights
  Quad2D* quad = &g_quad_2d_std;
  quad->set_mode(m);
  rsln->set_quad_2d(quad);
  double3* pt = quad->get_points(20);
  int np = quad->get_num_points(20);

  // everything is done on the reference domain
  // no reference mapping, no transformations
  rsln->enable_transform(false);

  // obtain reference solution values on all four refined sons
  scalar* rval0[4], *rval1[4], *rd1dx[4], *rd0dy[4];
  Element* base = rsln->get_mesh()->get_element(e->id);
  assert(!base->active);
  for (son = 0; son < 4; son++)
  {
    Element* e = base->sons[son];
    assert(e != NULL);
    rsln->set_active_element(e);
    rsln->set_quad_order(20);
    rval0[son] = rsln->get_fn_values(0);
    rval1[son] = rsln->get_fn_values(1);
    rd1dx[son] = rsln->get_dx_values(1);
    rd0dy[son] = rsln->get_dy_values(0);
  }

  // h-candidates: calculate products of the reference solution with orthonormal basis
  // functions on son elements, obtaining (partial) projections and their errors
  scalar proj_0[4][121];
  scalar proj_1[4][121];
  scalar proj_c[4][121];
  for (son = 0; son < 4; son++)
  {
    memset(proj_0[0], 0, sizeof(proj_0[0]));
    memset(proj_1[0], 0, sizeof(proj_1[0]));
    memset(proj_c[0], 0, sizeof(proj_c[0]));

    for (i = 0; i <= order; i++)  // h-candidates: max order equals to original element order
    {
      // update the projection to the current order
      for (j = basecnt[m][i]; j < basecnt[m][i+1]; j++)
      {
        for (k = 0, prod = 0.0; k < np; k++)
        {
          scalar rcurl = (rd1dx[son][k] - rd0dy[son][k]);
          scalar r0 = rval0[son][k];
          scalar r1 = rval1[son][k];
          prod += pt[k][2] * (( r0    * obase_0[m][8][j][k] ) +
                              ( r1    * obase_1[m][8][j][k] ) +
                              ( rcurl * obase_c[m][8][j][k] ) );
        }
        for (k = 0; k < np; k++)
        {
          proj_0[0][k] += obase_0[m][8][j][k] * prod;
          proj_1[0][k] += obase_1[m][8][j][k] * prod;
          proj_c[0][k] += obase_c[m][8][j][k] * prod;
        }
      }

      // calculate the H(curl) error of the projection
      for (k = 0, error = 0.0; k < np; k++)
      {
        scalar rcurl = (rd1dx[son][k] - rd0dy[son][k]);
        scalar r0 = rval0[son][k];
        scalar r1 = rval1[son][k];
        error += pt[k][2] *  ( sqr(r0    - proj_0[0][k]) +
                               sqr(r1    - proj_1[0][k]) +
                               sqr(rcurl - proj_c[0][k]) );
      }
      herr[son][i] = error;
    }
  }

  // aniso-candidates: calculate projections and their errors (only quadrilaterals)
  if (m) {
    const double mx[4] = { 2.0, 2.0, 1.0, 1.0};
    const double my[4] = { 1.0, 1.0, 2.0, 2.0};
    const int sons[4][2] = {{0,1},{3,2},{0,3},{1,2}};
    const int tr[4][2] = {{6,7},{6,7},{4,5},{4,5}};

    for (son = 0; son < 4; son++) // 2 sons for vertical split, 2 sons for horizontal split
    {
      memset(proj_0, 0, sizeof(proj_0));
      memset(proj_1, 0, sizeof(proj_1));
      memset(proj_c, 0, sizeof(proj_c));

      for (i = 0; i <= order+1; i++)  // h-candidates: max order equals to original element order+1
      {
        // update the projection to the current order
        for (j = basecnt[m][i]; j < basecnt[m][i+1]; j++)
        {
          for (s = 0, prod = 0.0; s < 2; s++)  // each son has 2 subsons (regular square sons)
          {
            for (k = 0; k < np; k++)
            {
              scalar rcurl = 2.0 * (rd1dx[sons[son][s]][k] - rd0dy[sons[son][s]][k]);
              scalar r0 = mx[son] * rval0[sons[son][s]][k];
              scalar r1 = my[son] * rval1[sons[son][s]][k];
              prod += pt[k][2] * ((r0    * obase_0[m][tr[son][s]][j][k]) +
                                  (r1    * obase_1[m][tr[son][s]][j][k]) +
                                  (rcurl * obase_c[m][tr[son][s]][j][k]));
            }
          }
          prod *= 0.5;

          for (s = 0; s < 2; s++)
            for (k = 0; k < np; k++)
            {
              proj_0[s][k] += prod * obase_0[m][tr[son][s]][j][k];
              proj_1[s][k] += prod * obase_1[m][tr[son][s]][j][k];
              proj_c[s][k] += prod * obase_c[m][tr[son][s]][j][k];
            }
        }


        // calculate the error of the projection
        for (s = 0, error = 0.0; s < 2; s++)
        {
          for (k = 0; k < np; k++)
          {
            scalar rcurl = 2.0 * (rd1dx[sons[son][s]][k] - rd0dy[sons[son][s]][k]);
            scalar r0 = mx[son] * rval0[sons[son][s]][k];
            scalar r1 = my[son] * rval1[sons[son][s]][k];
            error += pt[k][2] * (sqr(r0    - proj_0[s][k]) +
                                 sqr(r1    - proj_1[s][k]) +
                                 sqr(rcurl - proj_c[s][k]));
          }
        }
        herr[4 + son][i] = error * 0.5;
      }
    }
  }

  // p-candidates: calculate projections and their errors
  memset(proj_0, 0, sizeof(proj_0));
  memset(proj_1, 0, sizeof(proj_1));
  memset(proj_c, 0, sizeof(proj_c));

  for (i = 0; i <= std::min(order+2, 9); i++)  // p-candidate: max order = original order + 2
  {
    // update the projection to the current order
    for (j = basecnt[m][i]; j < basecnt[m][i+1]; j++)
    {
      for (son = 0, prod = 0.0; son < 4; son++)
      {
        // transformations to the quarter of the reference element
        double mm = (e->is_triangle() && son == 3) ? -2.0 : 2.0;

        for (k = 0; k < np; k++)
        {
          scalar rcurl = 4.0 * (rd1dx[son][k] - rd0dy[son][k]);
          scalar r0 = mm * rval0[son][k];
          scalar r1 = mm * rval1[son][k];
          prod += pt[k][2] * ((r0    * obase_0[m][son][j][k]) +
                              (r1    * obase_1[m][son][j][k]) +
                              (rcurl * obase_c[m][son][j][k]));
        }
      }
      prod *= 0.25;

      for (son = 0; son < 4; son++)
        for (k = 0; k < np; k++)
        {
          proj_0[son][k] += prod * obase_0[m][son][j][k];
          proj_1[son][k] += prod * obase_1[m][son][j][k];
          proj_c[son][k] += prod * obase_c[m][son][j][k];
        }
    }


    // calculate the error of the projection
    for (son = 0, error = 0.0; son < 4; son++)
    {
      double mm = (e->is_triangle() && son == 3) ? -2.0 : 2.0;

      for (k = 0; k < np; k++)
      {
        scalar rcurl = 4.0 * (rd1dx[son][k] - rd0dy[son][k]);
        scalar r0 = mm * rval0[son][k];
        scalar r1 = mm * rval1[son][k];
        error += pt[k][2] * (sqr(r0    - proj_0[son][k]) +
                             sqr(r1    - proj_1[son][k]) +
                             sqr(rcurl - proj_c[son][k]));
      }
    }
    perr[i] = error * 0.25;
  }
}
Beispiel #2
0
void L2OrthoHP::calc_projection_errors(Element* e, int order, Solution* rsln,
                                       double herr[8][11], double perr[11])
{
  int i, j, s, k, r, son;
  int m = e->get_mode();
  double error;
  Scalar prod;

  if (!obase_ready) calc_ortho_base();

  // select quadrature, obtain integration points and weights
  Quad2D* quad = &g_quad_2d_std;
  quad->set_mode(m);
  rsln->set_quad_2d(quad);
  double3* pt = quad->get_points(20);
  int np = quad->get_num_points(20);

  // everything is done on the reference domain
  // -- no reference mapping, no transformations
  rsln->enable_transform(false);

  // obtain reference solution values on all four refined sons
  Scalar* rval[4][3];
  Element* base = rsln->get_mesh()->get_element(e->id);
  assert(!base->active);
  for (son = 0; son < 4; son++)
  {
    Element* e = base->sons[son];
    assert(e != NULL);
    rsln->set_active_element(e);
    rsln->set_quad_order(20);
    rval[son][0] = rsln->get_fn_values();
    rval[son][1] = rsln->get_dx_values();
    rval[son][2] = rsln->get_dy_values();
  }

  // h-cadidates: calculate products of the reference solution with orthonormal basis
  // functions on son elements, obtaining (partial) projections and their errors
  Scalar3 proj[4][121];
  for (son = 0; son < 4; son++)
  {
    memset(proj[0], 0, sizeof(proj[0]));
    for (i = 1; i <= order; i++)
    {
      // update the projection to the current order
      for (j = basecnt[m][i-1]; j < basecnt[m][i]; j++)
      {
        for (k = 0, prod = 0.0; k < np; k++)
          prod += pt[k][2] * (rval[son][0][k] * obase[m][8][j][k][0]);

        for (k = 0; k < np; k++)
          for (r = 0; r < 3; r++)
            proj[0][k][r] += obase[m][8][j][k][r] * prod;
      }

      // calculate the error of the projection
      for (k = 0, error = 0.0; k < np; k++)
        error += pt[k][2] * (sqr(rval[son][0][k] - proj[0][k][0]));
      herr[son][i] = error;
    }
  }

  // aniso-candidates: calculate projections and their errors (only quadrilaterals)
  if (m)
  {
    const double mx[4] = { 2.0, 2.0, 1.0, 1.0};
    const double my[4] = { 1.0, 1.0, 2.0, 2.0};
    const int sons[4][2] = { {0,1}, {3,2}, {0,3}, {1,2} };
    const int tr[4][2]   = { {6,7}, {6,7}, {4,5}, {4,5} };

    for (son = 0; son < 4; son++) // 2 sons for vertical split, 2 sons for horizontal split
    {
      memset(proj, 0, sizeof(proj));
      for (i = 1; i <= order+1; i++)  // h-candidates: max order equals to original element order+1
      {
        // update the projection to the current order
        for (j = basecnt[m][i-1]; j < basecnt[m][i]; j++)
        {
          for (s = 0, prod = 0.0; s < 2; s++) // each son has 2 subsons (regular square sons)
            for (k = 0; k < np; k++)
              prod += pt[k][2] * rval[sons[son][s]][0][k] * obase[m][tr[son][s]][j][k][0];
          prod *= 0.5;

          for (s = 0; s < 2; s++)
            for (k = 0; k < np; k++)
              for (r = 0; r < 1; r++)
                proj[s][k][r] += prod * obase[m][tr[son][s]][j][k][r];
        }

        // calculate the error of the projection
        for (s = 0, error = 0.0; s < 2; s++)
          for (k = 0; k < np; k++)
            error += pt[k][2] * sqr(rval[sons[son][s]][0][k] - proj[s][k][0]);
        herr[4 + son][i] = error * 0.5;
      }
    }
  }

  // p-candidates: calculate projections and their errors
  memset(proj, 0, sizeof(proj));
  for (i = 1; i <= std::min(order+2, 10); i++)
  {
    // update the projection to the current order
    for (j = basecnt[m][i-1]; j < basecnt[m][i]; j++)
    {
      for (son = 0, prod = 0.0; son < 4; son++)
      {
        // (transforming to the quarter of the reference element)
        double mm = (e->is_triangle() && son == 3) ? -2.0 : 2.0;

        for (k = 0; k < np; k++)
        {
          prod += pt[k][2] * rval[son][0][k] * obase[m][son][j][k][0];
        }
      }
      prod *= 0.25;

      for (son = 0; son < 4; son++)
        for (k = 0; k < np; k++)
          for (r = 0; r < 1; r++)
            proj[son][k][r] += prod * obase[m][son][j][k][r];
    }

    // calculate the error of the projection
    for (son = 0, error = 0.0; son < 4; son++)
    {
      double mm = (e->is_triangle() && son == 3) ? -2.0 : 2.0;

      for (k = 0; k < np; k++)
        error += pt[k][2] * sqr(rval[son][0][k] - proj[son][k][0]);
    }
    perr[i] = error * 0.25;
  }
}