void HcurlOrthoHP::get_optimal_refinement(Element* e, int order, Solution* rsln, int& split, int p[4],
                                          bool h_only, bool iso_only, int max_order)
{
  int i, j, k, n = 0;
  const int maxcand = 300;

  order = std::max(get_h_order(order), get_v_order(order));
  bool tri = e->is_triangle();

  // calculate maximal order of elements
  // linear elements = 6
  // curvilinear elements = depends on iro_cache (how curved they are)
  if (max_order == -1)
    max_order = std::min(6, (20 - e->iro_cache)/2 - 1); // default
  else
    max_order = std::min(max_order, (20 - e->iro_cache)/2 - 1); // user specified

  struct Cand
  {
    double error;
    int dofs, p[4];
    int split;
  };
  Cand cand[maxcand];

  #define make_p_cand(q) { \
    assert(n < maxcand);   \
    cand[n].split = -1; \
    cand[n].p[1] = cand[n].p[2] = cand[n].p[3] = 0; \
    cand[n++].p[0] = (q); }

  #define make_hp_cand(q0, q1, q2, q3) { \
    assert(n < maxcand);  \
    cand[n].split = 0; \
    cand[n].p[0] = (q0); \
    cand[n].p[1] = (q1); \
    cand[n].p[2] = (q2); \
    cand[n++].p[3] = (q3); }

  #define make_ani_cand(q0, q1, iso) { \
    assert(n < maxcand);  \
    cand[n].split = iso; \
    cand[n].p[2] = cand[n].p[3] = 0; \
    cand[n].p[0] = (q0); \
    cand[n++].p[1] = (q1); }\

  int first_hp;
  if (h_only)
  {
    make_p_cand(order);
    make_hp_cand(order, order, order, order);
    if ((!tri) && (!iso_only))
    {
      make_ani_cand(order, order, 1);
      make_ani_cand(order, order, 2);
    }
  }
  else {
    // prepare p-candidates
    int p0, p1 = std::min(max_order, order+2);
    for (p0 = order; p0 <= p1; p0++)
      make_p_cand(p0);

    // prepare hp-candidates
    first_hp = n;
    p0 = std::max(1, (order-1)/ 2);
    p1 = std::min(p0 + 2, order);
    int q0, q1, q2, q3;
    for (q0 = p0; q0 <= p1; q0++)
      for (q1 = p0; q1 <= p1; q1++)
        for (q2 = p0; q2 <= p1; q2++)
          for (q3 = p0; q3 <= p1; q3++)
            make_hp_cand(q0,q1,q2,q3);

    // anisotropic candidates
    // only for quadrilaterals
    // too distorted (curved) elements cannot have aniso refinement (produces even worse elements)
    if ((!tri) && (e->iro_cache < 8) && !iso_only) {
      p0 = std::max(1, 2 * (order) / 3);
      int p_max = std::min(max_order, order+1);
      p1 = std::min(p0 + 3, p_max);
      for (q0 = p0; q0 <= p1; q0++)
        for (q1 = p0; q1 <= p1; q1++) {
          if ((q0 < order+1) || (q1 < order+1)) {
            make_ani_cand(q0, q1, 1);
            make_ani_cand(q0, q1, 2);
          }
        }
    }
  }
  // calculate (partial) projection errors
  double herr[8][11], perr[11];
  calc_projection_errors(e, order, rsln, herr, perr);

  // evaluate candidates (sum partial projection errors, calculate dofs)
  double avg = 0.0;
  double dev = 0.0;
  double dev1 = 0.0;
  for (i = k = 0; i < n; i++)
  {
    Cand* c = cand + i;
    if (c->split == 0)  // isotropic split
    {
      c->error = 0.0;
      c->dofs = 0;
      for (j = 0; j < 4; j++)
      {
        c->error += herr[j][c->p[j]];// * 0.25;
        if (tri)
        {
          if (j < 3) {
            c->dofs += sqr(c->p[j] + 1); // num of bubble and bnd edges
            c->dofs += std::min(c->p[j], c->p[3]) + 1; // internal edge dofs
          }
          else
            c->dofs += 3 * (c->p[j] - 1) + (c->p[j] - 1) * (c->p[j] - 2);
        }
        else
        {
          c->dofs += 2 * sqr(c->p[j] + 1); // number of bubble and boundary edges
          c->dofs += std::min(c->p[j], c->p[j>0 ? j-1 : 3]) + 1; // number of internal edges in element
        }
      }
    }
    else if ((c->split == 1) || (c->split == 2))  // aniso splits
    {
      c->error = 0.0;
      c->dofs = 0;
      for (j = 0; j < 2 ; j++) {
        c->error += herr[ (c->split == 1) ? j+4 : j+6 ][c->p[j]];// * 0.5;
        c->dofs += 3 * (c->p[j] + 1) + 2 * c->p[j] * (c->p[j] + 1);
      }
      c->dofs += std::min(c->p[0], c->p[1]) + 1;
    }
    else // p-candidate
    {
      c->error = perr[c->p[0]];
      if (tri)
        c->dofs = (c->p[0] + 1) * (c->p[0] + 2);
      else
        c->dofs = 2 * (c->p[0] + 1) * (c->p[0] + 2); // number of bubble and boundary edges
    }
    c->error = sqrt(c->error);

     //verbose("Cand #%d: Orders %d %d %d %d, Error %g, Dofs %d", i, c->p[0],c->p[1],c->p[2],c->p[3],c->error, c->dofs);

    if (!i || c->error <= cand[0].error)
    {
      avg += log10(c->error);
      dev += sqr(log10(c->error));
      k++;
    }
  }
  avg /= k;  // mean
  dev /= k;  // second moment
  dev = sqrt(dev - sqr(avg));  // deviation is square root of variance

  // select an above-average candidate with the steepest error decrease
  int imax = 0;
  double score, maxscore = 0.0;
  for (i = 1; i < n; i++)
  {
    if ((log10(cand[i].error) < avg + dev) && (cand[i].dofs > cand[0].dofs))
    {
      score = (log10(cand[0].error) - log10(cand[i].error)) / (cand[i].dofs - cand[0].dofs);
      if (score > maxscore) { maxscore = score; imax = i; }
    }
  }
  if (imax == 0) imax = first_hp;

  // return result
  split = cand[imax].split;
  memcpy(p, cand[imax].p, 4*sizeof(int));

}
Example #2
0
void L2OrthoHP::get_optimal_refinement(Element* e, int order, Solution* rsln, int& split, int p[4],
                                       bool h_only, bool iso_only, double conv_exp, int max_order)

{
  int i, j, k, n = 0;
  const int maxcand = 300;

  order = std::max(H2D_GET_H_ORDER(order), H2D_GET_V_ORDER(order));
  bool tri = e->is_triangle();

  // calculate maximal order of elements
  // linear elements = 9
  // curvilinear elements = depends on iro_cache (how curved they are)
  if (max_order == -1)
    max_order = (20 - e->iro_cache)/2 - 2; // default
  else
    max_order = std::min( max_order, (20 - e->iro_cache)/2 - 2); // user specified

  Cand* cand = new Cand[maxcand];

  #define make_p_cand(q) { \
    assert(n < maxcand);   \
    cand[n].split = -1; \
    cand[n].p[1] = cand[n].p[2] = cand[n].p[3] = 0; \
    cand[n++].p[0] = (q); }

  #define make_hp_cand(q0, q1, q2, q3) { \
    assert(n < maxcand);  \
    cand[n].split = 0; \
    cand[n].p[0] = (q0); \
    cand[n].p[1] = (q1); \
    cand[n].p[2] = (q2); \
    cand[n++].p[3] = (q3); }

  #define make_ani_cand(q0, q1, iso) { \
    assert(n < maxcand);  \
    cand[n].split = iso; \
    cand[n].p[2] = cand[n].p[3] = 0; \
    cand[n].p[0] = (q0); \
    cand[n++].p[1] = (q1); }\


  if (h_only)
  {
    make_p_cand(order);
    make_hp_cand(order, order, order, order);
    make_ani_cand(order, order, 1);
    make_ani_cand(order, order, 2);
  }
  else
  {
    // prepare p-candidates
    int p0, p1 = std::min(max_order, order+1);
    for (p0 = order; p0 <= p1; p0++)
      make_p_cand(p0);

    // prepare hp-candidates
    p0 = (order+1) / 2;
    p1 = std::min(p0 + 3, order);
    int q0, q1, q2, q3;
    for (q0 = p0; q0 <= p1; q0++)
      for (q1 = p0; q1 <= p1; q1++)
        for (q2 = p0; q2 <= p1; q2++)
          for (q3 = p0; q3 <= p1; q3++)
            make_hp_cand(q0, q1, q2, q3);

    // prepare anisotropic candidates
    // only for quadrilaterals
    // too distorted (curved) elements cannot have aniso refinement (produces even worse elements)
    if ((!tri) && (e->iro_cache < 8) && !iso_only) {
      p0 = 2 * (order+1) / 3;
      int p_max = std::min(max_order, order+1);
      p1 = std::min(p0 + 3, p_max);
      for (q0 = p0; q0 <= p1; q0++)
        for (q1 = p0; q1 <= p1; q1++) {
          if ((q0 < order+1) || (q1 < order+1)) {
            make_ani_cand(q0, q1, 1);
            make_ani_cand(q0, q1, 2);
          }
        }
    }
  }
  // calculate (partial) projection errors
  double herr[8][11], perr[11];
  calc_projection_errors(e, order, rsln, herr, perr);

  // evaluate candidates (sum partial projection errors, calculate dofs)
  double avg = 0.0;
  double dev = 0.0;
  for (i = k = 0; i < n; i++)
  {
    Cand* c = cand + i;
    if (c->split == 0)
    {
      c->error = 0.0;
      c->dofs = tri ? 6 : 9;
      for (j = 0; j < 4; j++)
      {
        int o = c->p[j];
        c->error += herr[j][o] * 0.25; // spravny vypocet chyby
        if (tri) {
          c->dofs += (o-2)*(o-1)/2;
          if (j < 3) c->dofs +=  std::min(o, c->p[3])-1 + 2*(o-1);
        }
        else {
          c->dofs += sqr(o)-1;
          c->dofs += 2 * std::min(o, c->p[j>0 ? j-1 : 3]) - 1;
        }
      }
    }
    else if (c->split == 1 || c->split == 2)  // aniso splits
    {
      c->dofs  = 6 /* vertex */ + 3*(c->p[0] - 1 + c->p[1] - 1); // edge fns
      c->dofs +=  std::min(c->p[0], c->p[1]) - 1; // common edge
      c->dofs += sqr(c->p[0] - 1) + sqr(c->p[1] - 1); // bubbles
      for (c->error = 0.0, j = 0; j < 2; j++)
        c->error += herr[(c->split == 1) ? j+4 : j+6][c->p[j]] * 0.5;  // spravny vypocet chyby

    }
    else
    {
      int o = c->p[0];
      c->error = perr[o];
      c->dofs  = tri ? (o+1)*(o+2)/2 : sqr(o+1);
    }
    c->error = sqrt(c->error);

    //verbose("Cand #%d: Orders %d %d %d %d, Error %g, Dofs %d", i, c->p[0],c->p[1],c->p[2],c->p[3],c->error, c->dofs);

    if (!i || c->error <= cand[0].error)
    {
      avg += log(c->error);
      dev += sqr(log(c->error));
      k++;
    }
  }
  avg /= k;  // mean
  dev /= k;  // second moment
  dev = sqrt(dev - sqr(avg));  // deviation is square root of variance

  // select an above-average candidate with the steepest error decrease
  int imax = 0;
  double score, maxscore = 0.0;
  for (i = 1; i < n; i++)
  {
    if ((log(cand[i].error) < avg + dev) && (cand[i].dofs > cand[0].dofs))
    {
      score = (log(cand[0].error) - log(cand[i].error)) /
	       //(pow(cand[i].dofs, conv_exp) - pow(cand[0].dofs, conv_exp));
               pow(cand[i].dofs - cand[0].dofs, conv_exp);
      if (score > maxscore) { maxscore = score; imax = i; }
    }
  }

  // return result
  split = cand[imax].split;
  memcpy(p, cand[imax].p, 4*sizeof(int));

  //verbose("Selected Candidate #%d: Orders %d %d %d %d\n", imax, p[0],p[1],p[2],p[3]);

}