void Solution::set_fe_solution(Space* space, PrecalcShapeset* pss, scalar* vec, double dir) { int i, j, k, l, o; // some sanity checks if (!space->is_up_to_date()) error("'space' is not up to date."); if (space->get_shapeset() != pss->get_shapeset()) error("'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 (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(get_h_order(o), get_v_order(o)); for (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; }
//// adapt ///////////////////////////////////////////////////////////////////////////////////////// bool HcurlOrthoHP::adapt(double thr, int strat, int adapt_type, bool iso_only, int regularize, int max_order) { if (!have_errors) error("Element errors have to be calculated first, see calc_error()."); int i, j; Mesh* mesh[10]; for (j = 0; j < num; j++) { mesh[j] = spaces[j]->get_mesh(); rsln[j]->set_quad_2d(&g_quad_2d_std); rsln[j]->enable_transform(false); } bool h_only = adapt_type == 1 ? true : false; double err0 = 1000.0; double processed_error = 0.0; int successfully_refined = 0; for (i = 0; i < nact; i++) { int comp = esort[i][1]; int id = esort[i][0]; double err = errors[comp][id]; // first refinement strategy: // refine elements until prescribed amount of error is processed // if more elements have similar error refine all to keep the mesh symmetric if ((strat == 0) && (processed_error > sqrt(thr) * total_err) && fabs((err - err0)/err0) > 1e-2) break; // second refinement strategy: // refine all elements whose error is bigger than some portion of maximal error if ((strat == 1) && (err < thr * errors[esort[0][1]][esort[0][0]])) break; Element* e; e = mesh[comp]->get_element(id); int split = 0; int p[4]; int current = spaces[comp]->get_element_order(id); // p-adaptivity if (adapt_type == 2) { split = -1; p[0] = std::min(9, get_h_order(current) + 1); if (get_h_order(current) < p[0]) successfully_refined++; } // h-adaptivity else if ((adapt_type == 1 && iso_only) || (adapt_type == 1 && e->is_triangle())) { p[0] = p[1] = p[2] = p[3] = current; } // hp-adaptivity else { get_optimal_refinement(e, current, rsln[comp], split, p, h_only, iso_only, max_order); successfully_refined++; } if (split < 0) spaces[comp]->set_element_order(id, p[0]); else if (split == 0) { mesh[comp]->refine_element(id); for (j = 0; j < 4; j++) spaces[comp]->set_element_order(e->sons[j]->id, p[j]); } else { mesh[comp]->refine_element(id, split); for (j = 0; j < 2; j++) spaces[comp]->set_element_order(e->sons[ (split == 1) ? j : j+2 ]->id, p[j]); } err0 = err; processed_error += err; } bool done = false; if (successfully_refined == 0) { warn("\nNone of the elements selected for refinement could be refined.\nAdaptivity step not successful, returning 'true'."); done = true; } // mesh regularization if (regularize >= 0) { if (regularize == 0) { regularize = 1; warn("Total mesh regularization is not supported in adaptivity. 1-irregular mesh is used instead."); } for (i = 0; i < num; i++) { int* parents; parents = mesh[i]->regularize(regularize); spaces[i]->distribute_orders(mesh[i], parents); delete [] parents; } } for (j = 0; j < num; j++) rsln[j]->enable_transform(true); verbose("Refined %d elements.", successfully_refined); have_errors = false; return done; }
void HcurlOrthoHP::get_optimal_refinement(Element* e, int order, Solution* rsln, int& split, int p[4], bool h_only, bool iso_only, int max_order) { int i, j, k, n = 0; const int maxcand = 300; order = std::max(get_h_order(order), get_v_order(order)); bool tri = e->is_triangle(); // calculate maximal order of elements // linear elements = 6 // curvilinear elements = depends on iro_cache (how curved they are) if (max_order == -1) max_order = std::min(6, (20 - e->iro_cache)/2 - 1); // default else max_order = std::min(max_order, (20 - e->iro_cache)/2 - 1); // user specified struct Cand { double error; int dofs, p[4]; int split; }; Cand 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); }\ int first_hp; if (h_only) { make_p_cand(order); make_hp_cand(order, order, order, order); if ((!tri) && (!iso_only)) { make_ani_cand(order, order, 1); make_ani_cand(order, order, 2); } } else { // prepare p-candidates int p0, p1 = std::min(max_order, order+2); for (p0 = order; p0 <= p1; p0++) make_p_cand(p0); // prepare hp-candidates first_hp = n; p0 = std::max(1, (order-1)/ 2); p1 = std::min(p0 + 2, 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); // 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 = std::max(1, 2 * (order) / 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; double dev1 = 0.0; for (i = k = 0; i < n; i++) { Cand* c = cand + i; if (c->split == 0) // isotropic split { c->error = 0.0; c->dofs = 0; for (j = 0; j < 4; j++) { c->error += herr[j][c->p[j]];// * 0.25; if (tri) { if (j < 3) { c->dofs += sqr(c->p[j] + 1); // num of bubble and bnd edges c->dofs += std::min(c->p[j], c->p[3]) + 1; // internal edge dofs } else c->dofs += 3 * (c->p[j] - 1) + (c->p[j] - 1) * (c->p[j] - 2); } else { c->dofs += 2 * sqr(c->p[j] + 1); // number of bubble and boundary edges c->dofs += std::min(c->p[j], c->p[j>0 ? j-1 : 3]) + 1; // number of internal edges in element } } } else if ((c->split == 1) || (c->split == 2)) // aniso splits { c->error = 0.0; c->dofs = 0; for (j = 0; j < 2 ; j++) { c->error += herr[ (c->split == 1) ? j+4 : j+6 ][c->p[j]];// * 0.5; c->dofs += 3 * (c->p[j] + 1) + 2 * c->p[j] * (c->p[j] + 1); } c->dofs += std::min(c->p[0], c->p[1]) + 1; } else // p-candidate { c->error = perr[c->p[0]]; if (tri) c->dofs = (c->p[0] + 1) * (c->p[0] + 2); else c->dofs = 2 * (c->p[0] + 1) * (c->p[0] + 2); // number of bubble and boundary edges } 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 += log10(c->error); dev += sqr(log10(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 ((log10(cand[i].error) < avg + dev) && (cand[i].dofs > cand[0].dofs)) { score = (log10(cand[0].error) - log10(cand[i].error)) / (cand[i].dofs - cand[0].dofs); if (score > maxscore) { maxscore = score; imax = i; } } } if (imax == 0) imax = first_hp; // return result split = cand[imax].split; memcpy(p, cand[imax].p, 4*sizeof(int)); }
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 ? 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 (get_h_order(o) == i || 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 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(get_h_order(order), 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 AUTOLA_CL(Cand, 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]); }