FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

isoSurface.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #include "isoSurface.H"
00027 #include <finiteVolume/fvMesh.H>
00028 #include <OpenFOAM/mergePoints.H>
00029 #include <OpenFOAM/syncTools.H>
00030 #include <OpenFOAM/addToRunTimeSelectionTable.H>
00031 #include <finiteVolume/slicedVolFields.H>
00032 #include <finiteVolume/volFields.H>
00033 #include <finiteVolume/surfaceFields.H>
00034 #include <OpenFOAM/OFstream.H>
00035 #include <meshTools/meshTools.H>
00036 
00037 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00038 
00039 namespace Foam
00040 {
00041     defineTypeNameAndDebug(isoSurface, 0);
00042 }
00043 
00044 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00045 
00046 bool Foam::isoSurface::noTransform(const tensor& tt) const
00047 {
00048     return
00049         (mag(tt.xx()-1) < mergeDistance_)
00050      && (mag(tt.yy()-1) < mergeDistance_)
00051      && (mag(tt.zz()-1) < mergeDistance_)
00052      && (mag(tt.xy()) < mergeDistance_)
00053      && (mag(tt.xz()) < mergeDistance_)
00054      && (mag(tt.yx()) < mergeDistance_)
00055      && (mag(tt.yz()) < mergeDistance_)
00056      && (mag(tt.zx()) < mergeDistance_)
00057      && (mag(tt.zy()) < mergeDistance_);
00058 }
00059 
00060 
00061 bool Foam::isoSurface::collocatedPatch(const polyPatch& pp)
00062 {
00063     const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>(pp);
00064 
00065     return cpp.parallel() && !cpp.separated();
00066 }
00067 
00068 
00069 // Calculates per face whether couple is collocated.
00070 Foam::PackedBoolList Foam::isoSurface::collocatedFaces
00071 (
00072     const coupledPolyPatch& pp
00073 ) const
00074 {
00075     // Initialise to false
00076     PackedBoolList collocated(pp.size());
00077 
00078     const vectorField& separation = pp.separation();
00079     const tensorField& forwardT = pp.forwardT();
00080 
00081     if (forwardT.size() == 0)
00082     {
00083         // Parallel.
00084         if (separation.size() == 0)
00085         {
00086             collocated = 1u;
00087         }
00088         else if (separation.size() == 1)
00089         {
00090             // Fully separate. Do not synchronise.
00091         }
00092         else
00093         {
00094             // Per face separation.
00095             forAll(pp, faceI)
00096             {
00097                 if (mag(separation[faceI]) < mergeDistance_)
00098                 {
00099                     collocated[faceI] = 1u;
00100                 }
00101             }
00102         }
00103     }
00104     else if (forwardT.size() == 1)
00105     {
00106         // Fully transformed.
00107     }
00108     else
00109     {
00110         // Per face transformation.
00111         forAll(pp, faceI)
00112         {
00113             if (noTransform(forwardT[faceI]))
00114             {
00115                 collocated[faceI] = 1u;
00116             }
00117         }
00118     }
00119     return collocated;
00120 }
00121 
00122 
00123 // Insert the data for local point patchPointI into patch local values
00124 // and/or into the shared values field.
00125 void Foam::isoSurface::insertPointData
00126 (
00127     const processorPolyPatch& pp,
00128     const Map<label>& meshToShared,
00129     const pointField& pointValues,
00130     const label patchPointI,
00131     pointField& patchValues,
00132     pointField& sharedValues
00133 ) const
00134 {
00135     label meshPointI = pp.meshPoints()[patchPointI];
00136 
00137     // Store in local field
00138     label nbrPointI = pp.neighbPoints()[patchPointI];
00139     if (nbrPointI >= 0 && nbrPointI < patchValues.size())
00140     {
00141         minEqOp<point>()(patchValues[nbrPointI], pointValues[meshPointI]);
00142     }
00143 
00144     // Store in shared field
00145     Map<label>::const_iterator iter = meshToShared.find(meshPointI);
00146     if (iter != meshToShared.end())
00147     {
00148         minEqOp<point>()(sharedValues[iter()], pointValues[meshPointI]);
00149     }
00150 }
00151 
00152 
00153 void Foam::isoSurface::syncUnseparatedPoints
00154 (
00155     pointField& pointValues,
00156     const point& nullValue
00157 ) const
00158 {
00159     // Until syncPointList handles separated coupled patches with multiple
00160     // transforms do our own synchronisation of non-separated patches only
00161     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00162     const globalMeshData& pd = mesh_.globalData();
00163     const labelList& sharedPtAddr = pd.sharedPointAddr();
00164     const labelList& sharedPtLabels = pd.sharedPointLabels();
00165 
00166     // Create map from meshPoint to globalShared index.
00167     Map<label> meshToShared(2*sharedPtLabels.size());
00168     forAll(sharedPtLabels, i)
00169     {
00170         meshToShared.insert(sharedPtLabels[i], sharedPtAddr[i]);
00171     }
00172 
00173     // Values on shared points.
00174     pointField sharedInfo(pd.nGlobalPoints(), nullValue);
00175 
00176 
00177     if (Pstream::parRun())
00178     {
00179         // Send
00180         forAll(patches, patchI)
00181         {
00182             if
00183             (
00184                 isA<processorPolyPatch>(patches[patchI])
00185              && patches[patchI].nPoints() > 0
00186             )
00187             {
00188                 const processorPolyPatch& pp =
00189                     refCast<const processorPolyPatch>(patches[patchI]);
00190                 const labelList& meshPts = pp.meshPoints();
00191 
00192                 pointField patchInfo(meshPts.size(), nullValue);
00193 
00194                 PackedBoolList isCollocated(collocatedFaces(pp));
00195 
00196                 forAll(isCollocated, faceI)
00197                 {
00198                     if (isCollocated[faceI])
00199                     {
00200                         const face& f = pp.localFaces()[faceI];
00201 
00202                         forAll(f, fp)
00203                         {
00204                             label pointI = f[fp];
00205 
00206                             insertPointData
00207                             (
00208                                 pp,
00209                                 meshToShared,
00210                                 pointValues,
00211                                 pointI,
00212                                 patchInfo,
00213                                 sharedInfo
00214                             );
00215                         }
00216                     }
00217                 }
00218 
00219                 OPstream toNbr(Pstream::blocking, pp.neighbProcNo());
00220                 toNbr << patchInfo;
00221             }
00222         }
00223 
00224         // Receive and combine.
00225 
00226         forAll(patches, patchI)
00227         {
00228             if
00229             (
00230                 isA<processorPolyPatch>(patches[patchI])
00231              && patches[patchI].nPoints() > 0
00232             )
00233             {
00234                 const processorPolyPatch& pp =
00235                     refCast<const processorPolyPatch>(patches[patchI]);
00236 
00237                 pointField nbrPatchInfo(pp.nPoints());
00238                 {
00239                     // We do not know the number of points on the other side
00240                     // so cannot use Pstream::read.
00241                     IPstream fromNbr(Pstream::blocking, pp.neighbProcNo());
00242                     fromNbr >> nbrPatchInfo;
00243                 }
00244 
00245                 // Null any value which is not on neighbouring processor
00246                 nbrPatchInfo.setSize(pp.nPoints(), nullValue);
00247 
00248                 const labelList& meshPts = pp.meshPoints();
00249 
00250                 forAll(meshPts, pointI)
00251                 {
00252                     label meshPointI = meshPts[pointI];
00253                     minEqOp<point>()
00254                     (
00255                         pointValues[meshPointI],
00256                         nbrPatchInfo[pointI]
00257                     );
00258                 }
00259             }
00260         }
00261     }
00262 
00263 
00264     // Don't do cyclics for now. Are almost always separated anyway.
00265 
00266 
00267     // Shared points
00268 
00269     // Combine on master.
00270     Pstream::listCombineGather(sharedInfo, minEqOp<point>());
00271     Pstream::listCombineScatter(sharedInfo);
00272 
00273     // Now we will all have the same information. Merge it back with
00274     // my local information. (Note assignment and not combine operator)
00275     forAll(sharedPtLabels, i)
00276     {
00277         label meshPointI = sharedPtLabels[i];
00278         pointValues[meshPointI] = sharedInfo[sharedPtAddr[i]];
00279     }
00280 }
00281 
00282 
00283 Foam::scalar Foam::isoSurface::isoFraction
00284 (
00285     const scalar s0,
00286     const scalar s1
00287 ) const
00288 {
00289     scalar d = s1-s0;
00290 
00291     if (mag(d) > VSMALL)
00292     {
00293         return (iso_-s0)/d;
00294     }
00295     else
00296     {
00297         return -1.0;
00298     }
00299 }
00300 
00301 
00302 bool Foam::isoSurface::isEdgeOfFaceCut
00303 (
00304     const scalarField& pVals,
00305     const face& f,
00306     const bool ownLower,
00307     const bool neiLower
00308 ) const
00309 {
00310     forAll(f, fp)
00311     {
00312         bool fpLower = (pVals[f[fp]] < iso_);
00313         if
00314         (
00315             (fpLower != ownLower)
00316          || (fpLower != neiLower)
00317          || (fpLower != (pVals[f[f.fcIndex(fp)]] < iso_))
00318         )
00319         {
00320             return true;
00321         }
00322     }
00323     return false;
00324 }
00325 
00326 
00327 // Get neighbour value and position.
00328 void Foam::isoSurface::getNeighbour
00329 (
00330     const labelList& boundaryRegion,
00331     const volVectorField& meshC,
00332     const volScalarField& cVals,
00333     const label cellI,
00334     const label faceI,
00335     scalar& nbrValue,
00336     point& nbrPoint
00337 ) const
00338 {
00339     const labelList& own = mesh_.faceOwner();
00340     const labelList& nei = mesh_.faceNeighbour();
00341 
00342     if (mesh_.isInternalFace(faceI))
00343     {
00344         label nbr = (own[faceI] == cellI ? nei[faceI] : own[faceI]);
00345         nbrValue = cVals[nbr];
00346         nbrPoint = meshC[nbr];
00347     }
00348     else
00349     {
00350         label bFaceI = faceI-mesh_.nInternalFaces();
00351         label patchI = boundaryRegion[bFaceI];
00352         const polyPatch& pp = mesh_.boundaryMesh()[patchI];
00353         label patchFaceI = faceI-pp.start();
00354 
00355         nbrValue = cVals.boundaryField()[patchI][patchFaceI];
00356         nbrPoint = meshC.boundaryField()[patchI][patchFaceI];
00357     }
00358 }
00359 
00360 
00361 // Determine for every face/cell whether it (possibly) generates triangles.
00362 void Foam::isoSurface::calcCutTypes
00363 (
00364     const labelList& boundaryRegion,
00365     const volVectorField& meshC,
00366     const volScalarField& cVals,
00367     const scalarField& pVals
00368 )
00369 {
00370     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
00371     const labelList& own = mesh_.faceOwner();
00372     const labelList& nei = mesh_.faceNeighbour();
00373 
00374     faceCutType_.setSize(mesh_.nFaces());
00375     faceCutType_ = NOTCUT;
00376 
00377     for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00378     {
00379         // CC edge.
00380         bool ownLower = (cVals[own[faceI]] < iso_);
00381 
00382         scalar nbrValue;
00383         point nbrPoint;
00384         getNeighbour
00385         (
00386             boundaryRegion,
00387             meshC,
00388             cVals,
00389             own[faceI],
00390             faceI,
00391             nbrValue,
00392             nbrPoint
00393         );
00394 
00395         bool neiLower = (nbrValue < iso_);
00396 
00397         if (ownLower != neiLower)
00398         {
00399             faceCutType_[faceI] = CUT;
00400         }
00401         else
00402         {
00403             // See if any mesh edge is cut by looping over all the edges of the
00404             // face.
00405             const face f = mesh_.faces()[faceI];
00406 
00407             if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
00408             {
00409                 faceCutType_[faceI] = CUT;
00410             }
00411         }
00412     }
00413 
00414     forAll(patches, patchI)
00415     {
00416         const polyPatch& pp = patches[patchI];
00417 
00418         label faceI = pp.start();
00419 
00420         forAll(pp, i)
00421         {
00422             bool ownLower = (cVals[own[faceI]] < iso_);
00423 
00424             scalar nbrValue;
00425             point nbrPoint;
00426             getNeighbour
00427             (
00428                 boundaryRegion,
00429                 meshC,
00430                 cVals,
00431                 own[faceI],
00432                 faceI,
00433                 nbrValue,
00434                 nbrPoint
00435             );
00436 
00437             bool neiLower = (nbrValue < iso_);
00438 
00439             if (ownLower != neiLower)
00440             {
00441                 faceCutType_[faceI] = CUT;
00442             }
00443             else
00444             {
00445                 // Mesh edge.
00446                 const face f = mesh_.faces()[faceI];
00447 
00448                 if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
00449                 {
00450                     faceCutType_[faceI] = CUT;
00451                 }
00452             }
00453 
00454             faceI++;
00455         }
00456     }
00457 
00458 
00459 
00460     nCutCells_ = 0;
00461     cellCutType_.setSize(mesh_.nCells());
00462     cellCutType_ = NOTCUT;
00463 
00464     for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
00465     {
00466         if (faceCutType_[faceI] != NOTCUT)
00467         {
00468             if (cellCutType_[own[faceI]] == NOTCUT)
00469             {
00470                 cellCutType_[own[faceI]] = CUT;
00471                 nCutCells_++;
00472             }
00473             if (cellCutType_[nei[faceI]] == NOTCUT)
00474             {
00475                 cellCutType_[nei[faceI]] = CUT;
00476                 nCutCells_++;
00477             }
00478         }
00479     }
00480     for (label faceI = mesh_.nInternalFaces(); faceI < mesh_.nFaces(); faceI++)
00481     {
00482         if (faceCutType_[faceI] != NOTCUT)
00483         {
00484             if (cellCutType_[own[faceI]] == NOTCUT)
00485             {
00486                 cellCutType_[own[faceI]] = CUT;
00487                 nCutCells_++;
00488             }
00489         }
00490     }
00491 
00492     if (debug)
00493     {
00494         Pout<< "isoSurface : detected " << nCutCells_
00495             << " candidate cut cells (out of " << mesh_.nCells()
00496             << ")." << endl;
00497     }
00498 }
00499 
00500 
00501 // Return the two common points between two triangles
00502 Foam::labelPair Foam::isoSurface::findCommonPoints
00503 (
00504     const labelledTri& tri0,
00505     const labelledTri& tri1
00506 )
00507 {
00508     labelPair common(-1, -1);
00509 
00510     label fp0 = 0;
00511     label fp1 = findIndex(tri1, tri0[fp0]);
00512 
00513     if (fp1 == -1)
00514     {
00515         fp0 = 1;
00516         fp1 = findIndex(tri1, tri0[fp0]);
00517     }
00518 
00519     if (fp1 != -1)
00520     {
00521         // So tri0[fp0] is tri1[fp1]
00522 
00523         // Find next common point
00524         label fp0p1 = tri0.fcIndex(fp0);
00525         label fp1p1 = tri1.fcIndex(fp1);
00526         label fp1m1 = tri1.rcIndex(fp1);
00527 
00528         if (tri0[fp0p1] == tri1[fp1p1] || tri0[fp0p1] == tri1[fp1m1])
00529         {
00530             common[0] = tri0[fp0];
00531             common[1] = tri0[fp0p1];
00532         }
00533     }
00534     return common;
00535 }
00536 
00537 
00538 // Caculate centre of surface.
00539 Foam::point Foam::isoSurface::calcCentre(const triSurface& s)
00540 {
00541     vector sum = vector::zero;
00542 
00543     forAll(s, i)
00544     {
00545         sum += s[i].centre(s.points());
00546     }
00547     return sum/s.size();
00548 }
00549 
00550 
00551 // Replace surface (localPoints, localTris) with single point. Returns
00552 // point. Destructs arguments.
00553 Foam::pointIndexHit Foam::isoSurface::collapseSurface
00554 (
00555     pointField& localPoints,
00556     DynamicList<labelledTri, 64>& localTris
00557 )
00558 {
00559     pointIndexHit info(false, vector::zero, localTris.size());
00560 
00561     if (localTris.size() == 1)
00562     {
00563         const labelledTri& tri = localTris[0];
00564         info.setPoint(tri.centre(localPoints));
00565         info.setHit();
00566     }
00567     else if (localTris.size() == 2)
00568     {
00569         // Check if the two triangles share an edge.
00570         const labelledTri& tri0 = localTris[0];
00571         const labelledTri& tri1 = localTris[0];
00572 
00573         labelPair shared = findCommonPoints(tri0, tri1);
00574 
00575         if (shared[0] != -1)
00576         {
00577             info.setPoint
00578             (
00579                 0.5
00580               * (
00581                     tri0.centre(localPoints)
00582                   + tri1.centre(localPoints)
00583                 )
00584             );
00585             info.setHit();
00586         }
00587     }
00588     else if (localTris.size())
00589     {
00590         // Check if single region. Rare situation.
00591         triSurface surf
00592         (
00593             localTris,
00594             geometricSurfacePatchList(0),
00595             localPoints,
00596             true
00597         );
00598         localTris.clearStorage();
00599 
00600         labelList faceZone;
00601         label nZones = surf.markZones
00602         (
00603             boolList(surf.nEdges(), false),
00604             faceZone
00605         );
00606 
00607         if (nZones == 1)
00608         {
00609             info.setPoint(calcCentre(surf));
00610             info.setHit();
00611         }
00612     }
00613 
00614     return info;
00615 }
00616 
00617 
00618 // Determine per cell centre whether all the intersections get collapsed
00619 // to a single point
00620 void Foam::isoSurface::calcSnappedCc
00621 (
00622     const labelList& boundaryRegion,
00623     const volVectorField& meshC,
00624     const volScalarField& cVals,
00625     const scalarField& pVals,
00626 
00627     DynamicList<point>& snappedPoints,
00628     labelList& snappedCc
00629 ) const
00630 {
00631     const pointField& pts = mesh_.points();
00632     const pointField& cc = mesh_.cellCentres();
00633 
00634     snappedCc.setSize(mesh_.nCells());
00635     snappedCc = -1;
00636 
00637     // Work arrays
00638     DynamicList<point, 64> localTriPoints(64);
00639 
00640     forAll(mesh_.cells(), cellI)
00641     {
00642         if (cellCutType_[cellI] == CUT)
00643         {
00644             scalar cVal = cVals[cellI];
00645 
00646             const cell& cFaces = mesh_.cells()[cellI];
00647 
00648             localTriPoints.clear();
00649             label nOther = 0;
00650             point otherPointSum = vector::zero;
00651 
00652             // Create points for all intersections close to cell centre
00653             // (i.e. from pyramid edges)
00654 
00655             forAll(cFaces, cFaceI)
00656             {
00657                 label faceI = cFaces[cFaceI];
00658 
00659                 scalar nbrValue;
00660                 point nbrPoint;
00661                 getNeighbour
00662                 (
00663                     boundaryRegion,
00664                     meshC,
00665                     cVals,
00666                     cellI,
00667                     faceI,
00668                     nbrValue,
00669                     nbrPoint
00670                 );
00671 
00672                 // Calculate intersection points of edges to cell centre
00673                 FixedList<scalar, 3> s;
00674                 FixedList<point, 3> pt;
00675 
00676                 // From cc to neighbour cc.
00677                 s[2] = isoFraction(cVal, nbrValue);
00678                 pt[2] = (1.0-s[2])*cc[cellI] + s[2]*nbrPoint;
00679 
00680                 const face& f = mesh_.faces()[cFaces[cFaceI]];
00681 
00682                 forAll(f, fp)
00683                 {
00684                     // From cc to fp
00685                     label p0 = f[fp];
00686                     s[0] = isoFraction(cVal, pVals[p0]);
00687                     pt[0] = (1.0-s[0])*cc[cellI] + s[0]*pts[p0];
00688 
00689                     // From cc to fp+1
00690                     label p1 = f[f.fcIndex(fp)];
00691                     s[1] = isoFraction(cVal, pVals[p1]);
00692                     pt[1] = (1.0-s[1])*cc[cellI] + s[1]*pts[p1];
00693 
00694                     if
00695                     (
00696                         (s[0] >= 0.0 && s[0] <= 0.5)
00697                      && (s[1] >= 0.0 && s[1] <= 0.5)
00698                      && (s[2] >= 0.0 && s[2] <= 0.5)
00699                     )
00700                     {
00701                         localTriPoints.append(pt[0]);
00702                         localTriPoints.append(pt[1]);
00703                         localTriPoints.append(pt[2]);
00704                     }
00705                     else
00706                     {
00707                         // Get average of all other points
00708                         forAll(s, i)
00709                         {
00710                             if (s[i] >= 0.0 && s[i] <= 0.5)
00711                             {
00712                                 otherPointSum += pt[i];
00713                                 nOther++;
00714                             }
00715                         }
00716                     }
00717                 }
00718             }
00719 
00720             if (localTriPoints.size() == 0)
00721             {
00722                 // No complete triangles. Get average of all intersection
00723                 // points.
00724                 if (nOther > 0)
00725                 {
00726                     snappedCc[cellI] = snappedPoints.size();
00727                     snappedPoints.append(otherPointSum/nOther);
00728 
00729                     //Pout<< "    point:" << pointI
00730                     //    << " replacing coord:" << mesh_.points()[pointI]
00731                     //    << " by average:" << collapsedPoint[pointI] << endl;
00732                 }
00733             }
00734             else if (localTriPoints.size() == 3)
00735             {
00736                 // Single triangle. No need for any analysis. Average points.
00737                 pointField points;
00738                 points.transfer(localTriPoints);
00739                 snappedCc[cellI] = snappedPoints.size();
00740                 snappedPoints.append(sum(points)/points.size());
00741 
00742                 //Pout<< "    point:" << pointI
00743                 //    << " replacing coord:" << mesh_.points()[pointI]
00744                 //    << " by average:" << collapsedPoint[pointI] << endl;
00745             }
00746             else
00747             {
00748                 // Convert points into triSurface.
00749 
00750                 // Merge points and compact out non-valid triangles
00751                 labelList triMap;               // merged to unmerged triangle
00752                 labelList triPointReverseMap;   // unmerged to merged point
00753                 triSurface surf
00754                 (
00755                     stitchTriPoints
00756                     (
00757                         false,              // do not check for duplicate tris
00758                         localTriPoints,
00759                         triPointReverseMap,
00760                         triMap
00761                     )
00762                 );
00763 
00764                 labelList faceZone;
00765                 label nZones = surf.markZones
00766                 (
00767                     boolList(surf.nEdges(), false),
00768                     faceZone
00769                 );
00770 
00771                 if (nZones == 1)
00772                 {
00773                     snappedCc[cellI] = snappedPoints.size();
00774                     snappedPoints.append(calcCentre(surf));
00775                     //Pout<< "    point:" << pointI << " nZones:" << nZones
00776                     //    << " replacing coord:" << mesh_.points()[pointI]
00777                     //    << " by average:" << collapsedPoint[pointI] << endl;
00778                 }
00779             }
00780         }
00781     }
00782 }
00783 
00784 
00785 // Determine per meshpoint whether all the intersections get collapsed
00786 // to a single point
00787 void Foam::isoSurface::calcSnappedPoint
00788 (
00789     const PackedBoolList& isBoundaryPoint,
00790     const labelList& boundaryRegion,
00791     const volVectorField& meshC,
00792     const volScalarField& cVals,
00793     const scalarField& pVals,
00794 
00795     DynamicList<point>& snappedPoints,
00796     labelList& snappedPoint
00797 ) const
00798 {
00799     const pointField& pts = mesh_.points();
00800     const pointField& cc = mesh_.cellCentres();
00801 
00802 
00803     const point greatPoint(VGREAT, VGREAT, VGREAT);
00804     pointField collapsedPoint(mesh_.nPoints(), greatPoint);
00805 
00806 
00807     // Work arrays
00808     DynamicList<point, 64> localTriPoints(100);
00809 
00810     forAll(mesh_.pointFaces(), pointI)
00811     {
00812         if (isBoundaryPoint.get(pointI) == 1)
00813         {
00814             continue;
00815         }
00816 
00817         const labelList& pFaces = mesh_.pointFaces()[pointI];
00818 
00819         bool anyCut = false;
00820 
00821         forAll(pFaces, i)
00822         {
00823             label faceI = pFaces[i];
00824 
00825             if (faceCutType_[faceI] == CUT)
00826             {
00827                 anyCut = true;
00828                 break;
00829             }
00830         }
00831 
00832         if (!anyCut)
00833         {
00834             continue;
00835         }
00836 
00837 
00838         localTriPoints.clear();
00839         label nOther = 0;
00840         point otherPointSum = vector::zero;
00841 
00842         forAll(pFaces, pFaceI)
00843         {
00844             // Create points for all intersections close to point
00845             // (i.e. from pyramid edges)
00846 
00847             label faceI = pFaces[pFaceI];
00848             const face& f = mesh_.faces()[faceI];
00849             label own = mesh_.faceOwner()[faceI];
00850 
00851             // Get neighbour value
00852             scalar nbrValue;
00853             point nbrPoint;
00854             getNeighbour
00855             (
00856                 boundaryRegion,
00857                 meshC,
00858                 cVals,
00859                 own,
00860                 faceI,
00861                 nbrValue,
00862                 nbrPoint
00863             );
00864 
00865             // Calculate intersection points of edges emanating from point
00866             FixedList<scalar, 4> s;
00867             FixedList<point, 4> pt;
00868 
00869             label fp = findIndex(f, pointI);
00870             s[0] = isoFraction(pVals[pointI], cVals[own]);
00871             pt[0] = (1.0-s[0])*pts[pointI] + s[0]*cc[own];
00872 
00873             s[1] = isoFraction(pVals[pointI], nbrValue);
00874             pt[1] = (1.0-s[1])*pts[pointI] + s[1]*nbrPoint;
00875 
00876             label nextPointI = f[f.fcIndex(fp)];
00877             s[2] = isoFraction(pVals[pointI], pVals[nextPointI]);
00878             pt[2] = (1.0-s[2])*pts[pointI] + s[2]*pts[nextPointI];
00879 
00880             label prevPointI = f[f.rcIndex(fp)];
00881             s[3] = isoFraction(pVals[pointI], pVals[prevPointI]);
00882             pt[3] = (1.0-s[3])*pts[pointI] + s[3]*pts[prevPointI];
00883 
00884             if
00885             (
00886                 (s[0] >= 0.0 && s[0] <= 0.5)
00887              && (s[1] >= 0.0 && s[1] <= 0.5)
00888              && (s[2] >= 0.0 && s[2] <= 0.5)
00889             )
00890             {
00891                 localTriPoints.append(pt[0]);
00892                 localTriPoints.append(pt[1]);
00893                 localTriPoints.append(pt[2]);
00894             }
00895             if
00896             (
00897                 (s[0] >= 0.0 && s[0] <= 0.5)
00898              && (s[1] >= 0.0 && s[1] <= 0.5)
00899              && (s[3] >= 0.0 && s[3] <= 0.5)
00900             )
00901             {
00902                 localTriPoints.append(pt[3]);
00903                 localTriPoints.append(pt[0]);
00904                 localTriPoints.append(pt[1]);
00905             }
00906 
00907             // Get average of points as fallback
00908             forAll(s, i)
00909             {
00910                 if (s[i] >= 0.0 && s[i] <= 0.5)
00911                 {
00912                     otherPointSum += pt[i];
00913                     nOther++;
00914                 }
00915             }
00916         }
00917 
00918         if (localTriPoints.size() == 0)
00919         {
00920             // No complete triangles. Get average of all intersection
00921             // points.
00922             if (nOther > 0)
00923             {
00924                 collapsedPoint[pointI] = otherPointSum/nOther;
00925             }
00926         }
00927         else if (localTriPoints.size() == 3)
00928         {
00929             // Single triangle. No need for any analysis. Average points.
00930             pointField points;
00931             points.transfer(localTriPoints);
00932             collapsedPoint[pointI] = sum(points)/points.size();
00933         }
00934         else
00935         {
00936             // Convert points into triSurface.
00937 
00938             // Merge points and compact out non-valid triangles
00939             labelList triMap;               // merged to unmerged triangle
00940             labelList triPointReverseMap;   // unmerged to merged point
00941             triSurface surf
00942             (
00943                 stitchTriPoints
00944                 (
00945                     false,                  // do not check for duplicate tris
00946                     localTriPoints,
00947                     triPointReverseMap,
00948                     triMap
00949                 )
00950             );
00951 
00952             labelList faceZone;
00953             label nZones = surf.markZones
00954             (
00955                 boolList(surf.nEdges(), false),
00956                 faceZone
00957             );
00958 
00959             if (nZones == 1)
00960             {
00961                 collapsedPoint[pointI] = calcCentre(surf);
00962             }
00963         }
00964     }
00965 
00966 
00967     // Synchronise snap location
00968     syncUnseparatedPoints(collapsedPoint, greatPoint);
00969 
00970 
00971     snappedPoint.setSize(mesh_.nPoints());
00972     snappedPoint = -1;
00973 
00974     forAll(collapsedPoint, pointI)
00975     {
00976         if (collapsedPoint[pointI] != greatPoint)
00977         {
00978             snappedPoint[pointI] = snappedPoints.size();
00979             snappedPoints.append(collapsedPoint[pointI]);
00980         }
00981     }
00982 }
00983 
00984 
00985 Foam::triSurface Foam::isoSurface::stitchTriPoints
00986 (
00987     const bool checkDuplicates,
00988     const List<point>& triPoints,
00989     labelList& triPointReverseMap,  // unmerged to merged point
00990     labelList& triMap               // merged to unmerged triangle
00991 ) const
00992 {
00993     label nTris = triPoints.size()/3;
00994 
00995     if ((triPoints.size() % 3) != 0)
00996     {
00997         FatalErrorIn("isoSurface::stitchTriPoints(..)")
00998             << "Problem: number of points " << triPoints.size()
00999             << " not a multiple of 3." << abort(FatalError);
01000     }
01001 
01002     pointField newPoints;
01003     mergePoints
01004     (
01005         triPoints,
01006         mergeDistance_,
01007         false,
01008         triPointReverseMap,
01009         newPoints
01010     );
01011 
01012     // Check that enough merged.
01013     if (debug)
01014     {
01015         pointField newNewPoints;
01016         labelList oldToNew;
01017         bool hasMerged = mergePoints
01018         (
01019             newPoints,
01020             mergeDistance_,
01021             true,
01022             oldToNew,
01023             newNewPoints
01024         );
01025 
01026         if (hasMerged)
01027         {
01028             FatalErrorIn("isoSurface::stitchTriPoints(..)")
01029                 << "Merged points contain duplicates"
01030                 << " when merging with distance " << mergeDistance_ << endl
01031                 << "merged:" << newPoints.size() << " re-merged:"
01032                 << newNewPoints.size()
01033                 << abort(FatalError);
01034         }
01035     }
01036 
01037 
01038     List<labelledTri> tris;
01039     {
01040         DynamicList<labelledTri> dynTris(nTris);
01041         label rawPointI = 0;
01042         DynamicList<label> newToOldTri(nTris);
01043 
01044         for (label oldTriI = 0; oldTriI < nTris; oldTriI++)
01045         {
01046             labelledTri tri
01047             (
01048                 triPointReverseMap[rawPointI],
01049                 triPointReverseMap[rawPointI+1],
01050                 triPointReverseMap[rawPointI+2],
01051                 0
01052             );
01053             rawPointI += 3;
01054 
01055             if ((tri[0] != tri[1]) && (tri[0] != tri[2]) && (tri[1] != tri[2]))
01056             {
01057                 newToOldTri.append(oldTriI);
01058                 dynTris.append(tri);
01059             }
01060         }
01061 
01062         triMap.transfer(newToOldTri);
01063         tris.transfer(dynTris);
01064     }
01065 
01066 
01067 
01068     // Determine 'flat hole' situation (see RMT paper).
01069     // Two unconnected triangles get connected because (some of) the edges
01070     // separating them get collapsed. Below only checks for duplicate triangles,
01071     // not non-manifold edge connectivity.
01072     if (checkDuplicates)
01073     {
01074         labelListList pointFaces;
01075         invertManyToMany(newPoints.size(), tris, pointFaces);
01076 
01077         // Filter out duplicates.
01078         DynamicList<label> newToOldTri(tris.size());
01079 
01080         forAll(tris, triI)
01081         {
01082             const labelledTri& tri = tris[triI];
01083             const labelList& pFaces = pointFaces[tri[0]];
01084 
01085             // Find the maximum of any duplicates. Maximum since the tris
01086             // below triI
01087             // get overwritten so we cannot use them in a comparison.
01088             label dupTriI = -1;
01089             forAll(pFaces, i)
01090             {
01091                 label nbrTriI = pFaces[i];
01092 
01093                 if (nbrTriI > triI && (tris[nbrTriI] == tri))
01094                 {
01095                     //Pout<< "Duplicate : " << triI << " verts:" << tri
01096                     //    << " to " << nbrTriI << " verts:" << tris[nbrTriI]
01097                     //    << endl;
01098                     dupTriI = nbrTriI;
01099                     break;
01100                 }
01101             }
01102 
01103             if (dupTriI == -1)
01104             {
01105                 // There is no (higher numbered) duplicate triangle
01106                 label newTriI = newToOldTri.size();
01107                 newToOldTri.append(triI);
01108                 tris[newTriI] = tris[triI];
01109             }
01110         }
01111 
01112         triMap.transfer(newToOldTri);
01113         tris.setSize(triMap.size());
01114 
01115         if (debug)
01116         {
01117             Pout<< "isoSurface : merged from " << nTris
01118                 << " down to " << tris.size() << " unique triangles." << endl;
01119         }
01120 
01121 
01122         if (debug)
01123         {
01124             triSurface surf(tris, geometricSurfacePatchList(0), newPoints);
01125 
01126             forAll(surf, faceI)
01127             {
01128                 const labelledTri& f = surf[faceI];
01129                 const labelList& fFaces = surf.faceFaces()[faceI];
01130 
01131                 forAll(fFaces, i)
01132                 {
01133                     label nbrFaceI = fFaces[i];
01134 
01135                     if (nbrFaceI <= faceI)
01136                     {
01137                         // lower numbered faces already checked
01138                         continue;
01139                     }
01140 
01141                     const labelledTri& nbrF = surf[nbrFaceI];
01142 
01143                     if (f == nbrF)
01144                     {
01145                         FatalErrorIn("validTri(const triSurface&, const label)")
01146                             << "Check : "
01147                             << " triangle " << faceI << " vertices " << f
01148                             << " fc:" << f.centre(surf.points())
01149                             << " has the same vertices as triangle " << nbrFaceI
01150                             << " vertices " << nbrF
01151                             << " fc:" << nbrF.centre(surf.points())
01152                             << abort(FatalError);
01153                     }
01154                 }
01155             }
01156         }
01157     }
01158 
01159     return triSurface(tris, geometricSurfacePatchList(0), newPoints, true);
01160 }
01161 
01162 
01163 // Does face use valid vertices?
01164 bool Foam::isoSurface::validTri(const triSurface& surf, const label faceI)
01165 {
01166     // Simple check on indices ok.
01167 
01168     const labelledTri& f = surf[faceI];
01169 
01170     if
01171     (
01172         (f[0] < 0) || (f[0] >= surf.points().size())
01173      || (f[1] < 0) || (f[1] >= surf.points().size())
01174      || (f[2] < 0) || (f[2] >= surf.points().size())
01175     )
01176     {
01177         WarningIn("validTri(const triSurface&, const label)")
01178             << "triangle " << faceI << " vertices " << f
01179             << " uses point indices outside point range 0.."
01180             << surf.points().size()-1 << endl;
01181 
01182         return false;
01183     }
01184 
01185     if ((f[0] == f[1]) || (f[0] == f[2]) || (f[1] == f[2]))
01186     {
01187         WarningIn("validTri(const triSurface&, const label)")
01188             << "triangle " << faceI
01189             << " uses non-unique vertices " << f
01190             << endl;
01191         return false;
01192     }
01193 
01194     // duplicate triangle check
01195 
01196     const labelList& fFaces = surf.faceFaces()[faceI];
01197 
01198     // Check if faceNeighbours use same points as this face.
01199     // Note: discards normal information - sides of baffle are merged.
01200     forAll(fFaces, i)
01201     {
01202         label nbrFaceI = fFaces[i];
01203 
01204         if (nbrFaceI <= faceI)
01205         {
01206             // lower numbered faces already checked
01207             continue;
01208         }
01209 
01210         const labelledTri& nbrF = surf[nbrFaceI];
01211 
01212         if
01213         (
01214             ((f[0] == nbrF[0]) || (f[0] == nbrF[1]) || (f[0] == nbrF[2]))
01215          && ((f[1] == nbrF[0]) || (f[1] == nbrF[1]) || (f[1] == nbrF[2]))
01216          && ((f[2] == nbrF[0]) || (f[2] == nbrF[1]) || (f[2] == nbrF[2]))
01217         )
01218         {
01219             WarningIn("validTri(const triSurface&, const label)")
01220                 << "triangle " << faceI << " vertices " << f
01221                 << " fc:" << f.centre(surf.points())
01222                 << " has the same vertices as triangle " << nbrFaceI
01223                 << " vertices " << nbrF
01224                 << " fc:" << nbrF.centre(surf.points())
01225                 << endl;
01226 
01227             return false;
01228         }
01229     }
01230     return true;
01231 }
01232 
01233 
01234 void Foam::isoSurface::calcAddressing
01235 (
01236     const triSurface& surf,
01237     List<FixedList<label, 3> >& faceEdges,
01238     labelList& edgeFace0,
01239     labelList& edgeFace1,
01240     Map<labelList>& edgeFacesRest
01241 ) const
01242 {
01243     const pointField& points = surf.points();
01244 
01245     pointField edgeCentres(3*surf.size());
01246     label edgeI = 0;
01247     forAll(surf, triI)
01248     {
01249         const labelledTri& tri = surf[triI];
01250         edgeCentres[edgeI++] = 0.5*(points[tri[0]]+points[tri[1]]);
01251         edgeCentres[edgeI++] = 0.5*(points[tri[1]]+points[tri[2]]);
01252         edgeCentres[edgeI++] = 0.5*(points[tri[2]]+points[tri[0]]);
01253     }
01254 
01255     pointField mergedCentres;
01256     labelList oldToMerged;
01257     bool hasMerged = mergePoints
01258     (
01259         edgeCentres,
01260         mergeDistance_,
01261         false,
01262         oldToMerged,
01263         mergedCentres
01264     );
01265 
01266     if (debug)
01267     {
01268         Pout<< "isoSurface : detected "
01269             << mergedCentres.size()
01270             << " geometric edges on " << surf.size() << " triangles." << endl;
01271     }
01272 
01273     if (!hasMerged)
01274     {
01275         if (surf.size() == 1)
01276         {
01277             faceEdges.setSize(1);
01278             faceEdges[0][0] = 0;
01279             faceEdges[0][1] = 1;
01280             faceEdges[0][2] = 2;
01281             edgeFace0.setSize(1);
01282             edgeFace0[0] = 0;
01283             edgeFace1.setSize(1);
01284             edgeFace1[0] = -1;
01285             edgeFacesRest.clear();
01286         }
01287         return;
01288     }
01289 
01290 
01291     // Determine faceEdges
01292     faceEdges.setSize(surf.size());
01293     edgeI = 0;
01294     forAll(surf, triI)
01295     {
01296         faceEdges[triI][0] = oldToMerged[edgeI++];
01297         faceEdges[triI][1] = oldToMerged[edgeI++];
01298         faceEdges[triI][2] = oldToMerged[edgeI++];
01299     }
01300 
01301 
01302     // Determine edgeFaces
01303     edgeFace0.setSize(mergedCentres.size());
01304     edgeFace0 = -1;
01305     edgeFace1.setSize(mergedCentres.size());
01306     edgeFace1 = -1;
01307     edgeFacesRest.clear();
01308 
01309     // Overflow edge faces for geometric shared edges that turned
01310     // out to be different anyway.
01311     EdgeMap<labelList> extraEdgeFaces(mergedCentres.size()/100);
01312 
01313     forAll(oldToMerged, oldEdgeI)
01314     {
01315         label triI = oldEdgeI / 3;
01316         label edgeI = oldToMerged[oldEdgeI];
01317 
01318         if (edgeFace0[edgeI] == -1)
01319         {
01320             // First triangle for edge
01321             edgeFace0[edgeI] = triI;
01322         }
01323         else
01324         {
01325             //- Check that the two triangles actually topologically
01326             //  share an edge
01327             const labelledTri& prevTri = surf[edgeFace0[edgeI]];
01328             const labelledTri& tri = surf[triI];
01329 
01330             label fp = oldEdgeI % 3;
01331 
01332             edge e(tri[fp], tri[tri.fcIndex(fp)]);
01333 
01334             label prevTriIndex = -1;
01335 
01336             forAll(prevTri, i)
01337             {
01338                 if (edge(prevTri[i], prevTri[prevTri.fcIndex(i)]) == e)
01339                 {
01340                     prevTriIndex = i;
01341                     break;
01342                 }
01343             }
01344 
01345             if (prevTriIndex == -1)
01346             {
01347                 // Different edge. Store for later.
01348                 EdgeMap<labelList>::iterator iter = extraEdgeFaces.find(e);
01349 
01350                 if (iter != extraEdgeFaces.end())
01351                 {
01352                     labelList& eFaces = iter();
01353                     label sz = eFaces.size();
01354                     eFaces.setSize(sz+1);
01355                     eFaces[sz] = triI;
01356                 }
01357                 else
01358                 {
01359                     extraEdgeFaces.insert(e, labelList(1, triI));
01360                 }
01361             }
01362             else if (edgeFace1[edgeI] == -1)
01363             {
01364                 edgeFace1[edgeI] = triI;
01365             }
01366             else
01367             {
01368                 //WarningIn("orientSurface(triSurface&)")
01369                 //    << "Edge " << edgeI << " with centre "
01370                 //    << mergedCentres[edgeI]
01371                 //    << " used by more than two triangles: "
01372                 //    << edgeFace0[edgeI] << ", "
01373                 //    << edgeFace1[edgeI] << " and " << triI << endl;
01374                 Map<labelList>::iterator iter = edgeFacesRest.find(edgeI);
01375 
01376                 if (iter != edgeFacesRest.end())
01377                 {
01378                     labelList& eFaces = iter();
01379                     label sz = eFaces.size();
01380                     eFaces.setSize(sz+1);
01381                     eFaces[sz] = triI;
01382                 }
01383                 else
01384                 {
01385                     edgeFacesRest.insert(edgeI, labelList(1, triI));
01386                 }
01387             }
01388         }
01389     }
01390 
01391     // Add extraEdgeFaces
01392     edgeI = edgeFace0.size();
01393 
01394     edgeFace0.setSize(edgeI + extraEdgeFaces.size());
01395     edgeFace1.setSize(edgeI + extraEdgeFaces.size(), -1);
01396 
01397     forAllConstIter(EdgeMap<labelList>, extraEdgeFaces, iter)
01398     {
01399         const labelList& eFaces = iter();
01400 
01401         // The current edge will become edgeI. Replace all occurrences in
01402         // faceEdges
01403         forAll(eFaces, i)
01404         {
01405             label triI = eFaces[i];
01406             const labelledTri& tri = surf[triI];
01407 
01408             FixedList<label, 3>& fEdges = faceEdges[triI];
01409             forAll(tri, fp)
01410             {
01411                 edge e(tri[fp], tri[tri.fcIndex(fp)]);
01412 
01413                 if (e == iter.key())
01414                 {
01415                     fEdges[fp] = edgeI;
01416                     break;
01417                 }
01418             }
01419         }
01420 
01421 
01422         // Add face to edgeFaces
01423 
01424         edgeFace0[edgeI] = eFaces[0];
01425 
01426         if (eFaces.size() >= 2)
01427         {
01428             edgeFace1[edgeI] = eFaces[1];
01429 
01430             if (eFaces.size() > 2)
01431             {
01432                 edgeFacesRest.insert
01433                 (
01434                     edgeI,
01435                     SubList<label>(eFaces, eFaces.size()-2, 2)
01436                 );
01437             }
01438         }
01439 
01440         edgeI++;
01441     }
01442 }
01443 
01444 
01445 void Foam::isoSurface::walkOrientation
01446 (
01447     const triSurface& surf,
01448     const List<FixedList<label, 3> >& faceEdges,
01449     const labelList& edgeFace0,
01450     const labelList& edgeFace1,
01451     const label seedTriI,
01452     labelList& flipState
01453 )
01454 {
01455     // Do walk for consistent orientation.
01456     DynamicList<label> changedFaces(surf.size());
01457 
01458     changedFaces.append(seedTriI);
01459 
01460     while (changedFaces.size())
01461     {
01462         DynamicList<label> newChangedFaces(changedFaces.size());
01463 
01464         forAll(changedFaces, i)
01465         {
01466             label triI = changedFaces[i];
01467             const labelledTri& tri = surf[triI];
01468             const FixedList<label, 3>& fEdges = faceEdges[triI];
01469 
01470             forAll(fEdges, fp)
01471             {
01472                 label edgeI = fEdges[fp];
01473 
01474                 // my points:
01475                 label p0 = tri[fp];
01476                 label p1 = tri[tri.fcIndex(fp)];
01477 
01478                 label nbrI =
01479                 (
01480                     edgeFace0[edgeI] != triI
01481                   ? edgeFace0[edgeI]
01482                   : edgeFace1[edgeI]
01483                 );
01484 
01485                 if (nbrI != -1 && flipState[nbrI] == -1)
01486                 {
01487                     const labelledTri& nbrTri = surf[nbrI];
01488 
01489                     // nbr points
01490                     label nbrFp = findIndex(nbrTri, p0);
01491 
01492                     if (nbrFp == -1)
01493                     {
01494                         FatalErrorIn("isoSurface::walkOrientation(..)")
01495                             << "triI:" << triI
01496                             << " tri:" << tri
01497                             << " p0:" << p0
01498                             << " p1:" << p1
01499                             << " fEdges:" << fEdges
01500                             << " edgeI:" << edgeI
01501                             << " edgeFace0:" << edgeFace0[edgeI]
01502                             << " edgeFace1:" << edgeFace1[edgeI]
01503                             << " nbrI:" << nbrI
01504                             << " nbrTri:" << nbrTri
01505                             << abort(FatalError);
01506                     }
01507 
01508 
01509                     label nbrP1 = nbrTri[nbrTri.rcIndex(nbrFp)];
01510 
01511                     bool sameOrientation = (p1 == nbrP1);
01512 
01513                     if (flipState[triI] == 0)
01514                     {
01515                         flipState[nbrI] = (sameOrientation ? 0 : 1);
01516                     }
01517                     else
01518                     {
01519                         flipState[nbrI] = (sameOrientation ? 1 : 0);
01520                     }
01521                     newChangedFaces.append(nbrI);
01522                 }
01523             }
01524         }
01525 
01526         changedFaces.transfer(newChangedFaces);
01527     }
01528 }
01529 
01530 
01531 void Foam::isoSurface::orientSurface
01532 (
01533     triSurface& surf,
01534     const List<FixedList<label, 3> >& faceEdges,
01535     const labelList& edgeFace0,
01536     const labelList& edgeFace1,
01537     const Map<labelList>& edgeFacesRest
01538 )
01539 {
01540     // -1 : unvisited
01541     //  0 : leave as is
01542     //  1 : flip
01543     labelList flipState(surf.size(), -1);
01544 
01545     label seedTriI = 0;
01546 
01547     while (true)
01548     {
01549         // Find first unvisited triangle
01550         for
01551         (
01552             ;
01553             seedTriI < surf.size() && flipState[seedTriI] != -1;
01554             seedTriI++
01555         )
01556         {}
01557 
01558         if (seedTriI == surf.size())
01559         {
01560             break;
01561         }
01562 
01563         // Note: Determine orientation of seedTriI?
01564         // for now assume it is ok
01565         flipState[seedTriI] = 0;
01566 
01567         walkOrientation
01568         (
01569             surf,
01570             faceEdges,
01571             edgeFace0,
01572             edgeFace1,
01573             seedTriI,
01574             flipState
01575         );
01576     }
01577 
01578     // Do actual flipping
01579     surf.clearOut();
01580     forAll(surf, triI)
01581     {
01582         if (flipState[triI] == 1)
01583         {
01584             labelledTri tri(surf[triI]);
01585 
01586             surf[triI][0] = tri[0];
01587             surf[triI][1] = tri[2];
01588             surf[triI][2] = tri[1];
01589         }
01590         else if (flipState[triI] == -1)
01591         {
01592             FatalErrorIn
01593             (
01594                 "isoSurface::orientSurface(triSurface&, const label)"
01595             )   << "problem" << abort(FatalError);
01596         }
01597     }
01598 }
01599 
01600 
01601 // Checks if triangle is connected through edgeI only.
01602 bool Foam::isoSurface::danglingTriangle
01603 (
01604     const FixedList<label, 3>& fEdges,
01605     const labelList& edgeFace1
01606 )
01607 {
01608     label nOpen = 0;
01609     forAll(fEdges, i)
01610     {
01611         if (edgeFace1[fEdges[i]] == -1)
01612         {
01613             nOpen++;
01614         }
01615     }
01616 
01617     if (nOpen == 1 || nOpen == 2 || nOpen == 3)
01618     {
01619         return true;
01620     }
01621     else
01622     {
01623         return false;
01624     }
01625 }
01626 
01627 
01628 // Mark triangles to keep. Returns number of dangling triangles.
01629 Foam::label Foam::isoSurface::markDanglingTriangles
01630 (
01631     const List<FixedList<label, 3> >& faceEdges,
01632     const labelList& edgeFace0,
01633     const labelList& edgeFace1,
01634     const Map<labelList>& edgeFacesRest,
01635     boolList& keepTriangles
01636 )
01637 {
01638     keepTriangles.setSize(faceEdges.size());
01639     keepTriangles = true;
01640 
01641     label nDangling = 0;
01642 
01643     // Remove any dangling triangles
01644     forAllConstIter(Map<labelList>,  edgeFacesRest, iter)
01645     {
01646         // These are all the non-manifold edges. Filter out all triangles
01647         // with only one connected edge (= this edge)
01648 
01649         label edgeI = iter.key();
01650         const labelList& otherEdgeFaces = iter();
01651 
01652         // Remove all dangling triangles
01653         if (danglingTriangle(faceEdges[edgeFace0[edgeI]], edgeFace1))
01654         {
01655             keepTriangles[edgeFace0[edgeI]] = false;
01656             nDangling++;
01657         }
01658         if (danglingTriangle(faceEdges[edgeFace1[edgeI]], edgeFace1))
01659         {
01660             keepTriangles[edgeFace1[edgeI]] = false;
01661             nDangling++;
01662         }
01663         forAll(otherEdgeFaces, i)
01664         {
01665             label triI = otherEdgeFaces[i];
01666             if (danglingTriangle(faceEdges[triI], edgeFace1))
01667             {
01668                 keepTriangles[triI] = false;
01669                 nDangling++;
01670             }
01671         }
01672     }
01673     return nDangling;
01674 }
01675 
01676 
01677 Foam::triSurface Foam::isoSurface::subsetMesh
01678 (
01679     const triSurface& s,
01680     const labelList& newToOldFaces,
01681     labelList& oldToNewPoints,
01682     labelList& newToOldPoints
01683 )
01684 {
01685     const boolList include
01686     (
01687         createWithValues<boolList>
01688         (
01689             s.size(),
01690             false,
01691             newToOldFaces,
01692             true
01693         )
01694     );
01695 
01696     newToOldPoints.setSize(s.points().size());
01697     oldToNewPoints.setSize(s.points().size());
01698     oldToNewPoints = -1;
01699     {
01700         label pointI = 0;
01701 
01702         forAll(include, oldFacei)
01703         {
01704             if (include[oldFacei])
01705             {
01706                 // Renumber labels for triangle
01707                 const labelledTri& tri = s[oldFacei];
01708 
01709                 forAll(tri, fp)
01710                 {
01711                     label oldPointI = tri[fp];
01712 
01713                     if (oldToNewPoints[oldPointI] == -1)
01714                     {
01715                         oldToNewPoints[oldPointI] = pointI;
01716                         newToOldPoints[pointI++] = oldPointI;
01717                     }
01718                 }
01719             }
01720         }
01721         newToOldPoints.setSize(pointI);
01722     }
01723 
01724     // Extract points
01725     pointField newPoints(newToOldPoints.size());
01726     forAll(newToOldPoints, i)
01727     {
01728         newPoints[i] = s.points()[newToOldPoints[i]];
01729     }
01730     // Extract faces
01731     List<labelledTri> newTriangles(newToOldFaces.size());
01732 
01733     forAll(newToOldFaces, i)
01734     {
01735         // Get old vertex labels
01736         const labelledTri& tri = s[newToOldFaces[i]];
01737 
01738         newTriangles[i][0] = oldToNewPoints[tri[0]];
01739         newTriangles[i][1] = oldToNewPoints[tri[1]];
01740         newTriangles[i][2] = oldToNewPoints[tri[2]];
01741         newTriangles[i].region() = tri.region();
01742     }
01743 
01744     // Reuse storage.
01745     return triSurface(newTriangles, s.patches(), newPoints, true);
01746 }
01747 
01748 
01749 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
01750 
01751 Foam::isoSurface::isoSurface
01752 (
01753     const volScalarField& cVals,
01754     const scalarField& pVals,
01755     const scalar iso,
01756     const bool regularise,
01757     const scalar mergeTol
01758 )
01759 :
01760     mesh_(cVals.mesh()),
01761     pVals_(pVals),
01762     iso_(iso),
01763     regularise_(regularise),
01764     mergeDistance_(mergeTol*mesh_.bounds().mag())
01765 {
01766     if (debug)
01767     {
01768         Pout<< "isoSurface:" << nl
01769             << "    isoField      : " << cVals.name() << nl
01770             << "    cell min/max  : "
01771             << min(cVals.internalField()) << " / "
01772             << max(cVals.internalField()) << nl
01773             << "    point min/max : "
01774             << min(pVals_) << " / "
01775             << max(pVals_) << nl
01776             << "    isoValue      : " << iso << nl
01777             << "    regularise    : " << regularise_ << nl
01778             << "    mergeTol      : " << mergeTol << nl
01779             << endl;
01780     }
01781 
01782     const polyBoundaryMesh& patches = mesh_.boundaryMesh();
01783 
01784 
01785     // Rewrite input field
01786     // ~~~~~~~~~~~~~~~~~~~
01787     // Rewrite input volScalarField to have interpolated values
01788     // on separated patches.
01789 
01790     cValsPtr_.reset(adaptPatchFields(cVals).ptr());
01791 
01792 
01793     // Construct cell centres field consistent with cVals
01794     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
01795     // Generate field to interpolate. This is identical to the mesh.C()
01796     // except on separated coupled patches and on empty patches.
01797 
01798     slicedVolVectorField meshC
01799     (
01800         IOobject
01801         (
01802             "C",
01803             mesh_.pointsInstance(),
01804             mesh_.meshSubDir,
01805             mesh_,
01806             IOobject::NO_READ,
01807             IOobject::NO_WRITE,
01808             false
01809         ),
01810         mesh_,
01811         dimLength,
01812         mesh_.cellCentres(),
01813         mesh_.faceCentres()
01814     );
01815     forAll(patches, patchI)
01816     {
01817         const polyPatch& pp = patches[patchI];
01818 
01819         // Adapt separated coupled (proc and cyclic) patches
01820         if (isA<coupledPolyPatch>(pp) && !collocatedPatch(pp))
01821         {
01822             fvPatchVectorField& pfld = const_cast<fvPatchVectorField&>
01823             (
01824                 meshC.boundaryField()[patchI]
01825             );
01826 
01827             PackedBoolList isCollocated
01828             (
01829                 collocatedFaces(refCast<const coupledPolyPatch>(pp))
01830             );
01831 
01832             forAll(isCollocated, i)
01833             {
01834                 if (!isCollocated[i])
01835                 {
01836                     pfld[i] = mesh_.faceCentres()[pp.start()+i];
01837                 }
01838             }
01839         }
01840         else if (isA<emptyPolyPatch>(pp))
01841         {
01842             typedef slicedVolVectorField::GeometricBoundaryField bType;
01843 
01844             bType& bfld = const_cast<bType&>(meshC.boundaryField());
01845 
01846             // Clear old value. Cannot resize it since is a slice.
01847             bfld.set(patchI, NULL);
01848 
01849             // Set new value we can change
01850             bfld.set
01851             (
01852                 patchI,
01853                 new calculatedFvPatchField<vector>
01854                 (
01855                     mesh_.boundary()[patchI],
01856                     meshC
01857                 )
01858             );
01859 
01860             // Change to face centres
01861             bfld[patchI] = pp.patchSlice(mesh_.faceCentres());
01862         }
01863     }
01864 
01865 
01866 
01867     // Pre-calculate patch-per-face to avoid whichPatch call.
01868     labelList boundaryRegion(mesh_.nFaces()-mesh_.nInternalFaces());
01869 
01870     forAll(patches, patchI)
01871     {
01872         const polyPatch& pp = patches[patchI];
01873 
01874         label faceI = pp.start();
01875 
01876         forAll(pp, i)
01877         {
01878             boundaryRegion[faceI-mesh_.nInternalFaces()] = patchI;
01879             faceI++;
01880         }
01881     }
01882 
01883 
01884 
01885     // Determine if any cut through face/cell
01886     calcCutTypes(boundaryRegion, meshC, cValsPtr_(), pVals_);
01887 
01888 
01889     DynamicList<point> snappedPoints(nCutCells_);
01890 
01891     // Per cc -1 or a point inside snappedPoints.
01892     labelList snappedCc;
01893     if (regularise_)
01894     {
01895         calcSnappedCc
01896         (
01897             boundaryRegion,
01898             meshC,
01899             cValsPtr_(),
01900             pVals_,
01901 
01902             snappedPoints,
01903             snappedCc
01904         );
01905     }
01906     else
01907     {
01908         snappedCc.setSize(mesh_.nCells());
01909         snappedCc = -1;
01910     }
01911 
01912 
01913 
01914     if (debug)
01915     {
01916         Pout<< "isoSurface : shifted " << snappedPoints.size()
01917             << " cell centres to intersection." << endl;
01918     }
01919 
01920     label nCellSnaps = snappedPoints.size();
01921 
01922 
01923     // Per point -1 or a point inside snappedPoints.
01924     labelList snappedPoint;
01925     if (regularise_)
01926     {
01927         // Determine if point is on boundary.
01928         PackedBoolList isBoundaryPoint(mesh_.nPoints());
01929 
01930         forAll(patches, patchI)
01931         {
01932             // Mark all boundary points that are not physically coupled
01933             // (so anything but collocated coupled patches)
01934 
01935             if (patches[patchI].coupled())
01936             {
01937                 if (!collocatedPatch(patches[patchI]))
01938                 {
01939                     const coupledPolyPatch& cpp =
01940                         refCast<const coupledPolyPatch>
01941                         (
01942                             patches[patchI]
01943                         );
01944 
01945                     PackedBoolList isCollocated(collocatedFaces(cpp));
01946 
01947                     forAll(isCollocated, i)
01948                     {
01949                         if (!isCollocated[i])
01950                         {
01951                             const face& f = mesh_.faces()[cpp.start()+i];
01952 
01953                             forAll(f, fp)
01954                             {
01955                                 isBoundaryPoint.set(f[fp], 1);
01956                             }
01957                         }
01958                     }
01959                 }
01960             }
01961             else
01962             {
01963                 const polyPatch& pp = patches[patchI];
01964 
01965                 forAll(pp, i)
01966                 {
01967                     const face& f = mesh_.faces()[pp.start()+i];
01968 
01969                     forAll(f, fp)
01970                     {
01971                         isBoundaryPoint.set(f[fp], 1);
01972                     }
01973                 }
01974             }
01975         }
01976 
01977         calcSnappedPoint
01978         (
01979             isBoundaryPoint,
01980             boundaryRegion,
01981             meshC,
01982             cValsPtr_(),
01983             pVals_,
01984 
01985             snappedPoints,
01986             snappedPoint
01987         );
01988     }
01989     else
01990     {
01991         snappedPoint.setSize(mesh_.nPoints());
01992         snappedPoint = -1;
01993     }
01994 
01995     if (debug)
01996     {
01997         Pout<< "isoSurface : shifted " << snappedPoints.size()-nCellSnaps
01998             << " vertices to intersection." << endl;
01999     }
02000 
02001 
02002 
02003     DynamicList<point> triPoints(nCutCells_);
02004     DynamicList<label> triMeshCells(nCutCells_);
02005 
02006     generateTriPoints
02007     (
02008         cValsPtr_(),
02009         pVals_,
02010 
02011         meshC,
02012         mesh_.points(),
02013 
02014         snappedPoints,
02015         snappedCc,
02016         snappedPoint,
02017 
02018         triPoints,
02019         triMeshCells
02020     );
02021 
02022     if (debug)
02023     {
02024         Pout<< "isoSurface : generated " << triMeshCells.size()
02025             << " unmerged triangles from " << triPoints.size()
02026             << " unmerged points." << endl;
02027     }
02028 
02029 
02030     // Merge points and compact out non-valid triangles
02031     labelList triMap;           // merged to unmerged triangle
02032     triSurface::operator=
02033     (
02034         stitchTriPoints
02035         (
02036             true,               // check for duplicate tris
02037             triPoints,
02038             triPointMergeMap_,  // unmerged to merged point
02039             triMap
02040         )
02041     );
02042 
02043     if (debug)
02044     {
02045         Pout<< "isoSurface : generated " << triMap.size()
02046             << " merged triangles." << endl;
02047     }
02048 
02049     meshCells_.setSize(triMap.size());
02050     forAll(triMap, i)
02051     {
02052         meshCells_[i] = triMeshCells[triMap[i]];
02053     }
02054 
02055     if (debug)
02056     {
02057         Pout<< "isoSurface : checking " << size()
02058             << " triangles for validity." << endl;
02059 
02060         forAll(*this, triI)
02061         {
02062             // Copied from surfaceCheck
02063             validTri(*this, triI);
02064         }
02065     }
02066 
02067 
02068 //if (false)
02069 {
02070     List<FixedList<label, 3> > faceEdges;
02071     labelList edgeFace0, edgeFace1;
02072     Map<labelList> edgeFacesRest;
02073 
02074 
02075     while (true)
02076     {
02077         // Calculate addressing
02078         calcAddressing(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
02079 
02080         // See if any dangling triangles
02081         boolList keepTriangles;
02082         label nDangling = markDanglingTriangles
02083         (
02084             faceEdges,
02085             edgeFace0,
02086             edgeFace1,
02087             edgeFacesRest,
02088             keepTriangles
02089         );
02090 
02091         if (debug)
02092         {
02093             Pout<< "isoSurface : detected " << nDangling
02094                 << " dangling triangles." << endl;
02095         }
02096 
02097         if (nDangling == 0)
02098         {
02099             break;
02100         }
02101 
02102         // Create face map (new to old)
02103         labelList subsetTriMap(findIndices(keepTriangles, true));
02104 
02105         labelList subsetPointMap;
02106         labelList reversePointMap;
02107         triSurface::operator=
02108         (
02109             subsetMesh
02110             (
02111                 *this,
02112                 subsetTriMap,
02113                 reversePointMap,
02114                 subsetPointMap
02115             )
02116         );
02117         meshCells_ = labelField(meshCells_, subsetTriMap);
02118         inplaceRenumber(reversePointMap, triPointMergeMap_);
02119     }
02120 
02121     orientSurface(*this, faceEdges, edgeFace0, edgeFace1, edgeFacesRest);
02122 }
02123 
02124 
02125     if (debug)
02126     {
02127         fileName stlFile = mesh_.time().path() + ".stl";
02128         Pout<< "Dumping surface to " << stlFile << endl;
02129         triSurface::write(stlFile);
02130     }
02131 }
02132 
02133 
02134 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines