diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index 7c616f22b69812672f1dfa1eea18a5d270957636..e998901bc093fbeefd59ba0c920324e2972fefe7 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -1204,7 +1204,7 @@ StringXNumber MeshOptions_Number[] = { { F|O, "Recombine3DLevel" , opt_mesh_recombine3d_level , 0 , "3d recombination level (0: hex, 1: hex+prisms, 2: hex+prism+pyramids)" }, { F|O, "Recombine3DConformity" , opt_mesh_recombine3d_conformity , 0 , - "3d recombination conformity type (0: nonconforming, 1: conformity using trihedra, 2: conformity using pyramids)" }, + "3d recombination conformity type (0: nonconforming, 1: trihedra, 2: pyramids+trihedra, 3:pyramids+hexSplit+trihedra, 4:hexSplit+trihedra)" }, { F|O, "DoRecombinationTest" , opt_mesh_do_recombination_test , 0 , "Apply recombination algorithm for test" }, { F|O, "RecombinationTestHorizStart" , opt_mesh_recombination_test_start , 1 , diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index 743d664f774702d271e3026644855a43be8e7606..e5a1e4c254ee4edcdeef76caf51b4d2692e7243a 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -600,53 +600,16 @@ static void addToMap(std::multimap< MFace , MElement *, Less_Face> &faceToElemen MFace outFace = fit->first; std::vector<std::pair<MElement *, bool> > &neigh = elToNeighbors[el]; for (size_t iN = 0; iN < neigh.size(); iN++) - if (neigh[iN].first == fit->second) + if (neigh[iN].first == fit->second) //Neigbor is already in the map return; int i0 = -1; while (face.getVertex(0) != outFace.getVertex(++i0)); bool sameOrientation = face.getVertex(1) == outFace.getVertex((i0+1)%face.getNumVertices()); - // if (sameOrientation) printf("Non-matching orientation between el %i and el %i for face IN %i %i %i out %i %i %i\n",el->getNum(),fit->second->getNum(),face.getVertex(0)->getNum(),face.getVertex(1)->getNum(),face.getVertex(2)->getNum(),outFace.getVertex(0)->getNum(),outFace.getVertex(1)->getNum(),outFace.getVertex(2)->getNum()); neigh.push_back(std::make_pair(fit->second, !sameOrientation)); elToNeighbors[fit->second].push_back(std::make_pair(el, !sameOrientation)); } } -//static void checkConformity(std::multimap< MFace , MElement *, Less_Face> &faceToElement, std::map< MElement *, std::vector < std::pair <MElement *, bool> > > &elToNeighbors, const MFace &face, MElement *el){ -// //Check conformity -// if (face.getNumVertices() == 4){ -// MVertex *v0 = face.getVertex(0); -// MVertex *v1 = face.getVertex(1); -// MVertex *v2 = face.getVertex(2); -// MVertex *v3 = face.getVertex(3); -// MFace f[5] = {MFace(v0, v1, v2), MFace(v0, v2, v3), MFace(v0, v1, v3), MFace(v1, v2, v3)}; -// if (faceToElement.find(f[0])!= faceToElement.end() || faceToElement.find(f[1])!= faceToElement.end() || faceToElement.find(f[2])!= faceToElement.end() || faceToElement.find(f[3])!= faceToElement.end() ){ -// //Check if the element is a trihedron used to recover conformity: -// //A single element contains the two triangles, the quad and no other face -// std::multiset<size_t> facesNeighborsId; -// int nFaces=0; -// for (int iFace = 0; iFace<4; iFace++){ -// int nbCount = faceToElement.count(f[iFace]); -// if (nbCount != 0){ -// nFaces++; -// if (nFaces > 3) Msg::Fatal("Topological fault: A quad face shares more than 3 triangles (element %i)",el->getNum()); -// std::pair <std::multimap< MFace , MElement *, Less_Face>::iterator, std::multimap< MFace , MElement *, Less_Face>::iterator> faceNeighbors; -// faceNeighbors = faceToElement.equal_range(f[iFace]); -// for (std::multimap< MFace , MElement *, Less_Face>::iterator itEl=faceNeighbors.first; itEl!=faceNeighbors.second; ++itEl) -// facesNeighborsId.insert(itEl->second->getNum()); -// } -// } -// //In some cases, there can be 3 triangles matching a quad face and result in a valid trihedron (1 or 4 triangles not allowed) -// if ((nFaces != 2 || nFaces != 3) && faceToElement.count(face)!= 2) Msg::Fatal("Nonconforming element which is not a trihedron (element %i nFaces %i nodes %i %i %i %i)",el->getNum(),nFaces,v0->getNum(),v1->getNum(),v2->getNum(),v3->getNum()); -// size_t maxOccurence=0; -// for (std::multiset<size_t>::iterator iElId = facesNeighborsId.begin(); iElId != facesNeighborsId.end(); ++iElId){ -// maxOccurence = std::max(facesNeighborsId.count(*iElId), maxOccurence); -// } -// if (maxOccurence != 3) //A trihedron should have 3 and only 3 neighbors -// Msg::Fatal("Nonconforming face for element: %i vertices %i %i %i %i. Number of neighbors: %i",el->getNum(), v0->getNum(), v1->getNum(), v2->getNum(), v3->getNum(),maxOccurence); -// } -// } -//} - static void checkConformity(std::multimap< MFace , MElement *, Less_Face> &faceToElement, std::map< MElement *, std::vector < std::pair <MElement *, bool> > > &elToNeighbors, MFace face, MElement *el){ int connectivity = faceToElement.count(face); if (ElementType::ParentTypeFromTag(el->getType()) == TYPE_TRIH){ @@ -658,8 +621,8 @@ static void checkConformity(std::multimap< MFace , MElement *, Less_Face> &faceT for (int iV = 0; iV < face.getNumVertices(); iV++) if (face.getVertex(iV)->onWhat()->dim() == 3 || connectivity != 1){ for (int jV = 0; jV < face.getNumVertices(); jV++) - Msg::Info("Vertex %i",face.getVertex(jV)->getNum()); - Msg::Fatal("Non conforming element %i (nb connections for a face %i vertex %i)",el->getNum(), connectivity, face.getVertex(iV)->getNum()); + Msg::Info("Vertex %i dim %i",face.getVertex(jV)->getNum(), face.getVertex(iV)->onWhat()->dim()); + Msg::Fatal("Non conforming element %i (%i connection(s) for a face located on dim %i (vertex %i))",el->getNum(), connectivity,face.getVertex(iV)->onWhat()->dim(), face.getVertex(iV)->getNum()); } } } diff --git a/Mesh/yamakawa.cpp b/Mesh/yamakawa.cpp index f78f3a6bff9f6a0bf53697683613e2415b497e57..8fd30452cf721438c8ab7645e972bb69f8d77949 100644 --- a/Mesh/yamakawa.cpp +++ b/Mesh/yamakawa.cpp @@ -4926,11 +4926,6 @@ void PostOp::execute(GRegion* gr,int level, int conformity){ estimate2 = 0; iterations = 0; - - nbFAILVERTEX=0; - nbFAILVALIDITY=0; - - build_tuples(gr); if (level >= 2){ @@ -4940,25 +4935,35 @@ void PostOp::execute(GRegion* gr,int level, int conformity){ rearrange(gr); } - printf("nb FAILS VERTEX after pyramids1 %i\n",nbFAILVERTEX); - printf("nb FAILS VALIDITY after pyramids1 %i\n",nbFAILVALIDITY); - nbFAILVERTEX=0; - nbFAILVALIDITY=0; +if(conformity == 2 || conformity == 3){ + init_markings(gr); + build_vertex_to_tetrahedra(gr); + build_vertex_to_pyramids(gr); + pyramids2(gr); + rearrange(gr); +} + + if (conformity == 3 || conformity == 4){ + init_markings_hex(gr); + build_vertex_to_tetrahedra(gr); + build_vertex_to_pyramids(gr); + split_hexahedra(gr); + rearrange(gr); - if(conformity == 2 || level >= 3){ - init_markings(gr); + init_markings_pri(gr); build_vertex_to_tetrahedra(gr); build_vertex_to_pyramids(gr); - pyramids2(gr); + split_prisms(gr); rearrange(gr); - } - - - printf("nb FAILS VERTEX after pyramids2 %i\n",nbFAILVERTEX); - printf("nb FAILS VALIDITY after pyramids2 %i\n",nbFAILVALIDITY); - + + init_markings_pyr(gr); + build_vertex_to_tetrahedra(gr); + build_vertex_to_pyramids(gr); + split_pyramids(gr); + rearrange(gr); + } - if (conformity == 1){ + if (conformity >= 1){ init_markings(gr); build_vertex_to_tetrahedra(gr); build_vertex_to_pyramids(gr); @@ -4971,6 +4976,43 @@ void PostOp::execute(GRegion* gr,int level, int conformity){ modify_surfaces(gr); } +void PostOp::init_markings_hex(GRegion* gr){ + unsigned int i; + MElement* element; + markings.clear(); + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(eight(element)){ + markings.insert(std::pair<MElement*,bool>(element,false)); + } + } +} + +void PostOp::init_markings_pri(GRegion* gr){ + unsigned int i; + MElement* element; + markings.clear(); + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(six(element)){ + markings.insert(std::pair<MElement*,bool>(element,false)); + } + } +} + +void PostOp::init_markings_pyr(GRegion* gr){ + unsigned int i; + MElement* element; + markings.clear(); + for(i=0;i<gr->getNumMeshElements();i++){ + element = gr->getMeshElement(i); + if(five(element)){ + markings.insert(std::pair<MElement*,bool>(element,false)); + } + } +} + + void PostOp::init_markings(GRegion* gr){ unsigned int i; MElement* element; @@ -4985,6 +5027,223 @@ void PostOp::init_markings(GRegion* gr){ } } +void PostOp::split_hexahedra(GRegion* gr){ + std::vector<MElement*> hexahedra; + std::vector<MHexahedron*> opt; + std::map<MElement*,bool>::iterator it; + + hexahedra.clear(); + + for(size_t i=0;i<gr->getNumMeshElements();i++){ + MElement *element = gr->getMeshElement(i); + if(eight(element)){ + hexahedra.push_back(element); + } + } + + for(size_t i=0;i<hexahedra.size();i++){ + MElement *element = hexahedra[i]; + MVertex *a = element->getVertex(0); + MVertex *b = element->getVertex(1); + MVertex *c = element->getVertex(2); + MVertex *d = element->getVertex(3); + MVertex *e = element->getVertex(4); + MVertex *f = element->getVertex(5); + MVertex *g = element->getVertex(6); + MVertex *h = element->getVertex(7); + + bool conform=true; + conform &= (nonConformDiag(b,a,d,c,gr) == 0); + if (conform) conform &= (nonConformDiag(e,f,g,h,gr) == 0); + if (conform) conform &= (nonConformDiag(a,b,f,e,gr) == 0); + if (conform) conform &= (nonConformDiag(b,c,g,f,gr) == 0); + if (conform) conform &= (nonConformDiag(c,d,h,g,gr) == 0); + if (conform) conform &= (nonConformDiag(d,a,e,h,gr) == 0); + if (!conform){ + double x = (a->x()+b->x()+c->x()+d->x()+e->x()+f->x()+g->x()+h->x())/8.0; + double y = (a->y()+b->y()+c->y()+d->y()+e->y()+f->y()+g->y()+h->y())/8.0; + double z = (a->z()+b->z()+c->z()+d->z()+e->z()+f->z()+g->z()+h->z())/8.0; + MVertex *mid = new MVertex(x,y,z,gr); + gr->addMeshVertex(mid); + + MPyramid *temp = new MPyramid(a,b,c,d,mid); + gr->addPyramid(temp); + temp = new MPyramid(h,g,f,e,mid); + gr->addPyramid(temp); + temp = new MPyramid(e,f,b,a,mid); + gr->addPyramid(temp); + temp = new MPyramid(f,g,c,b,mid); + gr->addPyramid(temp); + temp = new MPyramid(g,h,d,c,mid); + gr->addPyramid(temp); + temp = new MPyramid(h,e,a,d,mid); + gr->addPyramid(temp); + it = markings.find(element); + it->second = true; + } + } + + opt.clear(); + opt.resize(gr->hexahedra.size()); + opt = gr->hexahedra; + gr->hexahedra.clear(); + + for(size_t i=0;i<opt.size();i++){ + MElement *element = (MElement*)(opt[i]); + it = markings.find(element); + if(it->second==0){ + gr->hexahedra.push_back(opt[i]); + } + } +} + +void PostOp::split_prisms(GRegion* gr){ + std::vector<MElement*> prisms; + std::vector<MPrism*> opt; + std::map<MElement*,bool>::iterator it; + + prisms.clear(); + + for(size_t i=0;i<gr->getNumMeshElements();i++){ + MElement *element = gr->getMeshElement(i); + if(six(element)){ + prisms.push_back(element); + } + } + + for(size_t i=0;i<prisms.size();i++){ + MElement *element = prisms[i]; + MVertex *a = element->getVertex(0); + MVertex *b = element->getVertex(1); + MVertex *c = element->getVertex(2); + MVertex *d = element->getVertex(3); + MVertex *e = element->getVertex(4); + MVertex *f = element->getVertex(5); + + pyramids1(a,d,f,c,gr); + pyramids1(a,b,e,d,gr); + pyramids1(b,c,f,e,gr); + + + bool conform=true; + conform &= (nonConformDiag(a,d,f,c,gr) == 0); + if (conform) conform &= (nonConformDiag(a,b,e,d,gr) == 0); + if (conform) conform &= (nonConformDiag(b,c,f,e,gr) == 0); + if (!conform){ + double x = (a->x()+b->x()+c->x()+d->x()+e->x()+f->x())/6.0; + double y = (a->y()+b->y()+c->y()+d->y()+e->y()+f->y())/6.0; + double z = (a->z()+b->z()+c->z()+d->z()+e->z()+f->z())/6.0; + MVertex *mid = new MVertex(x,y,z,gr); + gr->addMeshVertex(mid); + + MPyramid *temp = new MPyramid(c,f,d,a,mid); + gr->addPyramid(temp); + temp = new MPyramid(d,e,b,a,mid); + gr->addPyramid(temp); + temp = new MPyramid(e,f,c,b,mid); + gr->addPyramid(temp); + MTetrahedron *temp2 = new MTetrahedron(d,f,e,mid); + gr->addTetrahedron(temp2); + temp2 = new MTetrahedron(a,b,c,mid); + gr->addTetrahedron(temp2); + it = markings.find(element); + it->second = true; + } + } + + opt.clear(); + opt.resize(gr->prisms.size()); + opt = gr->prisms; + gr->prisms.clear(); + + for(size_t i=0;i<opt.size();i++){ + MElement *element = (MElement*)(opt[i]); + it = markings.find(element); + if(it->second==0){ + gr->prisms.push_back(opt[i]); + } + } +} + +void PostOp::split_pyramids(GRegion* gr){ + std::vector<MElement*> pyramids; + std::vector<MPyramid*> opt; + std::map<MElement*,bool>::iterator it; + + pyramids.clear(); + + for(size_t i=0;i<gr->getNumMeshElements();i++){ + MElement *element = gr->getMeshElement(i); + if(five(element)){ + pyramids.push_back(element); + } + } + + for(size_t i=0;i<pyramids.size();i++){ + MElement *element = pyramids[i]; + MVertex *a = element->getVertex(0); + MVertex *b = element->getVertex(1); + MVertex *c = element->getVertex(2); + MVertex *d = element->getVertex(3); + MVertex *apex = element->getVertex(4); + + int nDiag = nonConformDiag(a,b,c,d,gr); + if (nDiag == 1){ + MTetrahedron *temp = new MTetrahedron(c,b,a,apex); + gr->addTetrahedron(temp); + temp = new MTetrahedron(c,a,d,apex); + gr->addTetrahedron(temp); + it = markings.find(element); + it->second = 1; + }else if (nDiag == 2){ + MTetrahedron *temp = new MTetrahedron(b,a,d,apex); + gr->addTetrahedron(temp); + temp = new MTetrahedron(b,d,c,apex); + gr->addTetrahedron(temp); + it = markings.find(element); + it->second = 1; + } + } + + opt.clear(); + opt.resize(gr->pyramids.size()); + opt = gr->pyramids; + gr->pyramids.clear(); + + for(size_t i=0;i<opt.size();i++){ + MElement *element = (MElement*)(opt[i]); + it = markings.find(element); + if(it->second==0){ + gr->pyramids.push_back(opt[i]); + } + } +} + + +int PostOp::nonConformDiag(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ + std::set<MElement*> diag1a; + std::set<MElement*> diag1b; + std::set<MElement*> diag2a; + std::set<MElement*> diag2b; + + find_tetrahedra(a,b,c,diag1a); + find_tetrahedra(a,c,d,diag1b); + find_tetrahedra(b,c,d,diag2a); + find_tetrahedra(a,b,d,diag2b); + find_pyramids_from_tri(a,b,c,diag1a); + find_pyramids_from_tri(a,c,d,diag1b); + find_pyramids_from_tri(b,c,d,diag2a); + find_pyramids_from_tri(a,b,d,diag2b); + if(diag1a.size()==1 || diag1b.size()==1){ + return 1; + }else if(diag2a.size()==1 || diag2b.size()==1){ + return 2; + } + return 0; +} + + + void PostOp::pyramids1(GRegion* gr){ unsigned int i; MVertex *a,*b,*c,*d; @@ -5199,8 +5458,8 @@ void PostOp::pyramids1(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr){ gr->addPyramid(pyr); it1->second = 1; it2->second = 1; - }else nbFAILVALIDITY++; - }else nbFAILVERTEX++; + } + } } } } @@ -5421,9 +5680,6 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr, MPyramid *pyr = new MPyramid(a,b,c,d,otherV[0]); - if (otherV[0] != otherV[1])nbFAILVERTEX++; - else if (!valid(pyr)) nbFAILVALIDITY++; - if (otherV[0] == otherV[1] && valid(pyr)){ estimate1 = estimate1 + tetrahedra.size() + 2*pyramids.size(); estimate2 = estimate2 + 1; @@ -5432,7 +5688,7 @@ void PostOp::pyramids2(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr, //y = (diagA->y() + diagB->y() + otherV[0]->y())/3; //z = (diagA->z() + diagB->z() + otherV[0]->z())/3; - //W create a flat pyramid and let the optimizer fix it + //We create a flat pyramid and let the optimizer fix it x = (diagA->x() + diagB->x())/2; y = (diagA->y() + diagB->y())/2; z = (diagA->z() + diagB->z())/2; diff --git a/Mesh/yamakawa.h b/Mesh/yamakawa.h index e4aa8c9e71bdb4d2369c0923d4e02f1734c22232..eadd202044b86915ff6924603885afbc1a16ed76 100644 --- a/Mesh/yamakawa.h +++ b/Mesh/yamakawa.h @@ -620,15 +620,13 @@ private: std::multiset<Tuple> tuples; std::set<MElement*> triangles; - int nbFAILVERTEX; - int nbFAILVALIDITY; public: PostOp(); ~PostOp(); void execute(int, int); - //level: 0: hex, 1: hex+prisms, 2: hex+prism+1-step pyramids, 3: hex+prism+2-steps pyramids - //conformity= 0=nonconforming, 1=conformity using trihedra + //level - 0: hex, 1: hex+prisms, 2: hex+prism+pyramids + //conformity - 0: nonconforming, 1: trihedra, 2: pyramids+trihedra, 3:pyramids+hexPrismSplit+trihedra, 4:hexPrismSplit+trihedra void execute(GRegion*,int level, int conformity); inline int get_nb_hexahedra()const{return nbr8;}; @@ -637,9 +635,16 @@ public: inline double get_vol_elements()const{return vol;}; void init_markings(GRegion*); + void init_markings_hex(GRegion*); + void init_markings_pri(GRegion*); + void init_markings_pyr(GRegion*); void pyramids1(GRegion*); void pyramids2(GRegion*, bool allowNonConforming=false); void trihedra(GRegion*); + void split_hexahedra(GRegion*); + void split_prisms(GRegion*); + void split_pyramids(GRegion*); + int nonConformDiag(MVertex* a,MVertex* b,MVertex* c,MVertex* d,GRegion* gr); void pyramids1(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*); void pyramids2(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*, bool allowNonConforming); void trihedra(MVertex*,MVertex*,MVertex*,MVertex*,GRegion*);