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

forces.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 "forces.H"
00027 #include <finiteVolume/volFields.H>
00028 #include <OpenFOAM/dictionary.H>
00029 #include <OpenFOAM/Time.H>
00030 
00031 #include <incompressibleTransportModels/singlePhaseTransportModel.H>
00032 #include <incompressibleRASModels/RASModel.H>
00033 #include <incompressibleLESModels/LESModel.H>
00034 
00035 #include <basicThermophysicalModels/basicThermo.H>
00036 #include <compressibleRASModels/RASModel.H>
00037 #include <compressibleLESModels/LESModel.H>
00038 
00039 
00040 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
00041 
00042 namespace Foam
00043 {
00044     defineTypeNameAndDebug(forces, 0);
00045 }
00046 
00047 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
00048 
00049 Foam::tmp<Foam::volSymmTensorField> Foam::forces::devRhoReff() const
00050 {
00051     if (obr_.foundObject<compressible::RASModel>("RASProperties"))
00052     {
00053         const compressible::RASModel& ras
00054             = obr_.lookupObject<compressible::RASModel>("RASProperties");
00055 
00056         return ras.devRhoReff();
00057     }
00058     else if (obr_.foundObject<incompressible::RASModel>("RASProperties"))
00059     {
00060         const incompressible::RASModel& ras
00061             = obr_.lookupObject<incompressible::RASModel>("RASProperties");
00062 
00063         return rho()*ras.devReff();
00064     }
00065     else if (obr_.foundObject<compressible::LESModel>("LESProperties"))
00066     {
00067         const compressible::LESModel& les =
00068         obr_.lookupObject<compressible::LESModel>("LESProperties");
00069 
00070         return les.devRhoBeff();
00071     }
00072     else if (obr_.foundObject<incompressible::LESModel>("LESProperties"))
00073     {
00074         const incompressible::LESModel& les
00075             = obr_.lookupObject<incompressible::LESModel>("LESProperties");
00076 
00077         return rho()*les.devBeff();
00078     }
00079     else if (obr_.foundObject<basicThermo>("thermophysicalProperties"))
00080     {
00081         const basicThermo& thermo =
00082              obr_.lookupObject<basicThermo>("thermophysicalProperties");
00083 
00084         const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
00085 
00086         return -thermo.mu()*dev(twoSymm(fvc::grad(U)));
00087     }
00088     else if
00089     (
00090         obr_.foundObject<singlePhaseTransportModel>("transportProperties")
00091     )
00092     {
00093         const singlePhaseTransportModel& laminarT =
00094             obr_.lookupObject<singlePhaseTransportModel>
00095             ("transportProperties");
00096 
00097         const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
00098 
00099         return -rho()*laminarT.nu()*dev(twoSymm(fvc::grad(U)));
00100     }
00101     else if (obr_.foundObject<dictionary>("transportProperties"))
00102     {
00103         const dictionary& transportProperties =
00104              obr_.lookupObject<dictionary>("transportProperties");
00105 
00106         dimensionedScalar nu(transportProperties.lookup("nu"));
00107 
00108         const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
00109 
00110         return -rho()*nu*dev(twoSymm(fvc::grad(U)));
00111     }
00112     else
00113     {
00114         FatalErrorIn("forces::devRhoReff()")
00115             << "No valid model for viscous stress calculation."
00116             << exit(FatalError);
00117 
00118         return volSymmTensorField::null();
00119     }
00120 }
00121 
00122 
00123 Foam::tmp<Foam::volScalarField> Foam::forces::rho() const
00124 {
00125     if (rhoName_ == "rhoInf")
00126     {
00127         const fvMesh& mesh = refCast<const fvMesh>(obr_);
00128 
00129         return tmp<volScalarField>
00130         (
00131             new volScalarField
00132             (
00133                 IOobject
00134                 (
00135                     "rho",
00136                     mesh.time().timeName(),
00137                     mesh
00138                 ),
00139                 mesh,
00140                 dimensionedScalar("rho", dimDensity, rhoRef_)
00141             )
00142         );
00143     }
00144     else
00145     {
00146         return(obr_.lookupObject<volScalarField>(rhoName_));
00147     }
00148 }
00149 
00150 
00151 Foam::scalar Foam::forces::rho(const volScalarField& p) const
00152 {
00153     if (p.dimensions() == dimPressure)
00154     {
00155         return 1.0;
00156     }
00157     else
00158     {
00159         if (rhoName_ != "rhoInf")
00160         {
00161             FatalErrorIn("forces::rho(const volScalarField& p)")
00162                 << "Dynamic pressure is expected but kinematic is provided."
00163                 << exit(FatalError);
00164         }
00165 
00166         return rhoRef_;
00167     }
00168 }
00169 
00170 
00171 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
00172 
00173 Foam::forces::forces
00174 (
00175     const word& name,
00176     const objectRegistry& obr,
00177     const dictionary& dict,
00178     const bool loadFromFiles
00179 )
00180 :
00181     name_(name),
00182     obr_(obr),
00183     active_(true),
00184     log_(false),
00185     patchSet_(),
00186     pName_(word::null),
00187     UName_(word::null),
00188     rhoName_(word::null),
00189     directForceDensity_(false),
00190     fDName_(""),
00191     rhoRef_(VGREAT),
00192     pRef_(0),
00193     CofR_(vector::zero),
00194     forcesFilePtr_(NULL)
00195 {
00196     // Check if the available mesh is an fvMesh otherise deactivate
00197     if (!isA<fvMesh>(obr_))
00198     {
00199         active_ = false;
00200         WarningIn
00201         (
00202             "Foam::forces::forces"
00203             "("
00204                 "const word&, "
00205                 "const objectRegistry&, "
00206                 "const dictionary&, "
00207                 "const bool"
00208             ")"
00209         )   << "No fvMesh available, deactivating."
00210             << endl;
00211     }
00212 
00213     read(dict);
00214 }
00215 
00216 
00217 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
00218 
00219 Foam::forces::~forces()
00220 {}
00221 
00222 
00223 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
00224 
00225 void Foam::forces::read(const dictionary& dict)
00226 {
00227     if (active_)
00228     {
00229         log_ = dict.lookupOrDefault<Switch>("log", false);
00230 
00231         const fvMesh& mesh = refCast<const fvMesh>(obr_);
00232 
00233         patchSet_ =
00234             mesh.boundaryMesh().patchSet(wordList(dict.lookup("patches")));
00235 
00236         dict.readIfPresent("directForceDensity", directForceDensity_);
00237 
00238         if (directForceDensity_)
00239         {
00240             // Optional entry for fDName
00241             fDName_ = dict.lookupOrDefault<word>("fDName", "fD");
00242 
00243             // Check whether fDName exists, if not deactivate forces
00244             if
00245             (
00246                 !obr_.foundObject<volVectorField>(fDName_)
00247             )
00248             {
00249                 active_ = false;
00250                 WarningIn("void forces::read(const dictionary& dict)")
00251                 << "Could not find " << fDName_ << " in database." << nl
00252                     << "    De-activating forces."
00253                     << endl;
00254             }
00255         }
00256         else
00257         {
00258             // Optional entries U and p
00259             pName_ = dict.lookupOrDefault<word>("pName", "p");
00260             UName_ = dict.lookupOrDefault<word>("UName", "U");
00261             rhoName_ = dict.lookupOrDefault<word>("rhoName", "rho");
00262 
00263             // Check whether UName, pName and rhoName exists,
00264             // if not deactivate forces
00265             if
00266             (
00267                 !obr_.foundObject<volVectorField>(UName_)
00268              || !obr_.foundObject<volScalarField>(pName_)
00269              || (
00270                     rhoName_ != "rhoInf"
00271                  && !obr_.foundObject<volScalarField>(rhoName_)
00272                 )
00273             )
00274             {
00275                 active_ = false;
00276 
00277                 WarningIn("void forces::read(const dictionary& dict)")
00278                     << "Could not find " << UName_ << ", " << pName_;
00279 
00280                 if (rhoName_ != "rhoInf")
00281                 {
00282                     Info<< " or " << rhoName_;
00283                 }
00284 
00285                 Info<< " in database." << nl << "    De-activating forces."
00286                     << endl;
00287             }
00288 
00289             // Reference density needed for incompressible calculations
00290             rhoRef_ = readScalar(dict.lookup("rhoInf"));
00291 
00292             // Reference pressure, 0 by default
00293             pRef_ = dict.lookupOrDefault<scalar>("pRef", 0.0);
00294         }
00295 
00296         // Centre of rotation for moment calculations
00297         CofR_ = dict.lookup("CofR");
00298     }
00299 }
00300 
00301 
00302 void Foam::forces::makeFile()
00303 {
00304     // Create the forces file if not already created
00305     if (forcesFilePtr_.empty())
00306     {
00307         if (debug)
00308         {
00309             Info<< "Creating forces file." << endl;
00310         }
00311 
00312         // File update
00313         if (Pstream::master())
00314         {
00315             fileName forcesDir;
00316             word startTimeName =
00317                 obr_.time().timeName(obr_.time().startTime().value());
00318 
00319             if (Pstream::parRun())
00320             {
00321                 // Put in undecomposed case (Note: gives problems for
00322                 // distributed data running)
00323                 forcesDir = obr_.time().path()/".."/name_/startTimeName;
00324             }
00325             else
00326             {
00327                 forcesDir = obr_.time().path()/name_/startTimeName;
00328             }
00329 
00330             // Create directory if does not exist.
00331             mkDir(forcesDir);
00332 
00333             // Open new file at start up
00334             forcesFilePtr_.reset(new OFstream(forcesDir/(type() + ".dat")));
00335 
00336             // Add headers to output data
00337             writeFileHeader();
00338         }
00339     }
00340 }
00341 
00342 
00343 void Foam::forces::writeFileHeader()
00344 {
00345     if (forcesFilePtr_.valid())
00346     {
00347         forcesFilePtr_()
00348             << "# Time" << tab
00349             << "forces(pressure, viscous) moment(pressure, viscous)"
00350             << endl;
00351     }
00352 }
00353 
00354 
00355 void Foam::forces::execute()
00356 {
00357     // Do nothing - only valid on write
00358 }
00359 
00360 
00361 void Foam::forces::end()
00362 {
00363     // Do nothing - only valid on write
00364 }
00365 
00366 
00367 void Foam::forces::write()
00368 {
00369     if (active_)
00370     {
00371         // Create the forces file if not already created
00372         makeFile();
00373 
00374         forcesMoments fm = calcForcesMoment();
00375 
00376         if (Pstream::master())
00377         {
00378             forcesFilePtr_() << obr_.time().value() << tab << fm << endl;
00379 
00380             if (log_)
00381             {
00382                 Info<< "forces output:" << nl
00383                     << "    forces(pressure, viscous)" << fm.first() << nl
00384                     << "    moment(pressure, viscous)" << fm.second() << nl
00385                     << endl;
00386             }
00387         }
00388     }
00389 }
00390 
00391 
00392 Foam::forces::forcesMoments Foam::forces::calcForcesMoment() const
00393 {
00394     forcesMoments fm
00395     (
00396         pressureViscous(vector::zero, vector::zero),
00397         pressureViscous(vector::zero, vector::zero)
00398     );
00399 
00400     if (directForceDensity_)
00401     {
00402         const volVectorField& fD = obr_.lookupObject<volVectorField>(fDName_);
00403 
00404         const fvMesh& mesh = fD.mesh();
00405 
00406         const surfaceVectorField::GeometricBoundaryField& Sfb =
00407             mesh.Sf().boundaryField();
00408 
00409         forAllConstIter(labelHashSet, patchSet_, iter)
00410         {
00411             label patchi = iter.key();
00412 
00413             vectorField Md = mesh.C().boundaryField()[patchi] - CofR_;
00414 
00415             scalarField sA = mag(Sfb[patchi]);
00416 
00417             // Normal force = surfaceUnitNormal * (surfaceNormal & forceDensity)
00418             vectorField fN =
00419                 Sfb[patchi]/sA
00420                *(
00421                     Sfb[patchi] & fD.boundaryField()[patchi]
00422                 );
00423 
00424             fm.first().first() += sum(fN);
00425             fm.second().first() += sum(Md ^ fN);
00426 
00427             // Tangential force (total force minus normal fN)
00428             vectorField fT = sA*fD.boundaryField()[patchi] - fN;
00429 
00430             fm.first().second() += sum(fT);
00431             fm.second().second() += sum(Md ^ fT);
00432         }
00433     }
00434     else
00435     {
00436         const volVectorField& U = obr_.lookupObject<volVectorField>(UName_);
00437         const volScalarField& p = obr_.lookupObject<volScalarField>(pName_);
00438 
00439         const fvMesh& mesh = U.mesh();
00440 
00441         const surfaceVectorField::GeometricBoundaryField& Sfb =
00442             mesh.Sf().boundaryField();
00443 
00444         tmp<volSymmTensorField> tdevRhoReff = devRhoReff();
00445         const volSymmTensorField::GeometricBoundaryField& devRhoReffb
00446             = tdevRhoReff().boundaryField();
00447 
00448         // Scale pRef by density for incompressible simulations
00449         scalar pRef = pRef_/rho(p);
00450 
00451         forAllConstIter(labelHashSet, patchSet_, iter)
00452         {
00453             label patchi = iter.key();
00454 
00455             vectorField Md = mesh.C().boundaryField()[patchi] - CofR_;
00456 
00457             vectorField pf = Sfb[patchi]*(p.boundaryField()[patchi] - pRef);
00458 
00459             fm.first().first() += rho(p)*sum(pf);
00460             fm.second().first() += rho(p)*sum(Md ^ pf);
00461 
00462             vectorField vf = Sfb[patchi] & devRhoReffb[patchi];
00463 
00464             fm.first().second() += sum(vf);
00465             fm.second().second() += sum(Md ^ vf);
00466         }
00467     }
00468 
00469     reduce(fm, sumOp());
00470 
00471     return fm;
00472 }
00473 
00474 
00475 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines