1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | foam-extend: Open Source CFD
4 \\ / O peration | Version: 3.2
5 \\ / A nd | Web: http://www.foam-extend.org
6 \\/ M anipulation | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
9 This file is part of foam-extend.
11 foam-extend 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 3 of the License, or (at your
14 option) any later version.
16 foam-extend is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with foam-extend. If not, see <http://www.gnu.org/licenses/>.
28 Legacy VTK file format writer.
30 - handles volScalar, volVector, pointScalar, pointVector, surfaceScalar
33 - both ascii and binary.
34 - single time step writing.
36 - automatic decomposition of cells; polygons on boundary undecomposed since
45 Write VTK data in ASCII format instead of binary.
47 @param -mesh \<name\>\n
48 Use a different mesh name (instead of -region)
50 @param -fields \<fields\>\n
51 Convert selected fields only. For example,
55 The quoting is required to avoid shell expansions and to pass the
56 information as a single argument.
58 @param -surfaceFields \n
59 Write surfaceScalarFields (e.g., phi)
61 @param -cellSet \<name\>\n
62 @param -faceSet \<name\>\n
63 @param -pointSet \<name\>\n
64 Restrict conversion to the cellSet, faceSet or pointSet.
66 @param -nearCellValue \n
67 Output cell value on patches instead of patch value itself
70 Do not generate file for mesh, only for patches
72 @param -noPointValues \n
75 @param -noFaceZones \n
79 (in parallel) do not link processor files to master
82 Combine all patches into a single file
84 @param -allWallPatches \n
85 Combine all wall patches into a single file
87 @param -excludePatches \<patchNames\>\n
88 Specify patches to exclude. For example,
90 -excludePatches "( inlet_1 inlet_2 )"
92 The quoting is required to avoid shell expansions and to pass the
93 information as a single argument.
95 @param -useTimeName \n
96 use the time index in the VTK file name instead of the time index
99 mesh subset is handled by vtkMesh. Slight inconsistency in
100 interpolation: on the internal field it interpolates the whole volfield
101 to the whole-mesh pointField and then selects only those values it
102 needs for the subMesh (using the fvMeshSubset cellMap(), pointMap()
103 functions). For the patches however it uses the
104 fvMeshSubset.interpolate function to directly interpolate the
105 whole-mesh values onto the subset patch.
107 \*---------------------------------------------------------------------------*/
110 #include "pointMesh.H"
111 #include "volPointInterpolation.H"
112 #include "emptyPolyPatch.H"
113 #include "labelIOField.H"
114 #include "scalarIOField.H"
115 #include "sphericalTensorIOField.H"
116 #include "symmTensorIOField.H"
117 #include "tensorIOField.H"
118 #include "faceZoneMesh.H"
119 #include "CloudTemplate.H"
120 #include "passiveParticle.H"
125 #include "readFields.H"
126 #include "writeFuns.H"
128 #include "internalWriter.H"
129 #include "patchWriter.H"
130 #include "faMeshWriter.H"
131 #include "lagrangianWriter.H"
133 #include "writeFaceSet.H"
134 #include "writePointSet.H"
135 #include "writePatchGeom.H"
136 #include "writeSurfFields.H"
139 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
142 static const label VTK_TETRA = 10;
143 static const label VTK_PYRAMID = 14;
144 static const label VTK_WEDGE = 13;
145 static const label VTK_HEXAHEDRON = 12;
148 template<class GeoField>
149 void print(const char* msg, Ostream& os, const PtrList<GeoField>& flds)
156 os<< ' ' << flds[i].name();
163 void print(Ostream& os, const wordList& flds)
173 labelList getSelectedPatches
175 const polyBoundaryMesh& patches,
176 const HashSet<word>& excludePatches
179 DynamicList<label> patchIDs(patches.size());
181 Info<< "Combining patches:" << endl;
183 forAll(patches, patchI)
185 const polyPatch& pp = patches[patchI];
189 isA<emptyPolyPatch>(pp)
190 || (Pstream::parRun() && isA<processorPolyPatch>(pp))
193 Info<< " discarding empty/processor patch " << patchI
194 << " " << pp.name() << endl;
196 else if (!excludePatches.found(pp.name()))
198 patchIDs.append(patchI);
199 Info<< " patch " << patchI << " " << pp.name() << endl;
202 return patchIDs.shrink();
210 int main(int argc, char *argv[])
212 timeSelector::addOptions();
214 # include "addRegionOption.H"
216 argList::validOptions.insert("fields", "fields");
217 argList::validOptions.insert("cellSet", "cellSet name");
218 argList::validOptions.insert("faceSet", "faceSet name");
219 argList::validOptions.insert("pointSet", "pointSet name");
220 argList::validOptions.insert("ascii","");
221 argList::validOptions.insert("surfaceFields","");
222 argList::validOptions.insert("nearCellValue","");
223 argList::validOptions.insert("noInternal","");
224 argList::validOptions.insert("noPointValues","");
225 argList::validOptions.insert("allPatches","");
226 argList::validOptions.insert("allWallPatches","");
227 argList::validOptions.insert("excludePatches","patches to exclude");
228 argList::validOptions.insert("noFaceZones","");
229 argList::validOptions.insert("faMesh","");
230 argList::validOptions.insert("noLinks","");
231 argList::validOptions.insert("useTimeName","");
233 # include "setRootCase.H"
234 # include "createTime.H"
236 bool doWriteInternal = !args.optionFound("noInternal");
237 bool doFaceZones = !args.optionFound("noFaceZones");
238 bool doLinks = !args.optionFound("noLinks");
239 bool binary = !args.optionFound("ascii");
240 bool useTimeName = args.optionFound("useTimeName");
242 if (binary && (sizeof(floatScalar) != 4 || sizeof(label) != 4))
244 FatalErrorIn(args.executable())
245 << "floatScalar and/or label are not 4 bytes in size" << nl
246 << "Hence cannot use binary VTK format. Please use -ascii"
250 bool nearCellValue = args.optionFound("nearCellValue");
254 Info<< "Using neighbouring cell value instead of patch value"
258 bool noPointValues = args.optionFound("noPointValues");
262 Info<< "Outputting cell values only" << nl << endl;
265 bool allPatches = args.optionFound("allPatches");
266 bool allWallPatches = args.optionFound("allWallPatches");
268 HashSet<word> excludePatches;
269 if (args.optionFound("excludePatches"))
271 args.optionLookup("excludePatches")() >> excludePatches;
273 Info<< "Not including patches " << excludePatches << nl << endl;
279 if (args.optionFound("cellSet"))
281 cellSetName = args.option("cellSet");
282 vtkName = cellSetName;
284 else if (Pstream::parRun())
286 // Strip off leading casename, leaving just processor_DDD ending.
287 vtkName = runTime.caseName();
289 string::size_type i = vtkName.rfind("processor");
291 if (i != string::npos)
293 vtkName = vtkName.substr(i);
298 vtkName = runTime.caseName();
302 instantList timeDirs = timeSelector::select0(runTime, args);
304 # include "createNamedMesh.H"
306 // VTK/ directory in the case
307 fileName fvPath(runTime.path()/"VTK");
308 // Directory of mesh (region0 gets filtered out)
309 fileName regionPrefix = "";
311 if (regionName != polyMesh::defaultRegion)
313 fvPath = fvPath/regionName;
314 regionPrefix = regionName;
321 args.optionFound("time")
322 || args.optionFound("latestTime")
323 || cellSetName.size()
324 || regionName != polyMesh::defaultRegion
327 Info<< "Keeping old VTK files in " << fvPath << nl << endl;
331 Info<< "Deleting old VTK files in " << fvPath << nl << endl;
340 // Mesh wrapper; does subsetting and decomposition
353 // Scan for all possible lagrangian clouds
354 HashSet<fileName> allCloudDirs;
355 forAll(timeDirs, timeI)
357 runTime.setTime(timeDirs[timeI], timeI);
358 fileNameList cloudDirs
362 runTime.timePath()/regionPrefix/cloud::prefix,
368 IOobjectList sprayObjs
372 cloud::prefix/cloudDirs[i]
375 IOobject* positionsPtr = sprayObjs.lookup("positions");
379 if (allCloudDirs.insert(cloudDirs[i]))
381 Info<< "At time: " << runTime.timeName()
382 << " detected cloud directory : " << cloudDirs[i]
390 forAll(timeDirs, timeI)
392 runTime.setTime(timeDirs[timeI], timeI);
394 Info<< "Time: " << runTime.timeName() << endl;
399 timeDesc = runTime.timeName();
403 timeDesc = name(runTime.timeIndex());
406 // Check for new polyMesh/ and update mesh, fvMeshSubset and cell
408 polyMesh::readUpdateState meshState = vMesh.readUpdate();
410 const fvMesh& mesh = vMesh.mesh();
414 meshState == polyMesh::TOPO_CHANGE
415 || meshState == polyMesh::TOPO_PATCH_CHANGE
418 Info<< " Read new mesh" << nl << endl;
422 // If faceSet: write faceSet only (as polydata)
423 if (args.optionFound("faceSet"))
426 faceSet set(mesh, args.option("faceSet"));
428 // Filename as if patch with same name.
429 mkDir(fvPath/set.name());
431 fileName patchFileName
433 fvPath/set.name()/set.name()
439 Info<< " FaceSet : " << patchFileName << endl;
441 writeFaceSet(binary, vMesh, set, patchFileName);
445 // If pointSet: write pointSet only (as polydata)
446 if (args.optionFound("pointSet"))
449 pointSet set(mesh, args.option("pointSet"));
451 // Filename as if patch with same name.
452 mkDir(fvPath/set.name());
454 fileName patchFileName
456 fvPath/set.name()/set.name()
462 Info<< " pointSet : " << patchFileName << endl;
464 writePointSet(binary, vMesh, set, patchFileName);
470 // Search for list of objects for this time
471 IOobjectList objects(mesh, runTime.timeName());
473 HashSet<word> selectedFields;
474 if (args.optionFound("fields"))
476 args.optionLookup("fields")() >> selectedFields;
479 // Construct the vol fields (on the original mesh if subsetted)
481 PtrList<volScalarField> vsf;
482 readFields(vMesh, vMesh, objects, selectedFields, vsf);
483 readFields(vMesh, vMesh, objects, selectedFields, vsf);
484 print(" volScalarFields :", Info, vsf);
486 PtrList<volVectorField> vvf;
487 readFields(vMesh, vMesh, objects, selectedFields, vvf);
488 print(" volVectorFields :", Info, vvf);
490 PtrList<volSphericalTensorField> vSpheretf;
491 readFields(vMesh, vMesh, objects, selectedFields, vSpheretf);
492 print(" volSphericalTensorFields :", Info, vSpheretf);
494 PtrList<volSymmTensorField> vSymmtf;
495 readFields(vMesh, vMesh, objects, selectedFields, vSymmtf);
496 print(" volSymmTensorFields :", Info, vSymmtf);
498 PtrList<volTensorField> vtf;
499 readFields(vMesh, vMesh, objects, selectedFields, vtf);
500 print(" volTensorFields :", Info, vtf);
502 const label nVolFields =
510 // Construct pointMesh only if nessecary since constructs edge
511 // addressing (expensive on polyhedral meshes)
514 Info<< " pointScalarFields : switched off"
515 << " (\"-noPointValues\" option)\n";
516 Info<< " pointVectorFields : switched off"
517 << " (\"-noPointValues\" option)\n";
520 PtrList<pointScalarField> psf;
521 PtrList<pointVectorField> pvf;
522 PtrList<pointSphericalTensorField> pSpheretf;
523 PtrList<pointSymmTensorField> pSymmtf;
524 PtrList<pointTensorField> ptf;
531 pointMesh::New(vMesh),
536 print(" pointScalarFields :", Info, psf);
541 pointMesh::New(vMesh),
546 print(" pointVectorFields :", Info, pvf);
551 pointMesh::New(vMesh),
556 print(" pointSphericalTensorFields :", Info, pSpheretf);
561 pointMesh::New(vMesh),
566 print(" pointSymmTensorFields :", Info, pSymmtf);
571 pointMesh::New(vMesh),
576 print(" pointTensorFields :", Info, ptf);
590 // Create file and write header
600 Info<< " Internal : " << vtkFileName << endl;
603 internalWriter writer(vMesh, binary, vtkFileName);
605 // VolFields + cellID
606 writeFuns::writeCellDataHeader
613 // Write cellID field
614 writer.writeCellIDs();
619 writer.write(vSpheretf);
620 writer.write(vSymmtf);
625 writeFuns::writePointDataHeader
628 vMesh.nFieldPoints(),
629 nVolFields+nPointFields
635 writer.write(pSpheretf);
636 writer.write(pSymmtf);
639 // Interpolated volFields
640 volPointInterpolation pInterp(mesh);
641 writer.write(pInterp, vsf);
642 writer.write(pInterp, vvf);
643 writer.write(pInterp, vSpheretf);
644 writer.write(pInterp, vSymmtf);
645 writer.write(pInterp, vtf);
649 //---------------------------------------------------------------------
651 // Write surface fields
653 //---------------------------------------------------------------------
655 if (args.optionFound("surfaceFields"))
657 PtrList<surfaceScalarField> ssf;
666 print(" surfScalarFields :", Info, ssf);
668 PtrList<surfaceVectorField> svf;
677 print(" surfVectorFields :", Info, svf);
679 if (ssf.size() + svf.size() > 0)
681 // Rework the scalar fields into vectorfields.
682 label sz = svf.size();
684 svf.setSize(sz+ssf.size());
686 surfaceVectorField n(mesh.Sf()/mesh.magSf());
690 svf.set(sz+i, ssf[i]*n);
691 svf[sz+i].rename(ssf[i].name());
695 mkDir(fvPath / "surfaceFields");
697 fileName surfFileName
718 //---------------------------------------------------------------------
720 // Write patches (POLYDATA file, one for each patch)
722 //---------------------------------------------------------------------
724 const polyBoundaryMesh& patches = mesh.boundaryMesh();
728 mkDir(fvPath/"allPatches");
730 fileName patchFileName;
732 if (vMesh.useSubMesh())
735 fvPath/"allPatches"/cellSetName
743 fvPath/"allPatches"/"allPatches"
749 Info<< " Combined patches : " << patchFileName << endl;
757 getSelectedPatches(patches, excludePatches)
760 // VolFields + patchID
761 writeFuns::writeCellDataHeader
768 // Write patchID field
769 writer.writePatchIDs();
774 writer.write(vSpheretf);
775 writer.write(vSymmtf);
780 writeFuns::writePointDataHeader
790 writer.write(pSpheretf);
791 writer.write(pSymmtf);
794 // no interpolated volFields since I cannot be bothered to
795 // create the patchInterpolation for all subpatches.
798 else if (allWallPatches)
800 mkDir(fvPath/"allWallPatches");
802 fileName wallPatchFileName;
804 if (vMesh.useSubMesh())
807 fvPath/"allWallPatches"/cellSetName
815 fvPath/"allWallPatches"/"allWallPatches"
821 // Go through the boundary and add all patches that are not
822 // of type wall onto the exclude{atches list
823 forAll (patches, patchI)
825 if (!isA<wallPolyPatch>(patches[patchI]))
827 excludePatches.insert(patches[patchI].name());
831 Info<< " Combined wall patches : " << wallPatchFileName
840 getSelectedPatches(patches, excludePatches)
843 // VolFields + patchID
844 writeFuns::writeCellDataHeader
851 // Write patchID field
852 writer.writePatchIDs();
857 writer.write(vSpheretf);
858 writer.write(vSymmtf);
863 writeFuns::writePointDataHeader
873 writer.write(pSpheretf);
874 writer.write(pSymmtf);
877 // no interpolated volFields since I cannot be bothered to
878 // create the patchInterpolation for all subpatches.
883 forAll(patches, patchI)
885 const polyPatch& pp = patches[patchI];
887 if (!excludePatches.found(pp.name()))
889 mkDir(fvPath/pp.name());
891 fileName patchFileName;
893 if (vMesh.useSubMesh())
896 fvPath/pp.name()/cellSetName
904 fvPath/pp.name()/pp.name()
910 Info<< " Patch : " << patchFileName << endl;
921 if (!isA<emptyPolyPatch>(pp))
923 // VolFields + patchID
924 writeFuns::writeCellDataHeader
931 // Write patchID field
932 writer.writePatchIDs();
937 writer.write(vSpheretf);
938 writer.write(vSymmtf);
943 writeFuns::writePointDataHeader
954 writer.write(pSpheretf);
955 writer.write(pSymmtf);
958 PrimitivePatchInterpolation<primitivePatch> pInter
963 // Write interpolated volFields
964 writer.write(pInter, vsf);
965 writer.write(pInter, vvf);
966 writer.write(pInter, vSpheretf);
967 writer.write(pInter, vSymmtf);
968 writer.write(pInter, vtf);
975 //---------------------------------------------------------------------
977 // Write faceZones (POLYDATA file, one for each zone)
979 //---------------------------------------------------------------------
983 const faceZoneMesh& zones = mesh.faceZones();
987 const faceZone& pp = zones[zoneI];
989 mkDir(fvPath/pp.name());
991 fileName patchFileName;
993 if (vMesh.useSubMesh())
996 fvPath/pp.name()/cellSetName
1004 fvPath/pp.name()/pp.name()
1010 Info<< " FaceZone : " << patchFileName << endl;
1012 std::ofstream str(patchFileName.c_str());
1014 writeFuns::writeHeader(str, binary, pp.name());
1015 str << "DATASET POLYDATA" << std::endl;
1029 //---------------------------------------------------------------------
1031 // Write finite area data
1033 //---------------------------------------------------------------------
1035 if (args.options().found("faMesh"))
1037 mkDir(fvPath/"faMesh");
1039 fileName faFileName =
1040 fvPath/"faMesh"/"faMesh"
1046 faMesh aMesh(vMesh.mesh());
1048 PtrList<areaScalarField> asf;
1049 readFieldsNoSubset(vMesh, aMesh, objects, selectedFields, asf);
1050 print(" areaScalarFields :", Info, asf);
1052 PtrList<areaVectorField> avf;
1053 readFieldsNoSubset(vMesh, aMesh, objects, selectedFields, avf);
1054 print(" areaVectorFields :", Info, avf);
1056 const label nAreaFields =
1067 writeFuns::writeCellDataHeader
1080 writeFuns::writePointDataHeader
1087 // Interpolated areaFields
1088 PrimitivePatchInterpolation<indirectPrimitivePatch> pInterp
1092 writer.write(pInterp, asf);
1093 writer.write(pInterp, avf);
1097 //---------------------------------------------------------------------
1099 // Write lagrangian data
1101 //---------------------------------------------------------------------
1103 forAllConstIter(HashSet<fileName>, allCloudDirs, iter)
1105 const fileName& cloudName = iter.key();
1107 // Always create the cloud directory.
1108 mkDir(fvPath/cloud::prefix/cloudName);
1110 fileName lagrFileName
1112 fvPath/cloud::prefix/cloudName/cloudName
1113 + "_" + timeDesc + ".vtk"
1116 Info<< " Lagrangian: " << lagrFileName << endl;
1119 IOobjectList sprayObjs
1123 cloud::prefix/cloudName
1126 IOobject* positionsPtr = sprayObjs.lookup("positions");
1130 wordList labelNames(sprayObjs.names(labelIOField::typeName));
1132 print(Info, labelNames);
1134 wordList scalarNames(sprayObjs.names(scalarIOField::typeName));
1135 Info<< " scalars :";
1136 print(Info, scalarNames);
1138 wordList vectorNames(sprayObjs.names(vectorIOField::typeName));
1139 Info<< " vectors :";
1140 print(Info, vectorNames);
1142 wordList sphereNames
1146 sphericalTensorIOField::typeName
1149 Info<< " spherical tensors :";
1150 print(Info, sphereNames);
1156 symmTensorIOField::typeName
1159 Info<< " symm tensors :";
1160 print(Info, symmNames);
1162 wordList tensorNames(sprayObjs.names(tensorIOField::typeName));
1163 Info<< " tensors :";
1164 print(Info, tensorNames);
1166 lagrangianWriter writer
1175 // Write number of fields
1176 writer.writeParcelHeader
1179 + scalarNames.size()
1180 + vectorNames.size()
1181 + sphereNames.size()
1183 + tensorNames.size()
1187 writer.writeIOField<label>(labelNames);
1188 writer.writeIOField<scalar>(scalarNames);
1189 writer.writeIOField<vector>(vectorNames);
1190 writer.writeIOField<sphericalTensor>(sphereNames);
1191 writer.writeIOField<symmTensor>(symmNames);
1192 writer.writeIOField<tensor>(tensorNames);
1196 lagrangianWriter writer
1205 // Write number of fields
1206 writer.writeParcelHeader(0);
1212 //---------------------------------------------------------------------
1214 // Link parallel outputs back to undecomposed case for ease of loading
1216 //---------------------------------------------------------------------
1218 if (Pstream::parRun() && doLinks)
1220 mkDir(runTime.path()/".."/"VTK");
1221 chDir(runTime.path()/".."/"VTK");
1223 Info<< "Linking all processor files to " << runTime.path()/".."/"VTK"
1226 // Get list of vtk files
1230 /"processor" + name(Pstream::myProcNo())
1234 fileNameList dirs(readDir(procVTK, fileName::DIRECTORY));
1235 label sz = dirs.size();
1241 fileNameList subFiles(readDir(procVTK/dirs[i], fileName::FILE));
1245 fileName procFile(procVTK/dirs[i]/subFiles[j]);
1247 if (exists(procFile))
1255 + name(Pstream::myProcNo())
1259 system(cmd.c_str());
1265 Info<< "End\n" << endl;
1271 // ************************************************************************* //