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

enrichedPatchCutFaces.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 Description
00025     Calculating cut faces of the enriched patch, together with the addressing
00026     into master and slave patch.
00027 
00028 \*---------------------------------------------------------------------------*/
00029 
00030 #include "enrichedPatch.H"
00031 #include <OpenFOAM/boolList.H>
00032 #include <OpenFOAM/DynamicList.H>
00033 #include <OpenFOAM/labelPair.H>
00034 #include <OpenFOAM/primitiveMesh.H>
00035 #include <OpenFOAM/HashSet.H>
00036 
00037 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00038 
00039 // If the cut face gets more than this number of points, it will be checked
00040 const Foam::label Foam::enrichedPatch::maxFaceSizeDebug_ = 100;
00041 
00042 
00043 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00044 
00045 // Index of debug signs:
00046 // x - skip a point
00047 // l - left turn
00048 // r - right turn
00049 
00050 void Foam::enrichedPatch::calcCutFaces() const
00051 {
00052     if (cutFacesPtr_ || cutFaceMasterPtr_ || cutFaceSlavePtr_)
00053     {
00054         FatalErrorIn("void enrichedPatch::calcCutFaces() const")
00055             << "Cut faces addressing already calculated."
00056             << abort(FatalError);
00057     }
00058 
00059     const faceList& enFaces = enrichedFaces();
00060     const labelList& mp = meshPoints();
00061     const faceList& lf = localFaces();
00062     const pointField& lp = localPoints();
00063     const labelListList& pp = pointPoints();
00064 //     Pout << "enFaces: " << enFaces << endl;
00065 //     Pout << "lf: " << lf << endl;
00066 //     Pout << "lp: " << lp << endl;
00067 //     Pout << "pp: " << pp << endl;
00068     const Map<labelList>& masterPointFaceAddr = masterPointFaces();
00069 
00070     // Prepare the storage
00071     DynamicList<face> cf(2*lf.size());
00072     DynamicList<label> cfMaster(2*lf.size());
00073     DynamicList<label> cfSlave(2*lf.size());
00074 
00075     // Algorithm
00076     // Go through all the faces
00077     // 1) For each face, start at point zero and grab the edge zero.
00078     //    Both points are added into the cut face.  Mark the first edge
00079     //    as used and position the current point as the end of the first
00080     //    edge and previous point as point zero.
00081     // 2) Grab all possible points from the current point.  Excluding
00082     //    the previous point find the point giving the biggest right
00083     //    turn. Add the point to the face and mark the edges as used.
00084     //    Continue doing this until the face is complete, i.e. the next point
00085     //    to add is the first point of the face.
00086     // 3) Once the facet is completed, register its owner from the face
00087     //    it has been created from (remember that the first lot of faces
00088     //    inserted into the enriched faces list are the slaves, to allow
00089     //    matching of the other side).
00090     // 4) If the facet is created from an original slave face, go
00091     //    through the master patch and try to identify the master face
00092     //    this facet belongs to.  This is recognised by the fact that the
00093     //    faces consists exclusively of the points of the master face and
00094     //    the points projected onto the face.
00095 
00096     // Create a set of edge usage parameters
00097     HashSet<edge, Hash<edge> > edgesUsedOnce(pp.size());
00098     HashSet<edge, Hash<edge> > edgesUsedTwice
00099         (pp.size()*primitiveMesh::edgesPerPoint_);
00100 
00101 
00102     forAll (lf, faceI)
00103     {
00104         const face& curLocalFace = lf[faceI];
00105         const face& curGlobalFace = enFaces[faceI];
00106 
00107 //         Pout<< "Doing face " << faceI << " local: " << curLocalFace << " or " << curGlobalFace << endl;
00108 //         if (faceI < slavePatch_.size())
00109 //         {
00110 //             Pout<< "original slave: " << slavePatch_[faceI]
00111 //                 << " local: " << slavePatch_.localFaces()[faceI] << endl;
00112 //         }
00113 //         else
00114 //         {
00115 //             Pout<< "original master: "
00116 //                 << masterPatch_[faceI - slavePatch_.size()] << " "
00117 //                 << masterPatch_.localFaces()[faceI - slavePatch_.size()]
00118 //                 << endl;
00119 //         }
00120 //         {
00121 //             pointField facePoints = curLocalFace.points(lp);
00122 //             forAll (curLocalFace, pointI)
00123 //             {
00124 //                 Pout << "v " << facePoints[pointI].x() << " "
00125 //                     << facePoints[pointI].y() << " "
00126 //                     << facePoints[pointI].z() << endl;
00127 //             }
00128 //         }
00129 
00130         // Track the usage of face edges.  When all edges are used, the
00131         // face decomposition is complete.
00132         // The seed edges include all the edges of the original face + all edges
00133         // of other faces that have been used in the construction of the
00134         // facet.  Edges from other faces can be considered as
00135         // internal to the current face if used only once.
00136 
00137         // Track the edge usage to avoid duplicate faces and reset it to unused
00138         boolList usedFaceEdges(curLocalFace.size(), false);
00139 
00140         SLList<edge> edgeSeeds;
00141 
00142         // Insert the edges of current face into the seed list.
00143         edgeList cfe = curLocalFace.edges();
00144         forAll (curLocalFace, edgeI)
00145         {
00146             edgeSeeds.append(cfe[edgeI]);
00147         }
00148 
00149         // Grab face normal
00150         vector normal = curLocalFace.normal(lp);
00151         normal /= mag(normal);
00152 
00153         while (edgeSeeds.size())
00154         {
00155 //             Pout << "edgeSeeds.size(): " << edgeSeeds.size() << endl;
00156             const edge curEdge = edgeSeeds.removeHead();
00157 
00158             // Locate the edge in current face
00159             const label curEdgeWhich = curLocalFace.which(curEdge.start());
00160 
00161             // Check if the edge is in current face and if it has been
00162             // used already.  If so, skip it
00163             if
00164             (
00165                 curEdgeWhich > -1
00166              && curLocalFace.nextLabel(curEdgeWhich) == curEdge.end()
00167             )
00168             {
00169                 // Edge is in the starting face.
00170                 // If unused, mark it as used; if used, skip it
00171                 if (usedFaceEdges[curEdgeWhich]) continue;
00172 
00173                 usedFaceEdges[curEdgeWhich] = true;
00174             }
00175 
00176             // If the edge has already been used twice, skip it
00177             if (edgesUsedTwice.found(curEdge)) continue;
00178 //             Pout << "Trying new edge (" << mp[curEdge.start()] << ", " << mp[curEdge.end()] << ") seed: " << curEdge << " used: " << edgesUsedTwice.found(curEdge) << endl;
00179 
00180             // Estimate the size of cut face as twice the size of original face
00181             DynamicList<label> cutFaceGlobalPoints(2*curLocalFace.size());
00182             DynamicList<label> cutFaceLocalPoints(2*curLocalFace.size());
00183 
00184             // Found unused edge.
00185             label prevPointLabel = curEdge.start();
00186             cutFaceGlobalPoints.append(mp[prevPointLabel]);
00187             cutFaceLocalPoints.append(prevPointLabel);
00188 //             Pout << "prevPointLabel: " << mp[prevPointLabel] << endl;
00189             // Grab current point and append it to the list
00190             label curPointLabel = curEdge.end();
00191             point curPoint = lp[curPointLabel];
00192             cutFaceGlobalPoints.append(mp[curPointLabel]);
00193             cutFaceLocalPoints.append(curPointLabel);
00194 
00195             bool completedCutFace = false;
00196 
00197             label faceSizeDebug = maxFaceSizeDebug_;
00198 
00199             do
00200             {
00201                 // Grab the next point options
00202 //                 Pout << "curPointLabel: " << mp[curPointLabel] << endl;
00203                 const labelList& nextPoints = pp[curPointLabel];
00204 //                 Pout << "nextPoints: " << UIndirectList<label>(mp, nextPoints) << endl;
00205                 // Get the vector along the edge and the right vector
00206                 vector ahead = curPoint - lp[prevPointLabel];
00207                 ahead -= normal*(normal & ahead);
00208                 ahead /= mag(ahead);
00209 
00210                 vector right = normal ^ ahead;
00211                 right /= mag(right);
00212 //                 Pout<< "normal: " << normal << " ahead: " << ahead << " right: " << right << endl;
00213 
00214                 scalar atanTurn = -GREAT;
00215                 label bestAtanPoint = -1;
00216 
00217                 forAll (nextPoints, nextI)
00218                 {
00219                     // Exclude the point we are coming from; there will always
00220                     // be more than one edge, so this is safe
00221                     if (nextPoints[nextI] != prevPointLabel)
00222                     {
00223 // Pout << "cur point: " << curPoint << " trying for point: " << mp[nextPoints[nextI]] << " " << lp[nextPoints[nextI]];
00224                         vector newDir = lp[nextPoints[nextI]] - curPoint;
00225 // Pout << " newDir: " << newDir << " mag: " << mag(newDir) << flush;
00226                         newDir -= normal*(normal & newDir);
00227                         scalar magNewDir = mag(newDir);
00228 // Pout << " corrected: " << newDir << " mag: " << mag(newDir) << flush;
00229 
00230                         if (magNewDir < SMALL)
00231                         {
00232                             FatalErrorIn
00233                             (
00234                                 "void enrichedPatch::"
00235                                 "calcCutFaces() const"
00236                             )   << "Zero length edge detected.  Probable "
00237                                 << "projection error: slave patch probably "
00238                                 << "does not project onto master.  "
00239                                 << "Please switch on "
00240                                 << "enriched patch debug for more info"
00241                                 << abort(FatalError);
00242                         }
00243 
00244                         newDir /= magNewDir;
00245 
00246                         scalar curAtanTurn =
00247                             atan2(newDir & right, newDir & ahead);
00248 
00249 //                         Pout << " atan: " << curAtanTurn << endl;
00250 
00251                         if (curAtanTurn > atanTurn)
00252                         {
00253                             bestAtanPoint = nextPoints[nextI];
00254                             atanTurn = curAtanTurn;
00255                         }
00256                     } // end of prev point skip
00257                 } // end of next point selection
00258 //                 Pout<< "   bestAtanPoint: " << bestAtanPoint << " or "
00259 //                     << mp[bestAtanPoint] << endl;
00260                 // Selected next best point.
00261 //                 Pout << "cutFaceGlobalPoints: " << cutFaceGlobalPoints << endl;
00262                 // Check if the edge about to be added has been used
00263                 // in the current face or twice in other faces.  If
00264                 // so, the face is bad.
00265                 const label whichNextPoint = curLocalFace.which(curPointLabel);
00266 
00267                 if
00268                 (
00269                     whichNextPoint > -1
00270                  && curLocalFace.nextLabel(whichNextPoint) == bestAtanPoint
00271                  && usedFaceEdges[whichNextPoint]
00272                 )
00273                 {
00274                     // This edge is already used in current face
00275                     // face cannot be good; start on a new one
00276 //                     Pout << "Double usage in current face, cannot be good" << endl;
00277                     completedCutFace = true;
00278                 }
00279 
00280 
00281                 if (edgesUsedTwice.found(edge(curPointLabel, bestAtanPoint)))
00282                 {
00283                     // This edge is already used -
00284                     // face cannot be good; start on a new one
00285                     completedCutFace = true;
00286 //                     Pout << "Double usage elsewhere, cannot be good" << endl;
00287                 }
00288 
00289                 if (completedCutFace) continue;
00290 
00291                 // Insert the next best point into the list
00292                 if (mp[bestAtanPoint] == cutFaceGlobalPoints[0])
00293                 {
00294                     // Face is completed.  Save it and move on to the next
00295                     // available edge
00296                     completedCutFace = true;
00297 
00298                     if (debug)
00299                     {
00300                         Pout<< " local: " << cutFaceLocalPoints
00301                             << " one side: " << faceI;
00302                     }
00303 
00304                     // Append the face
00305                     face cutFaceGlobal;
00306                     cutFaceGlobal.transfer(cutFaceGlobalPoints);
00307 
00308                     cf.append(cutFaceGlobal);
00309 
00310                     face cutFaceLocal;
00311                     cutFaceLocal.transfer(cutFaceLocalPoints);
00312 //                     Pout << "\ncutFaceLocal: " << cutFaceLocal.points(lp) << endl;
00313                     // Go through all edges of the cut faces.
00314                     // If the edge corresponds to a starting face edge,
00315                     // mark the starting face edge as true
00316 
00317                     forAll (cutFaceLocal, cutI)
00318                     {
00319                         const edge curCutFaceEdge
00320                         (
00321                             cutFaceLocal[cutI],
00322                             cutFaceLocal.nextLabel(cutI)
00323                         );
00324 
00325                         // Increment the usage count using two hash sets
00326                         HashSet<edge, Hash<edge> >::iterator euoIter =
00327                             edgesUsedOnce.find(curCutFaceEdge);
00328 
00329                         if (euoIter == edgesUsedOnce.end())
00330                         {
00331 //                             Pout << "Found edge not used before: "<< curCutFaceEdge << endl;
00332                             edgesUsedOnce.insert(curCutFaceEdge);
00333                         }
00334                         else
00335                         {
00336 //                             Pout << "Found edge used once: " << curCutFaceEdge << endl;
00337                             edgesUsedOnce.erase(euoIter);
00338                             edgesUsedTwice.insert(curCutFaceEdge);
00339                         }
00340 
00341                         const label curCutFaceEdgeWhich = curLocalFace.which(curCutFaceEdge.start());
00342 
00343                         if
00344                         (
00345                             curCutFaceEdgeWhich > -1
00346                          && curLocalFace.nextLabel(curCutFaceEdgeWhich) == curCutFaceEdge.end()
00347                         )
00348                         {
00349                             // Found edge in original face
00350 //                             Pout << "Found edge in orig face: " << curCutFaceEdge << ": " << curCutFaceEdgeWhich << endl;
00351                             usedFaceEdges[curCutFaceEdgeWhich] = true;
00352                         }
00353                         else
00354                         {
00355                             // Edge not in original face.  Add it to seeds
00356 //                             Pout << "Found new edge seed: " << curCutFaceEdge << endl;
00357                             edgeSeeds.append(curCutFaceEdge.reverseEdge());
00358                         }
00359                     }
00360 
00361 
00362                     // Find out what the other side is
00363 
00364                     // Algorithm
00365                     // If the face is in the slave half of the
00366                     // enrichedFaces lists, it may be matched against
00367                     // the master face.  It can be recognised by the
00368                     // fact that all its points belong to one master
00369                     // face.  For this purpose:
00370                     // 1) Grab the master faces around the point zero
00371                     // of the cut face and collect all master faces
00372                     // around it.
00373                     // 2) Loop through the rest of cut face points and
00374                     // if the point refers to one of the faces marked
00375                     // by point zero, increment its count.
00376                     // 3) When completed, the face whose count is
00377                     // equal to the number of points in the cut face
00378                     // is the other side.  If this is not the case, there is no
00379                     // face on the other side.
00380 
00381                     if (faceI < slavePatch_.size())
00382                     {
00383                         Map<labelList>::const_iterator mpfAddrIter =
00384                             masterPointFaceAddr.find(cutFaceGlobal[0]);
00385 
00386                         bool otherSideFound = false;
00387 
00388                         if (mpfAddrIter != masterPointFaceAddr.end())
00389                         {
00390                             bool miss = false;
00391 
00392                             // Create the label count using point zero
00393                             const labelList& masterFacesOfPZero = mpfAddrIter();
00394 
00395                             labelList hits(masterFacesOfPZero.size(), 1);
00396 
00397                             for
00398                             (
00399                                 label pointI = 1;
00400                                 pointI < cutFaceGlobal.size();
00401                                 pointI++
00402                             )
00403                             {
00404                                 Map<labelList>::const_iterator
00405                                     mpfAddrPointIter =
00406                                         masterPointFaceAddr.find
00407                                         (
00408                                             cutFaceGlobal[pointI]
00409                                         );
00410 
00411                                 if
00412                                 (
00413                                     mpfAddrPointIter
00414                                  == masterPointFaceAddr.end()
00415                                 )
00416                                 {
00417                                     // Point is off the master patch. Skip
00418                                     miss = true;
00419                                     break;
00420                                 }
00421 
00422                                 const labelList& curMasterFaces =
00423                                     mpfAddrPointIter();
00424 
00425                                 // For every current face, try to find it in the
00426                                 // zero-list
00427                                 forAll (curMasterFaces, i)
00428                                 {
00429                                     forAll (masterFacesOfPZero, j)
00430                                     {
00431                                         if
00432                                         (
00433                                             curMasterFaces[i]
00434                                          == masterFacesOfPZero[j]
00435                                         )
00436                                         {
00437                                             hits[j]++;
00438                                             break;
00439                                         }
00440                                     }
00441                                 }
00442                             }
00443 
00444                             // If all point are found attempt matching
00445                             if (!miss)
00446                             {
00447                                 forAll (hits, pointI)
00448                                 {
00449                                     if (hits[pointI] == cutFaceGlobal.size())
00450                                     {
00451                                         // Found other side.
00452                                         otherSideFound = true;
00453 
00454                                         cfMaster.append
00455                                         (
00456                                             masterFacesOfPZero[pointI]
00457                                         );
00458 
00459                                         cfSlave.append(faceI);
00460 
00461                                         // Reverse the face such that it
00462                                         // points out of the master patch
00463                                         cf[cf.size() - 1] =
00464                                             cf[cf.size() - 1].reverseFace();
00465 
00466                                         if (debug)
00467                                         {
00468                                             Pout<< " other side: "
00469                                                 << masterFacesOfPZero[pointI]
00470                                                 << endl;
00471                                         }
00472                                     } // end of hits
00473                                 } // end of for all hits
00474 
00475                             } // end of not miss
00476 
00477                             if (!otherSideFound || miss)
00478                             {
00479                                 if (debug)
00480                                 {
00481                                     Pout << " solo slave A" << endl;
00482                                 }
00483 
00484                                 cfMaster.append(-1);
00485                                 cfSlave.append(faceI);
00486                             }
00487                         }
00488                         else
00489                         {
00490                             // First point not in master patch
00491                             if (debug)
00492                             {
00493                                 Pout << " solo slave B" << endl;
00494                             }
00495 
00496                             cfMaster.append(-1);
00497                             cfSlave.append(faceI);
00498                         }
00499                     }
00500                     else
00501                     {
00502                         if (debug)
00503                         {
00504                             Pout << " master side" << endl;
00505                         }
00506 
00507                         cfMaster.append(faceI - slavePatch_.size());
00508                         cfSlave.append(-1);
00509                     }
00510                 }
00511                 else
00512                 {
00513                     // Face not completed.  Prepare for the next point search
00514                     prevPointLabel = curPointLabel;
00515                     curPointLabel = bestAtanPoint;
00516                     curPoint = lp[curPointLabel];
00517                     cutFaceGlobalPoints.append(mp[curPointLabel]);
00518                     cutFaceLocalPoints.append(curPointLabel);
00519 
00520                     if (debug || cutFaceGlobalPoints.size() > faceSizeDebug)
00521                     {
00522                         faceSizeDebug *= 2;
00523 
00524                         // Check for duplicate points in the face
00525                         forAll (cutFaceGlobalPoints, checkI)
00526                         {
00527                             for
00528                             (
00529                                 label checkJ = checkI + 1;
00530                                 checkJ < cutFaceGlobalPoints.size();
00531                                 checkJ++
00532                             )
00533                             {
00534                                 if
00535                                 (
00536                                     cutFaceGlobalPoints[checkI]
00537                                  == cutFaceGlobalPoints[checkJ]
00538                                 )
00539                                 {
00540                                     // Shrink local points for debugging
00541                                     cutFaceLocalPoints.shrink();
00542 
00543                                     face origFace;
00544                                     face origFaceLocal;
00545                                     if (faceI < slavePatch_.size())
00546                                     {
00547                                         origFace = slavePatch_[faceI];
00548                                         origFaceLocal =
00549                                             slavePatch_.localFaces()[faceI];
00550                                     }
00551                                     else
00552                                     {
00553                                         origFace =
00554                                             masterPatch_
00555                                             [faceI - slavePatch_.size()];
00556 
00557                                         origFaceLocal =
00558                                             masterPatch_.localFaces()
00559                                             [faceI - slavePatch_.size()];
00560                                     }
00561 
00562                                     FatalErrorIn
00563                                     (
00564                                         "void enrichedPatch::"
00565                                         "calcCutFaces() const"
00566                                     )   << "Duplicate point found in cut face. "
00567                                         << "Error in the face cutting "
00568                                         << "algorithm for global face "
00569                                         << origFace << " local face "
00570                                         << origFaceLocal << nl
00571                                         << "Slave size: " << slavePatch_.size()
00572                                         << " Master size: "
00573                                         << masterPatch_.size()
00574                                         << " index: " << faceI << ".\n"
00575                                         << "Face: " << curGlobalFace << nl
00576                                         << "Cut face: " << cutFaceGlobalPoints
00577                                         << " local: " << cutFaceLocalPoints
00578                                         << nl << "Points: "
00579                                         << face(cutFaceLocalPoints).points(lp)
00580                                         << abort(FatalError);
00581                                 }
00582                             }
00583                         }
00584                     } // end of debug
00585                 }
00586             } while (!completedCutFace);
00587         } // end of used edges
00588 
00589         if (debug)
00590         {
00591             Pout << " Finished face " << faceI << endl;
00592         }
00593 
00594     } // end of local faces
00595 
00596     // Re-pack the list into compact storage
00597     cutFacesPtr_ = new faceList();
00598     cutFacesPtr_->transfer(cf);
00599 
00600     cutFaceMasterPtr_ = new labelList();
00601     cutFaceMasterPtr_->transfer(cfMaster);
00602 
00603     cutFaceSlavePtr_ = new labelList();
00604     cutFaceSlavePtr_->transfer(cfSlave);
00605 }
00606 
00607 
00608 void Foam::enrichedPatch::clearCutFaces()
00609 {
00610     deleteDemandDrivenData(cutFacesPtr_);
00611     deleteDemandDrivenData(cutFaceMasterPtr_);
00612     deleteDemandDrivenData(cutFaceSlavePtr_);
00613 }
00614 
00615 
00616 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00617 
00618 const Foam::faceList& Foam::enrichedPatch::cutFaces() const
00619 {
00620     if (!cutFacesPtr_)
00621     {
00622         calcCutFaces();
00623     }
00624 
00625     return *cutFacesPtr_;
00626 }
00627 
00628 
00629 const Foam::labelList& Foam::enrichedPatch::cutFaceMaster() const
00630 {
00631     if (!cutFaceMasterPtr_)
00632     {
00633         calcCutFaces();
00634     }
00635 
00636     return *cutFaceMasterPtr_;
00637 }
00638 
00639 
00640 const Foam::labelList& Foam::enrichedPatch::cutFaceSlave() const
00641 {
00642     if (!cutFaceSlavePtr_)
00643     {
00644         calcCutFaces();
00645     }
00646 
00647     return *cutFaceSlavePtr_;
00648 }
00649 
00650 
00651 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines