/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation \\/ M anipulation | Copyright (C) 2016 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 foamFormatConvert Group grpMiscUtilities Description Converts all IOobjects associated with a case into the format specified in the controlDict. Mainly used to convert binary mesh/field files to ASCII. Problem: any zero-size List written binary gets written as '0'. When reading the file as a dictionary this is interpreted as a label. This is (usually) not a problem when doing patch fields since these get the 'uniform', 'nonuniform' prefix. However zone contents are labelLists not labelFields and these go wrong. For now hacked a solution where we detect the keywords in zones and redo the dictionary entries to be labelLists. Usage - foamFormatConvert [OPTION] \param -noConstant \n Exclude the constant/ directory from the times list \param -enableFunctionEntries \n By default all dictionary preprocessing of fields is disabled \*---------------------------------------------------------------------------*/ #include "argList.H" #include "timeSelector.H" #include "Time.H" #include "volFields.H" #include "surfaceFields.H" #include "pointFields.H" #include "cellIOList.H" #include "IOobjectList.H" #include "IOPtrList.H" #include "cloud.H" #include "labelIOField.H" #include "scalarIOField.H" #include "sphericalTensorIOField.H" #include "symmTensorIOField.H" #include "tensorIOField.H" #include "labelFieldIOField.H" #include "vectorFieldIOField.H" #include "Cloud.H" #include "passiveParticle.H" #include "fieldDictionary.H" #include "writeMeshObject.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { defineTemplateTypeNameAndDebug(IOPtrList, 0); } // Hack to do zones which have Lists in them. See above. bool writeZones(const word& name, const fileName& meshDir, Time& runTime) { IOobject io ( name, runTime.timeName(), meshDir, runTime, IOobject::MUST_READ, IOobject::NO_WRITE, false ); bool writeOk = false; if (io.typeHeaderOk(false)) { Info<< " Reading " << io.headerClassName() << " : " << name << endl; // Switch off type checking (for reading e.g. faceZones as // generic list of dictionaries). const word oldTypeName = IOPtrList::typeName; const_cast(IOPtrList::typeName) = word::null; IOPtrList meshObject(io); forAll(meshObject, i) { if (meshObject[i].isDict()) { dictionary& d = meshObject[i].dict(); if (d.found("faceLabels")) { d.set("faceLabels", labelList(d.lookup("faceLabels"))); } if (d.found("flipMap")) { d.set("flipMap", boolList(d.lookup("flipMap"))); } if (d.found("cellLabels")) { d.set("cellLabels", labelList(d.lookup("cellLabels"))); } if (d.found("pointLabels")) { d.set("pointLabels", labelList(d.lookup("pointLabels"))); } } } const_cast(IOPtrList::typeName) = oldTypeName; // Fake type back to what was in field const_cast(meshObject.type()) = io.headerClassName(); Info<< " Writing " << name << endl; // Force writing as ascii writeOk = meshObject.regIOobject::writeObject ( IOstream::ASCII, IOstream::currentVersion, runTime.writeCompression(), true ); } return writeOk; } // Reduction for non-empty strings. template struct uniqueEqOp { void operator()(List& x, const List& y) const { List newX(x.size()+y.size()); label n = 0; forAll(x, i) { if (!x[i].empty()) { newX[n++] = x[i]; } } forAll(y, i) { if (!y[i].empty() && !x.found(y[i])) { newX[n++] = y[i]; } } newX.setSize(n); x.transfer(newX); } }; template bool writeOptionalMeshObject ( const word& name, const fileName& meshDir, Time& runTime, const bool valid ) { IOobject io ( name, runTime.timeName(), meshDir, runTime, IOobject::MUST_READ, IOobject::NO_WRITE, false ); bool writeOk = false; bool haveFile = io.typeHeaderOk>(false); // Make sure all know if there is a valid class name wordList classNames(1, io.headerClassName()); combineReduce(classNames, uniqueEqOp()); // Check for correct type if (classNames[0] == T::typeName) { Info<< " Reading " << classNames[0] << " : " << name << endl; T meshObject(io, valid && haveFile); Info<< " Writing " << name << endl; writeOk = meshObject.regIOobject::write(valid && haveFile); } return writeOk; } int main(int argc, char *argv[]) { timeSelector::addOptions(); argList::addBoolOption ( "noConstant", "exclude the 'constant/' dir in the times list" ); argList::addBoolOption ( "enableFunctionEntries", "enable expansion of dictionary directives - #include, #codeStream etc" ); #include "addRegionOption.H" #include "setRootCase.H" // enable noConstant by switching if (!args.found("noConstant")) { args.setOption("constant", ""); } else { args.unsetOption("constant"); Info<< "Excluding the constant directory." << nl << endl; } #include "createTime.H" // Optional mesh (used to read Clouds) autoPtr meshPtr; const bool enableEntries = args.found("enableFunctionEntries"); if (enableEntries) { Info<< "Allowing dictionary preprocessing ('#include', '#codeStream')." << endl; } const int oldFlag = entry::disableFunctionEntries; if (!enableEntries) { // By default disable dictionary expansion for fields entry::disableFunctionEntries = 1; } // Make sure we do not use the master-only reading since we read // fields (different per processor) as dictionaries. regIOobject::fileModificationChecking = regIOobject::timeStamp; fileName meshDir = polyMesh::meshSubDir; fileName regionPrefix = ""; word regionName = polyMesh::defaultRegion; if (args.readIfPresent("region", regionName)) { Info<< "Using region " << regionName << nl << endl; regionPrefix = regionName; meshDir = regionName/polyMesh::meshSubDir; } Foam::instantList timeDirs = Foam::timeSelector::select0(runTime, args); forAll(timeDirs, timeI) { runTime.setTime(timeDirs[timeI], timeI); Info<< "Time = " << runTime.timeName() << endl; // Convert all the standard mesh files writeMeshObject ( "cells", meshDir, runTime ); writeMeshObject("owner", meshDir, runTime); writeMeshObject("neighbour", meshDir, runTime); writeMeshObject ( "faces", meshDir, runTime ); writeMeshObject("points", meshDir, runTime); // Write boundary in ascii. This is only needed for fileHandler to // kick in. Should not give problems since always writing ascii. writeZones("boundary", meshDir, runTime); writeMeshObject("pointProcAddressing", meshDir, runTime); writeMeshObject("faceProcAddressing", meshDir, runTime); writeMeshObject("cellProcAddressing", meshDir, runTime); writeMeshObject ( "boundaryProcAddressing", meshDir, runTime ); // foamyHexMesh vertices writeMeshObject ( "internalDelaunayVertices", regionPrefix, runTime ); if (runTime.writeFormat() == IOstream::ASCII) { // Only do zones when converting from binary to ascii // The other way gives problems since working on dictionary level. writeZones("cellZones", meshDir, runTime); writeZones("faceZones", meshDir, runTime); writeZones("pointZones", meshDir, runTime); } // Get list of objects from the database IOobjectList objects(runTime, runTime.timeName(), regionPrefix); forAllConstIter(IOobjectList, objects, iter) { const word& headerClassName = iter()->headerClassName(); if ( headerClassName == volScalarField::typeName || headerClassName == volVectorField::typeName || headerClassName == volSphericalTensorField::typeName || headerClassName == volSymmTensorField::typeName || headerClassName == volTensorField::typeName || headerClassName == surfaceScalarField::typeName || headerClassName == surfaceVectorField::typeName || headerClassName == surfaceSphericalTensorField::typeName || headerClassName == surfaceSymmTensorField::typeName || headerClassName == surfaceTensorField::typeName || headerClassName == pointScalarField::typeName || headerClassName == pointVectorField::typeName || headerClassName == pointSphericalTensorField::typeName || headerClassName == pointSymmTensorField::typeName || headerClassName == pointTensorField::typeName || headerClassName == volScalarField::Internal::typeName || headerClassName == volVectorField::Internal::typeName || headerClassName == volSphericalTensorField::Internal::typeName || headerClassName == volSymmTensorField::Internal::typeName || headerClassName == volTensorField::Internal::typeName ) { Info<< " Reading " << headerClassName << " : " << iter()->name() << endl; fieldDictionary fDict(*iter(), headerClassName); Info<< " Writing " << iter()->name() << endl; fDict.regIOobject::write(); } } // Check for lagrangian fileNameList lagrangianDirs ( 1, fileHandler().filePath ( runTime.timePath() / regionPrefix / cloud::prefix ) ); combineReduce(lagrangianDirs, uniqueEqOp()); if (!lagrangianDirs.empty()) { if (meshPtr.valid()) { meshPtr().readUpdate(); } else { Info<< " Create polyMesh for time = " << runTime.timeName() << endl; meshPtr.reset ( new polyMesh ( IOobject ( polyMesh::defaultRegion, runTime.timeName(), runTime, Foam::IOobject::MUST_READ ) ) ); } fileNameList cloudDirs ( fileHandler().readDir ( lagrangianDirs[0], fileName::DIRECTORY ) ); combineReduce(cloudDirs, uniqueEqOp()); forAll(cloudDirs, i) { fileName dir(cloud::prefix/cloudDirs[i]); Cloud parcels(meshPtr(), cloudDirs[i], false); parcels.writeObject ( runTime.writeFormat(), IOstream::currentVersion, runTime.writeCompression(), parcels.size() ); // Do local scan for valid cloud objects IOobjectList sprayObjs(runTime, runTime.timeName(), dir); // Combine with all other cloud objects wordList sprayFields(sprayObjs.sortedToc()); combineReduce(sprayFields, uniqueEqOp()); for (const word& name : sprayFields) { // Note: try the various field types. Make sure to // exit once successful conversion to avoid re-read // converted file. if ( name == "positions" || name == "coordinates" || name == "origProcId" || name == "origId" ) { continue; } bool writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (writeOk) continue; writeOk = writeOptionalMeshObject ( name, dir, runTime, parcels.size() > 0 ); if (!writeOk) { Info<< " Failed converting " << name << endl; } } } } Info<< endl; } entry::disableFunctionEntries = oldFlag; Info<< "End\n" << endl; return 0; } // ************************************************************************* //