diff --git a/entity.cpp b/entity.cpp index c7d9b88dcf68844784d487e15c10bcde53b3c74f..fb246a2b5f4e5a7ba5d7d5f5b5217537d317b7e6 100644 --- a/entity.cpp +++ b/entity.cpp @@ -386,7 +386,7 @@ entity::populate_normals(entity_data_cpu& ed) const { auto fnum = 4*iT+iF; assert(fnum < physical_faces.size()); - Eigen::Vector3d n = physical_faces[fnum].jacobian(iQp).inverse()*ref_normal; + Eigen::Vector3d n = physical_faces[fnum].jacobian(iQp)*ref_normal; auto norm_offset = (4*iT+iF)*num_face_qps + iQp; assert(norm_offset < ed.normals.rows()); ed.normals.block(norm_offset, 0, 1, 3) = n.transpose()/n.norm(); diff --git a/gmsh_io.cpp b/gmsh_io.cpp index 59663b0cf1187ea398bcd27d36377fcc4d4cd55a..dbde114eeedeb164b7463c44f9438e759d440d89 100644 --- a/gmsh_io.cpp +++ b/gmsh_io.cpp @@ -77,6 +77,7 @@ model::remesh() gmm::setOrder( geometric_order ); entities.clear(); import_gmsh_entities(); + map_boundaries(); } void @@ -155,18 +156,8 @@ model::map_boundaries(void) assert(elemTypes.size() == 1); for (auto& elemType : elemTypes) { - std::vector<size_t> nTags; - gmm::getElementFaceNodes(elemType, 3, nTags, tag, true); - - std::vector<face_key> fkeys; - for (size_t i = 0; i < nTags.size(); i+= 3) - { - auto fk = face_key({nTags[i+0], nTags[i+1], nTags[i+2]}); - fkeys.push_back( fk ); - } - std::sort(fkeys.begin(), fkeys.end()); - - boundaries_elemTags[tag] = std::move(fkeys); + element_key_factory ekf(DIMENSION(2), tag, elemType); + boundary_map[tag] = ekf.get_keys(); } } } \ No newline at end of file diff --git a/gmsh_io.h b/gmsh_io.h index ee27d25528c5d510bb9d9234eeac6a06b31086d1..6bb94845742d9a4ffeb2e7ebbc7a788d28974cc0 100644 --- a/gmsh_io.h +++ b/gmsh_io.h @@ -31,7 +31,8 @@ class model int approximation_order; - std::vector<entity> entities; + std::vector<entity> entities; + std::map<size_t, std::vector<element_key>> boundary_map; void map_boundaries(void); void import_gmsh_entities(void); @@ -46,6 +47,11 @@ public: void remesh(void); void remesh(int); + std::vector<element_key> get_bnd(size_t which) + { + return boundary_map.at(which); + } + std::vector<entity>::const_iterator begin() const; std::vector<entity>::const_iterator end() const; std::vector<entity>::iterator begin(); diff --git a/physical_element.cpp b/physical_element.cpp index 6a866c171ed3aee97fcf4c54ebd5a4cb3369d132..d806625292a9b953bc88421c3f39b030b89beb4f 100644 --- a/physical_element.cpp +++ b/physical_element.cpp @@ -44,6 +44,18 @@ physical_element::element_tag() const return m_element_tag; } +int +physical_element::element_type() const +{ + return m_gmsh_elemtype; +} + +vec_size_t +physical_element::node_tags(void) const +{ + return m_node_tags; +} + /* Return only one determinant: this is used for geometric order 1 * where the determinants and the jacobians are constant */ double @@ -105,13 +117,6 @@ physical_element::jacobians(void) const - - - - - - - physical_elements_factory::physical_elements_factory(const entity_params& ep) : dim(ep.dim), tag(ep.tag), elemType(ep.etype), geom_order(ep.gorder), approx_order(ep.aorder) @@ -148,6 +153,7 @@ physical_elements_factory::get_elements() new_pe.m_orientation = cellOrientations[elem]; new_pe.m_element_tag = cellTags[elem]; new_pe.m_measure = 0.0; + new_pe.m_gmsh_elemtype = elemType; new_pe.m_node_tags.resize(num_nodes); for (size_t i = 0; i < num_nodes; i++) @@ -194,3 +200,103 @@ physical_elements_factory::get_elements() return ret; } + +element_key::element_key() +{} + +element_key::element_key(const physical_element& pe) +{ + m_dim = pe.dimension(); + m_elemType = pe.element_type(); + + auto nodes = pe.node_tags(); + + if (m_dim == 2) + { + m_key_data[0] = 3; + m_key_data[1] = nodes[0]; + m_key_data[2] = nodes[1]; + m_key_data[3] = nodes[2]; + std::sort(std::next(m_key_data.begin()), m_key_data.end()); + return; + } + + std::stringstream ss; + ss << "Key not implemented for element type " << m_elemType; + throw std::invalid_argument(ss.str()); +} + +bool +element_key::operator<(const element_key& other) const +{ + if (m_dim != other.m_dim or m_elemType != other.m_elemType) + return false; + + if (m_key_data[0] != other.m_key_data[0]) + return false; + + auto mb = std::next(m_key_data.begin()); + auto me = m_key_data.end(); + auto ob = std::next(other.m_key_data.begin()); + auto oe = other.m_key_data.end(); + + return std::lexicographical_compare(mb, me, ob, oe); +} + +bool +element_key::operator==(const element_key& other) const +{ + if (m_dim != other.m_dim or m_elemType != other.m_elemType) + return false; + + if (m_key_data[0] != other.m_key_data[0]) + return false; + + auto mb = std::next(m_key_data.begin()); + auto me = m_key_data.end(); + auto ob = std::next(other.m_key_data.begin()); + + return std::equal(mb, me, ob); +} + + +std::ostream& operator<<(std::ostream& os, const element_key& ek) +{ + os << "ek: " << ek.m_dim << " " << ek.m_elemType << " ("; + for (size_t i = 0; i < 8; i++) + os << ek.m_key_data[i] << " "; + os << ")"; + return os; +} + + + +element_key_factory::element_key_factory(int dim, int tag, int etype) +{ + assert(dim == 2); + + std::vector<size_t> nTags; + gmm::getElementFaceNodes(etype, 3, nTags, tag, true); + + for (size_t i = 0; i < nTags.size(); i+= 3) + { + element_key ek; + ek.m_dim = dim; + ek.m_elemType = etype; + ek.m_key_data[0] = 3; + ek.m_key_data[1] = nTags[i+0]; + ek.m_key_data[2] = nTags[i+1]; + ek.m_key_data[3] = nTags[i+2]; + + std::sort(std::next(ek.m_key_data.begin()), ek.m_key_data.end()); + + ekeys.push_back( ek ); + } + std::sort(ekeys.begin(), ekeys.end()); +} + +std::vector<element_key> +element_key_factory::get_keys(void) const +{ + return ekeys; +} diff --git a/physical_element.h b/physical_element.h index c86f54611c9cc7e6123a4d3790173a9a849d1784..819fa91d69c68845f6a3f102a63c044a6589f1b4 100644 --- a/physical_element.h +++ b/physical_element.h @@ -9,6 +9,7 @@ class physical_element int m_dimension; /* Geometric dimension */ int m_orientation; /* GMSH orientation */ int m_parent_entity_tag; /* Tag of the parent entity */ + int m_gmsh_elemtype; /* GMSH element type */ size_t m_element_tag; /* Tag of the element */ vec_size_t m_node_tags; /* Tags of the element nodes */ vec_double m_determinants; /* SIGNED determinants in the quadrature points */ @@ -27,6 +28,7 @@ public: int orientation(void) const; int parent_entity_tag(void) const; int element_tag(void) const; + int element_type(void) const; vec_size_t node_tags(void) const; double determinant(void) const; @@ -70,8 +72,38 @@ public: }; +class element_key +{ + int m_dim; + int m_elemType; + std::array<size_t, 8> m_key_data{}; +public: + element_key(); + element_key(const element_key&) = default; + element_key(element_key&&) = default; + element_key(const physical_element&); + + element_key& operator=(const element_key&) = default; + + bool operator<(const element_key&) const; + bool operator==(const element_key&) const; + + friend class element_key_factory; + friend std::ostream& operator<<(std::ostream& os, const element_key& ek); +}; +std::ostream& operator<<(std::ostream& os, const element_key& ek); + +class element_key_factory +{ + std::vector<element_key> ekeys; + +public: + element_key_factory(int dim, int tag, int etype); + + std::vector<element_key> get_keys(void) const; +}; diff --git a/test.cpp b/test.cpp index 8d0922766150cfc445d95595468817378d5f5676..1aaf28a71fc7fc7eb0816f6499ac7db49b3cc937 100644 --- a/test.cpp +++ b/test.cpp @@ -29,7 +29,6 @@ int main(void) int failed_tests = 0; -#if 0 std::cout << Bmagentafg << " *** TESTING: BASIC OPERATIONS ***" << reset << std::endl; for (size_t go = 1; go < 5; go++) { @@ -52,10 +51,11 @@ int main(void) for (size_t ao = go; ao < 5; ao++) failed_tests += test_differentiation_convergence(go, ao); -#endif /*****************************************/ - test_normals(2,2); + std::cout << Bmagentafg << " *** TESTING: NORMAL COMPUTATION ***" << reset << std::endl; + for (size_t i = 1; i < 5; i++) + test_normals(i,i); gmsh::finalize(); diff --git a/test_basics.cpp b/test_basics.cpp index fe78195fb571bfe271fcc7e210f3776788f27744..4f1d63c149509a35c8e56fd5875bb2c27c475e60 100644 --- a/test_basics.cpp +++ b/test_basics.cpp @@ -165,6 +165,9 @@ test_normals(int geometric_order, int approximation_order) gm::getPhysicalGroups(pgs); assert(pgs.size() == 1); + std::cout << cyanfg << "Testing normals (order " << geometric_order; + std::cout << ")" << reset << std::endl; + for (auto [dim, pgtag] : pgs) { std::vector<int> tags; @@ -180,7 +183,6 @@ test_normals(int geometric_order, int approximation_order) for (auto& elemType : elemTypes) { - std::ofstream ofs_vecs("ofs_vecs.txt"); std::vector<size_t> faceTags, faceNodesTags; gmm::getElementsByType(elemType, faceTags, faceNodesTags, tags[0]); @@ -191,7 +193,9 @@ test_normals(int geometric_order, int approximation_order) e0.populate_entity_data(ed); auto ft = e0.face_tags(); - for (size_t iT = 0; iT < 10; iT++) + auto bm = mod.get_bnd(7); + + for (size_t iT = 0; iT < e0.num_cells(); iT++) { for (size_t iF = 0; iF < 4; iF++) { @@ -199,23 +203,32 @@ test_normals(int geometric_order, int approximation_order) auto rf = e0.face_refelem(pf); auto qps = pf.integration_points(); - std::cout << pf.element_tag() << std::endl; + auto ek = element_key(pf); + if ( !std::binary_search(bm.begin(), bm.end(), ek) ) + continue; + + size_t num_qp = (geometric_order == 1) ? 1 : qps.size(); - for (size_t iQp = 0; iQp < qps.size(); iQp++) + for (size_t iQp = 0; iQp < num_qp; iQp++) { - Eigen::Vector3d n = ed.normals.row((4*iT+iF)*qps.size() + iQp); + Eigen::Vector3d n = ed.normals.row((4*iT+iF)*num_qp + iQp); point_3d p = qps[iQp].point(); point_3d v = p - point_3d(0.5, 0.5, 0.5); Eigen::Vector3d nref; nref(0) = v.x(); nref(1) = v.y(); nref(2) = v.z(); nref /= nref.norm(); - std::cout << n.cross(nref).transpose() << std::endl; - ofs_vecs << p.x() << " " << p.y() << " " << p.z() << " "; - ofs_vecs << v.x() << " " << v.y() << " " << v.z() << std::endl; + if ( n.cross(nref).norm() > 1e-2 ) + { + std::cout << "Wrong normal. Expected: " << nref.transpose() << ", "; + std::cout << "got: " << n.transpose() << std::endl; + return 1; + } } } } } } + + return 0; } \ No newline at end of file