void Linearizer::process_solution(MeshFunction* sln, int item, double eps, double max_abs, MeshFunction* xdisp, MeshFunction* ydisp, double dmult) { lock_data(); begin_time(); // initialization this->sln = sln; this->item = item; this->eps = eps; this->xdisp = xdisp; this->ydisp = ydisp; this->dmult = dmult; nv = nt = ne = 0; del_slot = -1; if (!item) error("'item' cannot be zero."); get_gv_a_b(item, ia, ib); if (ib >= 6) error("Invalid 'item'."); disp = (xdisp != NULL || ydisp != NULL); if (disp && (xdisp == NULL || ydisp == NULL)) error("Both displacement components must be supplied."); // estimate the required number of vertices and triangles Mesh* mesh = sln->get_mesh(); int nn = mesh->get_num_elements(); int ev = std::max(32 * nn, 10000); // todo: check this int et = std::max(64 * nn, 20000); int ee = std::max(24 * nn, 7500); // check that displacement meshes are the same if (disp) { unsigned seq1 = mesh->get_seq(); unsigned seq2 = xdisp->get_mesh()->get_seq(); unsigned seq3 = ydisp->get_mesh()->get_seq(); if (seq1 != seq2 || seq1 != seq3) error("Displacements must be defined on the same mesh as the solution."); } // 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); info = (int4*) malloc(sizeof(int4) * cv); // initialize the hash table int size = 0x2000; while (size*2 < cv) size *= 2; hash_table = (int*) malloc(sizeof(int) * size); memset(hash_table, 0xff, sizeof(int) * size); mask = size-1; // select the linearization quadrature Quad2D *old_quad, *old_quad_x, *old_quad_y; old_quad = sln->get_quad_2d(); sln->set_quad_2d(&quad_lin); if (disp) { old_quad_x = xdisp->get_quad_2d(); old_quad_y = ydisp->get_quad_2d(); xdisp->set_quad_2d(&quad_lin); ydisp->set_quad_2d(&quad_lin); } // create all top-level vertices (corresponding to vertex nodes), with // all parent-son relations preserved; this is necessary for regularization to // work on irregular meshes nn = mesh->get_max_node_id(); int* id2id = new int[nn]; memset(id2id, 0xff, sizeof(int) * nn); bool finished; do { finished = true; Node* node; for_all_vertex_nodes(node, mesh) { if (id2id[node->id] < 0 && node->ref != TOP_LEVEL_REF) if (node->p1 < 0) id2id[node->id] = get_vertex(node->id, node->id, node->x, node->y, 0); else if (id2id[node->p1] >= 0 && id2id[node->p2] >= 0) id2id[node->id] = get_vertex(id2id[node->p1], id2id[node->p2], node->x, node->y, 0); else finished = false; } } while (!finished); auto_max = (max_abs < 0.0); max = auto_max ? 0.0 : max_abs; // obtain the solution in vertices, estimate the maximum solution value Element* e; for_all_active_elements(e, mesh) { sln->set_active_element(e); sln->set_quad_order(0, item); scalar* val = sln->get_values(ia, ib); if (val == NULL) error("item not defined in the solution."); scalar *dx, *dy; if (disp) { xdisp->set_active_element(e); ydisp->set_active_element(e); xdisp->set_quad_order(0, FN_VAL); ydisp->set_quad_order(0, FN_VAL); dx = xdisp->get_fn_values(); dy = ydisp->get_fn_values(); } for (unsigned int i = 0; i < e->nvert; i++) { double f = getval(i); if (auto_max && finite(f) && fabs(f) > max) max = fabs(f); int id = id2id[e->vn[i]->id]; verts[id][2] = f; if (disp) { verts[id][0] = e->vn[i]->x + dmult*realpart(dx[i]); verts[id][1] = e->vn[i]->y + dmult*realpart(dy[i]); } } }
void Vectorizer::process_solution(MeshFunction* xsln, int xitem, MeshFunction* ysln, int yitem, double eps) { // sanity check if (xsln == NULL || ysln == NULL) error("One of the solutions is NULL in Vectorizer:process_solution()."); lock_data(); TimePeriod cpu_time; // initialization this->xsln = xsln; this->ysln = ysln; this->xitem = xitem; this->yitem = yitem; this->eps = eps; nv = nt = ne = nd = 0; del_slot = -1; Mesh* meshes[2] = { xsln->get_mesh(), ysln->get_mesh() }; if (meshes[0] == NULL || meshes[1] == NULL) { error("One of the meshes is NULL in Vectorizer:process_solution()."); } Transformable* fns[2] = { xsln, ysln }; Traverse trav; // estimate the required number of vertices and triangles // (based on the assumption that the linear mesh will be // about four-times finer than the original mesh). int nn = meshes[0]->get_num_elements() + meshes[1]->get_num_elements(); int ev = std::max(32 * nn, 10000); int et = std::max(64 * nn, 20000); int ee = std::max(24 * nn, 7500); int ed = ee; lin_init_array(verts, double4, cv, ev); lin_init_array(tris, int3, ct, et); lin_init_array(edges, int3, ce, ee); lin_init_array(dashes, int2, cd, ed); info = (int4*) malloc(sizeof(int4) * cv); // initialize the hash table int size = 0x1000; while (size*2 < cv) size *= 2; hash_table = (int*) malloc(sizeof(int) * size); memset(hash_table, 0xff, sizeof(int) * size); mask = size-1; // select the linearization quadrature Quad2D *old_quad_x, *old_quad_y; old_quad_x = xsln->get_quad_2d(); old_quad_y = ysln->get_quad_2d(); xsln->set_quad_2d((Quad2D*) &quad_lin); ysln->set_quad_2d((Quad2D*) &quad_lin); if (!xitem) error("Parameter 'xitem' cannot be zero."); if (!yitem) error("Parameter 'yitem' cannot be zero."); get_gv_a_b(xitem, xia, xib); get_gv_a_b(yitem, yia, yib); if (xib >= 6) error("Invalid value of paremeter 'xitem'."); if (yib >= 6) error("Invalid value of paremeter 'yitem'."); max = 1e-10; trav.begin(2, meshes, fns); Element** e; while ((e = trav.get_next_state(NULL, NULL)) != NULL) { xsln->set_quad_order(0, xitem); ysln->set_quad_order(0, yitem); scalar* xval = xsln->get_values(xia, xib); scalar* yval = ysln->get_values(yia, yib); for (unsigned int i = 0; i < e[0]->nvert; i++) { double fx = getvalx(i); double fy = getvaly(i); if (fabs(sqrt(fx*fx + fy*fy)) > max) max = fabs(sqrt(fx*fx + fy*fy)); } } trav.finish(); trav.begin(2, meshes, fns); // process all elements of the mesh while ((e = trav.get_next_state(NULL, NULL)) != NULL) { xsln->set_quad_order(0, xitem); ysln->set_quad_order(0, yitem); scalar* xval = xsln->get_values(xia, xib); scalar* yval = ysln->get_values(yia, yib); double* x = xsln->get_refmap()->get_phys_x(0); double* y = ysln->get_refmap()->get_phys_y(0); int iv[4]; for (unsigned int i = 0; i < e[0]->nvert; i++) { double fx = getvalx(i); double fy = getvaly(i); iv[i] = create_vertex(x[i], y[i], fx, fy); } // we won't bother calculating physical coordinates from the refmap if this is not a curved element curved = (e[0]->cm != NULL); // recur to sub-elements if (e[0]->is_triangle()) process_triangle(iv[0], iv[1], iv[2], 0, NULL, NULL, NULL, NULL, NULL); else process_quad(iv[0], iv[1], iv[2], iv[3], 0, NULL, NULL, NULL, NULL, NULL); // process edges and dashes (bold line for edge in both meshes, dashed line for edge in one of the meshes) Trf* xctm = xsln->get_ctm(); Trf* yctm = ysln->get_ctm(); double r[4] = { -1.0, 1.0, 1.0, -1.0 }; double ref[4][2] = { {-1.0,-1.0}, {1.0,-1.0}, {1.0,1.0}, {-1.0,1.0} }; for (unsigned int i = 0; i < e[0]->nvert; i++) { bool bold = false; double px = ref[i][0]; double py = ref[i][1]; // for odd edges (1, 3) we check x coordinate after ctm transformation, if it's the same (1 or -1) in both meshes => bold if (i & 1) { if ((xctm->m[0]*px + xctm->t[0] == r[i]) && (yctm->m[0]*px + yctm->t[0] == r[i])) bold = true; } // for even edges (0, 4) we check y coordinate after ctm transformation, if it's the same (-1 or 1) in both meshes => bold else { if ((xctm->m[1]*py + xctm->t[1] == r[i]) && (yctm->m[1]*py + yctm->t[1] == r[i])) bold = true; } int j = e[0]->next_vert(i); // we draw a line only if both edges lies on the boundary or if the line is from left top to right bottom if (((e[0]->en[i]->bnd) && (e[1]->en[i]->bnd)) || (verts[iv[i]][1] < verts[iv[j]][1]) || (verts[iv[i]][1] == verts[iv[j]][1] && verts[iv[i]][0] < verts[iv[j]][0])) { if (bold) process_edge(iv[i], iv[j], e[0]->en[i]->marker); else process_dash(iv[i], iv[j]); } } } trav.finish(); find_min_max(); verbose("Vectorizer created %d verts and %d tris in %0.3g s", nv, nt, cpu_time.tick().last()); //if (verbose_mode) print_hash_stats(); unlock_data(); // select old quadratrues xsln->set_quad_2d(old_quad_x); ysln->set_quad_2d(old_quad_y); // clean up ::free(hash_table); ::free(info); }