diff --git a/contrib/HighOrderMeshOptimizer/MetaEl.cpp b/contrib/HighOrderMeshOptimizer/MetaEl.cpp index 8a3c3ea7a34cce96ce0d520b073c3dd9d16d62a5..17fd8b3e913532cf1d4193a39ef707933a17d1e6 100644 --- a/contrib/HighOrderMeshOptimizer/MetaEl.cpp +++ b/contrib/HighOrderMeshOptimizer/MetaEl.cpp @@ -109,28 +109,31 @@ MetaEl::metaInfoType::metaInfoType(int type, int order) } -MetaEl::MetaEl(int type, int order, const std::vector<MVertex*> &baseVert, - const std::vector<MVertex*> &topPrimVert) : _metaEl(0), _metaEl0(0) -{ - // Get useful info on meta-element type if not already there - std::map<int, MetaEl::metaInfoType>::iterator itSInfo = _metaInfo.find(type); - if (itSInfo == _metaInfo.end()) { - const metaInfoType mInfo(type, order); - itSInfo = _metaInfo.insert(std::pair<int,metaInfoType>(type, mInfo)).first; +const MetaEl::metaInfoType &MetaEl::getMetaInfo(int elType, int order) +{ + std::map<int, MetaEl::metaInfoType>::iterator itMInfo = _metaInfo.find(elType); + if (itMInfo == _metaInfo.end()) { + const metaInfoType mInfo(elType, order); + itMInfo = _metaInfo.insert(std::pair<int, metaInfoType>(elType, mInfo)).first; } - MetaEl::metaInfoType &sInfo = itSInfo->second; + return itMInfo->second; +} - // Exit if unknown type - if (sInfo.nbVert == 0) return; - // References for easier writing - const int &nbVert = sInfo.nbVert; - const fullMatrix<double> &points = sInfo.points; - const std::vector<int> &baseInd = sInfo.baseInd; - const std::vector<int> &topInd = sInfo.topInd; - const std::vector<int> &edgeInd = sInfo.edgeInd; - const std::vector<int> &otherInd = sInfo.otherInd; + +MetaEl::MetaEl(int type, int order, const std::vector<MVertex*> &baseVert, + const std::vector<MVertex*> &topPrimVert) : + _mInfo(getMetaInfo(type, order)), _metaEl(0), _metaEl0(0) +{ + // Get info on meta-element type + if (_mInfo.nbVert == 0) return; + const int &nbVert = _mInfo.nbVert; + const fullMatrix<double> &points = _mInfo.points; + const std::vector<int> &baseInd = _mInfo.baseInd; + const std::vector<int> &topInd = _mInfo.topInd; + const std::vector<int> &edgeInd = _mInfo.edgeInd; + const std::vector<int> &otherInd = _mInfo.otherInd; // Add copies of vertices in base & top faces (only first-order vertices for top face) _metaVert.resize(nbVert); @@ -242,6 +245,32 @@ MetaEl::~MetaEl() } + +void MetaEl::curveTop(double factor) +{ + // Get info on meta-element type + // const int &nbVert = _mInfo.nbVert; + const fullMatrix<double> &points = _mInfo.points; + const std::vector<int> &baseInd = _mInfo.baseInd; + const std::vector<int> &topInd = _mInfo.topInd; + // const std::vector<int> &edgeInd = _mInfo.edgeInd; + // const std::vector<int> &otherInd = _mInfo.otherInd; + + // Compute displacement of HO vertices in base face + for (int iV = 0; iV < baseInd.size(); iV++) { + SPoint3 p0B, p0T; + const int indB = baseInd[iV], indT = topInd[iV]; + _metaEl0->pnt(points(indB, 0), points(indB, 1), points(indB, 2), p0B); + _metaEl0->pnt(points(indT, 0), points(indT, 1), points(indT, 2), p0T); + SPoint3 pB = _metaVert[indB]->point(); + _metaVert[indT]->x() = p0T.x() + factor * (pB.x()-p0B.x()); + _metaVert[indT]->y() = p0T.y() + factor * (pB.y()-p0B.y()); + _metaVert[indT]->z() = p0T.z() + factor * (pB.z()-p0B.z()); + } +} + + + bool MetaEl::isPointIn(const SPoint3 p) const { double xyz[3] = {p.x(), p.y(), p.z()}, uvw[3]; diff --git a/contrib/HighOrderMeshOptimizer/MetaEl.h b/contrib/HighOrderMeshOptimizer/MetaEl.h index 37ad9bbb129041323fd70191b063db08945af0ab..e39a2d61c7e6d28eb9235aa631c4a48406a9f556 100644 --- a/contrib/HighOrderMeshOptimizer/MetaEl.h +++ b/contrib/HighOrderMeshOptimizer/MetaEl.h @@ -35,17 +35,18 @@ class MetaEl { - public: +public: MetaEl(int type, int order, const std::vector<MVertex*> &baseVert, const std::vector<MVertex*> &topPrimVert); ~MetaEl(); + void curveTop(double factor); bool isOK() const { return _metaEl; } bool isPointIn(const SPoint3 p) const; bool straightToCurved(double *xyzS, double *xyzC) const; std::string printPOS(); void printCoord() { - std::cout << "DBGTT: superEl -> "; + std::cout << "DBGTT: metaEl -> "; for(int i = 0; i < _metaVert.size(); i++){ std::cout << "v" << i << " = (" << _metaVert[i]->x() << "," << _metaVert[i]->y() << "," << _metaVert[i]->z() << ")"; @@ -54,7 +55,7 @@ class MetaEl } MElement *getMElement() { return _metaEl; } - private: +private: struct metaInfoType { int nbVert; fullMatrix<double> points; @@ -62,8 +63,12 @@ class MetaEl metaInfoType(int type, int order); }; static std::map<int, metaInfoType> _metaInfo; + + const metaInfoType &_mInfo; std::vector<MVertex*> _metaVert; MElement *_metaEl, *_metaEl0; + + const metaInfoType &getMetaInfo(int elType, int order); }; #endif // _METAEL_H_ diff --git a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp index e517b77d97196fe4f07b1d2d943ea054db6c8376..536c15fc8435b15e3f1fc18d086e93886db4e5f6 100644 --- a/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp +++ b/contrib/HighOrderMeshOptimizer/OptHomFastCurving.cpp @@ -208,7 +208,8 @@ void getOppositeEdgeTri(MElement *el, const MEdge &elBaseEd, MEdge &elTopEd, void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, - MEdge &elBaseEd, std::vector<MElement*> &blob) + MEdge &elBaseEd, std::vector<MElement*> &blob, + MElement* &aboveElt) { const double maxDP = std::cos(p.maxAngle); @@ -217,6 +218,7 @@ void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, for (int iLayer = 0; iLayer < p.maxNumLayers; iLayer++) { std::vector<MElement*> newElts = ed2el[elBaseEd]; el = (newElts[0] == el) ? newElts[1] : newElts[0]; + aboveElt = el; if (el->getType() != TYPE_QUA) break; MEdge elTopEd; double edLenMin, edLenMax; @@ -234,7 +236,8 @@ void getColumnQuad(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, void getColumnTri(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, - MEdge &elBaseEd, std::vector<MElement*> &blob) + MEdge &elBaseEd, std::vector<MElement*> &blob, + MElement* &aboveElt) { const double maxDP = std::cos(p.maxAngle); const double maxDPIn = std::cos(p.maxAngleInner); @@ -245,6 +248,7 @@ void getColumnTri(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, // Get first element in layer std::vector<MElement*> newElts0 = ed2el[elBaseEd]; el0 = (newElts0[0] == el1) ? newElts0[1] : newElts0[0]; + aboveElt = el0; if (el0->getType() != TYPE_TRI) break; MEdge elTopEd0; double edLenMin0, edLenMax0; @@ -281,7 +285,7 @@ void getColumnTri(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, const MEdge &baseEd, std::vector<MVertex*> &baseVert, std::vector<MVertex*> &topPrimVert, - std::vector<MElement*> &blob) + std::vector<MElement*> &blob, MElement* &aboveElt) { // Get first element and base vertices std::vector<MElement*> firstElts = ed2el[baseEd]; @@ -292,8 +296,9 @@ bool getColumn2D(MEdgeVecMEltMap &ed2el, const FastCurvingParameters &p, MEdge elBaseEd(baseVert[0], baseVert[1]); // Sweep column upwards by choosing largest edges in each element - if (el->getType() == TYPE_TRI) getColumnTri(ed2el, p, elBaseEd, blob); - else getColumnQuad(ed2el, p, elBaseEd, blob); + if (el->getType() == TYPE_TRI) + getColumnTri(ed2el, p, elBaseEd, blob, aboveElt); + else getColumnQuad(ed2el, p, elBaseEd, blob, aboveElt); topPrimVert.resize(2); topPrimVert[0] = elBaseEd.getVertex(0); @@ -433,7 +438,7 @@ void getOppositeFaceTet(MElement *el, const MFace &elBaseFace, MFace &elTopFace, // Column of tets: assume tets obtained from subdivision of prism void getColumnTet(MFaceVecMEltMap &face2el, const FastCurvingParameters &p, MFace &elBaseFace, - std::vector<MElement*> &blob) + std::vector<MElement*> &blob, MElement* &aboveElt) { const double maxDP = std::cos(p.maxAngle); const double maxDPIn = std::cos(p.maxAngleInner); @@ -444,6 +449,7 @@ void getColumnTet(MFaceVecMEltMap &face2el, // Get first element in layer std::vector<MElement*> newElts0 = face2el[elBaseFace]; el0 = (newElts0[0] == el2) ? newElts0[1] : newElts0[0]; + aboveElt = el0; if (el0->getType() != TYPE_TET) break; MFace elTopFace0; double faceSurfMin0, faceSurfMax0; @@ -492,7 +498,7 @@ void getColumnTet(MFaceVecMEltMap &face2el, void getColumnPrismHex(int elType, MFaceVecMEltMap &face2el, const FastCurvingParameters &p, MFace &elBaseFace, - std::vector<MElement*> &blob) + std::vector<MElement*> &blob, MElement* &aboveElt) { const double maxDP = std::cos(p.maxAngle); @@ -501,6 +507,7 @@ void getColumnPrismHex(int elType, MFaceVecMEltMap &face2el, for (int iLayer = 0; iLayer < p.maxNumLayers; iLayer++) { std::vector<MElement*> newElts = face2el[elBaseFace]; el = (newElts[0] == el) ? newElts[1] : newElts[0]; + aboveElt = el; if (el->getType() != elType) break; MFace elTopFace; @@ -524,7 +531,7 @@ void getColumnPrismHex(int elType, MFaceVecMEltMap &face2el, bool getColumn3D(MFaceVecMEltMap &face2el, const FastCurvingParameters &p, const MFace &baseFace, std::vector<MVertex*> &baseVert, std::vector<MVertex*> &topPrimVert, - std::vector<MElement*> &blob) + std::vector<MElement*> &blob, MElement* &aboveElt) { // Get first element and base vertices const int nbBaseFaceVert = baseFace.getNumVertices(); @@ -539,12 +546,12 @@ bool getColumn3D(MFaceVecMEltMap &face2el, const FastCurvingParameters &p, // 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); + getColumnPrismHex(TYPE_PRI, face2el, p, elBaseFace, blob, aboveElt); else if (el->getType() == TYPE_TET) - getColumnTet(face2el, p, elBaseFace, blob); + getColumnTet(face2el, p, elBaseFace, blob, aboveElt); } else if ((nbBaseFaceVert == 4) && (el->getType() == TYPE_HEX)) // Get BL column of hexas - getColumnPrismHex(TYPE_HEX, face2el, p, elBaseFace, blob); + getColumnPrismHex(TYPE_HEX, face2el, p, elBaseFace, blob, aboveElt); else return false; // Not a BL if (blob.size() == 0) return false; // Could not find column (may not be a BL) @@ -647,6 +654,81 @@ private: +void curveElement(const MetaEl &metaElt, std::set<MVertex*> &movedVert, + MElement *elt) +{ + makeStraight(elt, movedVert); + for (int iV = elt->getNumPrimaryVertices(); + 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 + double xyzS[3] = {vert->x(), vert->y(), vert->z()}, xyzC[3]; + if (metaElt.straightToCurved(xyzS, xyzC)) { + vert->setXYZ(xyzC[0], xyzC[1], xyzC[2]); + movedVert.insert(vert); + } + } + } +} + + + +double curveAndMeasureAboveEl(MetaEl &metaElt, MElement *lastElt, + MElement *aboveElt, double deformFact) +{ + double minJacDet, maxJacDet; + metaElt.curveTop(deformFact); + std::set<MVertex*> movedVertDum; + curveElement(metaElt, movedVertDum, lastElt); + jacobianBasedQuality::minMaxJacobianDeterminant(aboveElt, minJacDet, maxJacDet); + return minJacDet/maxJacDet; +} + + + +void curveColumn(int metaElType, const std::vector<MVertex*> &baseVert, + const std::vector<MVertex*> &topPrimVert, MElement *aboveElt, + std::vector<MElement*> &blob, std::set<MVertex*> &movedVert, + DbgOutputMeta &dbgOut) +{ + static const double MINQUAL = 0.1, TOL = 0.01, MAXITER = 10; + + // Create meta-element + int order = blob[0]->getPolynomialOrder(); + MetaEl metaElt(metaElType, order, baseVert, topPrimVert); + + // Curve top face of meta-element while avoiding breaking the element above + MElement* &lastElt = blob.back(); + // std::cout << "DBGTT: lastElt = " << lastElt->getNum() << ", aboveElt " << aboveElt->getNum() << " min. SJ: " << aboveElt->minScaledJacobian(); + double minJacDet, maxJacDet; + double deformMin = 0., qualDeformMin = 1.; + double deformMax = 1.; + double qualDeformMax = curveAndMeasureAboveEl(metaElt, lastElt, aboveElt, + deformMax); + if (qualDeformMax < MINQUAL) { // Max deformation makes element above invalid + for (int iter = 0; iter < MAXITER; iter++) { // Bisection to find max. deformation that makes element above valid + const double deformMid = 0.5 * (deformMin + deformMax); + const double qualDeformMid = curveAndMeasureAboveEl(metaElt, lastElt, + aboveElt, deformMid); + if (std::abs(deformMax-deformMin) < TOL) break; + const bool signDeformMax = (qualDeformMax < MINQUAL); + const bool signDeformMid = (qualDeformMid < MINQUAL); + if (signDeformMid == signDeformMax) deformMax = deformMid; + else deformMin = deformMid; + } + } + for (int iV = 0; iV < lastElt->getNumVertices(); iV++) + movedVert.insert(lastElt->getVertex(iV)); + // std::cout << " -> " << aboveElt->minScaledJacobian() << "\n"; + + dbgOut.addMetaEl(metaElt); + + for (int iEl = 0; iEl < blob.size()-1; iEl++) + curveElement(metaElt, movedVert, blob[iEl]); +} + + + void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, GEntity *bndEnt, const FastCurvingParameters &p) { @@ -678,12 +760,14 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, bool foundCol; std::vector<MVertex*> baseVert, topPrimVert; std::vector<MElement*> blob; + MElement *aboveElt = 0; if (bndType == TYPE_LIN) { // 1D boundary MVertex *vb0 = (*itBE)->getVertex(0); MVertex *vb1 = (*itBE)->getVertex(1); metaElType = TYPE_QUA; MEdge baseEd(vb0, vb1); - foundCol = getColumn2D(ed2el, p, baseEd, baseVert, topPrimVert, blob); + foundCol = getColumn2D(ed2el, p, baseEd, baseVert, + topPrimVert, blob, aboveElt); } else { // 2D boundary MVertex *vb0 = (*itBE)->getVertex(0); @@ -699,30 +783,15 @@ void curveMeshFromBnd(MEdgeVecMEltMap &ed2el, MFaceVecMEltMap &face2el, metaElType = TYPE_PRI; } MFace baseFace(vb0, vb1, vb2, vb3); - foundCol = getColumn3D(face2el, p, baseFace, baseVert, topPrimVert, blob); + foundCol = getColumn3D(face2el, p, baseFace, baseVert, topPrimVert, + blob, aboveElt); } if (!foundCol) continue; // Skip bnd. el. if top vertices not found DbgOutputCol dbgOutCol; dbgOutCol.addBlob(blob); dbgOutCol.write("col_KO", (*itBE)->getNum()); - int order = blob[0]->getPolynomialOrder(); - MetaEl metaEl(metaElType, order, baseVert, topPrimVert); - dbgOut.addMetaEl(metaEl); - for (int iEl = 0; iEl < blob.size(); iEl++) { - 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 - MVertex* vert = elt->getVertex(iV); - 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]); - movedVert.insert(vert); - } - } - } - } + curveColumn(metaElType, baseVert, topPrimVert, aboveElt, blob, movedVert, + dbgOut); dbgOutCol.write("col_OK", (*itBE)->getNum()); }