/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 1991-2007 OpenCFD Ltd. \\/ 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \*---------------------------------------------------------------------------*/ #include "argList.H" #include "OSspecific.H" #include "meshSearch.H" #include "interpolation.H" #include "volPointInterpolation.H" #include "cuttingPlane.H" #include "OFstream.H" #include "Pstream.H" #include "ListListOps.H" #include "Cloud.H" #include "passiveParticle.H" #include "mergePoints.H" #include "fieldsCache.H" #include "surface.H" #include "surfaceWriter.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Used to offset faces in Pstream::combineOffset namespace Foam { template <> class offsetOp { public: face operator() ( const face& x, const label offset ) const { face result(x.size()); forAll(x, xI) { result[xI] = x[xI] + offset; } return result; } }; } void mergePoints ( const polyMesh& mesh, const scalar mergeTol, List& allPoints, List& allFaces, labelListList& allOldToNew ) { const boundBox& bb = mesh.globalData().bb(); scalar mergeDim = mergeTol * mag(bb.max() - bb.min()); Info<< nl << "Merging all points within " << mergeDim << " meter." << endl; allOldToNew.setSize(allPoints.size()); forAll(allPoints, surfaceI) { pointField newPoints; labelList oldToNew; bool hasMerged = mergePoints ( allPoints[surfaceI], mergeDim, false, // verbosity oldToNew, newPoints ); if (hasMerged) { // Copy points allPoints[surfaceI].transfer(newPoints); // Store point mapping allOldToNew[surfaceI].transfer(oldToNew); // Relabel faces. faceList& faces = allFaces[surfaceI]; forAll(faces, faceI) { inplaceRenumber(allOldToNew[surfaceI], faces[faceI]); } Info<< "For surface " << surfaceI << " merged from " << allOldToNew[surfaceI].size() << " points down to " << allPoints[surfaceI].size() << " points." << endl; } } } template void renumberData ( const labelList& oldToNewPoints, const label newSize, Field& values ) { if (oldToNewPoints.size() == values.size()) { inplaceReorder(oldToNewPoints, values); values.setSize(newSize); } } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Main program: int main(int argc, char *argv[]) { # include "addTimeOptions.H" # include "setRootCase.H" # include "createTime.H" // Get times list instantList Times = runTime.times(); // set startTime and endTime depending on -time and -latestTime options # include "checkTimeOptions.H" runTime.setTime(Times[startTime], startTime); # include "createMesh.H" // // Hack: initialize Cloud to initialize the processor table so from // now on we can use cloud (in meshSearch) on single processors only. // Cloud dummyCloud(mesh, IDLList()); // // Read control dictionary // IOdictionary sampleDict ( IOobject ( "sampleSurfaceDict", runTime.system(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE ) ); const word interpolationScheme(sampleDict.lookup("interpolationScheme")); const wordList fieldNames = sampleDict.lookup("fields"); // // Construct writers // word writeFormat(sampleDict.lookup("surfaceFormat")); autoPtr > scalarFormatter ( surfaceWriter::New(writeFormat) ); autoPtr > vectorFormatter ( surfaceWriter::New(writeFormat) ); autoPtr > sphericalTensorFormatter ( surfaceWriter::New(writeFormat) ); autoPtr > symmTensorFormatter ( surfaceWriter::New(writeFormat) ); autoPtr > tensorFormatter ( surfaceWriter::New(writeFormat) ); // // Construct interpolation dictionary (same interpolation for all fields) // dictionary interpolationSchemes; forAll(fieldNames, fieldI) { interpolationSchemes.add ( fieldNames[fieldI], interpolationScheme ); } fileName samplePath; if (Pstream::parRun()) { samplePath = runTime.path()/".."/"sampleSurfaces"; } else { samplePath = runTime.path()/"sampleSurfaces"; } if (Pstream::master() && exists(samplePath)) { Info<< "Deleting sampleSurfaces/ directory" << endl << endl; rmDir(samplePath); } // Set up interpolation autoPtr pMeshPtr(new pointMesh(mesh)); autoPtr pInterpPtr ( new volPointInterpolation(mesh, pMeshPtr()) ); // Set up mesh searching meshSearch searchEngine(mesh, true); // Create sample surfaces PtrList surfaces ( sampleDict.lookup("surfaces"), surface::iNew(mesh, searchEngine) ); Info<< endl; fileName oldPointsDir("constant"); for (label i=startTime; i scalarCache; fieldsCache vectorCache; fieldsCache sphericalTensorCache; fieldsCache symmTensorCache; fieldsCache tensorCache; forAll(fieldNames, fieldI) { const word& fieldName = fieldNames[fieldI]; IOobject fieldHeader ( fieldName, runTime.timeName(), mesh, IOobject::MUST_READ ); if (fieldHeader.headerOk()) { if ( fieldHeader.headerClassName() == volScalarField::typeName ) { Info<< "Loading " << fieldHeader.headerClassName() << ' ' << fieldName << endl; volScalarField* fieldPtr ( new volScalarField ( fieldHeader, mesh ) ); scalarCache.insert(fieldName, fieldPtr); } else if ( fieldHeader.headerClassName() == volVectorField::typeName ) { Info<< "Loading " << fieldHeader.headerClassName() << ' ' << fieldName << endl; volVectorField* fieldPtr ( new volVectorField ( fieldHeader, mesh ) ); vectorCache.insert(fieldName, fieldPtr); } else if ( fieldHeader.headerClassName() == volSphericalTensorField::typeName ) { Info<< "Loading " << fieldHeader.headerClassName() << ' ' << fieldName << endl; volSphericalTensorField* fieldPtr ( new volSphericalTensorField ( fieldHeader, mesh ) ); sphericalTensorCache.insert(fieldName, fieldPtr); } else if ( fieldHeader.headerClassName() == volSymmTensorField::typeName ) { Info<< "Loading " << fieldHeader.headerClassName() << ' ' << fieldName << endl; volSymmTensorField* fieldPtr ( new volSymmTensorField ( fieldHeader, mesh ) ); symmTensorCache.insert(fieldName, fieldPtr); } else if ( fieldHeader.headerClassName() == volTensorField::typeName ) { Info<< "Loading " << fieldHeader.headerClassName() << ' ' << fieldName << endl; volTensorField* fieldPtr ( new volTensorField ( fieldHeader, mesh ) ); tensorCache.insert(fieldName, fieldPtr); } } } // // Now we have fields cached and know whether mesh has changed. // Update surfaces with this information. // forAll(surfaces, surfaceI) { surfaces[surfaceI].correct ( meshChanged, pInterpPtr, interpolationSchemes, scalarCache ); } // // Combine surfaces onto master (bug:should not be redone for static // meshes) // List allPoints(surfaces.size()); List allFaces(surfaces.size()); forAll(surfaces, surfaceI) { // Collect points from all processors List gatheredPoints(Pstream::nProcs()); gatheredPoints[Pstream::myProcNo()] = surfaces[surfaceI].points(); Pstream::gatherList(gatheredPoints); if (Pstream::master()) { allPoints[surfaceI] = ListListOps::combine ( gatheredPoints, accessOp() ); } // Collect faces from all processors and renumber using sizes of // gathered points List gatheredFaces(Pstream::nProcs()); gatheredFaces[Pstream::myProcNo()] = surfaces[surfaceI].faces(); Pstream::gatherList(gatheredFaces); if (Pstream::master()) { allFaces[surfaceI] = static_cast ( ListListOps::combineOffset ( gatheredFaces, ListListOps::subSizes ( gatheredPoints, accessOp() ), accessOp(), offsetOp() ) ); } } // Merge close points (1E-10 of mesh bounding box) labelListList allOldToNewPoints; mergePoints(mesh, 1E-10, allPoints, allFaces, allOldToNewPoints); // // Do actual interpolation // forAll(fieldNames, fieldI) { Info<< endl; const word& fieldName = fieldNames[fieldI]; // Scalar fields if (scalarCache.found(fieldName)) { Info<< "Sampling volScalarField " << fieldName << endl << endl; forAll(surfaces, surfaceI) { const surface& s = surfaces[surfaceI]; scalarField values ( s.interpolate ( fieldName, scalarCache, pInterpPtr, interpolationSchemes ) ); // Collect values from all processors List gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = values; Pstream::gatherList(gatheredValues); if (Pstream::master()) { // Combine values into single field scalarField allValues ( ListListOps::combine ( gatheredValues, accessOp() ) ); // Renumber (point data) to correspond to merged points renumberData ( allOldToNewPoints[surfaceI], allPoints[surfaceI].size(), allValues ); // Write to time directory under sampleSurfaces/ scalarFormatter().write ( samplePath, runTime.timeName(), s.name(), allPoints[surfaceI], allFaces[surfaceI], fieldName, allValues ); } } } // Vector fields else if (vectorCache.found(fieldName)) { Info<< "Sampling volVectorField " << fieldName << endl << endl; forAll(surfaces, surfaceI) { const surface& s = surfaces[surfaceI]; vectorField values ( s.interpolate ( fieldName, vectorCache, pInterpPtr, interpolationSchemes ) ); // Collect values from all processors List gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = values; Pstream::gatherList(gatheredValues); if (Pstream::master()) { vectorField allValues ( ListListOps::combine ( gatheredValues, accessOp() ) ); // Renumber (point data) to correspond to merged points renumberData ( allOldToNewPoints[surfaceI], allPoints[surfaceI].size(), allValues ); // Write to time directory under sampleSurfaces/ vectorFormatter().write ( samplePath, runTime.timeName(), s.name(), allPoints[surfaceI], allFaces[surfaceI], fieldName, allValues ); } } } // SphericalTensor fields else if (sphericalTensorCache.found(fieldName)) { Info<< "Sampling volSphericalTensorField " << fieldName << endl << endl; forAll(surfaces, surfaceI) { const surface& s = surfaces[surfaceI]; sphericalTensorField values ( s.interpolate ( fieldName, sphericalTensorCache, pInterpPtr, interpolationSchemes ) ); // Collect values from all processors List gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = values; Pstream::gatherList(gatheredValues); if (Pstream::master()) { sphericalTensorField allValues ( ListListOps::combine ( gatheredValues, accessOp() ) ); // Renumber (point data) to correspond to merged points renumberData ( allOldToNewPoints[surfaceI], allPoints[surfaceI].size(), allValues ); // Write to time directory under sampleSurfaces/ sphericalTensorFormatter().write ( samplePath, runTime.timeName(), s.name(), allPoints[surfaceI], allFaces[surfaceI], fieldName, allValues ); } } } // SymmTensor fields else if (symmTensorCache.found(fieldName)) { Info<< "Sampling volSymmTensorField " << fieldName << endl << endl; forAll(surfaces, surfaceI) { const surface& s = surfaces[surfaceI]; symmTensorField values ( s.interpolate ( fieldName, symmTensorCache, pInterpPtr, interpolationSchemes ) ); // Collect values from all processors List gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = values; Pstream::gatherList(gatheredValues); if (Pstream::master()) { symmTensorField allValues ( ListListOps::combine ( gatheredValues, accessOp() ) ); // Renumber (point data) to correspond to merged points renumberData ( allOldToNewPoints[surfaceI], allPoints[surfaceI].size(), allValues ); // Write to time directory under sampleSurfaces/ symmTensorFormatter().write ( samplePath, runTime.timeName(), s.name(), allPoints[surfaceI], allFaces[surfaceI], fieldName, allValues ); } } } // Tensor fields else if (tensorCache.found(fieldName)) { Info<< "Sampling volTensorField " << fieldName << endl << endl; forAll(surfaces, surfaceI) { const surface& s = surfaces[surfaceI]; tensorField values ( s.interpolate ( fieldName, tensorCache, pInterpPtr, interpolationSchemes ) ); // Collect values from all processors List gatheredValues(Pstream::nProcs()); gatheredValues[Pstream::myProcNo()] = values; Pstream::gatherList(gatheredValues); if (Pstream::master()) { tensorField allValues ( ListListOps::combine ( gatheredValues, accessOp() ) ); // Renumber (point data) to correspond to merged points renumberData ( allOldToNewPoints[surfaceI], allPoints[surfaceI].size(), allValues ); // Write to time directory under sampleSurfaces/ tensorFormatter().write ( samplePath, runTime.timeName(), s.name(), allPoints[surfaceI], allFaces[surfaceI], fieldName, allValues ); } } } } Info<< endl; } Info<< "End\n" << endl; return 0; } // ************************************************************************* //