From 5288b803560c659c55438c46bdb839fcc41cd25f Mon Sep 17 00:00:00 2001 From: Francisco Orlandini Date: Wed, 18 Sep 2024 20:18:30 -0300 Subject: [PATCH] feat(gmshreader): adds support for multiple periodic entities FillPeriodicData (former SetPeriodicElements) actually fills a SPZPeriodicData --- Pre/TPZGmshReader.cpp | 176 ++++++++++++++++++------------------------ Pre/TPZGmshReader.h | 22 +++--- 2 files changed, 84 insertions(+), 114 deletions(-) diff --git a/Pre/TPZGmshReader.cpp b/Pre/TPZGmshReader.cpp index 0dcb693840..4f92588736 100644 --- a/Pre/TPZGmshReader.cpp +++ b/Pre/TPZGmshReader.cpp @@ -8,6 +8,8 @@ #include "TPZGmshReader.h" +#include "TPZGeoMeshTools.h" + #include "pzgeopoint.h" #include "TPZGeoLinear.h" #include "TPZGeoCube.h" @@ -443,14 +445,12 @@ void TPZGmshReader::ReadPeriodic4(std::istream &read) std::cout << "Finished reading periodic elements, setting periodicity..."<< std::endl; /*now we need to find the correspondence between periodic elements we will both: - - create the periodic_els map that relates the ids of dependent/independent - element - change the node ids of the dependent el so as to match the ones - in the independent el. - this ensures that they will have the same orientation + in the independent el. this ensures that they will have the same orientation + - check the ordering of the nodes in the independent el */ - SetPeriodicElements(m_gmesh, entity_periodic_nodes, periodic_entities); + FillPeriodicData(m_gmesh, entity_periodic_nodes, periodic_entities); std::cout<<"Finished setting periodicity!"<>> &entity_periodic_nodes, const TPZVec> &periodic_entities) { + m_periodic_data = new SPZPeriodicData; + SPZPeriodicData &periodic_data = m_periodic_data; const auto max_dimension = gmesh->Dimension(); - // associates ids of periodic regions - std::map periodic_physical_ids; - /**for a given region, all the periodic nodes. - indexed by the dimension of the physical region.*/ - constexpr int big_alloc{20000}; - - TPZManVector dep_ids, indep_ids; - std::map periodic_nodes_map; - for (int idim = 0; idim < max_dimension; idim++) { // just to make it more readable auto &physical_entity_map = m_dim_entity_tag_and_physical_tag[idim]; @@ -1377,111 +1370,88 @@ void TPZGmshReader::SetPeriodicElements( } // we only care if there is an associated physical id for(int id_count=0;id_count < ndepid;id_count++){ - const int64_t depid = physical_entity_map[deptag][id_count]; - const int64_t indepid = physical_entity_map[indeptag][id_count]; - periodic_physical_ids[depid] = indepid; + const int depid = physical_entity_map[deptag][id_count]; + const int indepid = physical_entity_map[indeptag][id_count]; + periodic_data.dep_mat_ids.push_back(depid); + periodic_data.indep_mat_ids.push_back(indepid); + TPZAutoPointer> map; const auto periodic_nodes = entity_periodic_nodes[idim][deptag]; for (auto [dep, indep] : periodic_nodes) { - dep_ids.push_back(dep); - indep_ids.push_back(indep); - periodic_nodes_map[dep]=indep; + map->insert({dep,indep}); } + periodic_data.nodes_map.push_back(map); } } } - + + //number of periodic regions + const auto n_periodic_reg = periodic_data.dep_mat_ids.size(); /* now we just want to change the ids of the dependent nodes - so as to match the ordering of the independent nodes - */ + so as to match the ids of the independent nodes - //contain all periodic nodes + we will iterate on the periodic regions with increasing dimension, + therefore we ensure that periodic surfaces containing periodic edges + will be fine + */ + for(auto ireg = 0; ireg < n_periodic_reg; ireg++) { - RemoveDuplicates(dep_ids); - RemoveDuplicates(indep_ids); - - TPZManVector common_ids; - std::set_intersection(dep_ids.begin(),dep_ids.end(), - indep_ids.begin(),indep_ids.end(), - std::inserter(common_ids,common_ids.begin())); - if(common_ids.size()){ - PZError<<__PRETTY_FUNCTION__ - <<"\nwe still not support nodes that are both dependent and independent" - <<"\nAborting..."<NodeVec()[dep_node].SetNodeId(*d_i++); - m_gmesh->NodeVec()[indep_node].SetNodeId(*i_i++); + const auto &dep_ids = periodic_data.dep_mat_ids[ireg]; + const auto &indep_ids = periodic_data.indep_mat_ids[ireg]; + const auto &node_map = *(periodic_data.nodes_map[ireg]); + const int n_nodes = node_map.size(); + for(const auto &[dep_node,indep_node] : node_map){ + const auto indep_node_id = m_gmesh->NodeVec()[indep_node].Id(); + m_gmesh->NodeVec()[dep_node].SetNodeId(indep_node_id); } } /** - now we want to map periodic ELEMENTS - IMPORTANT: since we have changed the node ids, - now we no longer have index == id + now we want to check if periodic ELEMENTS + have the correct node ordering */ - for (auto depel : gmesh->ElementVec()) { - const auto depmatid = depel->MaterialId(); - //not a dependent periodic mat - if (periodic_physical_ids.find(depmatid) == - periodic_physical_ids.end()){continue;} - //we have found a dependent el - const auto nnodes = depel->NNodes(); - const auto nsides = depel->NSides(); - const auto dep_type = depel->Type(); - constexpr int max_nnodes{8}; - TPZManVector mapped_nodes(nnodes); - for (auto in = 0; in < nnodes; in++) { - const auto depnode = depel->NodeIndex(in); - mapped_nodes[in] = periodic_nodes_map.at(depnode); - } - const auto indepmatid = periodic_physical_ids[depmatid]; - TPZGeoEl* indepel{nullptr}; - const int nelem = gmesh->ElementVec().NElements(); - for(auto gel : gmesh->ElementVec()){ - if(indepel){break;} - if (gel->MaterialId() != indepmatid || - gel->Type() != dep_type) {continue;} - + TPZVec>> el_map; + + TPZGeoMeshTools::FindPeriodicElements(gmesh, + periodic_data.dep_mat_ids, + periodic_data.indep_mat_ids, + periodic_data.nodes_map, + el_map); + + const int nperiodic = periodic_data.dep_mat_ids.size(); + for(auto iper = 0; iper < nperiodic; iper++){ + for(auto [dep_el_idx, indep_el_idx] : *el_map[iper]){ + auto depel = gmesh->Element(dep_el_idx); + auto indepel = gmesh->Element(indep_el_idx); + const auto nnodes = depel->NNodes(); + constexpr int max_nnodes{8}; + TPZManVector mapped_nodes(nnodes); + for (auto in = 0; in < nnodes; in++) { + const auto depnode = depel->NodeIndex(in); + mapped_nodes[in] = + periodic_data.nodes_map[iper]->at(depnode); + } TPZManVector indepnodes(nnodes); - gel->GetNodeIndices(indepnodes); - bool samenodes = true; - for (auto in = 0; in < nnodes && samenodes; in++) { - const auto indepnode = indepnodes[in]; - const bool hasnode = - std::find(mapped_nodes.begin(), mapped_nodes.end(), - indepnode) != mapped_nodes.end(); - samenodes = samenodes && hasnode; + indepel->GetNodeIndices(indepnodes); + bool sameorient{true}; + for (auto in = 0; in < nnodes && sameorient; in++) { + if(indepnodes[in] != mapped_nodes[in]){ + sameorient=false; + } } - if (!samenodes) {continue;} - indepel=gel; - } - m_periodic_els[depel->Id()] = indepel->Id(); - //now we check for node ordering - TPZManVector indepnodes(nnodes); - indepel->GetNodeIndices(indepnodes); - bool sameorient{true}; - for (auto in = 0; in < nnodes && sameorient; in++) { - if(indepnodes[in] != mapped_nodes[in]){ - sameorient=false; + //nothing to else be done here + if(sameorient){continue;} + /* + WARNING: + right now, SetPeriodic is called before BuildConnectivity. + should this change in the future, changing node ordering is + not enough, connectivity should be changed as well. + For this purpose, TPZChangeEl::ChangeNodeOrdering + should be sued. + */ + for (auto in = 0; in < nnodes; in++) { + const auto mapped = mapped_nodes[in]; + indepel->SetNodeIndex(in, mapped); } } - //nothing to else be done here - if(sameorient){continue;} - /* - WARNING: - right now, SetPeriodic is called before BuildConnectivity. - should this change in the future, changing node ordering is - not enough, connectivity should be changed as well. - For this purpose, TPZChangeEl::ChangeNodeOrdering - should be sued. - */ - for (auto in = 0; in < nnodes; in++) { - const auto mapped = mapped_nodes[in]; - indepel->SetNodeIndex(in, mapped); - } } } diff --git a/Pre/TPZGmshReader.h b/Pre/TPZGmshReader.h index db2cd5e833..83843d4728 100644 --- a/Pre/TPZGmshReader.h +++ b/Pre/TPZGmshReader.h @@ -15,7 +15,7 @@ #include #include #include "pzgmesh.h" - +#include "SPZPeriodicData.h" class TPZGeoMesh; @@ -102,11 +102,8 @@ class TPZGmshReader{ REAL m_characteristic_lentgh = 1; //////////// Members related to file format with version 4 //////////// - /// Data structure for storing periodic elements (only available in v4) - std::map m_periodic_els; /// Data structure of both: physical entities and names indexed by dimension TPZManVector>,4> m_dim_entity_tag_and_physical_tag; - //////////// Members related to file format with version 3 //////////// /// Structure of both: physical entities and names indexed by dimension @@ -123,6 +120,9 @@ class TPZGmshReader{ /// Entity index to which the element belongs TPZVec m_entity_index; + + /// Structure for periodic entities + TPZAutoPointer m_periodic_data; /// Number of hexahedra int m_n_hexahedron_els = 0; @@ -175,11 +175,11 @@ class TPZGmshReader{ void ReadPeriodic4(std::istream &input); //! Fills m_periodic_els structure after creating the mesh - void SetPeriodicElements( - TPZGeoMesh *gmesh, - const TPZVec>> - &entity_periodic_nodes, - const TPZVec> &periodic_entities); + void FillPeriodicData( + TPZGeoMesh *gmesh, + const TPZVec>> + &entity_periodic_nodes, + const TPZVec> &periodic_entities); public: /// Default constructor @@ -215,8 +215,8 @@ class TPZGmshReader{ int GetNumberofNodes(int & el_type); - //! Get periodic elements - auto GetPeriodicEls() const { return m_periodic_els; } + //! Get periodic data + auto GetPeriodicData() const { return m_periodic_data; } /// Insert elements following msh file format */ bool InsertElement(TPZGeoMesh * gmesh, std::ifstream & line);