/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2018 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . Application createBoxTurb Description Create a box of isotropic turbulence based on a user-specified energy spectrum. Based on the reference \verbatim Saad, T., Cline, D., Stoll, R., Sutherland, J.C. "Scalable Tools for Generating Synthetic Isotropic Turbulence with Arbitrary Spectra" AIAA Journal, Vol. 55, No. 1 (2017), pp. 327-331. \endverbatim The \c -createBlockMesh option creates a block mesh and exits, which can then be decomposed and the utility run in parallel. \*---------------------------------------------------------------------------*/ #include "fvCFD.H" #include "block.H" #include "mathematicalConstants.H" using namespace Foam::constant; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // Foam::vector randomUnitVector(Random& rndGen) { // Sample point on a sphere scalar t = rndGen.globalPosition(-1, 1); scalar phim = rndGen.globalSample01()*mathematical::twoPi; scalar thetam = Foam::acos(t); return vector ( Foam::sin(thetam*Foam::cos(phim)), Foam::sin(thetam*Foam::sin(phim)), Foam::cos(thetam) ); } int main(int argc, char *argv[]) { argList::addNote ( "Create a box of isotropic turbulence based on a user-specified" " energy spectrum." ); argList::addBoolOption ( "createBlockMesh", "create the block mesh and exit" ); #include "setRootCase.H" #include "createTime.H" #include "createFields.H" if (args.found("createBlockMesh")) { // Create a box block mesh with cyclic patches #include "createBlockMesh.H" Info<< "\nEnd\n" << endl; return 0; } #include "createMesh.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Minimum wave number scalar kappa0 = mathematical::twoPi/cmptMin(L); // Maximum wave number scalar kappaMax = mathematical::pi/cmptMin(delta); Info<< "Wave number min/max = " << kappa0 << ", " << kappaMax << endl; Info<< "Generating velocity field" << endl; volVectorField U ( IOobject ( "U", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::NO_WRITE ), mesh, dimensionedVector(dimVelocity, Zero) ); vectorField& Uc = U.primitiveFieldRef(); const scalar deltaKappa = (kappaMax - kappa0)/scalar(nModes - 1); const vectorField& C(mesh.C()); for (label modei = 1; modei <= nModes; ++modei) { // Equidistant wave mode scalar kappaM = kappa0 + deltaKappa*(modei-1); Info<< "Processing mode:" << modei << " kappaM:" << kappaM << endl; // Energy scalar E = Ek->value(kappaM); // Wave amplitude scalar qm = Foam::sqrt(E*deltaKappa); // Wave number unit vector const vector kappaHatm(randomUnitVector(rndGen)); vector kappaTildem(0.5*kappaM*cmptMultiply(kappaHatm, delta)); for (direction i = 0; i < 3; ++i) { kappaTildem[i] = 2/delta[i]*Foam::sin(kappaTildem[i]); } // Intermediate unit vector zeta const vector zetaHatm(randomUnitVector(rndGen)); // Unit vector sigma vector sigmaHatm(zetaHatm^kappaTildem); sigmaHatm /= mag(kappaTildem); // Phase angle scalar psim = 0.5*rndGen.position(-mathematical::pi, mathematical::pi); // Add the velocity contribution per mode Uc += 2*qm*cos(kappaM*(kappaHatm & C) + psim)*sigmaHatm; } U.write(); { Info<< "Generating kinetic energy field" << endl; volScalarField k("k", 0.5*magSqr(U)); k.write(); Info<< "min/max/average k = " << gMin(k) << ", " << gMax(k) << ", " << gAverage(k) << endl; } { Info<< "Generating div(U) field" << endl; volScalarField divU(fvc::div(U)); divU.write(); Info<< "min/max/average div(U) = " << gMin(divU) << ", " << gMax(divU) << ", " << gAverage(divU) << endl; } Info<< nl; runTime.printExecutionTime(Info); Info<< "End\n" << endl; return 0; } // ************************************************************************* //