diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp index afbe2d0f4bc4627a61df93501c115a66eb291b02..f056d5850655c40e4031652f7da78155215caf35 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp @@ -170,6 +170,7 @@ void getOppositeEdge(MElement *el, const MEdge &elBaseEd, MEdge &elTopEd, { static const double BIG = 1e300; + // Find base face const int iElBaseEd = getElementEdge(elBaseEd, el); edLenMin = BIG; edLenMax = -BIG; @@ -206,6 +207,7 @@ void getOppositeEdge(MElement *el, const MEdge &elBaseEd, MEdge &elTopEd, } + void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, MEdge &elBaseEd, std::vector<MElement*> &blob) { @@ -231,6 +233,7 @@ void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, } + void getColumnTri(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, MEdge &elBaseEd, std::vector<MElement*> &blob) { @@ -274,11 +277,6 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, { // Get first element and base vertices std::vector<MElement*> firstElts = ed2el[baseEd]; - if (firstElts.size() != 1) { - Msg::Error("%i edge(s) found for edge (%i, %i)", firstElts.size(), - baseEd.getVertex(0)->getNum(), baseEd.getVertex(1)->getNum()); - return false; - } MElement *el = firstElts[0]; const int iFirstElEd = getElementEdge(baseEd, el); el->getEdgeVertices(iFirstElEd, baseVert); @@ -288,7 +286,6 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, if (el->getType() == TYPE_TRI) getColumnTri(ed2el, p, elBaseEd, blob); else getColumnQuad(ed2el, p, elBaseEd, blob); - // TODO: improve by taking all vertices? topPrimVert.resize(2); topPrimVert[0] = elBaseEd.getVertex(0); topPrimVert[1] = elBaseEd.getVertex(1); @@ -297,12 +294,203 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, -// TODO: Implement 3D +void getOppositeFacePrism(MElement *el, const MFace &elBaseFace, + MFace &elTopFace, double &faceSurfMin, + double &faceSurfMax) +{ + // Find base face + int iElBaseFace = -1, iDum; + el->getFaceInfo(elBaseFace, iElBaseFace, iDum, iDum); + + // Check side edges to find opposite vertices + int edCheck[3] = {2, 4, 5}; + std::vector<MVertex*> topVert(3); + for (int iEd = 0; iEd < 3; iEd++) { + MEdge ed = el->getEdge(edCheck[iEd]); + for (int iV = 0; iV < 3; iV++) { + if (elBaseFace.getVertex(iV) == ed.getVertex(0)) + topVert[iV] = ed.getVertex(1); + else if (elBaseFace.getVertex(iV) == ed.getVertex(1)) + topVert[iV] = ed.getVertex(0); + } + } + elTopFace = MFace(topVert); + + // Compute min. (side faces) and max. (top face) face areas + faceSurfMax = elTopFace.area(); + MFace sideFace0 = el->getFace(2); + faceSurfMin = sideFace0.area(); + MFace sideFace1 = el->getFace(3); + faceSurfMin = std::min(faceSurfMin, sideFace1.area()); + MFace sideFace2 = el->getFace(4); + faceSurfMin = std::min(faceSurfMin, sideFace2.area()); +} + + + +void getOppositeFaceHex(MElement *el, const MFace &elBaseFace, MFace &elTopFace, + double &faceSurfMin, double &faceSurfMax) +{ + // Find base face + int iElBaseFace = -1, iDum; + el->getFaceInfo(elBaseFace, iElBaseFace, iDum, iDum); + + // Determine side edges + int sideEd[4], sideFace[4]; + if ((iElBaseFace == 0) || (iElBaseFace == 5)) { + sideEd[0] = 2; sideEd[1] = 4; sideEd[2] = 6; sideEd[3] = 7; + sideFace[0] = 1; sideFace[1] = 2; sideFace[2] = 3; sideFace[3] = 4; + } + else if ((iElBaseFace == 1) || (iElBaseFace == 4)) { + sideEd[0] = 1; sideEd[1] = 3; sideEd[2] = 10; sideEd[3] = 9; + sideFace[0] = 0; sideFace[1] = 2; sideFace[2] = 3; sideFace[3] = 5; + } + else if ((iElBaseFace == 2) || (iElBaseFace == 3)) { + sideEd[0] = 0; sideEd[1] = 5; sideEd[2] = 11; sideEd[3] = 8; + sideFace[0] = 0; sideFace[1] = 1; sideFace[2] = 4; sideFace[3] = 5; + } + + // Check side edges to find opposite vertices + std::vector<MVertex*> topVert(4); + for (int iEd = 0; iEd < 4; iEd++) { + MEdge ed = el->getEdge(sideEd[iEd]); + for (int iV = 0; iV < 4; iV++) { + if (elBaseFace.getVertex(iV) == ed.getVertex(0)) + topVert[iV] = ed.getVertex(1); + else if (elBaseFace.getVertex(iV) == ed.getVertex(1)) + topVert[iV] = ed.getVertex(0); + } + } + elTopFace = MFace(topVert); + + // Compute min. (side faces) and max. (top face) face areas + faceSurfMax = elTopFace.area(); + MFace sideFace0 = el->getFace(sideFace[0]); + faceSurfMin = sideFace0.area(); + MFace sideFace1 = el->getFace(sideFace[1]); + faceSurfMin = std::min(faceSurfMin, sideFace1.area()); + MFace sideFace2 = el->getFace(sideFace[2]); + faceSurfMin = std::min(faceSurfMin, sideFace2.area()); + MFace sideFace3 = el->getFace(sideFace[3]); + faceSurfMin = std::min(faceSurfMin, sideFace3.area()); +} + + + +void getOppositeFaceTet(MElement *el, const MFace &elBaseFace, MFace &elTopFace, + double &faceSurfMin, double &faceSurfMax) +{ + static const double BIG = 1e300; + + int iElBaseFace = -1, iDum; + el->getFaceInfo(elBaseFace, iElBaseFace, iDum, iDum); + faceSurfMin = BIG; + faceSurfMax = -BIG; + MFace elMaxFace; + + // Look for largest face except base one + for (int iElFace = 0; iElFace < el->getNumFaces(); iElFace++) { + if (iElFace != iElBaseFace) { + MFace faceTest = el->getFace(iElFace); + const double faceSurfTest = faceTest.area(); + if (faceSurfTest < faceSurfMin) faceSurfMin = faceSurfTest; + if (faceSurfTest > faceSurfMax) { + faceSurfMax = faceSurfTest; + elMaxFace = faceTest; + } + } + } + + // Build top face from max face (with right correspondance) + MVertex *const &v0 = elMaxFace.getVertex(0); + MVertex *const &v1 = elMaxFace.getVertex(1); + MVertex *const &v2 = elMaxFace.getVertex(2); + std::vector<MVertex*> topVert(3); + if (elBaseFace.getVertex(0) == v0) { + topVert[0] = v0; + if (elBaseFace.getVertex(1) == v1) { topVert[1] = v1; topVert[2] = v2; } + else { topVert[1] = v2; topVert[2] = v1; } + } + else if (elBaseFace.getVertex(0) == v1) { + topVert[0] = v1; + if (elBaseFace.getVertex(1) == v0) { topVert[1] = v0; topVert[2] = v2; } + else { topVert[1] = v2; topVert[2] = v0; } + } + else { + topVert[0] = v2; + if (elBaseFace.getVertex(1) == v0) { topVert[1] = v0; topVert[2] = v1; } + else { topVert[1] = v1; topVert[2] = v0; } + } + elTopFace = MFace(topVert); +} + + + +void getColumnPrismHex(int elType, MFaceVecMEltMap &face2el, + const FastCurvingParameters &p, MFace &elBaseFace, + std::vector<MElement*> &blob) +{ + const double maxDP = std::cos(p.maxAngle); + + MElement *el = 0; + + for (int iLayer = 0; iLayer < p.maxNumLayers; iLayer++) { + std::vector<MElement*> newElts = face2el[elBaseFace]; + el = (newElts[0] == el) ? newElts[1] : newElts[0]; + if (el->getType() != elType) break; + + MFace elTopFace; + double faceSurfMin, faceSurfMax; + if (el->getType() == TYPE_PRI) + getOppositeFacePrism(el, elBaseFace, elTopFace, faceSurfMin, faceSurfMax); + else if (el->getType() == TYPE_HEX) + getOppositeFaceHex(el, elBaseFace, elTopFace, faceSurfMin, faceSurfMax); +// else if (el->getType() == TYPE_TET) +// getOppositeFaceTet(el, elBaseFace, elTopFace, faceSurfMin, faceSurfMax); + + if (faceSurfMin > faceSurfMax*p.maxRho) break; + const double dp = dot(elBaseFace.normal(), elTopFace.normal()); + if (std::abs(dp) < maxDP) break; + + blob.push_back(el); + elBaseFace = elTopFace; + } +} + + + bool getColumn3D(MFaceVecMEltMap &face2el, const FastCurvingParameters &p, const MFace &baseFace, std::vector<MVertex*> &baseVert, std::vector<MVertex*> &topPrimVert, std::vector<MElement*> &blob) { + // Get first element and base vertices + const int nbBaseFaceVert = baseFace.getNumVertices(); + std::vector<MElement*> firstElts = face2el[baseFace]; + MElement *el = firstElts[0]; + const int iFirstElFace = getElementFace(baseFace, el); + el->getFaceVertices(iFirstElFace, baseVert); + MFace elBaseFace(baseVert[0], baseVert[1], baseVert[2], + (nbBaseFaceVert == 3) ? 0 : baseVert[3]); + + // Sweep column upwards by choosing largest faces in each element + if (nbBaseFaceVert == 3) { + if (el->getType() == TYPE_PRI) // Get BL column of prisms + getColumnPrismHex(TYPE_PRI, face2el, p, elBaseFace, blob); +// else if (el->getType() == TYPE_TET) // TODO: finish implementing BL with tets +// getColumnTet(baseFace, p, elBaseEd, blob); + } + else if ((nbBaseFaceVert == 4) && (el->getType() == TYPE_HEX)) // Get BL column of hexas + getColumnPrismHex(TYPE_HEX, face2el, p, elBaseFace, blob); + else return false; // Not a BL + if (blob.size() == 0) return false; // Could not find column (may not be a BL) + + // Create top face of column with last face vertices + topPrimVert.resize(nbBaseFaceVert); + topPrimVert[0] = elBaseFace.getVertex(0); + topPrimVert[1] = elBaseFace.getVertex(1); + topPrimVert[2] = elBaseFace.getVertex(2); + if (nbBaseFaceVert == 4) topPrimVert[3] = elBaseFace.getVertex(3); return true; } @@ -389,7 +577,7 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, MEdge baseEd(vb0, vb1); foundCol = getColumn2D(ed2el, p, baseEd, baseVert, topPrimVert, blob); } - else { // 2D boundary + else { // 2D boundary MVertex *vb0 = (*itBE)->getVertex(0); MVertex *vb1 = (*itBE)->getVertex(1); MVertex *vb2 = (*itBE)->getVertex(2); @@ -405,7 +593,7 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, MFace baseFace(vb0, vb1, vb2, vb3); foundCol = getColumn3D(face2el, p, baseFace, baseVert, topPrimVert, blob); } - if (!foundCol) continue; // Skip bnd. el. if top vertices not found + if (!foundCol) continue; // Skip bnd. el. if top vertices not found int order = blob[0]->getPolynomialOrder(); MetaEl metaEl(metaElType, order, baseVert, topPrimVert); dbgOut.addMetaEl(metaEl); @@ -413,9 +601,9 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, MElement *&elt = blob[iEl]; makeStraight(elt, movedVert); for (int iV = elt->getNumPrimaryVertices(); - iV < elt->getNumVertices(); ++iV) { // Loop over HO vert. of each el. in blob + iV < elt->getNumVertices(); iV++) { // Loop over HO vert. of each el. in blob MVertex* vert = elt->getVertex(iV); - if (movedVert.find(vert) == movedVert.end()) { // Try to move vert. not already moved + if (movedVert.find(vert) == movedVert.end()) { // Try to move vert. not already moved double xyzS[3] = {vert->x(), vert->y(), vert->z()}, xyzC[3]; if (metaEl.straightToCurved(xyzS,xyzC)) { vert->setXYZ(xyzC[0], xyzC[1], xyzC[2]); @@ -457,7 +645,9 @@ void HighOrderMeshFastCurving(GModel *gm, FastCurvingParameters &p) for (int iEnt = 0; iEnt < allEntities.size(); ++iEnt) { GEntity *dummy = 0; GEntity* &entity = allEntities[iEnt]; - if (entity->dim() == p.dim-1 && (!p.onlyVisible || entity->getVisibility())) // Consider boundary entities + if (entity->dim() == p.dim-1 && + (!p.onlyVisible || entity->getVisibility()) && + (entity->geomType() != GEntity::Plane)) // Consider non-plane boundary entities entities.insert(std::pair<GEntity*,GEntity*>(dummy, entity)); }