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

shellSurfaces.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 <meshTools/searchableSurface.H>
00027 #include "shellSurfaces.H"
00028 #include <OpenFOAM/boundBox.H>
00029 #include <meshTools/triSurfaceMesh.H>
00030 #include <autoMesh/refinementSurfaces.H>
00031 #include <meshTools/searchableSurfaces.H>
00032 #include <meshTools/orientedSurface.H>
00033 #include <meshTools/pointIndexHit.H>
00034 
00035 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00036 
00037 
00038 namespace Foam
00039 {
00040 
00041 template<>
00042 const char*
00043 NamedEnum<shellSurfaces::refineMode, 3>::
00044 names[] =
00045 {
00046     "inside",
00047     "outside",
00048     "distance"
00049 };
00050 
00051 const NamedEnum<shellSurfaces::refineMode, 3> shellSurfaces::refineModeNames_;
00052 
00053 } // End namespace Foam
00054 
00055 
00056 
00057 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00058 
00059 void Foam::shellSurfaces::setAndCheckLevels
00060 (
00061     const label shellI,
00062     const List<Tuple2<scalar, label> >& distLevels
00063 )
00064 {
00065     if (modes_[shellI] != DISTANCE && distLevels.size() != 1)
00066     {
00067         FatalErrorIn
00068         (
00069             "shellSurfaces::shellSurfaces"
00070             "(const searchableSurfaces&, const dictionary&)"
00071         )   << "For refinement mode "
00072             << refineModeNames_[modes_[shellI]]
00073             << " specify only one distance+level."
00074             << " (its distance gets discarded)"
00075             << exit(FatalError);
00076     }
00077     // Extract information into separate distance and level
00078     distances_[shellI].setSize(distLevels.size());
00079     levels_[shellI].setSize(distLevels.size());
00080 
00081     forAll(distLevels, j)
00082     {
00083         distances_[shellI][j] = distLevels[j].first();
00084         levels_[shellI][j] = distLevels[j].second();
00085 
00086         // Check in incremental order
00087         if (j > 0)
00088         {
00089             if
00090             (
00091                 (distances_[shellI][j] <= distances_[shellI][j-1])
00092              || (levels_[shellI][j] > levels_[shellI][j-1])
00093             )
00094             {
00095                 FatalErrorIn
00096                 (
00097                     "shellSurfaces::shellSurfaces"
00098                     "(const searchableSurfaces&, const dictionary&)"
00099                 )   << "For refinement mode "
00100                     << refineModeNames_[modes_[shellI]]
00101                     << " : Refinement should be specified in order"
00102                     << " of increasing distance"
00103                     << " (and decreasing refinement level)." << endl
00104                     << "Distance:" << distances_[shellI][j]
00105                     << " refinementLevel:" << levels_[shellI][j]
00106                     << exit(FatalError);
00107             }
00108         }
00109     }
00110 
00111     const searchableSurface& shell = allGeometry_[shells_[shellI]];
00112 
00113     if (modes_[shellI] == DISTANCE)
00114     {
00115         Info<< "Refinement level according to distance to "
00116             << shell.name() << endl;
00117         forAll(levels_[shellI], j)
00118         {
00119             Info<< "    level " << levels_[shellI][j]
00120                 << " for all cells within " << distances_[shellI][j]
00121                 << " meter." << endl;
00122         }
00123     }
00124     else
00125     {
00126         if (!allGeometry_[shells_[shellI]].hasVolumeType())
00127         {
00128             FatalErrorIn
00129             (
00130                 "shellSurfaces::shellSurfaces"
00131                 "(const searchableSurfaces&"
00132                 ", const PtrList<dictionary>&)"
00133             )   << "Shell " << shell.name()
00134                 << " does not support testing for "
00135                 << refineModeNames_[modes_[shellI]] << endl
00136                 << "Probably it is not closed."
00137                 << exit(FatalError);
00138         }
00139 
00140         if (modes_[shellI] == INSIDE)
00141         {
00142             Info<< "Refinement level " << levels_[shellI][0]
00143                 << " for all cells inside " << shell.name() << endl;
00144         }
00145         else
00146         {
00147             Info<< "Refinement level " << levels_[shellI][0]
00148                 << " for all cells outside " << shell.name() << endl;
00149         }
00150     }
00151 }
00152 
00153 
00154 // Specifically orient triSurfaces using a calculated point outside.
00155 // Done since quite often triSurfaces not of consistent orientation which
00156 // is (currently) necessary for sideness calculation
00157 void Foam::shellSurfaces::orient()
00158 {
00159     // Determine outside point.
00160     boundBox overallBb = boundBox::invertedBox;
00161 
00162     bool hasSurface = false;
00163 
00164     forAll(shells_, shellI)
00165     {
00166         const searchableSurface& s = allGeometry_[shells_[shellI]];
00167 
00168         if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
00169         {
00170             const triSurfaceMesh& shell = refCast<const triSurfaceMesh>(s);
00171 
00172             if (shell.triSurface::size())
00173             {
00174                 const pointField& points = shell.points();
00175 
00176                 hasSurface = true;
00177 
00178                 boundBox shellBb(points[0], points[0]);
00179                 // Assume surface is compact!
00180                 for (label i = 0; i < points.size(); i++)
00181                 {
00182                     const point& pt = points[i];
00183                     shellBb.min() = min(shellBb.min(), pt);
00184                     shellBb.max() = max(shellBb.max(), pt);
00185                 }
00186 
00187                 overallBb.min() = min(overallBb.min(), shellBb.min());
00188                 overallBb.max() = max(overallBb.max(), shellBb.max());
00189             }
00190         }
00191     }
00192 
00193     if (hasSurface)
00194     {
00195         const point outsidePt = overallBb.max() + overallBb.span();
00196 
00197         //Info<< "Using point " << outsidePt << " to orient shells" << endl;
00198 
00199         forAll(shells_, shellI)
00200         {
00201             const searchableSurface& s = allGeometry_[shells_[shellI]];
00202 
00203             if (modes_[shellI] != DISTANCE && isA<triSurfaceMesh>(s))
00204             {
00205                 triSurfaceMesh& shell = const_cast<triSurfaceMesh&>
00206                 (
00207                     refCast<const triSurfaceMesh>(s)
00208                 );
00209 
00210                 // Flip surface so outsidePt is outside.
00211                 bool anyFlipped = orientedSurface::orient
00212                 (
00213                     shell,
00214                     outsidePt,
00215                     true
00216                 );
00217 
00218                 if (anyFlipped)
00219                 {
00220                     // orientedSurface will have done a clearOut of the surface.
00221                     // we could do a clearout of the triSurfaceMeshes::trees()
00222                     // but these aren't affected by orientation
00223                     // (except for cached
00224                     // sideness which should not be set at this point.
00225                     // !!Should check!)
00226 
00227                     Info<< "shellSurfaces : Flipped orientation of surface "
00228                         << s.name()
00229                         << " so point " << outsidePt << " is outside." << endl;
00230                 }
00231             }
00232         }
00233     }
00234 }
00235 
00236 
00237 // Find maximum level of a shell.
00238 void Foam::shellSurfaces::findHigherLevel
00239 (
00240     const pointField& pt,
00241     const label shellI,
00242     labelList& maxLevel
00243 ) const
00244 {
00245     const labelList& levels = levels_[shellI];
00246 
00247     if (modes_[shellI] == DISTANCE)
00248     {
00249         // Distance mode.
00250 
00251         const scalarField& distances = distances_[shellI];
00252 
00253         // Collect all those points that have a current maxLevel less than
00254         // (any of) the shell. Also collect the furthest distance allowable
00255         // to any shell with a higher level.
00256 
00257         pointField candidates(pt.size());
00258         labelList candidateMap(pt.size());
00259         scalarField candidateDistSqr(pt.size());
00260         label candidateI = 0;
00261 
00262         forAll(maxLevel, pointI)
00263         {
00264             forAllReverse(levels, levelI)
00265             {
00266                 if (levels[levelI] > maxLevel[pointI])
00267                 {
00268                     candidates[candidateI] = pt[pointI];
00269                     candidateMap[candidateI] = pointI;
00270                     candidateDistSqr[candidateI] = sqr(distances[levelI]);
00271                     candidateI++;
00272                     break;
00273                 }
00274             }
00275         }
00276         candidates.setSize(candidateI);
00277         candidateMap.setSize(candidateI);
00278         candidateDistSqr.setSize(candidateI);
00279 
00280         // Do the expensive nearest test only for the candidate points.
00281         List<pointIndexHit> nearInfo;
00282         allGeometry_[shells_[shellI]].findNearest
00283         (
00284             candidates,
00285             candidateDistSqr,
00286             nearInfo
00287         );
00288 
00289         // Update maxLevel
00290         forAll(nearInfo, candidateI)
00291         {
00292             if (nearInfo[candidateI].hit())
00293             {
00294                 // Check which level it actually is in.
00295                 label minDistI = findLower
00296                 (
00297                     distances,
00298                     mag(nearInfo[candidateI].hitPoint()-candidates[candidateI])
00299                 );
00300 
00301                 label pointI = candidateMap[candidateI];
00302 
00303                 // pt is inbetween shell[minDistI] and shell[minDistI+1]
00304                 maxLevel[pointI] = levels[minDistI+1];
00305             }
00306         }
00307     }
00308     else
00309     {
00310         // Inside/outside mode
00311 
00312         // Collect all those points that have a current maxLevel less than the
00313         // shell.
00314 
00315         pointField candidates(pt.size());
00316         labelList candidateMap(pt.size());
00317         label candidateI = 0;
00318 
00319         forAll(maxLevel, pointI)
00320         {
00321             if (levels[0] > maxLevel[pointI])
00322             {
00323                 candidates[candidateI] = pt[pointI];
00324                 candidateMap[candidateI] = pointI;
00325                 candidateI++;
00326             }
00327         }
00328         candidates.setSize(candidateI);
00329         candidateMap.setSize(candidateI);
00330 
00331         // Do the expensive nearest test only for the candidate points.
00332         List<searchableSurface::volumeType> volType;
00333         allGeometry_[shells_[shellI]].getVolumeType(candidates, volType);
00334 
00335         forAll(volType, i)
00336         {
00337             label pointI = candidateMap[i];
00338 
00339             if
00340             (
00341                 (
00342                     modes_[shellI] == INSIDE
00343                  && volType[i] == searchableSurface::INSIDE
00344                 )
00345              || (
00346                     modes_[shellI] == OUTSIDE
00347                  && volType[i] == searchableSurface::OUTSIDE
00348                 )
00349             )
00350             {
00351                 maxLevel[pointI] = levels[0];
00352             }
00353         }
00354     }
00355 }
00356 
00357 
00358 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00359 
00360 Foam::shellSurfaces::shellSurfaces
00361 (
00362     const searchableSurfaces& allGeometry,
00363     const PtrList<dictionary>& shellDicts
00364 )
00365 :
00366     allGeometry_(allGeometry)
00367 {
00368     shells_.setSize(shellDicts.size());
00369     modes_.setSize(shellDicts.size());
00370     distances_.setSize(shellDicts.size());
00371     levels_.setSize(shellDicts.size());
00372 
00373     forAll(shellDicts, shellI)
00374     {
00375         const dictionary& dict = shellDicts[shellI];
00376         const word name = dict.lookup("name");
00377         const word type = dict.lookup("type");
00378 
00379         shells_[shellI] = allGeometry_.findSurfaceID(name);
00380 
00381         if (shells_[shellI] == -1)
00382         {
00383             FatalErrorIn
00384             (
00385                 "shellSurfaces::shellSurfaces"
00386                 "(const searchableSurfaces&, const PtrList<dictionary>&)"
00387             )   << "No surface called " << name << endl
00388                 << "Valid surfaces are " << allGeometry_.names()
00389                 << exit(FatalError);
00390         }
00391 
00392         modes_[shellI] = refineModeNames_.read(dict.lookup("refineMode"));
00393 
00394         // Read pairs of distance+level
00395         setAndCheckLevels(shellI, dict.lookup("levels"));
00396     }
00397 
00398     // Orient shell surfaces before any searching is done. Note that this
00399     // only needs to be done for inside or outside. Orienting surfaces
00400     // constructs lots of addressing which we want to avoid.
00401     orient();
00402 }
00403 
00404 
00405 Foam::shellSurfaces::shellSurfaces
00406 (
00407     const searchableSurfaces& allGeometry,
00408     const dictionary& shellsDict
00409 )
00410 :
00411     allGeometry_(allGeometry)
00412 {
00413     shells_.setSize(shellsDict.size());
00414     modes_.setSize(shellsDict.size());
00415     distances_.setSize(shellsDict.size());
00416     levels_.setSize(shellsDict.size());
00417 
00418     label shellI = 0;
00419     forAllConstIter(dictionary, shellsDict, iter)
00420     {
00421         shells_[shellI] = allGeometry_.findSurfaceID(iter().keyword());
00422 
00423         if (shells_[shellI] == -1)
00424         {
00425             FatalErrorIn
00426             (
00427                 "shellSurfaces::shellSurfaces"
00428                 "(const searchableSurfaces&, const dictionary>&"
00429             )   << "No surface called " << iter().keyword() << endl
00430                 << "Valid surfaces are " << allGeometry_.names()
00431                 << exit(FatalError);
00432         }
00433         const dictionary& dict = shellsDict.subDict(iter().keyword());
00434 
00435         modes_[shellI] = refineModeNames_.read(dict.lookup("mode"));
00436 
00437         // Read pairs of distance+level
00438         setAndCheckLevels(shellI, dict.lookup("levels"));
00439 
00440         shellI++;
00441     }
00442 
00443     // Orient shell surfaces before any searching is done. Note that this
00444     // only needs to be done for inside or outside. Orienting surfaces
00445     // constructs lots of addressing which we want to avoid.
00446     orient();
00447 }
00448 
00449 
00450 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00451 
00452 // Highest shell level
00453 Foam::label Foam::shellSurfaces::maxLevel() const
00454 {
00455     label overallMax = 0;
00456     forAll(levels_, shellI)
00457     {
00458         overallMax = max(overallMax, max(levels_[shellI]));
00459     }
00460     return overallMax;
00461 }
00462 
00463 
00464 void Foam::shellSurfaces::findHigherLevel
00465 (
00466     const pointField& pt,
00467     const labelList& ptLevel,
00468     labelList& maxLevel
00469 ) const
00470 {
00471     // Maximum level of any shell. Start off with level of point.
00472     maxLevel = ptLevel;
00473 
00474     forAll(shells_, shellI)
00475     {
00476         findHigherLevel(pt, shellI, maxLevel);
00477     }
00478 }
00479 
00480 
00481 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines