1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright held by original author
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 Legacy VTK file format writer.
31 - handles volScalar, volVector, pointScalar, pointVector, surfaceScalar
34 - both ascii and binary.
35 - single time step writing.
37 - automatic decomposition of cells; polygons on boundary undecomposed since
46 Write VTK data in ASCII format instead of binary.
48 @param -mesh \<name\>\n
49 Use a different mesh name (instead of -region)
51 @param -fields \<fields\>\n
52 Convert selected fields only. For example,
56 The quoting is required to avoid shell expansions and to pass the
57 information as a single argument.
59 @param -surfaceFields \n
60 Write surfaceScalarFields (e.g., phi)
62 @param -cellSet \<name\>\n
63 @param -faceSet \<name\>\n
64 @param -pointSet \<name\>\n
65 Restrict conversion to the cellSet, faceSet or pointSet.
67 @param -nearCellValue \n
68 Output cell value on patches instead of patch value itself
71 Do not generate file for mesh, only for patches
73 @param -noPointValues \n
76 @param -noFaceZones \n
80 (in parallel) do not link processor files to master
83 Combine all patches into a single file
85 @param -allWallPatches \n
86 Combine all wall patches into a single file
88 @param -excludePatches \<patchNames\>\n
89 Specify patches to exclude. For example,
91 -excludePatches "( inlet_1 inlet_2 )"
93 The quoting is required to avoid shell expansions and to pass the
94 information as a single argument.
96 @param -useTimeName \n
97 use the time index in the VTK file name instead of the time index
100 mesh subset is handled by vtkMesh. Slight inconsistency in
101 interpolation: on the internal field it interpolates the whole volfield
102 to the whole-mesh pointField and then selects only those values it
103 needs for the subMesh (using the fvMeshSubset cellMap(), pointMap()
104 functions). For the patches however it uses the
105 fvMeshSubset.interpolate function to directly interpolate the
106 whole-mesh values onto the subset patch.
108 \*---------------------------------------------------------------------------*/
111 #include "pointMesh.H"
112 #include "volPointInterpolation.H"
113 #include "emptyPolyPatch.H"
114 #include "labelIOField.H"
115 #include "scalarIOField.H"
116 #include "sphericalTensorIOField.H"
117 #include "symmTensorIOField.H"
118 #include "tensorIOField.H"
119 #include "faceZoneMesh.H"
121 #include "passiveParticle.H"
126 #include "readFields.H"
127 #include "writeFuns.H"
129 #include "internalWriter.H"
130 #include "patchWriter.H"
131 #include "faMeshWriter.H"
132 #include "lagrangianWriter.H"
134 #include "writeFaceSet.H"
135 #include "writePointSet.H"
136 #include "writePatchGeom.H"
137 #include "writeSurfFields.H"
140 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
143 static const label VTK_TETRA = 10;
144 static const label VTK_PYRAMID = 14;
145 static const label VTK_WEDGE = 13;
146 static const label VTK_HEXAHEDRON = 12;
149 template<class GeoField>
150 void print(const char* msg, Ostream& os, const PtrList<GeoField>& flds)
157 os<< ' ' << flds[i].name();
164 void print(Ostream& os, const wordList& flds)
174 labelList getSelectedPatches
176 const polyBoundaryMesh& patches,
177 const HashSet<word>& excludePatches
180 DynamicList<label> patchIDs(patches.size());
182 Info<< "Combining patches:" << endl;
184 forAll(patches, patchI)
186 const polyPatch& pp = patches[patchI];
190 isA<emptyPolyPatch>(pp)
191 || (Pstream::parRun() && isA<processorPolyPatch>(pp))
194 Info<< " discarding empty/processor patch " << patchI
195 << " " << pp.name() << endl;
197 else if (!excludePatches.found(pp.name()))
199 patchIDs.append(patchI);
200 Info<< " patch " << patchI << " " << pp.name() << endl;
203 return patchIDs.shrink();
211 int main(int argc, char *argv[])
213 timeSelector::addOptions();
215 # include "addRegionOption.H"
217 argList::validOptions.insert("fields", "fields");
218 argList::validOptions.insert("cellSet", "cellSet name");
219 argList::validOptions.insert("faceSet", "faceSet name");
220 argList::validOptions.insert("pointSet", "pointSet name");
221 argList::validOptions.insert("ascii","");
222 argList::validOptions.insert("surfaceFields","");
223 argList::validOptions.insert("nearCellValue","");
224 argList::validOptions.insert("noInternal","");
225 argList::validOptions.insert("noPointValues","");
226 argList::validOptions.insert("allPatches","");
227 argList::validOptions.insert("allWallPatches","");
228 argList::validOptions.insert("excludePatches","patches to exclude");
229 argList::validOptions.insert("noFaceZones","");
230 argList::validOptions.insert("faMesh","");
231 argList::validOptions.insert("noLinks","");
232 argList::validOptions.insert("useTimeName","");
234 # include "setRootCase.H"
235 # include "createTime.H"
237 bool doWriteInternal = !args.optionFound("noInternal");
238 bool doFaceZones = !args.optionFound("noFaceZones");
239 bool doLinks = !args.optionFound("noLinks");
240 bool binary = !args.optionFound("ascii");
241 bool useTimeName = args.optionFound("useTimeName");
243 if (binary && (sizeof(floatScalar) != 4 || sizeof(label) != 4))
245 FatalErrorIn(args.executable())
246 << "floatScalar and/or label are not 4 bytes in size" << nl
247 << "Hence cannot use binary VTK format. Please use -ascii"
251 bool nearCellValue = args.optionFound("nearCellValue");
255 Info<< "Using neighbouring cell value instead of patch value"
259 bool noPointValues = args.optionFound("noPointValues");
263 Info<< "Outputting cell values only" << nl << endl;
266 bool allPatches = args.optionFound("allPatches");
267 bool allWallPatches = args.optionFound("allWallPatches");
269 HashSet<word> excludePatches;
270 if (args.optionFound("excludePatches"))
272 args.optionLookup("excludePatches")() >> excludePatches;
274 Info<< "Not including patches " << excludePatches << nl << endl;
280 if (args.optionFound("cellSet"))
282 cellSetName = args.option("cellSet");
283 vtkName = cellSetName;
285 else if (Pstream::parRun())
287 // Strip off leading casename, leaving just processor_DDD ending.
288 vtkName = runTime.caseName();
290 string::size_type i = vtkName.rfind("processor");
292 if (i != string::npos)
294 vtkName = vtkName.substr(i);
299 vtkName = runTime.caseName();
303 instantList timeDirs = timeSelector::select0(runTime, args);
305 # include "createNamedMesh.H"
307 // VTK/ directory in the case
308 fileName fvPath(runTime.path()/"VTK");
309 // Directory of mesh (region0 gets filtered out)
310 fileName regionPrefix = "";
312 if (regionName != polyMesh::defaultRegion)
314 fvPath = fvPath/regionName;
315 regionPrefix = regionName;
322 args.optionFound("time")
323 || args.optionFound("latestTime")
324 || cellSetName.size()
325 || regionName != polyMesh::defaultRegion
328 Info<< "Keeping old VTK files in " << fvPath << nl << endl;
332 Info<< "Deleting old VTK files in " << fvPath << nl << endl;
341 // Mesh wrapper; does subsetting and decomposition
354 // Scan for all possible lagrangian clouds
355 HashSet<fileName> allCloudDirs;
356 forAll(timeDirs, timeI)
358 runTime.setTime(timeDirs[timeI], timeI);
359 fileNameList cloudDirs
363 runTime.timePath()/regionPrefix/cloud::prefix,
369 IOobjectList sprayObjs
373 cloud::prefix/cloudDirs[i]
376 IOobject* positionsPtr = sprayObjs.lookup("positions");
380 if (allCloudDirs.insert(cloudDirs[i]))
382 Info<< "At time: " << runTime.timeName()
383 << " detected cloud directory : " << cloudDirs[i]
391 forAll(timeDirs, timeI)
393 runTime.setTime(timeDirs[timeI], timeI);
395 Info<< "Time: " << runTime.timeName() << endl;
400 timeDesc = runTime.timeName();
404 timeDesc = name(runTime.timeIndex());
407 // Check for new polyMesh/ and update mesh, fvMeshSubset and cell
409 polyMesh::readUpdateState meshState = vMesh.readUpdate();
411 const fvMesh& mesh = vMesh.mesh();
415 meshState == polyMesh::TOPO_CHANGE
416 || meshState == polyMesh::TOPO_PATCH_CHANGE
419 Info<< " Read new mesh" << nl << endl;
423 // If faceSet: write faceSet only (as polydata)
424 if (args.optionFound("faceSet"))
427 faceSet set(mesh, args.option("faceSet"));
429 // Filename as if patch with same name.
430 mkDir(fvPath/set.name());
432 fileName patchFileName
434 fvPath/set.name()/set.name()
440 Info<< " FaceSet : " << patchFileName << endl;
442 writeFaceSet(binary, vMesh, set, patchFileName);
446 // If pointSet: write pointSet only (as polydata)
447 if (args.optionFound("pointSet"))
450 pointSet set(mesh, args.option("pointSet"));
452 // Filename as if patch with same name.
453 mkDir(fvPath/set.name());
455 fileName patchFileName
457 fvPath/set.name()/set.name()
463 Info<< " pointSet : " << patchFileName << endl;
465 writePointSet(binary, vMesh, set, patchFileName);
471 // Search for list of objects for this time
472 IOobjectList objects(mesh, runTime.timeName());
474 HashSet<word> selectedFields;
475 if (args.optionFound("fields"))
477 args.optionLookup("fields")() >> selectedFields;
480 // Construct the vol fields (on the original mesh if subsetted)
482 PtrList<volScalarField> vsf;
483 readFields(vMesh, vMesh, objects, selectedFields, vsf);
484 readFields(vMesh, vMesh, objects, selectedFields, vsf);
485 print(" volScalarFields :", Info, vsf);
487 PtrList<volVectorField> vvf;
488 readFields(vMesh, vMesh, objects, selectedFields, vvf);
489 print(" volVectorFields :", Info, vvf);
491 PtrList<volSphericalTensorField> vSpheretf;
492 readFields(vMesh, vMesh, objects, selectedFields, vSpheretf);
493 print(" volSphericalTensorFields :", Info, vSpheretf);
495 PtrList<volSymmTensorField> vSymmtf;
496 readFields(vMesh, vMesh, objects, selectedFields, vSymmtf);
497 print(" volSymmTensorFields :", Info, vSymmtf);
499 PtrList<volTensorField> vtf;
500 readFields(vMesh, vMesh, objects, selectedFields, vtf);
501 print(" volTensorFields :", Info, vtf);
503 const label nVolFields =
511 // Construct pointMesh only if nessecary since constructs edge
512 // addressing (expensive on polyhedral meshes)
515 Info<< " pointScalarFields : switched off"
516 << " (\"-noPointValues\" option)\n";
517 Info<< " pointVectorFields : switched off"
518 << " (\"-noPointValues\" option)\n";
521 PtrList<pointScalarField> psf;
522 PtrList<pointVectorField> pvf;
523 PtrList<pointSphericalTensorField> pSpheretf;
524 PtrList<pointSymmTensorField> pSymmtf;
525 PtrList<pointTensorField> ptf;
532 pointMesh::New(vMesh),
537 print(" pointScalarFields :", Info, psf);
542 pointMesh::New(vMesh),
547 print(" pointVectorFields :", Info, pvf);
552 pointMesh::New(vMesh),
557 print(" pointSphericalTensorFields :", Info, pSpheretf);
562 pointMesh::New(vMesh),
567 print(" pointSymmTensorFields :", Info, pSymmtf);
572 pointMesh::New(vMesh),
577 print(" pointTensorFields :", Info, ptf);
591 // Create file and write header
601 Info<< " Internal : " << vtkFileName << endl;
604 internalWriter writer(vMesh, binary, vtkFileName);
606 // VolFields + cellID
607 writeFuns::writeCellDataHeader
614 // Write cellID field
615 writer.writeCellIDs();
620 writer.write(vSpheretf);
621 writer.write(vSymmtf);
626 writeFuns::writePointDataHeader
629 vMesh.nFieldPoints(),
630 nVolFields+nPointFields
636 writer.write(pSpheretf);
637 writer.write(pSymmtf);
640 // Interpolated volFields
641 volPointInterpolation pInterp(mesh);
642 writer.write(pInterp, vsf);
643 writer.write(pInterp, vvf);
644 writer.write(pInterp, vSpheretf);
645 writer.write(pInterp, vSymmtf);
646 writer.write(pInterp, vtf);
650 //---------------------------------------------------------------------
652 // Write surface fields
654 //---------------------------------------------------------------------
656 if (args.optionFound("surfaceFields"))
658 PtrList<surfaceScalarField> ssf;
667 print(" surfScalarFields :", Info, ssf);
669 PtrList<surfaceVectorField> svf;
678 print(" surfVectorFields :", Info, svf);
680 if (ssf.size() + svf.size() > 0)
682 // Rework the scalar fields into vectorfields.
683 label sz = svf.size();
685 svf.setSize(sz+ssf.size());
687 surfaceVectorField n(mesh.Sf()/mesh.magSf());
691 svf.set(sz+i, ssf[i]*n);
692 svf[sz+i].rename(ssf[i].name());
696 mkDir(fvPath / "surfaceFields");
698 fileName surfFileName
719 //---------------------------------------------------------------------
721 // Write patches (POLYDATA file, one for each patch)
723 //---------------------------------------------------------------------
725 const polyBoundaryMesh& patches = mesh.boundaryMesh();
729 mkDir(fvPath/"allPatches");
731 fileName patchFileName;
733 if (vMesh.useSubMesh())
736 fvPath/"allPatches"/cellSetName
744 fvPath/"allPatches"/"allPatches"
750 Info<< " Combined patches : " << patchFileName << endl;
758 getSelectedPatches(patches, excludePatches)
761 // VolFields + patchID
762 writeFuns::writeCellDataHeader
769 // Write patchID field
770 writer.writePatchIDs();
775 writer.write(vSpheretf);
776 writer.write(vSymmtf);
781 writeFuns::writePointDataHeader
791 writer.write(pSpheretf);
792 writer.write(pSymmtf);
795 // no interpolated volFields since I cannot be bothered to
796 // create the patchInterpolation for all subpatches.
799 else if (allWallPatches)
801 mkDir(fvPath/"allWallPatches");
803 fileName wallPatchFileName;
805 if (vMesh.useSubMesh())
808 fvPath/"allWallPatches"/cellSetName
816 fvPath/"allWallPatches"/"allWallPatches"
822 // Go through the boundary and add all patches that are not
823 // of type wall onto the exclude{atches list
824 forAll (patches, patchI)
826 if (!isA<wallPolyPatch>(patches[patchI]))
828 excludePatches.insert(patches[patchI].name());
832 Info<< " Combined wall patches : " << wallPatchFileName
841 getSelectedPatches(patches, excludePatches)
844 // VolFields + patchID
845 writeFuns::writeCellDataHeader
852 // Write patchID field
853 writer.writePatchIDs();
858 writer.write(vSpheretf);
859 writer.write(vSymmtf);
864 writeFuns::writePointDataHeader
874 writer.write(pSpheretf);
875 writer.write(pSymmtf);
878 // no interpolated volFields since I cannot be bothered to
879 // create the patchInterpolation for all subpatches.
884 forAll(patches, patchI)
886 const polyPatch& pp = patches[patchI];
888 if (!excludePatches.found(pp.name()))
890 mkDir(fvPath/pp.name());
892 fileName patchFileName;
894 if (vMesh.useSubMesh())
897 fvPath/pp.name()/cellSetName
905 fvPath/pp.name()/pp.name()
911 Info<< " Patch : " << patchFileName << endl;
922 if (!isA<emptyPolyPatch>(pp))
924 // VolFields + patchID
925 writeFuns::writeCellDataHeader
932 // Write patchID field
933 writer.writePatchIDs();
938 writer.write(vSpheretf);
939 writer.write(vSymmtf);
944 writeFuns::writePointDataHeader
955 writer.write(pSpheretf);
956 writer.write(pSymmtf);
959 PrimitivePatchInterpolation<primitivePatch> pInter
964 // Write interpolated volFields
965 writer.write(pInter, vsf);
966 writer.write(pInter, vvf);
967 writer.write(pInter, vSpheretf);
968 writer.write(pInter, vSymmtf);
969 writer.write(pInter, vtf);
976 //---------------------------------------------------------------------
978 // Write faceZones (POLYDATA file, one for each zone)
980 //---------------------------------------------------------------------
984 const faceZoneMesh& zones = mesh.faceZones();
988 const faceZone& pp = zones[zoneI];
990 mkDir(fvPath/pp.name());
992 fileName patchFileName;
994 if (vMesh.useSubMesh())
997 fvPath/pp.name()/cellSetName
1005 fvPath/pp.name()/pp.name()
1011 Info<< " FaceZone : " << patchFileName << endl;
1013 std::ofstream str(patchFileName.c_str());
1015 writeFuns::writeHeader(str, binary, pp.name());
1016 str << "DATASET POLYDATA" << std::endl;
1030 //---------------------------------------------------------------------
1032 // Write finite area data
1034 //---------------------------------------------------------------------
1036 if (args.options().found("faMesh"))
1038 mkDir(fvPath/"faMesh");
1040 fileName faFileName =
1041 fvPath/"faMesh"/"faMesh"
1047 faMesh aMesh(vMesh.mesh());
1049 PtrList<areaScalarField> asf;
1050 readFieldsNoSubset(vMesh, aMesh, objects, selectedFields, asf);
1051 print(" areaScalarFields :", Info, asf);
1053 PtrList<areaVectorField> avf;
1054 readFieldsNoSubset(vMesh, aMesh, objects, selectedFields, avf);
1055 print(" areaVectorFields :", Info, avf);
1057 const label nAreaFields =
1068 writeFuns::writeCellDataHeader
1081 writeFuns::writePointDataHeader
1088 // Interpolated areaFields
1089 PrimitivePatchInterpolation<indirectPrimitivePatch> pInterp
1093 writer.write(pInterp, asf);
1094 writer.write(pInterp, avf);
1098 //---------------------------------------------------------------------
1100 // Write lagrangian data
1102 //---------------------------------------------------------------------
1104 forAllConstIter(HashSet<fileName>, allCloudDirs, iter)
1106 const fileName& cloudName = iter.key();
1108 // Always create the cloud directory.
1109 mkDir(fvPath/cloud::prefix/cloudName);
1111 fileName lagrFileName
1113 fvPath/cloud::prefix/cloudName/cloudName
1114 + "_" + timeDesc + ".vtk"
1117 Info<< " Lagrangian: " << lagrFileName << endl;
1120 IOobjectList sprayObjs
1124 cloud::prefix/cloudName
1127 IOobject* positionsPtr = sprayObjs.lookup("positions");
1131 wordList labelNames(sprayObjs.names(labelIOField::typeName));
1133 print(Info, labelNames);
1135 wordList scalarNames(sprayObjs.names(scalarIOField::typeName));
1136 Info<< " scalars :";
1137 print(Info, scalarNames);
1139 wordList vectorNames(sprayObjs.names(vectorIOField::typeName));
1140 Info<< " vectors :";
1141 print(Info, vectorNames);
1143 wordList sphereNames
1147 sphericalTensorIOField::typeName
1150 Info<< " spherical tensors :";
1151 print(Info, sphereNames);
1157 symmTensorIOField::typeName
1160 Info<< " symm tensors :";
1161 print(Info, symmNames);
1163 wordList tensorNames(sprayObjs.names(tensorIOField::typeName));
1164 Info<< " tensors :";
1165 print(Info, tensorNames);
1167 lagrangianWriter writer
1176 // Write number of fields
1177 writer.writeParcelHeader
1180 + scalarNames.size()
1181 + vectorNames.size()
1182 + sphereNames.size()
1184 + tensorNames.size()
1188 writer.writeIOField<label>(labelNames);
1189 writer.writeIOField<scalar>(scalarNames);
1190 writer.writeIOField<vector>(vectorNames);
1191 writer.writeIOField<sphericalTensor>(sphereNames);
1192 writer.writeIOField<symmTensor>(symmNames);
1193 writer.writeIOField<tensor>(tensorNames);
1197 lagrangianWriter writer
1206 // Write number of fields
1207 writer.writeParcelHeader(0);
1213 //---------------------------------------------------------------------
1215 // Link parallel outputs back to undecomposed case for ease of loading
1217 //---------------------------------------------------------------------
1219 if (Pstream::parRun() && doLinks)
1221 mkDir(runTime.path()/".."/"VTK");
1222 chDir(runTime.path()/".."/"VTK");
1224 Info<< "Linking all processor files to " << runTime.path()/".."/"VTK"
1227 // Get list of vtk files
1231 /"processor" + name(Pstream::myProcNo())
1235 fileNameList dirs(readDir(procVTK, fileName::DIRECTORY));
1236 label sz = dirs.size();
1242 fileNameList subFiles(readDir(procVTK/dirs[i], fileName::FILE));
1246 fileName procFile(procVTK/dirs[i]/subFiles[j]);
1248 if (exists(procFile))
1256 + name(Pstream::myProcNo())
1260 system(cmd.c_str());
1266 Info<< "End\n" << endl;
1272 // ************************************************************************* //