void ProjBasedSelector::calc_projection_errors(Element* e, const CandsInfo& info_h, const CandsInfo& info_p, const CandsInfo& info_aniso, Solution* rsln, CandElemProjError herr[4], CandElemProjError perr, CandElemProjError anisoerr[4]) { assert_msg(info_h.is_empty() || (H2D_GET_H_ORDER(info_h.max_quad_order) <= H2DRS_MAX_ORDER && H2D_GET_V_ORDER(info_h.max_quad_order) <= H2DRS_MAX_ORDER), "Maximum allowed order of a son of H-candidate is %d but order (H:%d,V:%d) requested.", H2DRS_MAX_ORDER, H2D_GET_H_ORDER(info_h.max_quad_order), H2D_GET_V_ORDER(info_h.max_quad_order)); assert_msg(info_p.is_empty() || (H2D_GET_H_ORDER(info_p.max_quad_order) <= H2DRS_MAX_ORDER && H2D_GET_V_ORDER(info_p.max_quad_order) <= H2DRS_MAX_ORDER), "Maximum allowed order of a son of P-candidate is %d but order (H:%d,V:%d) requested.", H2DRS_MAX_ORDER, H2D_GET_H_ORDER(info_p.max_quad_order), H2D_GET_V_ORDER(info_p.max_quad_order)); assert_msg(info_aniso.is_empty() || (H2D_GET_H_ORDER(info_aniso.max_quad_order) <= H2DRS_MAX_ORDER && H2D_GET_V_ORDER(info_aniso.max_quad_order) <= H2DRS_MAX_ORDER), "Maximum allowed order of a son of ANISO-candidate is %d but order (H:%d,V:%d) requested.", H2DRS_MAX_ORDER, H2D_GET_H_ORDER(info_aniso.max_quad_order), H2D_GET_V_ORDER(info_aniso.max_quad_order)); int mode = e->get_mode(); // select quadrature, obtain integration points and weights Quad2D* quad = &g_quad_2d_std; quad->set_mode(mode); rsln->set_quad_2d(quad); double3* gip_points = quad->get_points(H2DRS_INTR_GIP_ORDER); int num_gip_points = quad->get_num_points(H2DRS_INTR_GIP_ORDER); // everything is done on the reference domain rsln->enable_transform(false); // obtain reference solution values on all four refined sons scalar** rval[H2D_MAX_ELEMENT_SONS]; Element* base_element = rsln->get_mesh()->get_element(e->id); assert(!base_element->active); for (int son = 0; son < H2D_MAX_ELEMENT_SONS; son++) { //set element Element* e = base_element->sons[son]; assert(e != NULL); //obtain precalculated values rval[son] = precalc_ref_solution(son, rsln, e, H2DRS_INTR_GIP_ORDER); } //retrieve transformations Trf* trfs = NULL; int num_noni_trfs = 0; if (mode == H2D_MODE_TRIANGLE) { trfs = tri_trf; num_noni_trfs = H2D_TRF_TRI_NUM; } else { trfs = quad_trf; num_noni_trfs = H2D_TRF_QUAD_NUM; } // precalculate values of shape functions TrfShape empty_shape_vals; if (!cached_shape_vals_valid[mode]) { precalc_ortho_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shape_indices[mode], max_shape_inx[mode], cached_shape_ortho_vals[mode]); precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shape_indices[mode], max_shape_inx[mode], cached_shape_vals[mode]); cached_shape_vals_valid[mode] = true; //issue a warning if ortho values are defined and the selected cand_list might benefit from that but it cannot because elements do not have uniform orders if (!warn_uniform_orders && mode == H2D_MODE_QUAD && !cached_shape_ortho_vals[mode][H2D_TRF_IDENTITY].empty()) { warn_uniform_orders = true; if (cand_list == H2D_H_ISO || cand_list == H2D_H_ANISO || cand_list == H2D_P_ISO || cand_list == H2D_HP_ISO || cand_list == H2D_HP_ANISO_H) { warn_if(!info_h.uniform_orders || !info_aniso.uniform_orders || !info_p.uniform_orders, "Possible inefficiency: %s might be more efficient if the input mesh contains elements with uniform orders strictly.", get_cand_list_str(cand_list)); } } } TrfShape& svals = cached_shape_vals[mode]; TrfShape& ortho_svals = cached_shape_ortho_vals[mode]; //H-candidates if (!info_h.is_empty()) { Trf* p_trf_identity[1] = { &trfs[H2D_TRF_IDENTITY] }; std::vector<TrfShapeExp>* p_trf_svals[1] = { &svals[H2D_TRF_IDENTITY] }; std::vector<TrfShapeExp>* p_trf_ortho_svals[1] = { &ortho_svals[H2D_TRF_IDENTITY] }; for(int son = 0; son < H2D_MAX_ELEMENT_SONS; son++) { scalar **sub_rval[1] = { rval[son] }; calc_error_cand_element(mode, gip_points, num_gip_points , 1, &base_element->sons[son], p_trf_identity, sub_rval , p_trf_svals, p_trf_ortho_svals , info_h, herr[son]); } } //ANISO-candidates if (!info_aniso.is_empty()) { const int sons[4][2] = { {0,1}, {3,2}, {0,3}, {1,2} }; //indices of sons for sub-areas const int tr[4][2] = { {6,7}, {6,7}, {4,5}, {4,5} }; //indices of ref. domain transformations for sub-areas for(int version = 0; version < 4; version++) { // 2 elements for vertical split, 2 elements for horizontal split Trf* sub_trfs[2] = { &trfs[tr[version][0]], &trfs[tr[version][1]] }; Element* sub_domains[2] = { base_element->sons[sons[version][0]], base_element->sons[sons[version][1]] }; scalar **sub_rval[2] = { rval[sons[version][0]], rval[sons[version][1]] }; std::vector<TrfShapeExp>* sub_svals[2] = { &svals[tr[version][0]], &svals[tr[version][1]] }; std::vector<TrfShapeExp>* sub_ortho_svals[2] = { &ortho_svals[tr[version][0]], &ortho_svals[tr[version][1]] }; calc_error_cand_element(mode, gip_points, num_gip_points , 2, sub_domains, sub_trfs, sub_rval , sub_svals, sub_ortho_svals , info_aniso, anisoerr[version]); } } //P-candidates if (!info_p.is_empty()) { Trf* sub_trfs[4] = { &trfs[0], &trfs[1], &trfs[2], &trfs[3] }; scalar **sub_rval[4] = { rval[0], rval[1], rval[2], rval[3] }; std::vector<TrfShapeExp>* sub_svals[4] = { &svals[0], &svals[1], &svals[2], &svals[3] }; std::vector<TrfShapeExp>* sub_ortho_svals[4] = { &ortho_svals[0], &ortho_svals[1], &ortho_svals[2], &ortho_svals[3] }; calc_error_cand_element(mode, gip_points, num_gip_points , 4, base_element->sons, sub_trfs, sub_rval , sub_svals, sub_ortho_svals , info_p, perr); } }
void ProjBasedSelector::calc_error_cand_element(const int mode , double3* gip_points, int num_gip_points , const int num_sub, Element** sub_domains, Trf** sub_trfs, scalar*** sub_rvals , std::vector<TrfShapeExp>** sub_nonortho_svals, std::vector<TrfShapeExp>** sub_ortho_svals , const CandsInfo& info , CandElemProjError errors_squared ) { //allocate space int max_num_shapes = next_order_shape[mode][current_max_order]; scalar* right_side = new scalar[max_num_shapes]; int* shape_inxs = new int[max_num_shapes]; int* indx = new int[max_num_shapes]; //solver data double* d = new double[max_num_shapes]; //solver data double** proj_matrix = new_matrix<double>(max_num_shapes, max_num_shapes); ProjMatrixCache& proj_matrices = proj_matrix_cache[mode]; std::vector<ShapeInx>& full_shape_indices = shape_indices[mode]; //check whether ortho-svals are available bool ortho_svals_available = true; for(int i = 0; i < num_sub && ortho_svals_available; i++) ortho_svals_available &= !sub_ortho_svals[i]->empty(); //clenup of the cache for(int i = 0; i <= max_shape_inx[mode]; i++) { nonortho_rhs_cache[i] = ValueCacheItem<scalar>(); ortho_rhs_cache[i] = ValueCacheItem<scalar>(); } //calculate for all orders double sub_area_corr_coef = 1.0 / num_sub; OrderPermutator order_perm(info.min_quad_order, info.max_quad_order, mode == H2D_MODE_TRIANGLE || info.uniform_orders); do { int quad_order = order_perm.get_quad_order(); int order_h = H2D_GET_H_ORDER(quad_order), order_v = H2D_GET_V_ORDER(quad_order); //build a list of shape indices from the full list int num_shapes = 0; unsigned int inx_shape = 0; while (inx_shape < full_shape_indices.size()) { ShapeInx& shape = full_shape_indices[inx_shape]; if (order_h >= shape.order_h && order_v >= shape.order_v) { assert_msg(num_shapes < max_num_shapes, "more shapes than predicted, possible incosistency"); shape_inxs[num_shapes] = shape.inx; num_shapes++; } inx_shape++; } //continue only if there are shapes to process if (num_shapes > 0) { bool use_ortho = ortho_svals_available && order_perm.get_order_h() == order_perm.get_order_v(); //error_if(!use_ortho, "Non-ortho"); //DEBUG //select a cache std::vector< ValueCacheItem<scalar> >& rhs_cache = use_ortho ? ortho_rhs_cache : nonortho_rhs_cache; std::vector<TrfShapeExp>** sub_svals = use_ortho ? sub_ortho_svals : sub_nonortho_svals; //calculate projection matrix iff no ortho is used if (!use_ortho) { //error_if(!use_ortho, "Non-ortho"); //DEBUG if (proj_matrices[order_h][order_v] == NULL) proj_matrices[order_h][order_v] = build_projection_matrix(gip_points, num_gip_points, shape_inxs, num_shapes); copy_matrix(proj_matrix, proj_matrices[order_h][order_v], num_shapes, num_shapes); //copy projection matrix because original matrix will be modified } //build right side (fill cache values that are missing) for(int inx_sub = 0; inx_sub < num_sub; inx_sub++) { Element* this_sub_domain = sub_domains[inx_sub]; ElemSubTrf this_sub_trf = { sub_trfs[inx_sub], 1 / sub_trfs[inx_sub]->m[0], 1 / sub_trfs[inx_sub]->m[1] }; ElemGIP this_sub_gip = { gip_points, num_gip_points, sub_rvals[inx_sub] }; std::vector<TrfShapeExp>& this_sub_svals = *(sub_svals[inx_sub]); for(int k = 0; k < num_shapes; k++) { int shape_inx = shape_inxs[k]; ValueCacheItem<scalar>& shape_rhs_cache = rhs_cache[shape_inx]; if (!shape_rhs_cache.is_valid()) { TrfShapeExp empty_sub_vals; ElemSubShapeFunc this_sub_shape = { shape_inx, this_sub_svals.empty() ? empty_sub_vals : this_sub_svals[shape_inx] }; shape_rhs_cache.set(shape_rhs_cache.get() + evaluate_rhs_subdomain(this_sub_domain, this_sub_gip, this_sub_trf, this_sub_shape)); } } } //copy values from cache and apply area correction coefficient for(int k = 0; k < num_shapes; k++) { ValueCacheItem<scalar>& rhs_cache_value = rhs_cache[shape_inxs[k]]; right_side[k] = sub_area_corr_coef * rhs_cache_value.get(); rhs_cache_value.mark(); } //solve iff no ortho is used if (!use_ortho) { //error_if(!use_ortho, "Non-ortho"); //DEBUG ludcmp(proj_matrix, num_shapes, indx, d); lubksb<scalar>(proj_matrix, num_shapes, indx, right_side); } //calculate error double error_squared = 0; for(int inx_sub = 0; inx_sub < num_sub; inx_sub++) { Element* this_sub_domain = sub_domains[inx_sub]; ElemSubTrf this_sub_trf = { sub_trfs[inx_sub], 1 / sub_trfs[inx_sub]->m[0], 1 / sub_trfs[inx_sub]->m[1] }; ElemGIP this_sub_gip = { gip_points, num_gip_points, sub_rvals[inx_sub] }; ElemProj elem_proj = { shape_inxs, num_shapes, *(sub_svals[inx_sub]), right_side, quad_order }; error_squared += evaluate_error_squared_subdomain(this_sub_domain, this_sub_gip, this_sub_trf, elem_proj); } errors_squared[order_h][order_v] = error_squared * sub_area_corr_coef; //apply area correction coefficient } } while (order_perm.next()); //clenaup delete[] proj_matrix; delete[] right_side; delete[] shape_inxs; delete[] indx; delete[] d; }
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]]; }