Skip to content

Commit

Permalink
feat(gmshreader): faster SetPeriodicElements
Browse files Browse the repository at this point in the history
  • Loading branch information
orlandini committed Sep 16, 2024
1 parent e3b8a1e commit 9420692
Showing 1 changed file with 67 additions and 128 deletions.
195 changes: 67 additions & 128 deletions Pre/TPZGmshReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
#include "TPZGeoElement.h"
#include "TPZRefPattern.h"
#include "tpzgeoelrefpattern.h"
#include "pzvec_extras.h"
#include "TPZParallelUtils.h"
#include <cassert>

TPZGmshReader::TPZGmshReader() {
Expand Down Expand Up @@ -438,6 +440,7 @@ void TPZGmshReader::ReadPeriodic4(std::istream &read)
std::string str_end;
read >> str_end;
assert(str_end == "$EndPeriodic" || str_end == "$EndPeriodic\r");
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
Expand All @@ -446,8 +449,9 @@ void TPZGmshReader::ReadPeriodic4(std::istream &read)
in the independent el.
this ensures that they will have the same orientation
*/

SetPeriodicElements(m_gmesh, entity_periodic_nodes, periodic_entities);

std::cout<<"Finished setting periodicity!"<<std::endl;
}


Expand Down Expand Up @@ -1353,8 +1357,11 @@ void TPZGmshReader::SetPeriodicElements(
std::map<int64_t, int64_t> periodic_physical_ids;
/**for a given region, all the periodic nodes.
indexed by the dimension of the physical region.*/
std::vector<std::map<int64_t, std::map<int64_t, int64_t>>>
periodic_nodes_by_physical_ids(4);
constexpr int big_alloc{20000};

TPZManVector<int64_t, big_alloc> dep_ids, indep_ids;
std::map<int64_t,int64_t> 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];
Expand All @@ -1375,36 +1382,25 @@ void TPZGmshReader::SetPeriodicElements(
periodic_physical_ids[depid] = indepid;
const auto periodic_nodes = entity_periodic_nodes[idim][deptag];
for (auto [dep, indep] : periodic_nodes) {
periodic_nodes_by_physical_ids[idim][depid][dep] = indep;
dep_ids.push_back(dep);
indep_ids.push_back(indep);
periodic_nodes_map[dep]=indep;
}
}
}
}

std::set<int64_t> dep_ids, indep_ids;

/*
now we just want to change the ids of the dependent nodes
so as to match the ordering of the independent nodes
*/

//contain all periodic nodes
{
TPZManVector<std::pair<int64_t,int64_t>,100000> all_per_nodes;

for(auto &all_periodic_ids : periodic_nodes_by_physical_ids){
for(const auto &[_,periodic_ids] : all_periodic_ids){
for(const auto &[dep_node,indep_node] : periodic_ids){
all_per_nodes.push_back({dep_node,indep_node});
}
}
}

for(auto [dep,indep] : all_per_nodes){
dep_ids.insert(dep);
indep_ids.insert(indep);
}
RemoveDuplicates(dep_ids);
RemoveDuplicates(indep_ids);

TPZManVector<int64_t,200> common_ids;
TPZManVector<int64_t,300> common_ids;
std::set_intersection(dep_ids.begin(),dep_ids.end(),
indep_ids.begin(),indep_ids.end(),
std::inserter(common_ids,common_ids.begin()));
Expand All @@ -1417,13 +1413,9 @@ void TPZGmshReader::SetPeriodicElements(
const int n_nodes = dep_ids.size();
auto d_i = dep_ids.begin();
auto i_i = indep_ids.begin();
for(auto i = 0; i < n_nodes; i++){
auto dep_node = all_per_nodes[i].first;
auto indep_node = all_per_nodes[i].second;
m_gmesh->NodeVec()[dep_node].SetNodeId(*d_i);
m_gmesh->NodeVec()[indep_node].SetNodeId(*i_i);
d_i++;
i_i++;
for(const auto &[dep_node,indep_node] : periodic_nodes_map){
m_gmesh->NodeVec()[dep_node].SetNodeId(*d_i++);
m_gmesh->NodeVec()[indep_node].SetNodeId(*i_i++);
}
}
/**
Expand All @@ -1432,117 +1424,64 @@ void TPZGmshReader::SetPeriodicElements(
now we no longer have index == id
*/
for (auto depel : gmesh->ElementVec()) {
const auto dim = depel->Dimension();
const auto depmatid = depel->MaterialId();
if (periodic_nodes_by_physical_ids[dim].find(depmatid) ==
periodic_nodes_by_physical_ids[dim].end()){continue;}
auto &periodic_nodes = periodic_nodes_by_physical_ids[dim][depmatid];
//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();
TPZManVector<int64_t,8> mapped_nodes(nnodes);
constexpr int max_nnodes{8};
TPZManVector<int64_t,max_nnodes> mapped_nodes(nnodes);
for (auto in = 0; in < nnodes; in++) {
const auto depnode = depel->NodeIndex(in);
#ifdef PZDEBUG
if(periodic_nodes.find(depnode) == periodic_nodes.end()){
PZError<<__PRETTY_FUNCTION__
<<"\nnode "<<depnode<<" was not found in periodic nodes"
<<" of mat id "<<depmatid<<":\n";
for(auto node : periodic_nodes){
std::cout<<' '<<node;
}
std::cout<<std::endl;
DebugStop();
}
#endif
mapped_nodes[in] = periodic_nodes.at(depnode);
mapped_nodes[in] = periodic_nodes_map.at(depnode);
}
const auto indepmatid = periodic_physical_ids[depmatid];
bool found_indep=false;
for (auto indepel : gmesh->ElementVec()) {
if(found_indep){break;}
const int indep_type = indepel->Type();
const bool sametype = indep_type == dep_type;
constexpr int max_nnodes{8};
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;}

TPZManVector<int64_t,max_nnodes> indepnodes(nnodes);
indepel->GetNodeIndices(indepnodes);
if (indepel->MaterialId() == indepmatid && sametype) {
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;
}
if (samenodes) {
m_periodic_els[depel->Id()] = indepel->Id();
found_indep=true;
//now we check if we need to change orientation
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){break;}
/*
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);
}
//since we are changing node ordering we dont need to perform this check again
#ifdef PZDEBUG2
const int dim = depel->Dimension();
TPZManVector<REAL,3> qsi(dim,0);
TPZFNMatrix<9,REAL> jac, jacinv;
REAL detjac;
TPZFNMatrix<9,REAL> dep_axes, indep_axes,res;
depel->Jacobian(qsi,jac,dep_axes,detjac,jacinv);
indepel->Jacobian(qsi,jac,indep_axes,detjac,jacinv);
res = dep_axes;
res -= indep_axes;
constexpr REAL tol{1e-8};
const int nr = res.Rows();
const int nc = res.Cols();
for(int ir = 0; ir < nr; ir++){
for(int ic = 0; ic < nc; ic++){
if(res.GetVal(ir,ic) > tol){
PZError<<__PRETTY_FUNCTION__
<<"\nError in periodic elements orientation!\n"
<<"dep el "<<depel->Id()<<" indep el "<<indepel->Id()<<std::endl;
TPZManVector<REAL,3> qsi(depel->Dimension(),0), xcenter(3,0);
depel->CenterPoint(depel->NSides()-1, qsi);
depel->X(qsi,xcenter);
PZError<<"dep el center : "<<xcenter[0]<<','<<xcenter[1]<<','<<xcenter[2]<<std::endl;
indepel->CenterPoint(indepel->NSides()-1, qsi);
indepel->X(qsi,xcenter);
PZError<<"indep el center : "<<xcenter[0]<<','<<xcenter[1]<<','<<xcenter[2]<<std::endl;
dep_axes.Print("dep axes",PZError);
indep_axes.Print("indep axes",PZError);
DebugStop();
}
}
}
#endif
// useful for checking periodicity
// for (auto in = 0; in < nnodes; in++) {
// std::cout<<"dep "<<depel->NodeIndex(in)
// <<" indep "<<indepel->NodeIndex(in)
// <<" map(dep) "<<periodic_nodes.at(depel->NodeIndex(in))
// <<std::endl;
// }
}
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;
}
if (!samenodes) {continue;}
indepel=gel;
}
m_periodic_els[depel->Id()] = indepel->Id();
//now we check for node ordering
TPZManVector<int64_t,max_nnodes> 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);
}
}
}

0 comments on commit 9420692

Please sign in to comment.