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

primitiveMeshCheckMotion.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     Given a set of points, find out if the mesh resulting from point motion will
00026     be valid without actually changing the mesh.
00027 
00028 \*---------------------------------------------------------------------------*/
00029 
00030 #include <OpenFOAM/primitiveMesh.H>
00031 #include <OpenFOAM/pyramidPointFaceRef.H>
00032 #include <OpenFOAM/cell.H>
00033 #include <OpenFOAM/mathematicalConstants.H>
00034 
00035 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00036 
00037 
00038 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00039 
00040 bool Foam::primitiveMesh::checkMeshMotion
00041 (
00042     const pointField& newPoints,
00043     const bool report
00044 ) const
00045 {
00046     if (debug || report)
00047     {
00048         Pout<< "bool primitiveMesh::checkMeshMotion("
00049             << "const pointField& newPoints, const bool report) const: "
00050             << "checking mesh motion" << endl;
00051     }
00052 
00053     bool error = false;
00054 
00055     const faceList& f = faces();
00056 
00057     const labelList& own = faceOwner();
00058     const labelList& nei = faceNeighbour();
00059 
00060     vectorField fCtrs(nFaces());
00061     vectorField fAreas(nFaces());
00062 
00063     makeFaceCentresAndAreas(newPoints, fCtrs, fAreas);
00064 
00065     // Check cell volumes and calculate new cell centres
00066     vectorField cellCtrs(nCells());
00067     scalarField cellVols(nCells());
00068 
00069     makeCellCentresAndVols(fCtrs, fAreas, cellCtrs, cellVols);
00070 
00071     scalar minVolume = GREAT;
00072     label nNegVols = 0;
00073 
00074     forAll (cellVols, cellI)
00075     {
00076         if (cellVols[cellI] < VSMALL)
00077         {
00078             if (debug || report)
00079             {
00080                 Pout<< "Zero or negative cell volume detected for cell "
00081                     << cellI << ".  Volume = " << cellVols[cellI] << endl;
00082             }
00083 
00084             nNegVols++;
00085         }
00086 
00087         minVolume = min(minVolume, cellVols[cellI]);
00088     }
00089 
00090     if (nNegVols > 0)
00091     {
00092         error = true;
00093 
00094         Pout<< "Zero or negative cell volume in mesh motion in " << nNegVols
00095             << " cells.  Min volume: " << minVolume << endl;
00096     }
00097     else
00098     {
00099         if (debug || report)
00100         {
00101             Pout<< "Min volume = " << minVolume
00102                 << ".  Total volume = " << sum(cellVols)
00103                 << ".  Cell volumes OK." << endl;
00104         }
00105     }
00106 
00107     // Check face areas
00108 
00109     scalar minArea = GREAT;
00110     label nNegAreas = 0;
00111     label nPyrErrors = 0;
00112     label nDotProductErrors = 0;
00113 
00114     forAll (f, faceI)
00115     {
00116         const scalar a = Foam::mag(fAreas[faceI]);
00117 
00118         if (a < VSMALL)
00119         {
00120             if (debug || report)
00121             {
00122                 if (isInternalFace(faceI))
00123                 {
00124                     Pout<< "Zero or negative face area detected for "
00125                         << "internal face "<< faceI << " between cells "
00126                         << own[faceI] << " and " << nei[faceI]
00127                         << ".  Face area magnitude = " << a << endl;
00128                 }
00129                 else
00130                 {
00131                     Pout<< "Zero or negative face area detected for "
00132                         << "boundary face " << faceI << " next to cell "
00133                         << own[faceI] << ".  Face area magnitude = "
00134                         << a << endl;
00135                 }
00136             }
00137 
00138             nNegAreas++;
00139         }
00140 
00141         minArea = min(minArea, a);
00142 
00143         // Create the owner pyramid - it will have negative volume
00144         scalar pyrVol =
00145             pyramidPointFaceRef(f[faceI], cellCtrs[own[faceI]]).mag(newPoints);
00146 
00147         if (pyrVol > SMALL)
00148         {
00149             if (debug || report)
00150             {
00151                 Pout<< "Negative pyramid volume: " << -pyrVol
00152                     << " for face " << faceI << " " << f[faceI]
00153                     << "  and owner cell: " << own[faceI] << endl
00154                     << "Owner cell vertex labels: "
00155                     << cells()[own[faceI]].labels(f)
00156                     << endl;
00157             }
00158 
00159             nPyrErrors++;
00160         }
00161 
00162         if (isInternalFace(faceI))
00163         {
00164             // Create the neighbour pyramid - it will have positive volume
00165             scalar pyrVol =
00166                 pyramidPointFaceRef
00167                 (
00168                     f[faceI],
00169                     cellCtrs[nei[faceI]]
00170                 ).mag(newPoints);
00171 
00172             if (pyrVol < -SMALL)
00173             {
00174                 if (debug || report)
00175                 {
00176                     Pout<< "Negative pyramid volume: " << pyrVol
00177                         << " for face " << faceI << " " << f[faceI]
00178                         << "  and neighbour cell: " << nei[faceI] << nl
00179                         << "Neighbour cell vertex labels: "
00180                         << cells()[nei[faceI]].labels(f)
00181                         << endl;
00182                 }
00183 
00184                 nPyrErrors++;
00185             }
00186 
00187             const vector d = cellCtrs[nei[faceI]] - cellCtrs[own[faceI]];
00188             const vector& s = fAreas[faceI];
00189             scalar dDotS = (d & s)/(mag(d)*mag(s) + VSMALL);
00190 
00191             // Only write full message the first time
00192             if (dDotS < SMALL && nDotProductErrors == 0)
00193             {
00194                 // Non-orthogonality greater than 90 deg
00195                 WarningIn
00196                 (
00197                     "primitiveMesh::checkMeshMotion"
00198                     "(const pointField& newPoints, const bool report) const"
00199                 )   << "Severe non-orthogonality in mesh motion for face "
00200                     << faceI
00201                     << " between cells " << own[faceI] << " and " << nei[faceI]
00202                     << ": Angle = " << ::acos(dDotS)/mathematicalConstant::pi*180.0
00203                     << " deg." << endl;
00204 
00205                 nDotProductErrors++;
00206             }
00207         }
00208     }
00209 
00210     if (nNegAreas > 0)
00211     {
00212         error = true;
00213 
00214         WarningIn
00215         (
00216             "primitiveMesh::checkMeshMotion"
00217             "(const pointField& newPoints, const bool report) const"
00218         )   << "Zero or negative face area in mesh motion in " << nNegAreas
00219             << " faces.  Min area: " << minArea << endl;
00220     }
00221     else
00222     {
00223         if (debug || report)
00224         {
00225             Pout<< "Min area = " << minArea
00226                 << ".  Face areas OK." << endl;
00227         }
00228     }
00229 
00230     if (nPyrErrors > 0)
00231     {
00232         Pout<< "Detected " << nPyrErrors
00233             << " negative pyramid volume in mesh motion" << endl;
00234 
00235         error = true;
00236     }
00237     else
00238     {
00239         if (debug || report)
00240         {
00241             Pout<< "Pyramid volumes OK." << endl;
00242         }
00243     }
00244 
00245     if (nDotProductErrors > 0)
00246     {
00247         Pout<< "Detected " << nDotProductErrors
00248             << " in non-orthogonality in mesh motion." << endl;
00249 
00250         error = true;
00251     }
00252     else
00253     {
00254         if (debug || report)
00255         {
00256             Pout<< "Non-orthogonality check OK." << endl;
00257         }
00258     }
00259 
00260     if (!error && (debug || report))
00261     {
00262         Pout << "Mesh motion check OK." << endl;
00263     }
00264 
00265     return error;
00266 }
00267 
00268 
00269 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines