// 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]; } }
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]]; }
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); } }
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]]; }
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); } }
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); }
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); }
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); } }