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 == HERMES_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 == HERMES_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 L2ProjBasedSelector::precalc_ortho_shapes(const double3* gip_points, const int num_gip_points, const Trf* trfs, const int num_noni_trfs, const std::vector<ShapeInx>& shapes, const int max_shape_inx, TrfShape& svals) { //calculate values precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shapes, max_shape_inx, svals); //calculate orthonormal basis const int num_shapes = (int)shapes.size(); for(int i = 0; i < num_shapes; i++) { const int inx_shape_i = shapes[i].inx; //orthogonalize for(int j = 0; j < i; j++) { const int inx_shape_j = shapes[j].inx; //calculate product of non-transformed functions double product = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_L2FE_VALUE][k]; product += gip_points[k][H2D_GIP2D_W] * sum; } //for all transformations int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] -= product * svals[inx_trf][inx_shape_j][H2D_L2FE_VALUE][k]; } //move to the next transformation if (inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if (inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } error_if(!done, "All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } //normalize //calculate norm double norm_squared = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_L2FE_VALUE][k]); norm_squared += gip_points[k][H2D_GIP2D_W] * sum; } double norm = sqrt(norm_squared); assert_msg(finite(1/norm), "Norm (%g) is almost zero.", norm); //for all transformations: normalize int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_L2FE_VALUE][k] /= norm; } //move to the next transformation if (inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if (inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } error_if(!done, "All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } }
void HcurlProjBasedSelector<Scalar>::precalc_ortho_shapes(const double3* gip_points, const int num_gip_points, const Trf* trfs, const int num_noni_trfs, const Hermes::vector<typename OptimumSelector<Scalar>::ShapeInx>& shapes, const int max_shape_inx, typename ProjBasedSelector<Scalar>::TrfShape& svals, ElementMode2D mode) { //calculate values precalc_shapes(gip_points, num_gip_points, trfs, num_noni_trfs, shapes, max_shape_inx, svals, mode); //calculate orthonormal basis const int num_shapes = (int)shapes.size(); for(int i = 0; i < num_shapes; i++) { const int inx_shape_i = shapes[i].inx; //orthogonalize for(int j = 0; j < i; j++) { const int inx_shape_j = shapes[j].inx; //calculate product of non-transformed functions double product = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE0][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_VALUE0][k]; sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE1][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_VALUE1][k]; sum += svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_CURL][k] * svals[H2D_TRF_IDENTITY][inx_shape_j][H2D_HCFE_CURL][k]; product += gip_points[k][H2D_GIP2D_W] * sum; } //for all transformations int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE0][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_VALUE0][k]; svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE1][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_VALUE1][k]; svals[inx_trf][inx_shape_i][H2D_HCFE_CURL][k] -= product * svals[inx_trf][inx_shape_j][H2D_HCFE_CURL][k]; } //move to the next transformation if(inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } if(!done) throw Exceptions::Exception("All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } //normalize //calculate norm double norm_squared = 0.0; for(int k = 0; k < num_gip_points; k++) { double sum = 0.0; sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE0][k]); sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_VALUE1][k]); sum += sqr(svals[H2D_TRF_IDENTITY][inx_shape_i][H2D_HCFE_CURL][k]); norm_squared += gip_points[k][H2D_GIP2D_W] * sum; } double norm = sqrt(norm_squared); if(!finite(1/norm)) throw Exceptions::Exception("Norm (%g) is almost zero.", norm); //for all transformations: normalize int inx_trf = 0; bool done = false; while (!done && inx_trf < H2D_TRF_NUM) { //for all integration points for(int k = 0; k < num_gip_points; k++) { svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE0][k] /= norm; svals[inx_trf][inx_shape_i][H2D_HCFE_VALUE1][k] /= norm; svals[inx_trf][inx_shape_i][H2D_HCFE_CURL][k] /= norm; } //move to the next transformation if(inx_trf == H2D_TRF_IDENTITY) done = true; else { inx_trf++; if(inx_trf >= num_noni_trfs) //if all transformations were processed, move to the identity transformation inx_trf = H2D_TRF_IDENTITY; } } if(!done) throw Exceptions::Exception("All transformation processed but identity transformation not found."); //identity transformation has to be the last transformation } }