OrderPermutator::OrderPermutator(int start_quad_order, int end_quad_order, bool iso_p, int* tgt_quad_order) : start_order_h(H2D_GET_H_ORDER(start_quad_order)), start_order_v(H2D_GET_V_ORDER(start_quad_order)) , end_order_h(H2D_GET_H_ORDER(end_quad_order)), end_order_v(H2D_GET_V_ORDER(end_quad_order)) , iso_p(iso_p), tgt_quad_order(tgt_quad_order) { reset(); }
void Space::H2D_CHECK_ORDER(int order) { if (H2D_GET_H_ORDER(order) < 0 || H2D_GET_V_ORDER(order) < 0) error("Order cannot be negative."); if (H2D_GET_H_ORDER(order) > 10 || H2D_GET_V_ORDER(order) > 10) error("Order = %d, maximum is 10.", order); }
int DiscreteProblemIntegrationOrderCalculator<Scalar>::calc_order_dg_matrix_form(const Hermes::vector<SpaceSharedPtr<Scalar> >& spaces, Traverse::State* current_state, MatrixFormDG<Scalar>* mfDG, RefMap** current_refmaps, Solution<Scalar>** current_u_ext, bool neighbor_supp_u, bool neighbor_supp_v, NeighborSearch<Scalar>** neighbor_searches) { NeighborSearch<Scalar>* nbs_u = neighbor_searches[mfDG->j]; unsigned int prev_size = this->rungeKutta ? this->RK_original_spaces_count : mfDG->wf->get_neq() - mfDG->u_ext_offset; // Order to return. int order = 0; DiscontinuousFunc<Hermes::Ord>** u_ext_ord = current_u_ext == nullptr ? nullptr : new DiscontinuousFunc<Hermes::Ord>*[this->rungeKutta ? this->RK_original_spaces_count : mfDG->wf->get_neq() - mfDG->u_ext_offset]; if (current_u_ext) for (int i = 0; i < prev_size; i++) if (current_u_ext[i + mfDG->u_ext_offset]) u_ext_ord[i] = init_ext_fn_ord(nbs_u, current_u_ext[i + mfDG->u_ext_offset]); else u_ext_ord[i] = new DiscontinuousFunc<Ord>(init_fn_ord(0), false, false); // Order of additional external functions. DiscontinuousFunc<Ord>** ext_ord = nullptr; Hermes::vector<MeshFunctionSharedPtr<Scalar> > ext_ord_fns = mfDG->ext.size() ? mfDG->ext.size() : mfDG->wf->ext.size(); if (ext_ord_fns.size() > 0) ext_ord = init_ext_fns_ord(ext_ord_fns, neighbor_searches); // Order of shape functions. int max_order_j = spaces[mfDG->j]->get_element_order(current_state->e[mfDG->j]->id); int max_order_i = spaces[mfDG->i]->get_element_order(current_state->e[mfDG->i]->id); if (H2D_GET_V_ORDER(max_order_i) > H2D_GET_H_ORDER(max_order_i)) max_order_i = H2D_GET_V_ORDER(max_order_i); else max_order_i = H2D_GET_H_ORDER(max_order_i); if (H2D_GET_V_ORDER(max_order_j) > H2D_GET_H_ORDER(max_order_j)) max_order_j = H2D_GET_V_ORDER(max_order_j); else max_order_j = H2D_GET_H_ORDER(max_order_j); // Order of shape functions. DiscontinuousFunc<Ord>* ou = new DiscontinuousFunc<Ord>(init_fn_ord(max_order_j), neighbor_supp_u); DiscontinuousFunc<Ord>* ov = new DiscontinuousFunc<Ord>(init_fn_ord(max_order_i), neighbor_supp_v); // Order of geometric attributes (eg. for multiplication of a solution with coordinates, normals, etc.). Geom<Hermes::Ord> tmp; double fake_wt = 1.0; // Total order of the matrix form. Ord o = mfDG->ord(1, &fake_wt, u_ext_ord, ou, ov, &tmp, ext_ord); adjust_order_to_refmaps(mfDG, order, &o, current_refmaps); // Cleanup. deinit_ext_fns_ord(mfDG, u_ext_ord, ext_ord); delete ou; delete ov; return order; }
int DiscreteProblemIntegrationOrderCalculator<Scalar>::calc_order_matrix_form(const Hermes::vector<SpaceSharedPtr<Scalar> >& spaces, MatrixForm<Scalar> *form, RefMap** current_refmaps, Func<Hermes::Ord>** ext, Func<Hermes::Ord>** u_ext) { int order; Func<Hermes::Ord>** local_ext = ext; // If the user supplied custom ext functions for this form. if (form->ext.size() > 0) local_ext = this->init_ext_orders(form->ext, (form->u_ext_fn.size() > 0 ? form->u_ext_fn : form->wf->u_ext_fn), u_ext); // Order of shape functions. int max_order_j = spaces[form->j]->get_element_order(current_state->e[form->j]->id); int max_order_i = spaces[form->i]->get_element_order(current_state->e[form->i]->id); if (H2D_GET_V_ORDER(max_order_i) > H2D_GET_H_ORDER(max_order_i)) max_order_i = H2D_GET_V_ORDER(max_order_i); else max_order_i = H2D_GET_H_ORDER(max_order_i); if (H2D_GET_V_ORDER(max_order_j) > H2D_GET_H_ORDER(max_order_j)) max_order_j = H2D_GET_V_ORDER(max_order_j); else max_order_j = H2D_GET_H_ORDER(max_order_j); for (unsigned int k = 0; k < current_state->rep->nvert; k++) { int eo = spaces[form->i]->get_edge_order(current_state->e[form->i], k); if (eo > max_order_i) max_order_i = eo; eo = spaces[form->j]->get_edge_order(current_state->e[form->j], k); if (eo > max_order_j) max_order_j = eo; } Func<Hermes::Ord>* ou = init_fn_ord(max_order_j + (spaces[form->j]->get_shapeset()->get_num_components() > 1 ? 1 : 0)); Func<Hermes::Ord>* ov = init_fn_ord(max_order_i + (spaces[form->i]->get_shapeset()->get_num_components() > 1 ? 1 : 0)); // Total order of the vector form. double fake_wt = 1.0; Geom<Hermes::Ord> tmp; Hermes::Ord o = form->ord(1, &fake_wt, u_ext, ou, ov, &tmp, local_ext); adjust_order_to_refmaps(form, order, &o, current_refmaps); // Cleanup. if (form->ext.size() > 0) this->deinit_ext_orders(form->ext, (form->u_ext_fn.size() > 0 ? form->u_ext_fn : form->wf->u_ext_fn), local_ext); delete ou; delete ov; return order; }
// using pss and coefficient array void Solution::set_coeff_vector(Space* space, PrecalcShapeset* pss, scalar* coeffs, bool add_dir_lift) { int o; // some sanity checks if (space == NULL) error("Space == NULL in Solution::set_coeff_vector()."); if (space->get_mesh() == NULL) error("Mesh == NULL in Solution::set_coeff_vector()."); if (pss == NULL) error("PrecalcShapeset == NULL in Solution::set_coeff_vector()."); if (coeffs == NULL) error("Coefficient vector == NULL in Solution::set_coeff_vector()."); if (!space->is_up_to_date()) error("Provided 'space' is not up to date."); if (space->get_shapeset() != pss->get_shapeset()) error("Provided 'space' and 'pss' must have the same shapesets."); int ndof = Space::get_num_dofs(space); space_type = space->get_type(); free(); num_components = pss->get_num_components(); type = HERMES_SLN; num_dofs = Space::get_num_dofs(space); // copy the mesh TODO: share meshes between solutions // WHAT??? mesh = space->get_mesh(); // allocate the coefficient arrays num_elems = mesh->get_max_element_id(); if(elem_orders != NULL) delete [] elem_orders; elem_orders = new int[num_elems]; memset(elem_orders, 0, sizeof(int) * num_elems); for (int l = 0; l < num_components; l++) { if(elem_coefs[l] != NULL) delete [] elem_coefs[l]; elem_coefs[l] = new int[num_elems]; memset(elem_coefs[l], 0, sizeof(int) * num_elems); } // obtain element orders, allocate mono_coefs Element* e; num_coefs = 0; for_all_active_elements(e, mesh) { mode = e->get_mode(); o = space->get_element_order(e->id); o = std::max(H2D_GET_H_ORDER(o), H2D_GET_V_ORDER(o)); for (unsigned int k = 0; k < e->nvert; k++) { int eo = space->get_edge_order(e, k); if (eo > o) o = eo; } // Hcurl: actual order of functions is one higher than element order if ((space->get_shapeset())->get_num_components() == 2) o++; num_coefs += mode ? sqr(o+1) : (o+1)*(o+2)/2; elem_orders[e->id] = o; }
int L2ShapesetTaylor::get_num_bubbles(int order, ElementMode2D mode) const { if(mode == HERMES_MODE_QUAD) { assert(H2D_GET_V_ORDER(order) == H2D_GET_H_ORDER(order)); return bubble_count[mode][H2D_GET_V_ORDER(order)]; } else return Shapeset::get_num_bubbles(order, mode); }
void Adapt<Scalar>::homogenize_shared_mesh_orders(Mesh** meshes) { Element* e; for (int i = 0; i < this->num; i++) { for_all_active_elements(e, meshes[i]) { int current_quad_order = this->spaces[i]->get_element_order(e->id); int current_order_h = H2D_GET_H_ORDER(current_quad_order), current_order_v = H2D_GET_V_ORDER(current_quad_order); for (int j = 0; j < this->num; j++) if ((j != i) && (meshes[j] == meshes[i])) // components share the mesh { int quad_order = this->spaces[j]->get_element_order(e->id); current_order_h = std::max(current_order_h, H2D_GET_H_ORDER(quad_order)); current_order_v = std::max(current_order_v, H2D_GET_V_ORDER(quad_order)); } this->spaces[i]->set_element_order_internal(e->id, H2D_MAKE_QUAD_ORDER(current_order_h, current_order_v)); } }
double KrivodonovaDiscontinuityDetector::calculate_h(Element* e, int polynomial_order) { double h = std::sqrt(std::pow(e->vn[(0 + 1) % e->get_num_surf()]->x - e->vn[0]->x, 2) + std::pow(e->vn[(0 + 1) % e->get_num_surf()]->y - e->vn[0]->y, 2)); for(int edge_i = 0; edge_i < e->get_num_surf(); edge_i++) { double edge_length = std::sqrt(std::pow(e->vn[(edge_i + 1) % e->get_num_surf()]->x - e->vn[edge_i]->x, 2) + std::pow(e->vn[(edge_i + 1) % e->get_num_surf()]->y - e->vn[edge_i]->y, 2)); if(edge_length < h) h = edge_length; } return std::pow(h, (0.5 * (H2D_GET_H_ORDER(spaces[0]->get_element_order(e->id)) + H2D_GET_V_ORDER(spaces[0]->get_element_order(e->id))) + 1) / 2); }
void Solution::set_fe_solution(Space* space, PrecalcShapeset* pss, scalar* vec, double dir) { int o; // some sanity checks if (!space->is_up_to_date()) error("Provided 'space' is not up to date."); if (space->get_shapeset() != pss->get_shapeset()) error("Provided 'space' and 'pss' must have the same shapesets."); space_type = space->get_type(); free(); num_components = pss->get_num_components(); type = SLN; num_dofs = space->get_num_dofs(); // copy the mesh TODO: share meshes between solutions mesh = new Mesh; mesh->copy(space->get_mesh()); own_mesh = true; // allocate the coefficient arrays num_elems = mesh->get_max_element_id(); elem_orders = new int[num_elems]; memset(elem_orders, 0, sizeof(int) * num_elems); for (int l = 0; l < num_components; l++) { elem_coefs[l] = new int[num_elems]; memset(elem_coefs[l], 0, sizeof(int) * num_elems); } // obtain element orders, allocate mono_coefs Element* e; num_coefs = 0; for_all_active_elements(e, mesh) { mode = e->get_mode(); o = space->get_element_order(e->id); o = std::max(H2D_GET_H_ORDER(o), H2D_GET_V_ORDER(o)); for (unsigned int k = 0; k < e->nvert; k++) { int eo = space->get_edge_order(e, k); if (eo > o) o = eo; } // FIXME: eo tam jeste porad necemu vadi... // Hcurl: actual order of functions is one higher than element order if ((space->get_shapeset())->get_num_components() == 2) o++; num_coefs += mode ? sqr(o+1) : (o+1)*(o+2)/2; elem_orders[e->id] = o; }
void FluxLimiter::limit_according_to_detector(std::set<int>& discontinuous_elements) { // First adjust the solution_vector. for(unsigned int space_i = 0; space_i < spaces.size(); space_i++) for(std::set<int>::iterator it = discontinuous_elements.begin(); it != discontinuous_elements.end(); it++) { AsmList al; spaces[space_i]->get_element_assembly_list(spaces[space_i]->get_mesh()->get_element(*it), &al); for(unsigned int shape_i = 0; shape_i < al.cnt; shape_i++) if(H2D_GET_H_ORDER(spaces[space_i]->get_shapeset()->get_order(al.idx[shape_i])) > 0) solution_vector[al.dof[shape_i]] = 0.0; } // Now adjust the solutions. Solution::vector_to_solutions(solution_vector, spaces, solutions); };
std::set<int>& DiscontinuityDetector::get_discontinuous_element_ids(double threshold) { Element* e; for_all_active_elements(e, mesh) { for(int edge_i = 0; edge_i < e->get_num_surf(); edge_i++) if(calculate_relative_flow_direction(e, edge_i) < -1e-3 && !e->en[edge_i]->bnd) { double jump = calculate_jumps(e, edge_i); double diameter_indicator = std::pow(e->get_diameter(), (H2D_GET_H_ORDER(spaces[0]->get_element_order(e->id)) + 1) / 2); double edge_length = std::sqrt(std::pow(e->vn[(edge_i + 1) % 4]->x - e->vn[edge_i]->x, 2) + std::pow(e->vn[(edge_i + 1) % 4]->y - e->vn[edge_i]->y, 2)); double norm = calculate_norm(e, edge_i); double discontinuity_detector = jump / (diameter_indicator * edge_length * norm); if(discontinuity_detector > threshold) discontinuous_element_ids.insert(e->id); } } return discontinuous_element_ids; };
Hermes::vector<Cand> create_candidates(Element* e, int quad_order) { Hermes::vector<Cand> candidates; // Get the current order range. int current_min_order, current_max_order; this->get_current_order_range(e, current_min_order, current_max_order); int order_h = H2D_GET_H_ORDER(quad_order), order_v = H2D_GET_V_ORDER(quad_order); if(current_max_order < std::max(order_h, order_v)) current_max_order = std::max(order_h, order_v); int last_order_h = std::min(current_max_order, order_h + 1), last_order_v = std::min(current_max_order, order_v + 1); int last_order = H2D_MAKE_QUAD_ORDER(last_order_h, last_order_v); switch(strategy) { case(hORpSelectionBasedOnDOFs): { candidates.push_back(Cand(H2D_REFINEMENT_P, quad_order)); } case(hXORpSelectionBasedOnError): { candidates.push_back(Cand(H2D_REFINEMENT_P, last_order)); candidates.push_back(Cand(H2D_REFINEMENT_H, quad_order, quad_order, quad_order, quad_order)); return candidates; } break; case(isoHPSelectionBasedOnDOFs): { this->cand_list = H2D_HP_ISO; return H1ProjBasedSelector<complex>::create_candidates(e, quad_order); } break; case(anisoHPSelectionBasedOnDOFs): { this->cand_list = H2D_HP_ANISO; return H1ProjBasedSelector<complex>::create_candidates(e, quad_order); } break; } }
void Orderizer::load_data(const char* filename) { FILE* f = fopen(filename, "rb"); if (f == NULL) error("Could not open %s for reading.", filename); lock_data(); struct { char magic[4]; int ver; } hdr; if (fread(&hdr, sizeof(hdr), 1, f) != 1) error("Error reading %s", filename); if (hdr.magic[0] != 'H' || hdr.magic[1] != '2' || hdr.magic[2] != 'D' || hdr.magic[3] != 'O') error("File %s is not a Hermes2D Orderizer<Scalar> file.", filename); if (hdr.ver > 1) error("File %s -- unsupported file version.", filename); #define read_array(array, type, n, c, what) \ if (fread(&n, sizeof(int), 1, f) != 1) \ error("Error reading the number of " what " from %s", filename); \ lin_init_array(array, type, c, n); \ if (fread(array, sizeof(type), n, f) != (unsigned) n) \ error("Error reading " what " from %s", filename); read_array(verts, double3, nv, cv, "vertices"); read_array(tris, int3, nt, ct, "triangles"); read_array(edges, int3, ne, ce, "edges"); read_array(lvert, int, nl, cl1, "label vertices"); lin_init_array(lbox, double2, cl3, nl); if (fread(lbox, sizeof(double2), nl, f) != (unsigned) nl) error("Error reading label bounding boxes from %s", filename); int* orders = new int[nl]; if (fread(orders, sizeof(int), nl, f) != (unsigned) nl) error("Error reading element orders from %s", filename); lin_init_array(ltext, char*, cl2, nl); for (int i = 0; i < nl; i++) ltext[i] = labels[H2D_GET_H_ORDER(orders[i])][H2D_GET_V_ORDER(orders[i])]; find_min_max(); unlock_data(); fclose(f); }
void VertexBasedLimiter::process() { // 0. Preparation. // Start by creating temporary solutions and states for paralelism. Solution<double>::vector_to_solutions(this->solution_vector, this->spaces, this->limited_solutions); // 1. Quadratic // Prepare the vertex values for the quadratic part. prepare_min_max_vertex_values(true); // Use those to incorporate the correction factor. Element* e; // Vector to remember if there was limiting of the second derivatives. Hermes::vector<bool> quadratic_correction_done; if (this->get_verbose_output()) std::cout << "Quadratic correction" << std::endl; for (int component = 0; component < this->component_count; component++) { MeshSharedPtr mesh = this->spaces[component]->get_mesh(); if (this->get_verbose_output() && this->component_count > 1) std::cout << "Component: " << component << std::endl; for_all_active_elements(e, mesh) { bool second_order = H2D_GET_H_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2 || H2D_GET_V_ORDER(this->spaces[component]->get_element_order(e->id)) >= 2; if (!second_order) { quadratic_correction_done.push_back(false); continue; } if (this->get_verbose_output()) std::cout << "Element: " << e->id << std::endl; quadratic_correction_done.push_back(this->impose_quadratic_correction_factor(e, component)); if (this->get_verbose_output()) std::cout << std::endl; } }
void PrecalcShapeset::set_active_shape(int index) { // Key creation. unsigned key = cur_quad | (mode << 3) | ((unsigned) (max_index[mode] - index) << 4); if(master_pss == NULL) { if(!tables.present(key)) tables.add(new std::map<uint64_t, LightArray<Node*>*>, key); sub_tables = tables.get(key); } else { if(!master_pss->tables.present(key)) master_pss->tables.add(new std::map<uint64_t, LightArray<Node*>*>, key); sub_tables = master_pss->tables.get(key); } // Update the Node table. update_nodes_ptr(); this->index = index; order = std::max(H2D_GET_H_ORDER(shapeset->get_order(index)), H2D_GET_V_ORDER(shapeset->get_order(index))); }
bool POnlySelector<Scalar>::select_refinement(Element* element, int order, MeshFunction<Scalar>* rsln, ElementToRefine& refinement) { refinement.split = H2D_REFINEMENT_P; //determin max. order int max_allowed_order = this->max_order; if(this->max_order == H2DRS_DEFAULT_ORDER) max_allowed_order = H2DRS_MAX_ORDER; //calculate new_ order int order_h = H2D_GET_H_ORDER(order), order_v = H2D_GET_V_ORDER(order); int new_order_h = std::min(max_allowed_order, order_h + order_h_inc); int new_order_v = std::min(max_allowed_order, order_v + order_v_inc); if(element->is_triangle()) refinement.refinement_polynomial_order[0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_P][0] = new_order_h; else refinement.refinement_polynomial_order[0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_P][0] = H2D_MAKE_QUAD_ORDER(new_order_h, new_order_v); //decide if successful if(new_order_h > order_h || new_order_v > order_v) return true; else return false; }
void L2OrthoHP::get_optimal_refinement(Element* e, int order, Solution* rsln, int& split, int p[4], bool h_only, bool iso_only, double conv_exp, int max_order) { int i, j, k, n = 0; const int maxcand = 300; order = std::max(H2D_GET_H_ORDER(order), H2D_GET_V_ORDER(order)); bool tri = e->is_triangle(); // calculate maximal order of elements // linear elements = 9 // curvilinear elements = depends on iro_cache (how curved they are) if (max_order == -1) max_order = (20 - e->iro_cache)/2 - 2; // default else max_order = std::min( max_order, (20 - e->iro_cache)/2 - 2); // user specified Cand* cand = new Cand[maxcand]; #define make_p_cand(q) { \ assert(n < maxcand); \ cand[n].split = -1; \ cand[n].p[1] = cand[n].p[2] = cand[n].p[3] = 0; \ cand[n++].p[0] = (q); } #define make_hp_cand(q0, q1, q2, q3) { \ assert(n < maxcand); \ cand[n].split = 0; \ cand[n].p[0] = (q0); \ cand[n].p[1] = (q1); \ cand[n].p[2] = (q2); \ cand[n++].p[3] = (q3); } #define make_ani_cand(q0, q1, iso) { \ assert(n < maxcand); \ cand[n].split = iso; \ cand[n].p[2] = cand[n].p[3] = 0; \ cand[n].p[0] = (q0); \ cand[n++].p[1] = (q1); }\ if (h_only) { make_p_cand(order); make_hp_cand(order, order, order, order); make_ani_cand(order, order, 1); make_ani_cand(order, order, 2); } else { // prepare p-candidates int p0, p1 = std::min(max_order, order+1); for (p0 = order; p0 <= p1; p0++) make_p_cand(p0); // prepare hp-candidates p0 = (order+1) / 2; p1 = std::min(p0 + 3, order); int q0, q1, q2, q3; for (q0 = p0; q0 <= p1; q0++) for (q1 = p0; q1 <= p1; q1++) for (q2 = p0; q2 <= p1; q2++) for (q3 = p0; q3 <= p1; q3++) make_hp_cand(q0, q1, q2, q3); // prepare anisotropic candidates // only for quadrilaterals // too distorted (curved) elements cannot have aniso refinement (produces even worse elements) if ((!tri) && (e->iro_cache < 8) && !iso_only) { p0 = 2 * (order+1) / 3; int p_max = std::min(max_order, order+1); p1 = std::min(p0 + 3, p_max); for (q0 = p0; q0 <= p1; q0++) for (q1 = p0; q1 <= p1; q1++) { if ((q0 < order+1) || (q1 < order+1)) { make_ani_cand(q0, q1, 1); make_ani_cand(q0, q1, 2); } } } } // calculate (partial) projection errors double herr[8][11], perr[11]; calc_projection_errors(e, order, rsln, herr, perr); // evaluate candidates (sum partial projection errors, calculate dofs) double avg = 0.0; double dev = 0.0; for (i = k = 0; i < n; i++) { Cand* c = cand + i; if (c->split == 0) { c->error = 0.0; c->dofs = tri ? 6 : 9; for (j = 0; j < 4; j++) { int o = c->p[j]; c->error += herr[j][o] * 0.25; // spravny vypocet chyby if (tri) { c->dofs += (o-2)*(o-1)/2; if (j < 3) c->dofs += std::min(o, c->p[3])-1 + 2*(o-1); } else { c->dofs += sqr(o)-1; c->dofs += 2 * std::min(o, c->p[j>0 ? j-1 : 3]) - 1; } } } else if (c->split == 1 || c->split == 2) // aniso splits { c->dofs = 6 /* vertex */ + 3*(c->p[0] - 1 + c->p[1] - 1); // edge fns c->dofs += std::min(c->p[0], c->p[1]) - 1; // common edge c->dofs += sqr(c->p[0] - 1) + sqr(c->p[1] - 1); // bubbles for (c->error = 0.0, j = 0; j < 2; j++) c->error += herr[(c->split == 1) ? j+4 : j+6][c->p[j]] * 0.5; // spravny vypocet chyby } else { int o = c->p[0]; c->error = perr[o]; c->dofs = tri ? (o+1)*(o+2)/2 : sqr(o+1); } c->error = sqrt(c->error); //verbose("Cand #%d: Orders %d %d %d %d, Error %g, Dofs %d", i, c->p[0],c->p[1],c->p[2],c->p[3],c->error, c->dofs); if (!i || c->error <= cand[0].error) { avg += log(c->error); dev += sqr(log(c->error)); k++; } } avg /= k; // mean dev /= k; // second moment dev = sqrt(dev - sqr(avg)); // deviation is square root of variance // select an above-average candidate with the steepest error decrease int imax = 0; double score, maxscore = 0.0; for (i = 1; i < n; i++) { if ((log(cand[i].error) < avg + dev) && (cand[i].dofs > cand[0].dofs)) { score = (log(cand[0].error) - log(cand[i].error)) / //(pow(cand[i].dofs, conv_exp) - pow(cand[0].dofs, conv_exp)); pow(cand[i].dofs - cand[0].dofs, conv_exp); if (score > maxscore) { maxscore = score; imax = i; } } } // return result split = cand[imax].split; memcpy(p, cand[imax].p, 4*sizeof(int)); //verbose("Selected Candidate #%d: Orders %d %d %d %d\n", imax, p[0],p[1],p[2],p[3]); }
void ProjBasedSelector::evaluate_cands_error(Element* e, Solution* rsln, double* avg_error, double* dev_error) { bool tri = e->is_triangle(); // find range of orders CandsInfo info_h, info_p, info_aniso; update_cands_info(info_h, info_p, info_aniso); // calculate squared projection errors of elements of candidates CandElemProjError herr[4], anisoerr[4], perr; calc_projection_errors(e, info_h, info_p, info_aniso, rsln, herr, perr, anisoerr); //evaluate errors and dofs double sum_err = 0.0; double sum_sqr_err = 0.0; int num_processed = 0; Cand& unrefined_c = candidates[0]; for (unsigned i = 0; i < candidates.size(); i++) { Cand& c = candidates[i]; double error_squared = 0.0; if (tri) { //triangle switch(c.split) { case H2D_REFINEMENT_H: error_squared = 0.0; for (int j = 0; j < H2D_MAX_ELEMENT_SONS; j++) { int order = H2D_GET_H_ORDER(c.p[j]); error_squared += herr[j][order][order]; } error_squared *= 0.25; //element of a candidate occupies 1/4 of the reference domain defined over a candidate break; case H2D_REFINEMENT_P: { int order = H2D_GET_H_ORDER(c.p[0]); error_squared = perr[order][order]; } break; default: error("Unknown split type \"%d\" at candidate %d", c.split, i); } } else { //quad switch(c.split) { case H2D_REFINEMENT_H: error_squared = 0.0; for (int j = 0; j < H2D_MAX_ELEMENT_SONS; j++) { int order_h = H2D_GET_H_ORDER(c.p[j]), order_v = H2D_GET_V_ORDER(c.p[j]); error_squared += herr[j][order_h][order_v]; } error_squared *= 0.25; //element of a candidate occupies 1/4 of the reference domain defined over a candidate break; case H2D_REFINEMENT_ANISO_H: case H2D_REFINEMENT_ANISO_V: { error_squared = 0.0; for (int j = 0; j < 2; j++) error_squared += anisoerr[(c.split == H2D_REFINEMENT_ANISO_H) ? j : j+2][H2D_GET_H_ORDER(c.p[j])][H2D_GET_V_ORDER(c.p[j])]; error_squared *= 0.5; //element of a candidate occupies 1/2 of the reference domain defined over a candidate } break; case H2D_REFINEMENT_P: { int order_h = H2D_GET_H_ORDER(c.p[0]), order_v = H2D_GET_V_ORDER(c.p[0]); error_squared = perr[order_h][order_v]; } break; default: error("Unknown split type \"%d\" at candidate %d", c.split, i); } } //calculate error from squared error c.error = sqrt(error_squared); //apply weights switch(c.split) { case H2D_REFINEMENT_H: c.error *= error_weight_h; break; case H2D_REFINEMENT_ANISO_H: case H2D_REFINEMENT_ANISO_V: c.error *= error_weight_aniso; break; case H2D_REFINEMENT_P: c.error *= error_weight_p; break; default: error("Unknown split type \"%d\" at candidate %d", c.split, i); } //calculate statistics if (i == 0 || c.error <= unrefined_c.error) { sum_err += log10(c.error); sum_sqr_err += sqr(log10(c.error)); num_processed++; } } *avg_error = sum_err / num_processed; // mean *dev_error = sqrt(sum_sqr_err/num_processed - sqr(*avg_error)); // deviation is square root of variance }
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 == HERMES_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 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 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]]; }
bool select_refinement(Element* element, int order, MeshFunction<complex>* rsln, ElementToRefine& refinement) { switch(strategy) { case(noSelectionH): { refinement.split = H2D_REFINEMENT_H; refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][1] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][2] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][3] = order; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H]); return true; } break; case(noSelectionHP): { int max_allowed_order = this->max_order; if(this->max_order == H2DRS_DEFAULT_ORDER) max_allowed_order = H2DRS_MAX_ORDER; int order_h = H2D_GET_H_ORDER(order), order_v = H2D_GET_V_ORDER(order); int increased_order_h = std::min(max_allowed_order, order_h + 1), increased_order_v = std::min(max_allowed_order, order_v + 1); int increased_order; if(element->is_triangle()) increased_order = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = H2D_MAKE_QUAD_ORDER(increased_order_h, increased_order_h); else increased_order = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = H2D_MAKE_QUAD_ORDER(increased_order_h, increased_order_v); refinement.split = H2D_REFINEMENT_H; refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][0] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][1] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][2] = refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H][3] = increased_order; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, refinement.best_refinement_polynomial_order_type[H2D_REFINEMENT_H]); return true; } case(hXORpSelectionBasedOnError): { //make an uniform order in a case of a triangle int order_h = H2D_GET_H_ORDER(order), order_v = H2D_GET_V_ORDER(order); int current_min_order, current_max_order; this->get_current_order_range(element, current_min_order, current_max_order); if(current_max_order < std::max(order_h, order_v)) current_max_order = std::max(order_h, order_v); int last_order_h = std::min(current_max_order, order_h + 1), last_order_v = std::min(current_max_order, order_v + 1); int last_order = H2D_MAKE_QUAD_ORDER(last_order_h, last_order_v); //build candidates. Hermes::vector<Cand> candidates; candidates.push_back(Cand(H2D_REFINEMENT_P, last_order)); candidates.push_back(Cand(H2D_REFINEMENT_H, order, order, order, order)); this->evaluate_cands_error(candidates, element, rsln); Cand* best_candidate = (candidates[0].error < candidates[1].error) ? &candidates[0] : &candidates[1]; Cand* best_candidates_specific_type[4]; best_candidates_specific_type[H2D_REFINEMENT_P] = &candidates[0]; best_candidates_specific_type[H2D_REFINEMENT_H] = &candidates[1]; best_candidates_specific_type[2] = NULL; best_candidates_specific_type[3] = NULL; //copy result to output refinement.split = best_candidate->split; ElementToRefine::copy_orders(refinement.refinement_polynomial_order, best_candidate->p); for(int i = 0; i < 4; i++) if(best_candidates_specific_type[i] != NULL) ElementToRefine::copy_orders(refinement.best_refinement_polynomial_order_type[i], best_candidates_specific_type[i]->p); ElementToRefine::copy_errors(refinement.errors, best_candidate->errors); //modify orders in a case of a triangle such that order_v is zero if(element->is_triangle()) for(int i = 0; i < H2D_MAX_ELEMENT_SONS; i++) refinement.refinement_polynomial_order[i] = H2D_MAKE_QUAD_ORDER(H2D_GET_H_ORDER(refinement.refinement_polynomial_order[i]), 0); return true; } default: H1ProjBasedSelector<complex>::select_refinement(element, order, rsln, refinement); return true; break; } }
void L2OrthoHP::calc_ortho_base() { int i, j, k, l, m, ii, nb, np, o, r; int n, idx[121]; H1Shapeset shapeset; // allocate the orthonormal base tables - these are simply the values of the // orthonormal functions in integration points; we store the basic functions // plus four son cut-outs of them (i.e. 5 times) for (i = 0; i < 9; i++) { if ((i < 4) || (i >= 8)) obase[0][i] = new_matrix<double3>(66, 79); // tri obase[1][i] = new_matrix<double3>(121, 121); // quad } // repeat for triangles and quads for (m = 0; m <= 1; m++) { shapeset.set_mode(m); // obtain a list of all shape functions up to the order 10, from lowest to highest order n = 0; int nv = m ? 4 : 3; int num_sons = m ? 8 : 4; for (i = 0; i < nv; i++) idx[n++] = shapeset.get_vertex_index(i); basecnt[m][0] = 0; basecnt[m][1] = n; for (i = 2; i <= 10; i++) { for (j = 0; j < nv; j++) idx[n++] = shapeset.get_edge_index(j, 0, i); ii = m ? H2D_MAKE_QUAD_ORDER(i, i) : i; nb = shapeset.get_num_bubbles(ii); int* bub = shapeset.get_bubble_indices(ii); for (j = 0; j < nb; j++) { o = shapeset.get_order(bub[j]); if (H2D_GET_H_ORDER(o) == i || H2D_GET_V_ORDER(o) == i) idx[n++] = bub[j]; } basecnt[m][i] = n; } // obtain their values for integration rule 20 g_quad_2d_std.set_mode(m); np = g_quad_2d_std.get_num_points(20); double3* pt = g_quad_2d_std.get_points(20); for (i = 0; i < n; i++) for (j = 0; j < np; j++) for (k = 0; k < 3; k++) obase[m][8][i][j][k] = shapeset.get_value(k, idx[i], pt[j][0], pt[j][1], 0); for (l = 0; l < num_sons; l++) { Trf* tr = (m ? quad_trf : tri_trf) + l; for (i = 0; i < n; i++) for (j = 0; j < np; j++) { double x = tr->m[0]*pt[j][0] + tr->t[0], y = tr->m[1]*pt[j][1] + tr->t[1]; for (k = 0; k < 3; k++) obase[m][l][i][j][k] = shapeset.get_value(k, idx[i], x, y, 0); } } // orthonormalize the basis functions for (i = 0; i < n; i++) { for (j = 0; j < i; j++) { double prod = 0.0; for (k = 0; k < np; k++) { double sum = 0.0; for (r = 0; r < 1; r++) sum += obase[m][8][i][k][r] * obase[m][8][j][k][r]; prod += pt[k][2] * sum; } for (l = 0; l < 9; l++) if (m || l < 4 || l >= 8) for (k = 0; k < np; k++) for (r = 0; r < 1; r++) obase[m][l][i][k][r] -= prod * obase[m][l][j][k][r]; } double norm = 0.0; for (k = 0; k < np; k++) { double sum = 0.0; for (r = 0; r < 1; r++) sum += sqr(obase[m][8][i][k][r]); norm += pt[k][2] * sum; } norm = sqrt(norm); for (l = 0; l < 9; l++) if (m || l < 4 || l >= 8) for (k = 0; k < np; k++) for (r = 0; r < 1; r++) obase[m][l][i][k][r] /= norm; } // check the orthonormal base /* if (m) { for (i = 0; i < n; i++) for (j = 0; j < n; j++) { double check = 0.0; for(int son = 4; son < 6; son++ ) for (k = 0; k < np; k++) check += pt[k][2] * (obase[m][son][i][k][0] * obase[m][son][j][k][0] + obase[m][son][i][k][1] * obase[m][son][j][k][1] + obase[m][son][i][k][2] * obase[m][son][j][k][2]); check *= 0.5; if ((i == j && fabs(check - 1.0) > 1e-8) || (i != j && fabs(check) > 1e-8)) warn("Not orthonormal: base %d times base %d = %g", i, j , check); } }*/ } obase_ready = true; }
void RefSystem::global_refinement() { // after this, meshes and spaces are NULL this->free_spaces(); // create new meshes and spaces this->meshes = new Mesh*[this->wf->neq]; this->spaces = new Space*[this->wf->neq]; this->sp_seq = new int[this->wf->neq]; int i, j; // copy meshes from the coarse problem and refine them for (i = 0; i < this->wf->neq; i++) { Mesh* mesh = base->spaces[i]->get_mesh(); // check if we already have the same mesh for (j = 0; j < i; j++) if (mesh->get_seq() == base->spaces[j]->get_mesh()->get_seq()) break; if (j < i) // yes { meshes[i] = meshes[j]; } else // no, copy and refine the coarse one { Mesh* rmesh = new Mesh; rmesh->copy(mesh); if (refinement == 1) rmesh->refine_all_elements(); if (refinement == -1) rmesh->unrefine_all_elements(); this->meshes[i] = rmesh; } } // duplicate spaces from the coarse problem, assign reference orders and dofs int ndof = 0; for (i = 0; i < this->wf->neq; i++) { this->spaces[i] = this->base->spaces[i]->dup(this->meshes[i]); if (refinement == -1) { Element* re; for_all_active_elements(re, meshes[i]) { Mesh* mesh = this->base->spaces[i]->get_mesh(); Element* e = mesh->get_element(re->id); int max_order_h = 0, max_order_v = 0; if (e->active) { int quad_order = base->spaces[i]->get_element_order(e->id); max_order_h = H2D_GET_H_ORDER(quad_order); max_order_v = H2D_GET_V_ORDER(quad_order); } else { //find maximum order of sons for (int son = 0; son < 4; son++) { if (e->sons[son] != NULL) { int quad_order = base->spaces[i]->get_element_order(e->sons[son]->id); max_order_h = std::max(max_order_h, H2D_GET_H_ORDER(quad_order)); max_order_v = std::max(max_order_v, H2D_GET_V_ORDER(quad_order)); } } } //increase order and set it to element max_order_h = std::max(1, max_order_h + order_increase); if (re->is_triangle()) max_order_v = 0; else max_order_v = std::max(1, max_order_v + order_increase); spaces[i]->set_element_order_internal(re->id, H2D_MAKE_QUAD_ORDER(max_order_h, max_order_v)); } }
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 L2ProjBasedSelector<Scalar>::create_candidates(Element* e, int quad_order, int max_ha_quad_order, int max_p_quad_order) { int order_h = H2D_GET_H_ORDER(quad_order), order_v = H2D_GET_V_ORDER(quad_order); int max_p_order_h = H2D_GET_H_ORDER(max_p_quad_order), max_p_order_v = H2D_GET_V_ORDER(max_p_quad_order); int max_ha_order_h = H2D_GET_H_ORDER(max_ha_quad_order), max_ha_order_v = H2D_GET_V_ORDER(max_ha_quad_order); bool tri = e->is_triangle(); //clear list of candidates this->candidates.clear(); if (this->candidates.capacity() < H2DRS_ASSUMED_MAX_CANDS) this->candidates.reserve(H2DRS_ASSUMED_MAX_CANDS); //generate all P-candidates (start from intention of generating all possible candidates //and restrict it according to the given adapt-type) bool iso_p = false; int start_quad_order = quad_order; int last_quad_order = H2D_MAKE_QUAD_ORDER(std::min(max_p_order_h, order_h+H2DRS_MAX_ORDER_INC), std::min(max_p_order_v, order_v+H2DRS_MAX_ORDER_INC)); switch(this->cand_list) { case H2D_H_ISO: case H2D_H_ANISO: last_quad_order = start_quad_order; break; //no P-candidates except the original candidate case H2D_P_ISO: case H2D_HP_ISO: case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders } this->append_candidates_split(quad_order, last_quad_order, H2D_REFINEMENT_P, tri || iso_p); //generate all H-candidates iso_p = false; int start_order_h = std::max(this->current_min_order, (order_h+1) / 2), start_order_v = std::max(this->current_min_order, (order_v+1) / 2); start_quad_order = H2D_MAKE_QUAD_ORDER(start_order_h, start_order_v); last_quad_order = H2D_MAKE_QUAD_ORDER(std::min(max_ha_order_h, start_order_h + H2DRS_MAX_ORDER_INC), std::min(max_ha_order_v, start_order_v + H2DRS_MAX_ORDER_INC)); switch(this->cand_list) { case H2D_H_ISO: case H2D_H_ANISO: last_quad_order = start_quad_order = quad_order; break; //no only one candidate will be created case H2D_P_ISO: case H2D_P_ANISO: last_quad_order = -1; break; //no H-candidate will be generated case H2D_HP_ISO: case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders } this->append_candidates_split(start_quad_order, last_quad_order, H2D_REFINEMENT_H, tri || iso_p); //generate all ANISO-candidates if (!tri && e->iro_cache < 8 /** \todo Find and why is iro_cache compared with the number 8. What does the number 8 mean? */ && (this->cand_list == H2D_H_ANISO || this->cand_list == H2D_HP_ANISO_H || this->cand_list == H2D_HP_ANISO)) { iso_p = false; int start_quad_order_hz = H2D_MAKE_QUAD_ORDER(order_h, std::max(this->current_min_order, (order_v+1) / 2)); int last_quad_order_hz = H2D_MAKE_QUAD_ORDER(std::min(max_ha_order_h, order_h+H2DRS_MAX_ORDER_INC), std::min(order_v, H2D_GET_V_ORDER(start_quad_order)+H2DRS_MAX_ORDER_INC)); int start_quad_order_vt = H2D_MAKE_QUAD_ORDER(std::max(this->current_min_order, (order_h+1) / 2), order_v); int last_quad_order_vt = H2D_MAKE_QUAD_ORDER(std::min(order_h, H2D_GET_H_ORDER(start_quad_order)+H2DRS_MAX_ORDER_INC), std::min(max_ha_order_v, order_v+H2DRS_MAX_ORDER_INC)); switch(this->cand_list) { case H2D_H_ANISO: last_quad_order_hz = start_quad_order_hz = quad_order; last_quad_order_vt = start_quad_order_vt = quad_order; break; //only one candidate will be created case H2D_HP_ANISO_H: iso_p = true; break; //iso change of orders } if (iso_p) { //make orders uniform: take mininmum order since nonuniformity is caused by different handling of orders along directions int order = std::min(H2D_GET_H_ORDER(start_quad_order_hz), H2D_GET_V_ORDER(start_quad_order_hz)); start_quad_order_hz = H2D_MAKE_QUAD_ORDER(order, order); order = std::min(H2D_GET_H_ORDER(start_quad_order_vt), H2D_GET_V_ORDER(start_quad_order_vt)); start_quad_order_vt = H2D_MAKE_QUAD_ORDER(order, order); order = std::min(H2D_GET_H_ORDER(last_quad_order_hz), H2D_GET_V_ORDER(last_quad_order_hz)); last_quad_order_hz = H2D_MAKE_QUAD_ORDER(order, order); order = std::min(H2D_GET_H_ORDER(last_quad_order_vt), H2D_GET_V_ORDER(last_quad_order_vt)); last_quad_order_vt = H2D_MAKE_QUAD_ORDER(order, order); } this->append_candidates_split(start_quad_order_hz, last_quad_order_hz, H2D_REFINEMENT_ANISO_H, iso_p); this->append_candidates_split(start_quad_order_vt, last_quad_order_vt, H2D_REFINEMENT_ANISO_V, iso_p); } }