int test_quadrature_3d() { int ret = ERR_SUCCESS; // Hexs. if (get_quadrature(HERMES_MODE_HEX) != NULL) { info("- Testing 3D quadrature (hex) -----"); TC3D fn_hex[] = { TC3D(fn_3d_1, 16.0, 2, 2, 2, "x^2 + y^2 + z^2 + x*y*z + x + y + z + 1"), TC3D(fn_3d_2, 184.0/15.0, 2, 3, 4, "x^2 + y^3 + z^4 + x*y*z + x + y + z + 1"), TC3D(fn_3d_3, 184.0/15.0, 3, 4, 2, "x^3 + y^4 + z^2 + x*y*z + x + y + z + 1"), TC3D(fn_3d_4, 184.0/15.0, 4, 2, 3, "x^4 + y^2 + z^3 + x*y*z + x + y + z + 1") }; for (unsigned int i = 0; i < countof(fn_hex); i++) { if ((ret = test_quadrature_3d_hex(fn_hex[i].fn, fn_hex[i].exact, fn_hex[i].min_h_order, fn_hex[i].min_v_order, fn_hex[i].min_u_order, fn_hex[i].fn_name)) != ERR_SUCCESS) return ret; } info("- Testing 3D quadrature (hex) - surf -----"); TC3D fn_hex_surf[] = { TC3D(fn_3d_1, 64.0, 2, 2, 2, "x^2 + y^2 + z^2 + x*y*z + x + y + z + 1") }; for (unsigned int i = 0; i < countof(fn_hex_surf); i++) { if ((ret = test_quadrature_3d_hex_surf(fn_hex_surf[i].fn, fn_hex_surf[i].exact, fn_hex_surf[i].min_h_order, fn_hex_surf[i].min_v_order, fn_hex_surf[i].min_u_order, fn_hex_surf[i].fn_name)) != ERR_SUCCESS) return ret; } } // Tetras. if (get_quadrature(HERMES_MODE_TET) != NULL) { info("- Testing 3D quadrature (tetra) -----"); TC3D Funcetra[] = { TC3D(fn_3d_1, 8.0/9.0, 3, 0, 0, "x^2 + y^2 + z^2 + x*y*z + x + y + z + 1") }; for (unsigned int i = 0; i < countof(Funcetra); i++) { if ((ret = test_quadrature_3d_tetra(Funcetra[i].fn, Funcetra[i].exact, Funcetra[i].min_h_order, Funcetra[i].fn_name)) != ERR_SUCCESS) return ret; } } // TODO: Prisms. return ERR_SUCCESS; }
// l2 product double l2_product(RealFunction *fu, RealFunction *fv) { _F_ Quad3D *quad = get_quadrature(MODE); // integrate with maximum order order3_t o = fu->get_fn_order() + fv->get_fn_order() + order3_t(2, 2, 2); o.limit(); int np = quad->get_num_points(o); QuadPt3D *pt = quad->get_points(o); fu->precalculate(np, pt, FN_DEFAULT); fv->precalculate(np, pt, FN_DEFAULT); scalar *u0, *u1, *u2; u0 = fu->get_fn_values(0); u1 = fu->get_fn_values(1); u2 = fu->get_fn_values(2); scalar *v0, *v1, *v2; v0 = fv->get_fn_values(0); v1 = fv->get_fn_values(1); v2 = fv->get_fn_values(2); // integrating over reference brick -> jacobian is 1.0 (we do not have to bother with refmap) double result = 0.0; for (int i = 0; i < np; i++) result += pt[i].w * (REAL(sqr(u0[i] - v0[i]) + sqr(u1[i] - v1[i]) + sqr(u2[i] - v2[i]))); return result; }
/// Calculates the absolute error between sln1 and sln2 using function fn double calc_error(double (*fn)(MeshFunction*, MeshFunction*, int, QuadPt3D*), MeshFunction *sln1, MeshFunction *sln2) { _F_ Mesh *meshes[2] = { sln1->get_mesh(), sln2->get_mesh() }; Transformable *tr[2] = { sln1, sln2 }; Traverse trav; trav.begin(2, meshes, tr); double error = 0.0; Element **ee; while ((ee = trav.get_next_state(NULL, NULL)) != NULL) { ElementMode3D mode = ee[0]->get_mode(); RefMap *ru = sln1->get_refmap(); Ord3 order = max(sln1->get_fn_order(), sln2->get_fn_order()) + ru->get_inv_ref_order(); order.limit(); Quad3D *quad = get_quadrature(mode); int np = quad->get_num_points(order); QuadPt3D *pt = quad->get_points(order); error += fn(sln1, sln2, np, pt); } trav.finish(); return error > H3D_TINY ? sqrt(error) : error; // do not ruin the precision by taking the sqrt }
// check bubble functions bool test_zero_values_of_bubble_fns(Shapeset *shapeset) { _F_ Quad3D *quad = get_quadrature(MODE); order3_t order(H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER); int n_fns = shapeset->get_num_bubble_fns(order); int *bubble_fn = shapeset->get_bubble_indices(order); for (int fn = 0; fn < n_fns; fn++) { printf(" * Bubble fn #%d ", bubble_fn[fn]); // vertices const Point3D *vtx_pt = REF_DOMAIN::get_vertices(); for (int i = 0; i < Hex::NUM_VERTICES; i++) { if (shapeset->get_fn_value(bubble_fn[fn], vtx_pt[i].x, vtx_pt[i].y, vtx_pt[i].z, 0) > EPS) { warning("Bubble fn #%d is not zero at (% lf, %lf, %lf), vertex #%d.", bubble_fn[fn], vtx_pt[i].x, vtx_pt[i].y, vtx_pt[i].z, i); return false; } } // edges for (int iedge = 0; iedge < Hex::NUM_EDGES; iedge++) { order1_t max_order = quad->get_edge_max_order(iedge); int np = quad->get_edge_num_points(iedge, max_order); QuadPt3D *pts = quad->get_edge_points(iedge, max_order); double vals[np]; shapeset->get_fn_values(bubble_fn[fn], np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Bubble fn #%d is not zero at (% lf, %lf, %lf), edge %d.", bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, iedge); return false; } } } // faces for (int iface = 0; iface < Hex::NUM_FACES; iface++) { order2_t max_order = quad->get_face_max_order(iface); int np = quad->get_face_num_points(iface, max_order); QuadPt3D *pts = quad->get_face_points(iface, max_order); double vals[np]; shapeset->get_fn_values(bubble_fn[fn], np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Bubble fn #%d is not zero at (% lf, %lf, %lf), face %d.", bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, iface); return false; } } } printf("... ok\n"); } return true; }
void SortMassVecs(struct StateData * state) { const QUAD * surfQuad = nil; const QUAD * volQuad = nil; if (!volQuad) { if (state->volume_mesh->parametric && !state->volume_mesh->parametric->not_all) { volQuad = get_quadrature(state->volume_mesh->dim, 2*state->fe_space_volume->bas_fcts->degree + 2); } else { volQuad = get_quadrature(state->volume_mesh->dim, 2*state->fe_space_volume->bas_fcts->degree - 2); } } if (!surfQuad) { if (state->surface_mesh->parametric && !state->surface_mesh->parametric->not_all) { surfQuad = get_quadrature(state->surface_mesh->dim, 2*state->fe_space_surface->bas_fcts->degree + 2); } else { surfQuad = get_quadrature(state->surface_mesh->dim, 2*state->fe_space_surface->bas_fcts->degree - 2); } } dof_set(0.0,state->massM_volume); L2scp_fct_bas(one_function, volQuad, state->massM_volume); dof_set(0.0,state->massM_surface); L2scp_fct_bas(one_function, surfQuad, state->massM_surface); FOR_ALL_DOFS(state->massM_surface_on_vol->fe_space->admin, int surfDOF = state->VolumeToSurfaceMap->vec[dof]; if(surfDOF != -1) state->massM_surface_on_vol->vec[dof] = state->massM_surface->vec[surfDOF]; else state->massM_surface_on_vol->vec[dof] = 0; );
void buildVolume(struct StateData * state) { FUNCNAME("buildVolume"); MSG("Building volume P: %d\n", state->solveCount); static struct op_info *op_info = nil; static const REAL **(*fill_a)(const EL_INFO *, void *) = nil; static void *a_info = nil; static const DOF_ADMIN *admin = nil; static int n; static const DOF *(*get_dof)(const EL *, const DOF_ADMIN *, DOF *); static const S_CHAR *(*get_bound)(const EL_INFO *, S_CHAR *); static const QUAD *quad = nil; TRAVERSE_STACK *stack = get_traverse_stack(); const EL_INFO *el_info; FLAGS fill_flag; const REAL **a_mat; if (!quad) quad = get_quadrature(state->fe_space_volume->bas_fcts->dim, 2*state->fe_space_volume->bas_fcts->degree); SortMassVecs(state); if (admin != state->fe_space_volume->admin) { OPERATOR_INFO o_info2 = {nil}; const EL_MATRIX_INFO *matrix_info; const BAS_FCTS *bas_fcts = state->fe_space_volume->bas_fcts; admin = state->fe_space_volume->admin; n = bas_fcts->n_bas_fcts; get_dof = bas_fcts->get_dof_indices; get_bound = bas_fcts->get_bound; if (!op_info) op_info = MEM_ALLOC(1, struct op_info); o_info2.row_fe_space = o_info2.col_fe_space = state->fe_space_volume; o_info2.quad[2] = quad; o_info2.init_element = init_element; o_info2.LALt = LALt; o_info2.LALt_symmetric = true; o_info2.user_data = op_info; matrix_info = fill_matrix_info(&o_info2, nil); fill_a = matrix_info->el_matrix_fct; a_info = matrix_info->fill_info; }
void HcurlSpace::calc_edge_boundary_projection(Element *elem, int iedge) { _F_ Edge::Key edge = mesh->get_edge_id(elem, iedge); EdgeData *enode = en_data[edge]; if (enode->bc_type != H3D_BC_ESSENTIAL) return; // process only Dirichlet BC if (enode->bc_proj != NULL) return; // projection already calculated int num_fns; if (enode->ced) { assert(enode->edge_ncomponents > 0); Edge::Key edge_id = enode->edge_baselist[0].edge_id; num_fns = en_data[edge_id]->n; } else num_fns = enode->n; if (num_fns <= 0) return; scalar *proj_rhs = new scalar[num_fns]; MEM_CHECK(proj_rhs); for (int i = 0; i < num_fns; i++) proj_rhs[i] = 0.0; RefMap ref_map(mesh); ref_map.set_active_element(elem); Quad3D *quad = get_quadrature(elem->get_mode()); Ord1 order_rhs = quad->get_edge_max_order(iedge); int np = quad->get_edge_num_points(iedge, order_rhs); QuadPt3D *pt = quad->get_edge_points(iedge, order_rhs); double *edge_phys_x = ref_map.get_phys_x(np, pt); double *edge_phys_y = ref_map.get_phys_y(np, pt); double *edge_phys_z = ref_map.get_phys_z(np, pt); for (int k = 0; k < np; k++) { // FIXME: use bc_vec_value_callback_by_coord if (bc_value_callback_by_coord(enode->marker, edge_phys_x[k], edge_phys_y[k], edge_phys_z[k]) != 0.) EXIT(HERMES_ERR_NOT_IMPLEMENTED); // projection of nonzero BC not implemented, see comment in .h } delete [] edge_phys_x; delete [] edge_phys_y; delete [] edge_phys_z; // save vector of zeros as a projection enode->bc_proj = proj_rhs; }
// check bubble functions bool test_zero_values_of_bubble_fns(Shapeset *shapeset) { _F_ Quad3D *quad = get_quadrature(MODE); order3_t order(H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER); int n_fns = shapeset->get_num_bubble_fns(order); int *bubble_fn = shapeset->get_bubble_indices(order); for (int fn = 0; fn < n_fns; fn++) { printf(" * Bubble fn #%d ", bubble_fn[fn]); // edges for (int i = 0; i < Hex::NUM_EDGES; i++) { int max_order = quad->get_edge_max_order(i); QuadPt3D *pts = quad->get_edge_points(i, max_order); for (int j = 0; j < quad->get_edge_num_points(i, max_order); j++) { int comp = RefHex::get_edge_tangent_direction(i); if (shapeset->get_fn_value(bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, comp) > EPS) { warning("Bubble fn #%d is not zero at (% lf, %lf, %lf), edge %d.", bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, i); return false; } } } // faces for (int i = 0; i < Hex::NUM_FACES; i++) { order2_t max_order = quad->get_face_max_order(i); QuadPt3D *pts = quad->get_face_points(i, max_order); for (int j = 0; j < quad->get_face_num_points(i, max_order); j++) { for(int i_comp = 0; i_comp < 2; i_comp++){ int comp = RefHex::get_face_tangent_direction(i, i_comp); if (shapeset->get_fn_value(bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, comp) > EPS) { warning("Bubble fn #%d is not zero at (% lf, %lf, %lf), face %d.", bubble_fn[fn], pts[j].x, pts[j].y, pts[j].z, i); return false; } } } } printf("... ok\n"); } return true; }
/// Calculates the norm of sln using function fn double calc_norm(double (*fn)(MeshFunction*, int, QuadPt3D*), MeshFunction *sln) { _F_ double norm = 0.0; Mesh *mesh = sln->get_mesh(); FOR_ALL_ACTIVE_ELEMENTS(eid, mesh) { Element *e = mesh->elements[eid]; sln->set_active_element(e); RefMap *ru = sln->get_refmap(); order3_t o = sln->get_fn_order() + ru->get_inv_ref_order(); o.limit(); Quad3D *quad = get_quadrature(e->get_mode()); int np = quad->get_num_points(o); QuadPt3D *pt = quad->get_points(o); norm += fn(sln, np, pt); }
// l2 product double l2_product(ShapeFunction *fu, ShapeFunction *fv) { _F_ Quad3D *quad = get_quadrature(MODE_HEXAHEDRON); Ord3 o = fu->get_fn_order() + fv->get_fn_order() + Ord3(1, 1, 1); QuadPt3D *pt = quad->get_points(o); int np = quad->get_num_points(o); fu->precalculate(np, pt, FN_VAL); fv->precalculate(np, pt, FN_VAL); double *uval = fu->get_fn_values(); double *vval = fv->get_fn_values(); // integrating over reference brick -> jacobian is 1.0 (we do not have to bother with refmap) double result = 0.0; for (int i = 0; i < np; i++) result += pt[i].w * (uval[i] * vval[i]); return result; }
void HcurlSpace::calc_face_boundary_projection(Element *elem, int iface) { _F_ Facet::Key facet_idx = mesh->get_facet_id(elem, iface); FaceData *fnode = fn_data[facet_idx]; if (fnode->bc_type != H3D_BC_ESSENTIAL) return; if (fnode->bc_proj != NULL) return; if (fnode->n <= 0) return; scalar *proj_rhs = new scalar[fnode->n]; MEM_CHECK(proj_rhs); for (int i = 0; i < fnode->n; i++) proj_rhs[i] = 0.0; RefMap ref_map(mesh); ref_map.set_active_element(elem); Quad3D *quad = get_quadrature(elem->get_mode()); Ord2 order_rhs = quad->get_face_max_order(iface); int np = quad->get_face_num_points(iface, order_rhs); QuadPt3D *pt = quad->get_face_points(iface, order_rhs); double *face_phys_x = ref_map.get_phys_x(np, pt); double *face_phys_y = ref_map.get_phys_y(np, pt); double *face_phys_z = ref_map.get_phys_z(np, pt); for (int k = 0; k < quad->get_face_num_points(iface, order_rhs); k++) { // FIXME: use bc_vec_value_callback_by_coord if (bc_value_callback_by_coord(fnode->marker, face_phys_x[k], face_phys_y[k], face_phys_z[k]) != 0.) EXIT(HERMES_ERR_NOT_IMPLEMENTED); // projection of nonzero BC not implemented, see comment in .h } delete [] face_phys_x; delete [] face_phys_y; delete [] face_phys_z; // save vector of zeros as a projection fnode->bc_proj = proj_rhs; }
/// Calculates the norm of sln using function fn double calc_norm(double (*fn)(MeshFunction*, int, QuadPt3D*), MeshFunction *sln) { _F_ double norm = 0.0; Mesh *mesh = sln->get_mesh(); for(std::map<unsigned int, Element*>::iterator it = mesh->elements.begin(); it != mesh->elements.end(); it++) if (it->second->used && it->second->active) { Element *e = mesh->elements[it->first]; sln->set_active_element(e); RefMap *ru = sln->get_refmap(); Ord3 o = sln->get_fn_order() + ru->get_inv_ref_order(); o.limit(); Quad3D *quad = get_quadrature(e->get_mode()); int np = quad->get_num_points(o); QuadPt3D *pt = quad->get_points(o); norm += fn(sln, np, pt); } return norm > H3D_TINY ? sqrt(norm) : norm; // do not ruin the precision by taking the sqrt }
Projection::Projection(Solution *afn, Element *e, Shapeset *ss) { _F_ this->sln = afn; this->ss = ss; mesh = sln->get_mesh(); // TODO: check that the element 'e' is not active and has 8 sons base_elem = mesh->elements[e->id]; quad = get_quadrature(e->get_mode()); fu = new ShapeFunction(ss); fv = new ShapeFunction(ss); fu->set_active_element(base_elem); fv->set_active_element(base_elem); // null n_fns = 0; fn_idx = NULL; proj_coef = NULL; }
bool test_cont_values_of_vertex_fns(Mesh *mesh, unsigned int fid, int pos0, int pos1, Shapeset *shapeset) { _F_ Facet *facet = mesh->facets[fid]; Quad3D *quad = get_quadrature(MODE); Element *h[2] = { mesh->elements[facet->left], mesh->elements[facet->right] }; // face vertices const int *face_vtx[] = { h[0]->get_face_vertices(facet->left_face_num), h[1]->get_face_vertices(facet->right_face_num) }; RefMap rm(mesh); Pts vpts[2]; // get coordinates of vertices on the face int vnp = Quad::NUM_VERTICES; for (int i = 0; i < 2; i++) { QuadPt3D *rd_vtx_pt = quad->get_vertex_points(); QuadPt3D *pt = new QuadPt3D[Quad::NUM_VERTICES]; for (int j = 0; j < vnp; j++) pt[j] = rd_vtx_pt[face_vtx[i][j]]; rm.set_active_element(h[i]); vpts[i].ref_pt = pt; vpts[i].phys_x = rm.get_phys_x(vnp, pt); vpts[i].phys_y = rm.get_phys_y(vnp, pt); vpts[i].phys_z = rm.get_phys_z(vnp, pt); // sort points by physical coordinates vpts[i].sort = new int [vnp]; for (int j = 0; j < vnp; j++) vpts[i].sort[j] = j; sort_pts = vpts + i; qsort(vpts[i].sort, vnp, sizeof(int), compare); } // we know which vertices correspond to each other, since we sorted them by their phys. coordinates // we use it for comparing matching vertex functions // obtain coordinates where vertex functions are going to be evaluated Pts fpts[2]; Ord2 face_ord = quad->get_face_max_order(facet->left_face_num); int np = quad->get_face_num_points(facet->left_face_num, face_ord); QuadPt3D *pt[2] = { quad->get_face_points(facet->left_face_num, face_ord), quad->get_face_points(facet->right_face_num, face_ord) }; // transform the coorinates so we can compare them for (int i = 0; i < 2; i++) { rm.set_active_element(h[i]); fpts[i].ref_pt = pt[i]; fpts[i].phys_x = rm.get_phys_x(np, pt[i]); fpts[i].phys_y = rm.get_phys_y(np, pt[i]); fpts[i].phys_z = rm.get_phys_z(np, pt[i]); // sort points by physical coordinates fpts[i].sort = new int [np]; for (int j = 0; j < np; j++) fpts[i].sort[j] = j; sort_pts = fpts + i; qsort(fpts[i].sort, np, sizeof(int), compare); } // loop through vertex functions for (int k = 0; k < Quad::NUM_VERTICES; k++) { int i1 = vpts[0].sort[k]; int i2 = vpts[1].sort[k]; // get values of vertex functions double uval[np], vval[np]; shapeset->get_fn_values(shapeset->get_vertex_index(face_vtx[0][i1]), np, pt[0], 0, uval); shapeset->get_fn_values(shapeset->get_vertex_index(face_vtx[1][i2]), np, pt[1], 0, vval); // compare their values for (int i = 0; i < np; i++) { int j1 = fpts[0].sort[i]; int j2 = fpts[1].sort[i]; if (fabs(uval[j1] - vval[j2]) > EPS) { printf("failed\n"); warning("Vertex fn not continuous @(% lf, % lf, % lf), diff = % e", fpts[0].ref_pt[j1].x, fpts[0].ref_pt[j1].y, fpts[0].ref_pt[j1].z, fabs(uval[j1] - vval[j2])); return false; } } } // free memory for (int i = 0; i < 2; i++) { delete [] vpts[i].ref_pt; delete [] vpts[i].phys_x; delete [] vpts[i].phys_y; delete [] vpts[i].phys_z; delete [] vpts[i].sort; delete [] fpts[i].phys_x; delete [] fpts[i].phys_y; delete [] fpts[i].phys_z; delete [] fpts[i].sort; } return true; }
// check edge functions bool test_zero_values_of_edge_fns(Shapeset *shapeset) { _F_ const int num_edges = 11; // indexing[edge] => { edges to check where the function is zero (local indices) } int edges[][num_edges] = { { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, }; const int num_faces = 4; // indexing[edge] => { faces to check where the function is zero (local indices) } int faces[][num_faces] = { { 0, 1, 3, 5 }, { 0, 2, 3, 5 }, { 0, 1, 2, 5 }, { 1, 2, 3, 5 }, { 1, 3, 4, 5 }, { 0, 3, 4, 5 }, { 0, 2, 4, 5 }, { 1, 2, 4, 5 }, { 0, 1, 3, 4 }, { 0, 2, 3, 4 }, { 0, 1, 2, 4 }, { 1, 2, 3, 4 }, }; Quad3D *quad = get_quadrature(MODE); for (int iedge = 0; iedge < Hex::NUM_EDGES; iedge++) { for (int ori = 0; ori < 2; ori++) { order1_t order = H3D_MAX_ELEMENT_ORDER; int n_fns = shapeset->get_num_edge_fns(order); int *edge_fn = shapeset->get_edge_indices(iedge, ori, order); for (int fn = 0; fn < n_fns; fn++) { printf(" * Edge fn #%d (edge = %d, ori = %d)", edge_fn[fn], iedge, ori); // edges for (int i = 0; i < num_edges; i++) { int max_order = quad->get_edge_max_order(edges[iedge][i]); QuadPt3D *pts = quad->get_edge_points(edges[iedge][i], max_order); for (int j = 0; j < quad->get_edge_num_points(iedge, max_order); j++) { int comp = RefHex::get_edge_tangent_direction(edges[iedge][i]); if (shapeset->get_fn_value(edge_fn[fn], pts[j].x, pts[j].y, pts[j].z, comp) > EPS) { warning("Edge fn #%d is not zero at (% lf, %lf, %lf), edge %d, component %d.\n", edge_fn[fn], pts[j].x, pts[j].y, pts[j].z, edges[iedge][i], comp); return false; } } } // faces for (int i = 0; i < num_faces; i++) { order2_t max_order = quad->get_face_max_order(faces[iedge][i]); QuadPt3D *pts = quad->get_face_points(faces[iedge][i], max_order); for (int j = 0; j < quad->get_face_num_points(faces[iedge][i], max_order); j++) { for (int icomp = 0; icomp < 2; icomp++) { int comp = RefHex::get_face_tangent_direction(faces[iedge][i], icomp); if (shapeset->get_fn_value(edge_fn[fn], pts[j].x, pts[j].y, pts[j].z, comp) > EPS) { warning("Edge fn #%d is not zero at (% lf, %lf, %lf), face %d.", edge_fn[fn], pts[j].x, pts[j].y, pts[j].z, faces[iedge][i]); return false; } } } } printf("... ok\n"); } } } return true; }
// check face functions bool test_zero_values_of_face_fns(Shapeset *shapeset) { _F_ const int num_vertices = 8; // indexing[face] => { vertices to check where the function is zero (local indices) } int vertices[][num_vertices] = { { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 }, { 0, 1, 2, 3, 4, 5, 6, 7 } }; const int num_edges = 12; // indexing[face] => { edges to check where the function is zero (local indices) } int edges[][num_edges] = { { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }, { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 } }; const int num_faces = 5; // indexing[face] => { faces to check where the function is zero (local indices) } int faces[][num_faces] = { { 1, 2, 3, 4, 5 }, { 0, 2, 3, 4, 5 }, { 0, 1, 3, 4, 5 }, { 0, 1, 2, 4, 5 }, { 0, 1, 2, 3, 5 }, { 0, 1, 2, 3, 4 } }; Quad3D *quad = get_quadrature(MODE); for (int face = 0; face < Hex::NUM_FACES; face++) { for (int ori = 0; ori < 8; ori++) { order2_t order(H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER); int n_fns = shapeset->get_num_face_fns(order); int *face_fn = shapeset->get_face_indices(face, ori, order); for (int fn = 0; fn < n_fns; fn++) { printf(" * Face fn #%d (face = %d, ori = %d) ", face_fn[fn], face, ori); // vertices const Point3D *vtx_pt = REF_DOMAIN::get_vertices(); int *idx = vertices[face]; for (int i = 0; i < num_vertices; i++) { if (shapeset->get_fn_value(face_fn[fn], vtx_pt[idx[i]].x, vtx_pt[idx[i]].y, vtx_pt[idx[i]].z, 0) > EPS) { warning("Face fn #%d is not zero at (% lf, %lf, %lf), vertex #%d.", face_fn[fn], vtx_pt[idx[i]].x, vtx_pt[idx[i]].y, vtx_pt[idx[i]].z, idx[i]); return false; } } // edges for (int i = 0; i < num_edges; i++) { order1_t max_order = quad->get_edge_max_order(edges[face][i]); int np = quad->get_edge_num_points(edges[face][i], max_order); QuadPt3D *pts = quad->get_edge_points(edges[face][i], max_order); double vals[np]; shapeset->get_fn_values(face_fn[fn], np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Face fn #%d is not zero at (% lf, %lf, %lf), edge %d.", face_fn[fn], pts[j].x, pts[j].y, pts[j].z, edges[face][i]); return false; } } } // faces for (int i = 0; i < num_faces; i++) { order2_t max_order = quad->get_face_max_order(faces[face][i]); int np = quad->get_face_num_points(faces[face][i], max_order); QuadPt3D *pts = quad->get_face_points(faces[face][i], max_order); double vals[np]; shapeset->get_fn_values(face_fn[fn], np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Face fn #%d is not zero at (% lf, %lf, %lf), face %d.", face_fn[fn], pts[j].x, pts[j].y, pts[j].z, faces[face][i]); return false; } } } printf("... ok\n"); } } } return true; }
// check vertex functions bool test_zero_values_of_vertex_fns(Shapeset *shapeset) { _F_ const int num_vertices = 7; // indexing[vertex] => { vertices to check where the function is zero (local indices) } int vertices[][num_vertices] = { { 1, 2, 3, 4, 5, 6, 7 }, { 0, 2, 3, 4, 5, 6, 7 }, { 0, 1, 3, 4, 5, 6, 7 }, { 0, 1, 2, 4, 5, 6, 7 }, { 0, 1, 2, 3, 5, 6, 7 }, { 0, 1, 2, 3, 4, 6, 7 }, { 0, 1, 2, 3, 4, 5, 7 }, { 0, 1, 2, 3, 4, 5, 6 } }; const int num_edges = 9; // indexing[vertex] => { edges to check where the function is zero (local indices) } int edges[][num_edges] = { { 1, 2, 5, 6, 7, 8, 9, 10, 11 }, { 2, 3, 4, 6, 7, 8, 9, 10, 11 }, { 0, 3, 4, 5, 7, 8, 9, 10, 11 }, { 0, 1, 4, 5, 6, 8, 9, 10, 11 }, { 0, 1, 2, 3, 5, 6, 7, 9, 10 }, { 0, 1, 2, 3, 4, 6, 7, 10, 11 }, { 0, 1, 2, 3, 4, 5, 7, 8, 11 }, { 0, 1, 2, 3, 4, 5, 6, 8, 9 }, }; const int num_faces = 3; // indexing[vertex] => { faces to check where the function is zero (local indices) } int faces[][num_faces] = { { 5, 1, 3 }, { 5, 3, 0 }, { 5, 0, 2 }, { 5, 2, 1 }, { 4, 1, 3 }, { 3, 0, 4 }, { 0, 2, 4 }, { 1, 4, 2 } }; Quad3D *quad = get_quadrature(MODE); for (int vtx = 0; vtx < Hex::NUM_VERTICES; vtx++) { int fn_idx = shapeset->get_vertex_index(vtx); printf(" * Vertex fn #%d (%d) ", vtx, fn_idx); // vertices const Point3D *vtx_pt = REF_DOMAIN::get_vertices(); int *idx = vertices[vtx]; for (int i = 0; i < num_vertices; i++) { if (shapeset->get_fn_value(fn_idx, vtx_pt[idx[i]].x, vtx_pt[idx[i]].y, vtx_pt[idx[i]].z, 0) > EPS) { warning("Vertex fn #%d (%d) is not zero at (% lf, %lf, %lf), vertex #%d.", vtx, fn_idx, vtx_pt[idx[i]].x, vtx_pt[idx[i]].y, vtx_pt[idx[i]].z, idx[i]); return false; } } // edges for (int i = 0; i < num_edges; i++) { order1_t max_order = quad->get_edge_max_order(edges[vtx][i]); int np = quad->get_edge_num_points(edges[vtx][i], max_order); QuadPt3D *pts = quad->get_edge_points(edges[vtx][i], max_order); double vals[np]; shapeset->get_fn_values(fn_idx, np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Vertex fn #%d (%d) is not zero at (% lf, %lf, %lf), edge %d.", vtx, fn_idx, pts[j].x, pts[j].y, pts[j].z, edges[vtx][i]); return false; } } } // faces for (int i = 0; i < num_faces; i++) { order2_t max_order = quad->get_face_max_order(faces[vtx][i]); int np = quad->get_face_num_points(faces[vtx][i], max_order); QuadPt3D *pts = quad->get_face_points(faces[vtx][i], max_order); double vals[np]; shapeset->get_fn_values(fn_idx, np, pts, 0, vals); for (int j = 0; j < np; j++) { if (vals[j] > EPS) { warning("Vertex fn #%d (%d) is not zero at (% lf, %lf, %lf), face %d.", vtx, fn_idx, pts[j].x, pts[j].y, pts[j].z, faces[vtx][i]); return false; } } } printf("... ok\n"); } return true; }
bool test_cont_values_of_edge_fns(Mesh *mesh, unsigned int fid, int pos0, int pos1, Shapeset *shapeset) { _F_ Facet *facet = mesh->facets[fid]; Quad3D *quad = get_quadrature(MODE); Element *h[2] = { mesh->elements[facet->left], mesh->elements[facet->right] }; // local number of edges on the face const int *face_edges[] = { h[0]->get_face_edges(facet->left_face_num), h[1]->get_face_edges(facet->right_face_num) }; // orientations of edges on the face int edge_ori[2][4]; for (int i = 0; i < 4; i++) { edge_ori[0][i] = h[0]->get_edge_orientation(face_edges[0][i]); edge_ori[1][i] = h[1]->get_edge_orientation(face_edges[1][i]); } RefMap rm(mesh); Pts epts[2]; // get coordinates of the point in the middle of an edge on the face // it is used to find matching edges int enp = Quad::NUM_EDGES; for (int i = 0; i < 2; i++) { QuadPt3D *pt = new QuadPt3D[Quad::NUM_EDGES]; for (int j = 0; j < enp; j++) { const int *edge_vtx = RefHex::get_edge_vertices(face_edges[i][j]); QuadPt3D *rd_vtx_pt = quad->get_vertex_points(); pt[j].x = (rd_vtx_pt[edge_vtx[0]].x + rd_vtx_pt[edge_vtx[1]].x) / 2.0; pt[j].y = (rd_vtx_pt[edge_vtx[0]].y + rd_vtx_pt[edge_vtx[1]].y) / 2.0; pt[j].z = (rd_vtx_pt[edge_vtx[0]].z + rd_vtx_pt[edge_vtx[1]].z) / 2.0; } rm.set_active_element(h[i]); epts[i].ref_pt = pt; epts[i].phys_x = rm.get_phys_x(enp, pt); epts[i].phys_y = rm.get_phys_y(enp, pt); epts[i].phys_z = rm.get_phys_z(enp, pt); // sort points by physical coordinates epts[i].sort = new int [enp]; for (int j = 0; j < enp; j++) epts[i].sort[j] = j; sort_pts = epts + i; qsort(epts[i].sort, enp, sizeof(int), compare); } // we know which edge correspond to each other, since we sorted them by their phys. coordinates // we use it for comparing matching edge functions // obtain coordinates where edge functions are going to be evaluated Pts fpts[2]; Ord2 face_ord = quad->get_face_max_order(facet->left_face_num); int np = quad->get_face_num_points(facet->left_face_num, face_ord); QuadPt3D *pt[2] = { quad->get_face_points(facet->left_face_num, face_ord), quad->get_face_points(facet->right_face_num, face_ord) }; // transform the coorinates so we can compare them for (int i = 0; i < 2; i++) { rm.set_active_element(h[i]); fpts[i].ref_pt = pt[i]; fpts[i].phys_x = rm.get_phys_x(np, pt[i]); fpts[i].phys_y = rm.get_phys_y(np, pt[i]); fpts[i].phys_z = rm.get_phys_z(np, pt[i]); // sort points by physical coordinates fpts[i].sort = new int [np]; for (int j = 0; j < np; j++) fpts[i].sort[j] = j; sort_pts = fpts + i; qsort(fpts[i].sort, np, sizeof(int), compare); } // loop through edges for (int k = 0; k < Quad::NUM_EDGES; k++) { int i1 = epts[0].sort[k]; int i2 = epts[1].sort[k]; // loop through edge functions // get all face functions on the face Ord1 order(H3D_MAX_ELEMENT_ORDER); int *edge_fn[] = { shapeset->get_edge_indices(face_edges[0][i1], edge_ori[0][i1], order), shapeset->get_edge_indices(face_edges[1][i2], edge_ori[1][i2], order) }; // loop through face functions int n_edge_fns = shapeset->get_num_edge_fns(order); for (int ifn = 0; ifn < n_edge_fns; ifn++) { // get values of edge functions double uval[np], vval[np]; shapeset->get_fn_values(edge_fn[0][ifn], np, pt[0], 0, uval); shapeset->get_fn_values(edge_fn[1][ifn], np, pt[1], 0, vval); // compare their values for (int i = 0; i < np; i++) { int j1 = fpts[0].sort[i]; int j2 = fpts[1].sort[i]; if (fabs(uval[j1] - vval[j2]) > EPS) { printf("failed\n"); warning("Edge fn not continuous @(% lf, % lf, % lf), diff = % e", fpts[0].ref_pt[j1].x, fpts[0].ref_pt[j1].y, fpts[0].ref_pt[j1].z, fabs(uval[j1] - vval[j2])); return false; } } } } // free memory for (int i = 0; i < 2; i++) { delete [] epts[i].ref_pt; delete [] epts[i].phys_x; delete [] epts[i].phys_y; delete [] epts[i].phys_z; delete [] epts[i].sort; delete [] fpts[i].phys_x; delete [] fpts[i].phys_y; delete [] fpts[i].phys_z; delete [] fpts[i].sort; } return true; }
bool test_cont_values_of_face_fns(Mesh *mesh, unsigned int fid, int pos0, int pos1, Shapeset *shapeset) { _F_ Quad3D *quad = get_quadrature(MODE); Facet *facet = mesh->facets[fid]; Element *h[2] = { mesh->elements[facet->left], mesh->elements[facet->right] }; int face_ori[2] = { h[0]->get_face_orientation(facet->left_face_num), h[1]->get_face_orientation(facet->right_face_num) }; RefMap rm(mesh); // get points where the functions are going to be evaluated Pts fpts[2]; Ord2 face_ord = quad->get_face_max_order(facet->left_face_num); int np = quad->get_face_num_points(facet->left_face_num, face_ord); QuadPt3D *pt[2] = { quad->get_face_points(facet->left_face_num, face_ord), quad->get_face_points(facet->right_face_num, face_ord) }; // transform points and sort them for (int i = 0; i < 2; i++) { rm.set_active_element(h[i]); fpts[i].ref_pt = pt[i]; fpts[i].phys_x = rm.get_phys_x(np, pt[i]); fpts[i].phys_y = rm.get_phys_y(np, pt[i]); fpts[i].phys_z = rm.get_phys_z(np, pt[i]); // sort points by physical coordinates fpts[i].sort = new int [np]; for (int j = 0; j < np; j++) fpts[i].sort[j] = j; sort_pts = fpts + i; qsort(fpts[i].sort, np, sizeof(int), compare); } // get all face functions on the face Ord2 order(H3D_MAX_ELEMENT_ORDER, H3D_MAX_ELEMENT_ORDER); int *face_fn[] = { shapeset->get_face_indices(facet->left_face_num, face_ori[0], order), shapeset->get_face_indices(facet->right_face_num, face_ori[1], order) }; // loop through face functions int n_face_fns = shapeset->get_num_face_fns(order); for (int ifn = 0; ifn < n_face_fns; ifn++) { // evaluate functions double uval[np], vval[np]; shapeset->get_fn_values(face_fn[0][ifn], np, pt[0], 0, uval); shapeset->get_fn_values(face_fn[1][ifn], np, pt[1], 0, vval); // compare for (int i = 0; i < np; i++) { int j1 = fpts[0].sort[i]; int j2 = fpts[1].sort[i]; if (fabs(uval[j1] - vval[j2]) > EPS) { printf("failed\n"); warning("Face fn not continuous @(% lf, % lf, % lf), diff = % e", fpts[0].ref_pt[j1].x, fpts[0].ref_pt[j1].y, fpts[0].ref_pt[j1].z, fabs(uval[j1] - vval[j2])); return false; } } } for (int i = 0; i < 2; i++) { delete [] fpts[i].phys_x; delete [] fpts[i].phys_y; delete [] fpts[i].phys_z; delete [] fpts[i].sort; } return true; }