Esempio n. 1
0
// Calculates maximum of a given function, including its coordinates.
Extremum get_peak(MeshFunction *sln)
{
  Quad2D* quad = &g_quad_2d_std;
  sln->set_quad_2d(quad);
  Element* e;
  Mesh* mesh = sln->get_mesh();
  
  scalar peak = 0.0;
  double pos_x = 0.0;
  double pos_y = 0.0;
  
  for_all_active_elements(e, mesh)
  {
    update_limit_table(e->get_mode());
    sln->set_active_element(e);
    RefMap* ru = sln->get_refmap();
    int o = sln->get_fn_order() + ru->get_inv_ref_order();
    limit_order(o);
    sln->set_quad_order(o, H2D_FN_VAL);
    scalar *uval = sln->get_fn_values();
    int np = quad->get_num_points(o);
    double* x = ru->get_phys_x(o);
    double* y = ru->get_phys_y(o);
    
    for (int i = 0; i < np; i++)
      if (uval[i] > peak) {
        peak = uval[i];
        pos_x = x[i];
        pos_y = y[i];
      }
  }
Esempio n. 2
0
      void Orderizer::process_space(SpaceSharedPtr<Scalar> space, bool show_edge_orders)
      {
        // sanity check
        if (space == nullptr)
          throw Hermes::Exceptions::Exception("Space is nullptr in Orderizer:process_space().");

        if (!space->is_up_to_date())
          throw Hermes::Exceptions::Exception("The space is not up to date.");

        MeshSharedPtr mesh = space->get_mesh();

        // Reallocate.
        this->reallocate(mesh);

        RefMap refmap;

        int oo, o[6];

        // make a mesh illustrating the distribution of polynomial orders over the space
        Element* e;
        for_all_active_elements(e, mesh)
        {
          oo = o[4] = o[5] = space->get_element_order(e->id);
          if (show_edge_orders)
          for (unsigned int k = 0; k < e->get_nvert(); k++)
            o[k] = space->get_edge_order(e, k);
          else if (e->is_curved())
          {
            if (e->is_triangle())
            for (unsigned int k = 0; k < e->get_nvert(); k++)
              o[k] = oo;
            else
            for (unsigned int k = 0; k < e->get_nvert(); k++)
              o[k] = H2D_GET_H_ORDER(oo);
          }

          double3* pt;
          int np;
          double* x;
          double* y;
          if (show_edge_orders || e->is_curved())
          {
            refmap.set_quad_2d(&quad_ord);
            refmap.set_active_element(e);
            x = refmap.get_phys_x(1);
            y = refmap.get_phys_y(1);

            pt = quad_ord.get_points(1, e->get_mode());
            np = quad_ord.get_num_points(1, e->get_mode());
          }
          else
          {
            refmap.set_quad_2d(&quad_ord_simple);
            refmap.set_active_element(e);
            x = refmap.get_phys_x(1);
            y = refmap.get_phys_y(1);

            pt = quad_ord_simple.get_points(1, e->get_mode());
            np = quad_ord_simple.get_num_points(1, e->get_mode());
          }

          int id[80];
          assert(np <= 80);

          int mode = e->get_mode();
          if (e->is_quad())
          {
            o[4] = H2D_GET_H_ORDER(oo);
            o[5] = H2D_GET_V_ORDER(oo);
          }
          if (show_edge_orders || e->is_curved())
          {
            make_vert(lvert[label_count], x[0], y[0], o[4]);

            for (int i = 1; i < np; i++)
              make_vert(id[i - 1], x[i], y[i], o[(int)pt[i][2]]);

            for (int i = 0; i < num_elem[mode][1]; i++)
              this->add_triangle(id[ord_elem[mode][1][i][0]], id[ord_elem[mode][1][i][1]], id[ord_elem[mode][1][i][2]], e->marker);

            for (int i = 0; i < num_edge[mode][1]; i++)
            {
              if (e->en[ord_edge[mode][1][i][2]]->bnd || (y[ord_edge[mode][1][i][0] + 1] < y[ord_edge[mode][1][i][1] + 1]) ||
                ((y[ord_edge[mode][1][i][0] + 1] == y[ord_edge[mode][1][i][1] + 1]) &&
                (x[ord_edge[mode][1][i][0] + 1] < x[ord_edge[mode][1][i][1] + 1])))
              {
                add_edge(id[ord_edge[mode][1][i][0]], id[ord_edge[mode][1][i][1]], e->en[ord_edge[mode][1][i][2]]->marker);
              }
            }
          }
          else
          {
            make_vert(lvert[label_count], x[0], y[0], o[4]);

            for (int i = 1; i < np; i++)
              make_vert(id[i - 1], x[i], y[i], o[(int)pt[i][2]]);

            for (int i = 0; i < num_elem_simple[mode][1]; i++)
              this->add_triangle(id[ord_elem_simple[mode][1][i][0]], id[ord_elem_simple[mode][1][i][1]], id[ord_elem_simple[mode][1][i][2]], e->marker);

            for (int i = 0; i < num_edge_simple[mode][1]; i++)
              add_edge(id[ord_edge_simple[mode][1][i][0]], id[ord_edge_simple[mode][1][i][1]], e->en[ord_edge_simple[mode][1][i][2]]->marker);
          }

          double xmin = 1e100, ymin = 1e100, xmax = -1e100, ymax = -1e100;
          for (unsigned int k = 0; k < e->get_nvert(); k++)
          {
            if (e->vn[k]->x < xmin) xmin = e->vn[k]->x;
            if (e->vn[k]->x > xmax) xmax = e->vn[k]->x;
            if (e->vn[k]->y < ymin) ymin = e->vn[k]->y;
            if (e->vn[k]->y > ymax) ymax = e->vn[k]->y;
          }
          lbox[label_count][0] = xmax - xmin;
          lbox[label_count][1] = ymax - ymin;
          ltext[label_count++] = labels[o[4]][o[5]];
        }
Esempio n. 3
0
      void Linearizer::process_quad(MeshFunction<double>** fns, int iv0, int iv1, int iv2, int iv3, int level,
        double* val, double* phx, double* phy, int* idx, bool curved)
      {
        double midval[3][5];

        // try not to split through the vertex with the largest value
        int a = (verts[iv0][2] > verts[iv1][2]) ? iv0 : iv1;
        int b = (verts[iv2][2] > verts[iv3][2]) ? iv2 : iv3;
        a = (verts[a][2] > verts[b][2]) ? a : b;
        int flip = (a == iv1 || a == iv3) ? 1 : 0;

        if(level < LinearizerBase::get_max_level(fns[0]->get_active_element(), fns[0]->get_fn_order(), fns[0]->get_mesh()))
        {
          int i;
          if(!(level & 1)) // this is an optimization: do the following only every other time
          {
            // obtain solution values
            fns[0]->set_quad_order(1, item);
            val = fns[0]->get_values(component, value_type);
            if(auto_max)
              for (i = 0; i < lin_np_quad[1]; i++)
              {
                double v = val[i];
                if(finite(v) && fabs(v) > max)
#pragma omp critical(max)
                  if(finite(v) && fabs(v) > max)
                    max = fabs(v);
              }

              // This is just to make some sense.
              if(fabs(max) < Hermes::HermesSqrtEpsilon)
                max = Hermes::HermesSqrtEpsilon;

              idx = quad_indices[0];

              if(curved)
              {
                RefMap* refmap = fns[0]->get_refmap();
                phx = refmap->get_phys_x(1);
                phy = refmap->get_phys_y(1);

                double* dx = nullptr;
                double* dy = nullptr;

                if(this->xdisp != nullptr)
                  fns[1]->set_quad_order(1, H2D_FN_VAL);
                if(this->ydisp != nullptr)
                  fns[this->xdisp == nullptr ? 1 : 2]->set_quad_order(1, H2D_FN_VAL);
                if(this->xdisp != nullptr)
                  dx = fns[1]->get_fn_values();
                if(this->ydisp != nullptr)
                  dy = fns[this->xdisp == nullptr ? 1 : 2]->get_fn_values();
                for (i = 0; i < lin_np_quad[1]; i++)
                {
                  if(this->xdisp != nullptr)
                    phx[i] += dmult*dx[i];
                  if(this->ydisp != nullptr)
                    phy[i] += dmult*dy[i];
                }
              }
          }

          // obtain linearized values and coordinates at the midpoints
          for (i = 0; i < 3; i++)
          {
            midval[i][0] = (verts[iv0][i] + verts[iv1][i]) * 0.5;
            midval[i][1] = (verts[iv1][i] + verts[iv2][i]) * 0.5;
            midval[i][2] = (verts[iv2][i] + verts[iv3][i]) * 0.5;
            midval[i][3] = (verts[iv3][i] + verts[iv0][i]) * 0.5;
            midval[i][4] = (midval[i][0]  + midval[i][2])  * 0.5;
          };

          // the value of the middle point is not the average of the four vertex values, since quad == 2 triangles
          midval[2][4] = flip ? (verts[iv0][2] + verts[iv2][2]) * 0.5 : (verts[iv1][2] + verts[iv3][2]) * 0.5;

          // determine whether or not to split the element
          int split;
          if(eps >= 1.0)
          {
            // if eps > 1, the user wants a fixed number of refinements (no adaptivity)
            split = (level < eps) ? 3 : 0;
          }
          else
          {
            if(!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max
              && fabs(verts[iv2][2]) > max && fabs(verts[iv3][2]) > max)
            {
              // do not split if the whole quad is above the specified maximum value
              split = 0;
            }
            else
            {
              // calculate the approximate error of linearizing the normalized solution
              double herr = fabs(val[idx[1]] - midval[2][1]) + fabs(val[idx[3]] - midval[2][3]);
              double verr = fabs(val[idx[0]] - midval[2][0]) + fabs(val[idx[2]] - midval[2][2]);
              double err  = fabs(val[idx[4]] - midval[2][4]) + herr + verr;
              split = (!finite(err) || err > max*4*eps) ? 3 : 0;

              // decide whether to split horizontally or vertically only
              if(level > 0 && split)
              {
                if(herr > 5*verr)
                  split = 1; // h-split
                else if(verr > 5*herr)
                  split = 2; // v-split
              }
            }

            // also decide whether to split because of the curvature
            if(split != 3 && curved)
            {
              double cm2 = sqr(fns[0]->get_active_element()->get_diameter()*this->get_curvature_epsilon());
              if(sqr(phx[idx[1]] - midval[0][1]) + sqr(phy[idx[1]] - midval[1][1]) > cm2 ||
                sqr(phx[idx[3]] - midval[0][3]) + sqr(phy[idx[3]] - midval[1][3]) > cm2) split |= 1;
              if(sqr(phx[idx[0]] - midval[0][0]) + sqr(phy[idx[0]] - midval[1][0]) > cm2 ||
                sqr(phx[idx[2]] - midval[0][2]) + sqr(phy[idx[2]] - midval[1][2]) > cm2) split |= 2;
            }

            // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints
            if(level == 0 && !split)
            {
              split = ((fabs(val[13] - 0.5*(midval[2][0] + midval[2][1])) +
                fabs(val[17] - 0.5*(midval[2][1] + midval[2][2])) +
                fabs(val[20] - 0.5*(midval[2][2] + midval[2][3])) +
                fabs(val[9]  - 0.5*(midval[2][3] + midval[2][0]))) > max*4*eps) ? 3 : 0;
            }
          }

          // split the quad if the error is too large, otherwise produce two linear triangles
          if(split)
          {
            if(curved)
              for (i = 0; i < 5; i++)
              {
                midval[0][i] = phx[idx[i]];
                midval[1][i] = phy[idx[i]];
              }

              // obtain mid-edge and mid-element vertices
              int mid0, mid1, mid2, mid3, mid4;
              if(split != 1) mid0 = get_vertex(iv0,  iv1,  midval[0][0], midval[1][0], val[idx[0]]);
              if(split != 2) mid1 = get_vertex(iv1,  iv2,  midval[0][1], midval[1][1], val[idx[1]]);
              if(split != 1) mid2 = get_vertex(iv2,  iv3,  midval[0][2], midval[1][2], val[idx[2]]);
              if(split != 2) mid3 = get_vertex(iv3,  iv0,  midval[0][3], midval[1][3], val[idx[3]]);
              if(split == 3) mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], val[idx[4]]);

              if(!this->exceptionMessageCaughtInParallelBlock.empty())
                return;

              // recur to sub-elements
              if(split == 3)
              {
                this->push_transforms(fns, 0);
                process_quad(fns, iv0, mid0, mid4, mid3, level + 1, val, phx, phy, quad_indices[1], curved);
                this->pop_transforms(fns);

                this->push_transforms(fns, 1);
                process_quad(fns, mid0, iv1, mid1, mid4, level + 1, val, phx, phy, quad_indices[2], curved);
                this->pop_transforms(fns);

                this->push_transforms(fns, 2);
                process_quad(fns, mid4, mid1, iv2, mid2, level + 1, val, phx, phy, quad_indices[3], curved);
                this->pop_transforms(fns);

                this->push_transforms(fns, 3);
                process_quad(fns, mid3, mid4, mid2, iv3, level + 1, val, phx, phy, quad_indices[4], curved);
                this->pop_transforms(fns);
              }
              else
                if(split == 1) // h-split
                {
                  this->push_transforms(fns, 4);
                  process_quad(fns, iv0, iv1, mid1, mid3, level + 1, val, phx, phy, quad_indices[5], curved);
                  this->pop_transforms(fns);

                  this->push_transforms(fns, 5);
                  process_quad(fns, mid3, mid1, iv2, iv3, level + 1, val, phx, phy, quad_indices[6], curved);
                  this->pop_transforms(fns);
                }
                else // v-split
                {
                  this->push_transforms(fns, 6);
                  process_quad(fns, iv0, mid0, mid2, iv3, level + 1, val, phx, phy, quad_indices[7], curved);
                  this->pop_transforms(fns);

                  this->push_transforms(fns, 7);
                  process_quad(fns, mid0, iv1, iv2, mid2, level + 1, val, phx, phy, quad_indices[8], curved);
                  this->pop_transforms(fns);
                }
                return;
          }
        }

        // output two linear triangles,
        if(!flip)
        {
          add_triangle(iv3, iv0, iv1, fns[0]->get_active_element()->marker);
          add_triangle(iv1, iv2, iv3, fns[0]->get_active_element()->marker);
        }
        else
        {
          add_triangle(iv0, iv1, iv2, fns[0]->get_active_element()->marker);
          add_triangle(iv2, iv3, iv0, fns[0]->get_active_element()->marker);
        }
      }
Esempio n. 4
0
void Orderizer::process_solution(Space* space)
{
  // sanity check
  if (space == NULL) error("Space is NULL in Orderizer:process_solution().");

  if (!space->is_up_to_date())
    error("The space is not up to date.");

  int type = 1;

  nv = nt = ne = nl = 0;
  del_slot = -1;

  // estimate the required number of vertices and triangles
  Mesh* mesh = space->get_mesh();
  if (mesh == NULL) {
    error("Mesh is NULL in Orderizer:process_solution().");
  }
  int nn = mesh->get_num_active_elements();
  int ev = 77 * nn, et = 64 * nn, ee = 16 * nn, el = nn + 10;

  // reuse or allocate vertex, triangle and edge arrays
  lin_init_array(verts, double3, cv, ev);
  lin_init_array(tris, int3, ct, et);
  lin_init_array(edges, int3, ce, ee);
  lin_init_array(lvert, int, cl1, el);
  lin_init_array(ltext, char*, cl2, el);
  lin_init_array(lbox, double2, cl3, el);
  info = NULL;

  int oo, o[6];

  RefMap refmap;
  refmap.set_quad_2d(&quad_ord);

  // make a mesh illustrating the distribution of polynomial orders over the space
  Element* e;
  for_all_active_elements(e, mesh)
  {
    oo = o[4] = o[5] = space->get_element_order(e->id);
    for (unsigned int k = 0; k < e->nvert; k++)
      o[k] = space->get_edge_order(e, k);

    refmap.set_active_element(e);
    double* x = refmap.get_phys_x(type);
    double* y = refmap.get_phys_y(type);

    double3* pt = quad_ord.get_points(type);
    int np = quad_ord.get_num_points(type);
    int id[80];
    assert(np <= 80);

    #define make_vert(index, x, y, val) \
      { (index) = add_vertex(); \
      verts[index][0] = (x); \
      verts[index][1] = (y); \
      verts[index][2] = (val); }

    int mode = e->get_mode();
    if (e->is_quad())
    {
      o[4] = H2D_GET_H_ORDER(oo);
      o[5] = H2D_GET_V_ORDER(oo);
    }
    make_vert(lvert[nl], x[0], y[0], o[4]);

    for (int i = 1; i < np; i++)
      make_vert(id[i-1], x[i], y[i], o[(int) pt[i][2]]);

    for (int i = 0; i < num_elem[mode][type]; i++)
      add_triangle(id[ord_elem[mode][type][i][0]], id[ord_elem[mode][type][i][1]], id[ord_elem[mode][type][i][2]]);

    for (int i = 0; i < num_edge[mode][type]; i++)
    {
      if (e->en[ord_edge[mode][type][i][2]]->bnd || (y[ord_edge[mode][type][i][0] + 1] < y[ord_edge[mode][type][i][1] + 1]) ||
          ((y[ord_edge[mode][type][i][0] + 1] == y[ord_edge[mode][type][i][1] + 1]) &&
           (x[ord_edge[mode][type][i][0] + 1] <  x[ord_edge[mode][type][i][1] + 1])))
      {
        add_edge(id[ord_edge[mode][type][i][0]], id[ord_edge[mode][type][i][1]], 0);
      }
    }

    double xmin = 1e100, ymin = 1e100, xmax = -1e100, ymax = -1e100;
    for (unsigned int k = 0; k < e->nvert; k++)
    {
      if (e->vn[k]->x < xmin) xmin = e->vn[k]->x;
      if (e->vn[k]->x > xmax) xmax = e->vn[k]->x;
      if (e->vn[k]->y < ymin) ymin = e->vn[k]->y;
      if (e->vn[k]->y > ymax) ymax = e->vn[k]->y;
    }
    lbox[nl][0] = xmax - xmin;
    lbox[nl][1] = ymax - ymin;
    ltext[nl++] = labels[o[4]][o[5]];
  }
Esempio n. 5
0
void Linearizer::process_quad(int iv0, int iv1, int iv2, int iv3, int level,
                              scalar* val, double* phx, double* phy, int* idx)
{
  double midval[3][5];

  // try not to split through the vertex with the largest value
  int a = (verts[iv0][2] > verts[iv1][2]) ? iv0 : iv1;
  int b = (verts[iv2][2] > verts[iv3][2]) ? iv2 : iv3;
  a = (verts[a][2] > verts[b][2]) ? a : b;
  int flip = (a == iv1 || a == iv3) ? 1 : 0;

  if (level < LIN_MAX_LEVEL)
  {
    int i;
    if (!(level & 1)) // this is an optimization: do the following only every other time
    {
      // obtain solution values
      sln->set_quad_order(1, item);
      val = sln->get_values(ia, ib);
      if (auto_max)
        for (i = 0; i < lin_np_quad[1]; i++) {
          double v = getval(i);
          if (finite(v) && fabs(v) > max) max = fabs(v);
        }

      // obtain physical element coordinates
      if (curved || disp)
      {
        RefMap* refmap = sln->get_refmap();
        phx = refmap->get_phys_x(1);
        phy = refmap->get_phys_y(1);

        if (disp)
        {
          xdisp->force_transform(sln);
          ydisp->force_transform(sln);
          xdisp->set_quad_order(1, FN_VAL);
          ydisp->set_quad_order(1, FN_VAL);
          scalar* dx = xdisp->get_fn_values();
          scalar* dy = ydisp->get_fn_values();
          for (i = 0; i < lin_np_quad[1]; i++) {
            phx[i] += dmult*realpart(dx[i]);
            phy[i] += dmult*realpart(dy[i]);
          }
        }
      }
      idx = quad_indices[0];
    }

    // obtain linearized values and coordinates at the midpoints
    for (i = 0; i < 3; i++)
    {
      midval[i][0] = (verts[iv0][i] + verts[iv1][i]) * 0.5;
      midval[i][1] = (verts[iv1][i] + verts[iv2][i]) * 0.5;
      midval[i][2] = (verts[iv2][i] + verts[iv3][i]) * 0.5;
      midval[i][3] = (verts[iv3][i] + verts[iv0][i]) * 0.5;
      midval[i][4] = (midval[i][0]  + midval[i][2])  * 0.5;
    };

    // the value of the middle point is not the average of the four vertex values, since quad == 2 triangles
    midval[2][4] = flip ? (verts[iv0][2] + verts[iv2][2]) * 0.5 : (verts[iv1][2] + verts[iv3][2]) * 0.5;


    // determine whether or not to split the element
    int split;
    if (eps >= 1.0)
    {
      // if eps > 1, the user wants a fixed number of refinements (no adaptivity)
      split = (level < eps) ? 3 : 0;
    }
    else
    {
      if (!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max
                         && fabs(verts[iv2][2]) > max && fabs(verts[iv3][2]) > max)
      {
        // do not split if the whole quad is above the specified maximum value
        split = 0;
      }
      else
      {
        // calculate the approximate error of linearizing the normalized solution
        double herr = fabs(getval(idx[1]) - midval[2][1]) + fabs(getval(idx[3]) - midval[2][3]);
        double verr = fabs(getval(idx[0]) - midval[2][0]) + fabs(getval(idx[2]) - midval[2][2]);
        double err  = fabs(getval(idx[4]) - midval[2][4]) + herr + verr;
        split = (!finite(err) || err > max*4*eps) ? 3 : 0;

        // decide whether to split horizontally or vertically only
        if (level > 0 && split)
          if (herr > 5*verr)
            split = 1; // h-split
          else if (verr > 5*herr)
            split = 2; // v-split
      }

      // also decide whether to split because of the curvature
      if (split != 3 && (curved || disp))
      {
        double cm2 = sqr(cmax*5e-4);
        if (sqr(phx[idx[1]] - midval[0][1]) + sqr(phy[idx[1]] - midval[1][1]) > cm2 ||
            sqr(phx[idx[3]] - midval[0][3]) + sqr(phy[idx[3]] - midval[1][3]) > cm2) split |= 1;
        if (sqr(phx[idx[0]] - midval[0][0]) + sqr(phy[idx[0]] - midval[1][0]) > cm2 ||
            sqr(phx[idx[2]] - midval[0][2]) + sqr(phy[idx[2]] - midval[1][2]) > cm2) split |= 2;

        /*for (i = 0; i < 5; i++)
          if (sqr(phx[idx[i]] - midval[0][i]) + sqr(phy[idx[i]] - midval[1][i]) > sqr(cmax*1e-3))
            { split = 1; break; }*/
      }

      // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints
      if (level == 0 && !split)
      {
        split = ((fabs(getval(13) - 0.5*(midval[2][0] + midval[2][1])) +
                  fabs(getval(17) - 0.5*(midval[2][1] + midval[2][2])) +
                  fabs(getval(20) - 0.5*(midval[2][2] + midval[2][3])) +
                  fabs(getval(9)  - 0.5*(midval[2][3] + midval[2][0]))) > max*4*eps) ? 3 : 0;
      }
    }

    // split the quad if the error is too large, otherwise produce two linear triangles
    if (split)
    {
      if (curved || disp)
        for (i = 0; i < 5; i++) {
          midval[0][i] = phx[idx[i]];
          midval[1][i] = phy[idx[i]];
        }

      // obtain mid-edge and mid-element vertices
      int mid0, mid1, mid2, mid3, mid4;
      if (split != 1) mid0 = get_vertex(iv0,  iv1,  midval[0][0], midval[1][0], getval(idx[0]));
      if (split != 2) mid1 = get_vertex(iv1,  iv2,  midval[0][1], midval[1][1], getval(idx[1]));
      if (split != 1) mid2 = get_vertex(iv2,  iv3,  midval[0][2], midval[1][2], getval(idx[2]));
      if (split != 2) mid3 = get_vertex(iv3,  iv0,  midval[0][3], midval[1][3], getval(idx[3]));
      if (split == 3) mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], getval(idx[4]));

      // recur to sub-elements
      if (split == 3)
      {
        sln->push_transform(0);  process_quad(iv0, mid0, mid4, mid3, level+1, val, phx, phy, quad_indices[1]);  sln->pop_transform();
        sln->push_transform(1);  process_quad(mid0, iv1, mid1, mid4, level+1, val, phx, phy, quad_indices[2]);  sln->pop_transform();
        sln->push_transform(2);  process_quad(mid4, mid1, iv2, mid2, level+1, val, phx, phy, quad_indices[3]);  sln->pop_transform();
        sln->push_transform(3);  process_quad(mid3, mid4, mid2, iv3, level+1, val, phx, phy, quad_indices[4]);  sln->pop_transform();
      }
      else if (split == 1) // h-split
      {
        sln->push_transform(4);  process_quad(iv0, iv1, mid1, mid3, level+1, val, phx, phy, quad_indices[5]);  sln->pop_transform();
        sln->push_transform(5);  process_quad(mid3, mid1, iv2, iv3, level+1, val, phx, phy, quad_indices[6]);  sln->pop_transform();
      }
      else // v-split
      {
        sln->push_transform(6);  process_quad(iv0, mid0, mid2, iv3, level+1, val, phx, phy, quad_indices[7]);  sln->pop_transform();
        sln->push_transform(7);  process_quad(mid0, iv1, iv2, mid2, level+1, val, phx, phy, quad_indices[8]);  sln->pop_transform();
      }
      return;
    }
  }

  // output two linear triangles,
  if (!flip)
  {
    add_triangle(iv3, iv0, iv1);
    add_triangle(iv1, iv2, iv3);
  }
  else
  {
    add_triangle(iv0, iv1, iv2);
    add_triangle(iv2, iv3, iv0);
  }
}
Esempio n. 6
0
void Linearizer::process_triangle(int iv0, int iv1, int iv2, int level,
                                  scalar* val, double* phx, double* phy, int* idx)
{
  double midval[3][3];

  if (level < LIN_MAX_LEVEL)
  {
    int i;
    if (!(level & 1))
    {
      // obtain solution values
      sln->set_quad_order(1, item);
      val = sln->get_values(ia, ib);
      if (auto_max)
        for (i = 0; i < lin_np_tri[1]; i++) {
          double v = getval(i);
          if (finite(v) && fabs(v) > max) max = fabs(v);
        }

      // obtain physical element coordinates
      if (curved || disp)
      {
        RefMap* refmap = sln->get_refmap();
        phx = refmap->get_phys_x(1);
        phy = refmap->get_phys_y(1);

        if (disp)
        {
          xdisp->force_transform(sln);
          ydisp->force_transform(sln);
          xdisp->set_quad_order(1, FN_VAL);
          ydisp->set_quad_order(1, FN_VAL);
          scalar* dx = xdisp->get_fn_values();
          scalar* dy = ydisp->get_fn_values();
          for (i = 0; i < lin_np_tri[1]; i++) {
            phx[i] += dmult*realpart(dx[i]);
            phy[i] += dmult*realpart(dy[i]);
          }
        }
      }
      idx = tri_indices[0];
    }

    // obtain linearized values and coordinates at the midpoints
    for (i = 0; i < 3; i++)
    {
      midval[i][0] = (verts[iv0][i] + verts[iv1][i])*0.5;
      midval[i][1] = (verts[iv1][i] + verts[iv2][i])*0.5;
      midval[i][2] = (verts[iv2][i] + verts[iv0][i])*0.5;
    };

    // determine whether or not to split the element
    bool split;
    if (eps >= 1.0)
    {
      // if eps > 1, the user wants a fixed number of refinements (no adaptivity)
      split = (level < eps);
    }
    else
    {
      if (!auto_max && fabs(verts[iv0][2]) > max && fabs(verts[iv1][2]) > max && fabs(verts[iv2][2]) > max)
      {
        // do not split if the whole triangle is above the specified maximum value
        split = false;
      }
      else
      {
        // calculate the approximate error of linearizing the normalized solution
        double err = fabs(getval(idx[0]) - midval[2][0]) +
                     fabs(getval(idx[1]) - midval[2][1]) +
                     fabs(getval(idx[2]) - midval[2][2]);
        split = !finite(err) || err > max*3*eps;
      }

      // do the same for the curvature
      if (!split && (curved || disp))
      {
        for (i = 0; i < 3; i++)
          if (sqr(phx[idx[i]] - midval[0][i]) + sqr(phy[idx[i]] - midval[1][i]) > sqr(cmax*1.5e-3))
            { split = true; break; }
      }

      // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints
      if (level == 0 && !split)
      {
        split = (fabs(getval(8) - 0.5*(midval[2][0] + midval[2][1])) +
                 fabs(getval(9) - 0.5*(midval[2][1] + midval[2][2])) +
                 fabs(getval(4) - 0.5*(midval[2][2] + midval[2][0]))) > max*3*eps;
      }
    }

    // split the triangle if the error is too large, otherwise produce a linear triangle
    if (split)
    {
      if (curved || disp)
        for (i = 0; i < 3; i++) {
          midval[0][i] = phx[idx[i]];
          midval[1][i] = phy[idx[i]];
        }

      // obtain mid-edge vertices
      int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], getval(idx[0]));
      int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], getval(idx[1]));
      int mid2 = get_vertex(iv2, iv0, midval[0][2], midval[1][2], getval(idx[2]));

      // recur to sub-elements
      sln->push_transform(0);  process_triangle(iv0, mid0, mid2,  level+1, val, phx, phy, tri_indices[1]);  sln->pop_transform();
      sln->push_transform(1);  process_triangle(mid0, iv1, mid1,  level+1, val, phx, phy, tri_indices[2]);  sln->pop_transform();
      sln->push_transform(2);  process_triangle(mid2, mid1, iv2,  level+1, val, phx, phy, tri_indices[3]);  sln->pop_transform();
      sln->push_transform(3);  process_triangle(mid1, mid2, mid0, level+1, val, phx, phy, tri_indices[4]);  sln->pop_transform();
      return;
    }
  }

  // no splitting: output a linear triangle
  add_triangle(iv0, iv1, iv2);
}
Esempio n. 7
0
void Vectorizer::process_triangle(int iv0, int iv1, int iv2, int level,
                                  scalar* xval, scalar* yval, double* phx, double* phy, int* idx)
{
  if (level < LIN_MAX_LEVEL)
  {
    int i;
    if (!(level & 1))
    {
      // obtain solution values and physical element coordinates
      xsln->set_quad_order(1, xitem);
      ysln->set_quad_order(1, yitem);
      xval = xsln->get_values(xia, xib);
      yval = ysln->get_values(yia, yib);
      for (i = 0; i < lin_np_tri[1]; i++) {
        double m = getmag(i);
        if (finite(m) && fabs(m) > max) max = fabs(m);
      }

      if (curved)
      {
        RefMap* refmap = xsln->get_refmap();
        phx = refmap->get_phys_x(1);
        phy = refmap->get_phys_y(1);
      }
      idx = tri_indices[0];
    }

    // obtain linearized values and coordinates at the midpoints
    double midval[4][3];
    for (i = 0; i < 4; i++)
    {
      midval[i][0] = (verts[iv0][i] + verts[iv1][i])*0.5;
      midval[i][1] = (verts[iv1][i] + verts[iv2][i])*0.5;
      midval[i][2] = (verts[iv2][i] + verts[iv0][i])*0.5;
    };

    // determine whether or not to split the element
    bool split;
    if (eps >= 1.0)
    {
      //if eps > 1, the user wants a fixed number of refinements (no adaptivity)
      split = (level < eps);
    }
    else
    {
      // calculate the approximate error of linearizing the normalized solution
      double err = fabs(getmag(idx[0]) - midmag(0)) +
                   fabs(getmag(idx[1]) - midmag(1)) +
                   fabs(getmag(idx[2]) - midmag(2));
      split = !finite(err) || err > max*3*eps;

      // do the same for the curvature
      if (curved && !split)
      {
        double cerr = 0.0, cden = 0.0; // fixme
        for (i = 0; i < 3; i++)
        {
          cerr += fabs(phx[idx[i]] - midval[0][i]) + fabs(phy[idx[i]] - midval[1][i]);
          cden += fabs(phx[idx[i]]) + fabs(phy[idx[i]]);
        }
        split = (cerr > cden*2.5e-4);
      }

      // do extra tests at level 0, so as not to miss some functions with zero error at edge midpoints
      if (level == 0 && !split)
      {
        split = (fabs(getmag(8) - 0.5*(midmag(0) + midmag(1))) +
                 fabs(getmag(9) - 0.5*(midmag(1) + midmag(2))) +
                 fabs(getmag(4) - 0.5*(midmag(2) + midmag(0)))) > max*3*eps;
      }
    }

    // split the triangle if the error is too large, otherwise produce a linear triangle
    if (split)
    {
      if (curved)
        for (i = 0; i < 3; i++) {
          midval[0][i] = phx[idx[i]];
          midval[1][i] = phy[idx[i]];
        }

      // obtain mid-edge vertices
      int mid0 = get_vertex(iv0, iv1, midval[0][0], midval[1][0], getvalx(idx[0]), getvaly(idx[0]));
      int mid1 = get_vertex(iv1, iv2, midval[0][1], midval[1][1], getvalx(idx[1]), getvaly(idx[1]));
      int mid2 = get_vertex(iv2, iv0, midval[0][2], midval[1][2], getvalx(idx[2]), getvaly(idx[2]));

      // recur to sub-elements
      push_transform(0);  process_triangle(iv0, mid0, mid2,  level+1, xval, yval, phx, phy, tri_indices[1]);  pop_transform();
      push_transform(1);  process_triangle(mid0, iv1, mid1,  level+1, xval, yval, phx, phy, tri_indices[2]);  pop_transform();
      push_transform(2);  process_triangle(mid2, mid1, iv2,  level+1, xval, yval, phx, phy, tri_indices[3]);  pop_transform();
      push_transform(3);  process_triangle(mid1, mid2, mid0, level+1, xval, yval, phx, phy, tri_indices[4]);  pop_transform();
      return;
    }
  }

  // no splitting: output a linear triangle
  add_triangle(iv0, iv1, iv2);
}
Esempio n. 8
0
void Vectorizer::process_quad(int iv0, int iv1, int iv2, int iv3, int level,
                              scalar* xval, scalar* yval, double* phx, double* phy, int* idx)
{
  // try not to split through the vertex with the largest value
  int a = (magvert(iv0) > magvert(iv1)) ? iv0 : iv1;
  int b = (magvert(iv2) > magvert(iv3)) ? iv2 : iv3;
  a = (magvert(a) > magvert(b)) ? a : b;

  int flip = (a == iv1 || a == iv3) ? 1 : 0;

  if (level < LIN_MAX_LEVEL)
  {
    int i;
    if (!(level & 1))
    {
      // obtain solution values and physical element coordinates
      xsln->set_quad_order(1, xitem);
      ysln->set_quad_order(1, yitem);
      xval = xsln->get_values(xia, xib);
      yval = ysln->get_values(yia, yib);
      for (i = 0; i < lin_np_quad[1]; i++) {
        double m = getmag(i);
        if (finite(m) && fabs(m) > max) max = fabs(m);
      }

      if (curved)
      {
        RefMap* refmap = xsln->get_refmap();
        phx = refmap->get_phys_x(1);
        phy = refmap->get_phys_y(1);
      }
      idx = quad_indices[0];
    }

    // obtain linearized values and coordinates at the midpoints
    double midval[4][5];
    for (i = 0; i < 4; i++)
    {
      midval[i][0] = (verts[iv0][i] + verts[iv1][i]) * 0.5;
      midval[i][1] = (verts[iv1][i] + verts[iv2][i]) * 0.5;
      midval[i][2] = (verts[iv2][i] + verts[iv3][i]) * 0.5;
      midval[i][3] = (verts[iv3][i] + verts[iv0][i]) * 0.5;
      midval[i][4] = (midval[i][0]  + midval[i][2])  * 0.5;
    };

    // determine whether or not to split the element
    bool split;
    if (eps >= 1.0)
    {
      //if eps > 1, the user wants a fixed number of refinements (no adaptivity)
      split = (level < eps);
    }

    else
    {
      // the value of the middle point is not the average of the four vertex values, since quad == 2 triangles
      midval[2][4] = flip ? (verts[iv0][2] + verts[iv2][2]) * 0.5 : (verts[iv1][2] + verts[iv3][2]) * 0.5;
      midval[3][4] = flip ? (verts[iv0][3] + verts[iv2][3]) * 0.5 : (verts[iv1][3] + verts[iv3][3]) * 0.5;

      // calculate the approximate error of linearizing the normalized solution
      double err = fabs(getmag(idx[0]) - midmag(0)) +
                   fabs(getmag(idx[1]) - midmag(1)) +
                   fabs(getmag(idx[2]) - midmag(2)) +
                   fabs(getmag(idx[3]) - midmag(3)) +
                   fabs(getmag(idx[4]) - midmag(4));
      split = !finite(err) || err > max*4*eps;

      // do the same for the curvature
      if (curved && !split)
      {
        double cerr = 0.0, cden = 0.0; // fixme
        for (i = 0; i < 5; i++)
        {
          cerr += fabs(phx[idx[i]] - midval[0][i]) + fabs(phy[idx[i]] - midval[1][i]);
          cden += fabs(phx[idx[i]]) + fabs(phy[idx[i]]);
        }
        split = (cerr > cden*2.5e-4);
      }

      // do extra tests at level 0, so as not to miss functions with zero error at edge midpoints
      if (level == 0 && !split)
      {
        err = fabs(getmag(13) - 0.5*(midmag(0) + midmag(1))) +
              fabs(getmag(17) - 0.5*(midmag(1) + midmag(2))) +
              fabs(getmag(20) - 0.5*(midmag(2) + midmag(3))) +
              fabs(getmag(9)  - 0.5*(midmag(3) + midmag(0)));
        split = !finite(err) || (err) > max*2*eps; //?
      }
    }

    // split the quad if the error is too large, otherwise produce two linear triangles
    if (split)
    {
      if (curved)
        for (i = 0; i < 5; i++) {
          midval[0][i] = phx[idx[i]];
          midval[1][i] = phy[idx[i]];
        }

      // obtain mid-edge and mid-element vertices
      int mid0 = get_vertex(iv0,  iv1,  midval[0][0], midval[1][0], getvalx(idx[0]), getvaly(idx[0]));
      int mid1 = get_vertex(iv1,  iv2,  midval[0][1], midval[1][1], getvalx(idx[1]), getvaly(idx[1]));
      int mid2 = get_vertex(iv2,  iv3,  midval[0][2], midval[1][2], getvalx(idx[2]), getvaly(idx[2]));
      int mid3 = get_vertex(iv3,  iv0,  midval[0][3], midval[1][3], getvalx(idx[3]), getvaly(idx[3]));
      int mid4 = get_vertex(mid0, mid2, midval[0][4], midval[1][4], getvalx(idx[4]), getvaly(idx[4]));

      // recur to sub-elements
      push_transform(0);  process_quad(iv0, mid0, mid4, mid3, level+1, xval, yval, phx, phy, quad_indices[1]);  pop_transform();
      push_transform(1);  process_quad(mid0, iv1, mid1, mid4, level+1, xval, yval, phx, phy, quad_indices[2]);  pop_transform();
      push_transform(2);  process_quad(mid4, mid1, iv2, mid2, level+1, xval, yval, phx, phy, quad_indices[3]);  pop_transform();
      push_transform(3);  process_quad(mid3, mid4, mid2, iv3, level+1, xval, yval, phx, phy, quad_indices[4]);  pop_transform();
      return;
    }
  }

  // output two linear triangles,
  if (!flip)
  {
    add_triangle(iv3, iv0, iv1);
    add_triangle(iv1, iv2, iv3);
  }
  else
  {
    add_triangle(iv0, iv1, iv2);
    add_triangle(iv2, iv3, iv0);
  }
}