OpenFOAM中的pout与reduce
-
/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation \\/ M anipulation | ------------------------------------------------------------------------------- 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 <http://www.gnu.org/licenses/>. \*---------------------------------------------------------------------------*/ #include "fvCFD.H" int main(int argc, char *argv[]) { #include "setRootCase.H" #include "createTime.H" #include "createMesh.H" // For a case being run in parallel, the domain is decomposed into several // processor meshes. Each of them is run in a separate process and holds // instances of objects like mesh, U or p just as in a single-threaded (serial) // computation. These will have different sizes, of course, as they hold // fewer elements than the whole, undecomposed, mesh. // Pout is a stream to which each processor can write, unlike Info which only // gets used by the head process (processor0) Pout << "Hello from processor " << Pstream::myProcNo() << "! I am working on " << mesh.C().size() << " cells" << endl; // To exchange information between processes, special OpenMPI routines need // to be called. // This goes over each cell in the subdomain and integrates their volume. scalar meshVolume(0.); forAll(mesh.V(),cellI) meshVolume += mesh.V()[cellI]; // Add the values from all processes together Pout << "Mesh volume on this processor: " << meshVolume << endl; reduce(meshVolume, sumOp<scalar>()); Info << "Total mesh volume on all processors: " << meshVolume // Note how the reudction operation may be done in place without defning // a temporary variable, where appropriate. << " over " << returnReduce(mesh.C().size(), sumOp<label>()) << " cells" << endl; // During the reduction stage, different operations may be carried out, summation, // described by the sumOp template, being one of them. // Other very useful operations are minOp and maxOp. // Note how the type // of the variable must be added to make an instance of the template, here // this is done by adding <scalar> in front of the brackets. // Custom reduction operations are easy to implement but need fluency in // object-oriented programming in OpenFOAM, so we'll skip this for now. // Spreading a value across all processors is done using a scatter operation. Pstream::scatter(meshVolume); Pout << "Mesh volume on this processor is now " << meshVolume << endl; // It is often useful to check the distribution of something across all // processors. This may be done using a list, with each element of it // being written to by only one processor. List<label> nInternalFaces (Pstream::nProcs()), nBoundaries (Pstream::nProcs()); nInternalFaces[Pstream::myProcNo()] = mesh.Cf().size(); nBoundaries[Pstream::myProcNo()] = mesh.boundary().size(); // The list may then be gathered on the head node as Pstream::gatherList(nInternalFaces); Pstream::gatherList(nBoundaries); // Scattering a list is also possbile Pstream::scatterList(nInternalFaces); Pstream::scatterList(nBoundaries); // It can also be useful to do things on the head node only // (in this case this is meaningless since we are using Info, which already // checks this and executes on the head node). // Note how the gathered lists hold information for all processors now. if (Pstream::master()) { forAll(nInternalFaces,i) Info << "Processor " << i << " has " << nInternalFaces[i] << " internal faces and " << nBoundaries[i] << " boundary patches" << endl; } // As the mesh is decomposed, interfaces between processors are turned // into patches, meaning each subdomain sees a processor boundary as a // boundary condition. forAll(mesh.boundary(),patchI) Pout << "Patch " << patchI << " named " << mesh.boundary()[patchI].name() << endl; // When looking for processor patches, it is useful to check their type, // similarly to how one can check if a patch is of empty type forAll(mesh.boundary(),patchI) { const polyPatch& pp = mesh.boundaryMesh()[patchI]; if (isA<processorPolyPatch>(pp)) Pout << "Patch " << patchI << " named " << mesh.boundary()[patchI].name() << " is definitely a processor boundary!" << endl; } // --- // this is an example implementation of the code from tutoral 2 which // has been adjusted to run in parallel. Each difference is highlighted // as a NOTE. // It is conventional in OpenFOAM to move large parts of code to separate // .H files to make the code of the solver itself more readable. This is not // a standard C++ practice, as header files are normally associated with // declarations rather than definitions. // A very common include, apart from the setRootCase, createTime, and createMesh, // which are generic, is createFields, which is often unique for each solver. // Here we've moved all of the parts of the code dealing with setting up the fields // and transport constants into this include file. #include "createFields.H" // pre-calculate geometric information using field expressions rather than // cell-by-cell assignment. const dimensionedVector originVector("x0", dimLength, vector(0.05,0.05,0.005)); volScalarField r (mag(mesh.C()-originVector)); // NOTE: we need to get a global value; convert from dimensionedScalar to scalar const scalar rFarCell = returnReduce(max(r).value(), maxOp<scalar>()); scalar f (1.); Info<< "\nStarting time loop\n" << endl; while (runTime.loop()) { Info<< "Time = " << runTime.timeName() << nl << endl; // assign values to the field; // sin function expects a dimensionless argument, hence need to convert // current time using .value(). // r has dimensions of length, hence the small value being added to it // needs to match that. // Finally, the result has to match dimensions of pressure, which are // m^2 / s^-2/ p = Foam::sin(2.*constant::mathematical::pi*f*runTime.time().value()) / (r/rFarCell + dimensionedScalar("small", dimLength, 1e-12)) * dimensionedScalar("tmp", dimensionSet(0, 3, -2, 0, 0), 1.); // NOTE: this is needed to update the values on the processor boundaries. // If this is not done, the gradient operator will get confused around the // processor patches. p.correctBoundaryConditions(); // calculate velocity from gradient of pressure U = fvc::grad(p)*dimensionedScalar("tmp", dimTime, 1.); runTime.write(); } Info<< "End\n" << endl; return 0; } // ************************************************************************* //
2022年10月13日 12:36
1/1
2022年10月13日 12:36