1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 -excludePatches \<patchNames\>\n
86 Specify patches to exclude. For example,
88 -excludePatches "( inlet_1 inlet_2 )"
90 The quoting is required to avoid shell expansions and to pass the
91 information as a single argument.
93 @param -useTimeName \n
94 use the time index in the VTK file name instead of the time index
97 mesh subset is handled by vtkMesh. Slight inconsistency in
98 interpolation: on the internal field it interpolates the whole volfield
99 to the whole-mesh pointField and then selects only those values it
100 needs for the subMesh (using the fvMeshSubset cellMap(), pointMap()
101 functions). For the patches however it uses the
102 fvMeshSubset.interpolate function to directly interpolate the
103 whole-mesh values onto the subset patch.
105 \*---------------------------------------------------------------------------*/
108 #include "pointMesh.H"
109 #include "volPointInterpolation.H"
110 #include "emptyPolyPatch.H"
111 #include "labelIOField.H"
112 #include "scalarIOField.H"
113 #include "sphericalTensorIOField.H"
114 #include "symmTensorIOField.H"
115 #include "tensorIOField.H"
116 #include "faceZoneMesh.H"
118 #include "passiveParticle.H"
121 #include "readFields.H"
122 #include "writeFuns.H"
124 #include "internalWriter.H"
125 #include "patchWriter.H"
126 #include "lagrangianWriter.H"
128 #include "writeFaceSet.H"
129 #include "writePointSet.H"
130 #include "writePatchGeom.H"
131 #include "writeSurfFields.H"
134 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
137 static const label VTK_TETRA = 10;
138 static const label VTK_PYRAMID = 14;
139 static const label VTK_WEDGE = 13;
140 static const label VTK_HEXAHEDRON = 12;
143 template<class GeoField>
144 void print(const char* msg, Ostream& os, const PtrList<GeoField>& flds)
151 os<< ' ' << flds[i].name();
158 void print(Ostream& os, const wordList& flds)
168 labelList getSelectedPatches
170 const polyBoundaryMesh& patches,
171 const HashSet<word>& excludePatches
174 DynamicList<label> patchIDs(patches.size());
176 Info<< "Combining patches:" << endl;
178 forAll(patches, patchI)
180 const polyPatch& pp = patches[patchI];
184 isA<emptyPolyPatch>(pp)
185 || (Pstream::parRun() && isA<processorPolyPatch>(pp))
188 Info<< " discarding empty/processor patch " << patchI
189 << " " << pp.name() << endl;
191 else if (!excludePatches.found(pp.name()))
193 patchIDs.append(patchI);
194 Info<< " patch " << patchI << " " << pp.name() << endl;
197 return patchIDs.shrink();
205 int main(int argc, char *argv[])
207 timeSelector::addOptions();
209 # include "addRegionOption.H"
211 argList::validOptions.insert("fields", "fields");
212 argList::validOptions.insert("cellSet", "cellSet name");
213 argList::validOptions.insert("faceSet", "faceSet name");
214 argList::validOptions.insert("pointSet", "pointSet name");
215 argList::validOptions.insert("ascii","");
216 argList::validOptions.insert("surfaceFields","");
217 argList::validOptions.insert("nearCellValue","");
218 argList::validOptions.insert("noInternal","");
219 argList::validOptions.insert("noPointValues","");
220 argList::validOptions.insert("allPatches","");
221 argList::validOptions.insert("excludePatches","patches to exclude");
222 argList::validOptions.insert("noFaceZones","");
223 argList::validOptions.insert("noLinks","");
224 argList::validOptions.insert("useTimeName","");
226 # include "setRootCase.H"
227 # include "createTime.H"
229 bool doWriteInternal = !args.optionFound("noInternal");
230 bool doFaceZones = !args.optionFound("noFaceZones");
231 bool doLinks = !args.optionFound("noLinks");
232 bool binary = !args.optionFound("ascii");
233 bool useTimeName = args.optionFound("useTimeName");
235 if (binary && (sizeof(floatScalar) != 4 || sizeof(label) != 4))
237 FatalErrorIn(args.executable())
238 << "floatScalar and/or label are not 4 bytes in size" << nl
239 << "Hence cannot use binary VTK format. Please use -ascii"
243 bool nearCellValue = args.optionFound("nearCellValue");
247 WarningIn(args.executable())
248 << "Using neighbouring cell value instead of patch value"
252 bool noPointValues = args.optionFound("noPointValues");
256 WarningIn(args.executable())
257 << "Outputting cell values only" << nl << endl;
260 bool allPatches = args.optionFound("allPatches");
262 HashSet<word> excludePatches;
263 if (args.optionFound("excludePatches"))
265 args.optionLookup("excludePatches")() >> excludePatches;
267 Info<< "Not including patches " << excludePatches << nl << endl;
273 if (args.optionFound("cellSet"))
275 cellSetName = args.option("cellSet");
276 vtkName = cellSetName;
278 else if (Pstream::parRun())
280 // Strip off leading casename, leaving just processor_DDD ending.
281 vtkName = runTime.caseName();
283 string::size_type i = vtkName.rfind("processor");
285 if (i != string::npos)
287 vtkName = vtkName.substr(i);
292 vtkName = runTime.caseName();
296 instantList timeDirs = timeSelector::select0(runTime, args);
298 # include "createNamedMesh.H"
300 // VTK/ directory in the case
301 fileName fvPath(runTime.path()/"VTK");
302 // Directory of mesh (region0 gets filtered out)
303 fileName regionPrefix = "";
305 if (regionName != polyMesh::defaultRegion)
307 fvPath = fvPath/regionName;
308 regionPrefix = regionName;
315 args.optionFound("time")
316 || args.optionFound("latestTime")
317 || cellSetName.size()
318 || regionName != polyMesh::defaultRegion
321 Info<< "Keeping old VTK files in " << fvPath << nl << endl;
325 Info<< "Deleting old VTK files in " << fvPath << nl << endl;
334 // mesh wrapper; does subsetting and decomposition
335 vtkMesh vMesh(mesh, cellSetName);
338 // Scan for all possible lagrangian clouds
339 HashSet<fileName> allCloudDirs;
340 forAll(timeDirs, timeI)
342 runTime.setTime(timeDirs[timeI], timeI);
343 fileNameList cloudDirs
347 runTime.timePath()/regionPrefix/cloud::prefix,
353 IOobjectList sprayObjs
357 cloud::prefix/cloudDirs[i]
360 IOobject* positionsPtr = sprayObjs.lookup("positions");
364 if (allCloudDirs.insert(cloudDirs[i]))
366 Info<< "At time: " << runTime.timeName()
367 << " detected cloud directory : " << cloudDirs[i]
375 forAll(timeDirs, timeI)
377 runTime.setTime(timeDirs[timeI], timeI);
379 Info<< "Time: " << runTime.timeName() << endl;
384 timeDesc = runTime.timeName();
388 timeDesc = name(runTime.timeIndex());
391 // Check for new polyMesh/ and update mesh, fvMeshSubset and cell
393 polyMesh::readUpdateState meshState = vMesh.readUpdate();
395 const fvMesh& mesh = vMesh.mesh();
399 meshState == polyMesh::TOPO_CHANGE
400 || meshState == polyMesh::TOPO_PATCH_CHANGE
403 Info<< " Read new mesh" << nl << endl;
407 // If faceSet: write faceSet only (as polydata)
408 if (args.optionFound("faceSet"))
411 faceSet set(mesh, args.option("faceSet"));
413 // Filename as if patch with same name.
414 mkDir(fvPath/set.name());
416 fileName patchFileName
418 fvPath/set.name()/set.name()
424 Info<< " FaceSet : " << patchFileName << endl;
426 writeFaceSet(binary, vMesh, set, patchFileName);
430 // If pointSet: write pointSet only (as polydata)
431 if (args.optionFound("pointSet"))
434 pointSet set(mesh, args.option("pointSet"));
436 // Filename as if patch with same name.
437 mkDir(fvPath/set.name());
439 fileName patchFileName
441 fvPath/set.name()/set.name()
447 Info<< " pointSet : " << patchFileName << endl;
449 writePointSet(binary, vMesh, set, patchFileName);
455 // Search for list of objects for this time
456 IOobjectList objects(mesh, runTime.timeName());
458 HashSet<word> selectedFields;
459 if (args.optionFound("fields"))
461 args.optionLookup("fields")() >> selectedFields;
464 // Construct the vol fields (on the original mesh if subsetted)
466 PtrList<volScalarField> vsf;
467 readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vsf);
468 print(" volScalarFields :", Info, vsf);
470 PtrList<volVectorField> vvf;
471 readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vvf);
472 print(" volVectorFields :", Info, vvf);
474 PtrList<volSphericalTensorField> vSpheretf;
475 readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vSpheretf);
476 print(" volSphericalTensorFields :", Info, vSpheretf);
478 PtrList<volSymmTensorField> vSymmtf;
479 readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vSymmtf);
480 print(" volSymmTensorFields :", Info, vSymmtf);
482 PtrList<volTensorField> vtf;
483 readFields(vMesh, vMesh.baseMesh(), objects, selectedFields, vtf);
484 print(" volTensorFields :", Info, vtf);
494 // Construct pointMesh only if nessecary since constructs edge
495 // addressing (expensive on polyhedral meshes)
498 Info<< " pointScalarFields : switched off"
499 << " (\"-noPointValues\" option)\n";
500 Info<< " pointVectorFields : switched off"
501 << " (\"-noPointValues\" option)\n";
504 PtrList<pointScalarField> psf;
505 PtrList<pointVectorField> pvf;
506 PtrList<pointSphericalTensorField> pSpheretf;
507 PtrList<pointSymmTensorField> pSymmtf;
508 PtrList<pointTensorField> ptf;
515 pointMesh::New(vMesh.baseMesh()),
520 print(" pointScalarFields :", Info, psf);
525 pointMesh::New(vMesh.baseMesh()),
530 print(" pointVectorFields :", Info, pvf);
535 pointMesh::New(vMesh.baseMesh()),
540 print(" pointSphericalTensorFields :", Info, pSpheretf);
545 pointMesh::New(vMesh.baseMesh()),
550 print(" pointSymmTensorFields :", Info, pSymmtf);
555 pointMesh::New(vMesh.baseMesh()),
560 print(" pointTensorFields :", Info, ptf);
574 // Create file and write header
584 Info<< " Internal : " << vtkFileName << endl;
587 internalWriter writer(vMesh, binary, vtkFileName);
589 // VolFields + cellID
590 writeFuns::writeCellDataHeader
597 // Write cellID field
598 writer.writeCellIDs();
603 writer.write(vSpheretf);
604 writer.write(vSymmtf);
609 writeFuns::writePointDataHeader
612 vMesh.nFieldPoints(),
613 nVolFields+nPointFields
619 writer.write(pSpheretf);
620 writer.write(pSymmtf);
623 // Interpolated volFields
624 volPointInterpolation pInterp(mesh);
625 writer.write(pInterp, vsf);
626 writer.write(pInterp, vvf);
627 writer.write(pInterp, vSpheretf);
628 writer.write(pInterp, vSymmtf);
629 writer.write(pInterp, vtf);
633 //---------------------------------------------------------------------
635 // Write surface fields
637 //---------------------------------------------------------------------
639 if (args.optionFound("surfaceFields"))
641 PtrList<surfaceScalarField> ssf;
650 print(" surfScalarFields :", Info, ssf);
652 PtrList<surfaceVectorField> svf;
661 print(" surfVectorFields :", Info, svf);
663 if (ssf.size() + svf.size() > 0)
665 // Rework the scalar fields into vectorfields.
666 label sz = svf.size();
668 svf.setSize(sz+ssf.size());
670 surfaceVectorField n(mesh.Sf()/mesh.magSf());
674 svf.set(sz+i, ssf[i]*n);
675 svf[sz+i].rename(ssf[i].name());
679 mkDir(fvPath / "surfaceFields");
681 fileName surfFileName
702 //---------------------------------------------------------------------
704 // Write patches (POLYDATA file, one for each patch)
706 //---------------------------------------------------------------------
708 const polyBoundaryMesh& patches = mesh.boundaryMesh();
712 mkDir(fvPath/"allPatches");
714 fileName patchFileName;
716 if (vMesh.useSubMesh())
719 fvPath/"allPatches"/cellSetName
727 fvPath/"allPatches"/"allPatches"
733 Info<< " Combined patches : " << patchFileName << endl;
741 getSelectedPatches(patches, excludePatches)
744 // VolFields + patchID
745 writeFuns::writeCellDataHeader
752 // Write patchID field
753 writer.writePatchIDs();
758 writer.write(vSpheretf);
759 writer.write(vSymmtf);
764 writeFuns::writePointDataHeader
774 writer.write(pSpheretf);
775 writer.write(pSymmtf);
778 // no interpolated volFields since I cannot be bothered to
779 // create the patchInterpolation for all subpatches.
784 forAll(patches, patchI)
786 const polyPatch& pp = patches[patchI];
788 if (!excludePatches.found(pp.name()))
790 mkDir(fvPath/pp.name());
792 fileName patchFileName;
794 if (vMesh.useSubMesh())
797 fvPath/pp.name()/cellSetName
805 fvPath/pp.name()/pp.name()
811 Info<< " Patch : " << patchFileName << endl;
822 if (!isA<emptyPolyPatch>(pp))
824 // VolFields + patchID
825 writeFuns::writeCellDataHeader
832 // Write patchID field
833 writer.writePatchIDs();
838 writer.write(vSpheretf);
839 writer.write(vSymmtf);
844 writeFuns::writePointDataHeader
855 writer.write(pSpheretf);
856 writer.write(pSymmtf);
859 PrimitivePatchInterpolation<primitivePatch> pInter
864 // Write interpolated volFields
865 writer.write(pInter, vsf);
866 writer.write(pInter, vvf);
867 writer.write(pInter, vSpheretf);
868 writer.write(pInter, vSymmtf);
869 writer.write(pInter, vtf);
876 //---------------------------------------------------------------------
878 // Write faceZones (POLYDATA file, one for each zone)
880 //---------------------------------------------------------------------
884 const faceZoneMesh& zones = mesh.faceZones();
888 const faceZone& pp = zones[zoneI];
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<< " FaceZone : " << patchFileName << endl;
913 std::ofstream str(patchFileName.c_str());
915 writeFuns::writeHeader(str, binary, pp.name());
916 str << "DATASET POLYDATA" << std::endl;
930 //---------------------------------------------------------------------
932 // Write lagrangian data
934 //---------------------------------------------------------------------
936 forAllConstIter(HashSet<fileName>, allCloudDirs, iter)
938 const fileName& cloudName = iter.key();
940 // Always create the cloud directory.
941 mkDir(fvPath/cloud::prefix/cloudName);
943 fileName lagrFileName
945 fvPath/cloud::prefix/cloudName/cloudName
946 + "_" + timeDesc + ".vtk"
949 Info<< " Lagrangian: " << lagrFileName << endl;
952 IOobjectList sprayObjs
956 cloud::prefix/cloudName
959 IOobject* positionsPtr = sprayObjs.lookup("positions");
963 wordList labelNames(sprayObjs.names(labelIOField::typeName));
965 print(Info, labelNames);
967 wordList scalarNames(sprayObjs.names(scalarIOField::typeName));
969 print(Info, scalarNames);
971 wordList vectorNames(sprayObjs.names(vectorIOField::typeName));
973 print(Info, vectorNames);
979 sphericalTensorIOField::typeName
982 Info<< " spherical tensors :";
983 print(Info, sphereNames);
989 symmTensorIOField::typeName
992 Info<< " symm tensors :";
993 print(Info, symmNames);
995 wordList tensorNames(sprayObjs.names(tensorIOField::typeName));
997 print(Info, tensorNames);
999 lagrangianWriter writer
1008 // Write number of fields
1009 writer.writeParcelHeader
1012 + scalarNames.size()
1013 + vectorNames.size()
1014 + sphereNames.size()
1016 + tensorNames.size()
1020 writer.writeIOField<label>(labelNames);
1021 writer.writeIOField<scalar>(scalarNames);
1022 writer.writeIOField<vector>(vectorNames);
1023 writer.writeIOField<sphericalTensor>(sphereNames);
1024 writer.writeIOField<symmTensor>(symmNames);
1025 writer.writeIOField<tensor>(tensorNames);
1029 lagrangianWriter writer
1038 // Write number of fields
1039 writer.writeParcelHeader(0);
1045 //---------------------------------------------------------------------
1047 // Link parallel outputs back to undecomposed case for ease of loading
1049 //---------------------------------------------------------------------
1051 if (Pstream::parRun() && doLinks)
1053 mkDir(runTime.path()/".."/"VTK");
1054 chDir(runTime.path()/".."/"VTK");
1056 Info<< "Linking all processor files to " << runTime.path()/".."/"VTK"
1059 // Get list of vtk files
1063 /"processor" + name(Pstream::myProcNo())
1067 fileNameList dirs(readDir(procVTK, fileName::DIRECTORY));
1068 label sz = dirs.size();
1074 fileNameList subFiles(readDir(procVTK/dirs[i], fileName::FILE));
1078 fileName procFile(procVTK/dirs[i]/subFiles[j]);
1080 if (exists(procFile))
1088 + name(Pstream::myProcNo())
1092 system(cmd.c_str());
1098 Info<< "End\n" << endl;
1104 // ************************************************************************* //