1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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, see <http://www.gnu.org/licenses/>.
25 Write out the OpenFOAM mesh in Version 3.0 Fieldview-UNS format (binary).
27 See Fieldview Release 9 Reference Manual - Appendix D
28 (Unstructured Data Format)
29 Borrows various from uns/write_binary_uns.c from FieldView dist.
31 \*---------------------------------------------------------------------------*/
34 #include "timeSelector.H"
35 #include "volFields.H"
36 #include "surfaceFields.H"
37 #include "pointFields.H"
38 #include "scalarIOField.H"
39 #include "volPointInterpolation.H"
40 #include "wallFvPatch.H"
41 #include "symmetryFvPatch.H"
44 #include "passiveParticle.H"
46 #include "IOobjectList.H"
48 #include "stringList.H"
49 #include "cellModeller.H"
51 #include "floatScalar.H"
52 #include "calcFaceAddressing.H"
53 #include "writeFunctions.H"
54 #include "fieldviewTopology.H"
58 #include "fv_reader_tags.h"
62 unsigned int fv_encode_elem_header(int elem_type, int wall_info[]);
67 typedef Field<floatScalar> floatField;
70 static HashTable<word> FieldviewNames;
73 static word getFieldViewName(const word& foamName)
75 if (FieldviewNames.found(foamName))
77 return FieldviewNames[foamName];
86 static void printNames(const wordList& names, Ostream& os)
90 Info<< " " << names[fieldI] << '/' << getFieldViewName(names[fieldI]);
95 // Count number of vertices used by celli
96 static label countVerts(const primitiveMesh& mesh, const label celli)
98 const cell& cll = mesh.cells()[celli];
100 // Count number of vertices used
101 labelHashSet usedVerts(10*cll.size());
103 forAll(cll, cellFacei)
105 const face& f = mesh.faces()[cll[cellFacei]];
109 if (!usedVerts.found(f[fp]))
111 usedVerts.insert(f[fp]);
115 return usedVerts.toc().size();
119 static void writeFaceData
121 const polyMesh& mesh,
122 const fieldviewTopology& topo,
124 const scalarField& patchField,
125 const bool writePolyFaces,
126 std::ofstream& fvFile
129 const polyPatch& pp = mesh.boundaryMesh()[patchI];
131 // Start off with dummy value.
134 floatField fField(topo.nPolyFaces()[patchI], 0.0);
136 // Fill selected faces with field values
138 forAll(patchField, faceI)
140 if (pp[faceI].size() > 4)
142 fField[polyFaceI++] = float(patchField[faceI]);
148 reinterpret_cast<char*>(fField.begin()), fField.size()*sizeof(float)
153 floatField fField(pp.size() - topo.nPolyFaces()[patchI], 0.0);
155 // Fill selected faces with field values
157 forAll(patchField, faceI)
159 if (pp[faceI].size() <= 4)
161 fField[quadFaceI++] = float(patchField[faceI]);
167 reinterpret_cast<char*>(fField.begin()), fField.size()*sizeof(float)
173 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
176 int main(int argc, char *argv[])
178 argList::noParallel();
179 argList::addBoolOption
182 "skip setting wall information"
184 timeSelector::addOptions(true, false);
186 # include "addRegionOption.H"
188 # include "setRootCase.H"
189 # include "createTime.H"
191 instantList timeDirs = timeSelector::select0(runTime, args);
193 # include "createNamedMesh.H"
195 // Initialize name mapping table
196 FieldviewNames.insert("alpha", "aalpha");
197 FieldviewNames.insert("Alpha", "AAlpha");
198 FieldviewNames.insert("fsmach", "ffsmach");
199 FieldviewNames.insert("FSMach", "FFSMach");
200 FieldviewNames.insert("re", "rre");
201 FieldviewNames.insert("Re", "RRe");
202 FieldviewNames.insert("time", "ttime");
203 FieldviewNames.insert("Time", "TTime");
204 FieldviewNames.insert("pi", "ppi");
205 FieldviewNames.insert("PI", "PPI");
206 FieldviewNames.insert("x", "xx");
207 FieldviewNames.insert("X", "XX");
208 FieldviewNames.insert("y", "yy");
209 FieldviewNames.insert("Y", "YY");
210 FieldviewNames.insert("z", "zz");
211 FieldviewNames.insert("Z", "ZZ");
212 FieldviewNames.insert("rcyl", "rrcyl");
213 FieldviewNames.insert("Rcyl", "RRcyl");
214 FieldviewNames.insert("theta", "ttheta");
215 FieldviewNames.insert("Theta", "TTheta");
216 FieldviewNames.insert("rsphere", "rrsphere");
217 FieldviewNames.insert("Rsphere", "RRsphere");
218 FieldviewNames.insert("k", "kk");
219 FieldviewNames.insert("K", "KK");
222 // Scan for all available fields, in all timesteps
223 // volScalarNames : all scalar fields
224 // volVectorNames : ,, vector ,,
225 // surfScalarNames : surface fields
226 // surfVectorNames : ,,
227 // sprayScalarNames: spray fields
228 // sprayVectorNames: ,,
229 # include "getFieldNames.H"
231 bool hasLagrangian = false;
232 if (sprayScalarNames.size() || sprayVectorNames.size())
234 hasLagrangian = true;
237 Info<< "All fields: Foam/Fieldview" << endl;
238 Info<< " volScalar :";
239 printNames(volScalarNames, Info);
241 Info<< " volVector :";
242 printNames(volVectorNames, Info);
244 Info<< " surfScalar :";
245 printNames(surfScalarNames, Info);
247 Info<< " surfVector :";
248 printNames(surfVectorNames, Info);
250 Info<< " sprayScalar :";
251 printNames(sprayScalarNames, Info);
253 Info<< " sprayVector :";
254 printNames(sprayVectorNames, Info);
262 // make a directory called FieldView in the case
263 fileName fvPath(runTime.path()/"Fieldview");
265 if (regionName != polyMesh::defaultRegion)
267 fvPath = fvPath/regionName;
272 if (regionName != polyMesh::defaultRegion)
274 Info<< "Keeping old FieldView files in " << fvPath << nl << endl;
278 Info<< "Deleting old FieldView files in " << fvPath << nl << endl;
285 fileName fvParticleFileName(fvPath/runTime.caseName() + ".fvp");
288 Info<< "Opening particle file " << fvParticleFileName << endl;
290 std::ofstream fvParticleFile(fvParticleFileName.c_str());
292 // Write spray file header
295 # include "writeSprayHeader.H"
298 // Current mesh. Start off from unloaded mesh.
299 autoPtr<fieldviewTopology> topoPtr(NULL);
301 label fieldViewTime = 0;
303 forAll(timeDirs, timeI)
305 runTime.setTime(timeDirs[timeI], timeI);
306 Info<< "Time: " << runTime.timeName() << endl;
308 fvMesh::readUpdateState state = mesh.readUpdate();
313 || state == fvMesh::TOPO_CHANGE
314 || state == fvMesh::TOPO_PATCH_CHANGE
317 // Mesh topo changed. Update Fieldview topo.
321 new fieldviewTopology
324 !args.optionFound("noWall")
328 Info<< " Mesh read:" << endl
329 << " tet : " << topoPtr().nTet() << endl
330 << " hex : " << topoPtr().nHex() << endl
331 << " prism : " << topoPtr().nPrism() << endl
332 << " pyr : " << topoPtr().nPyr() << endl
333 << " poly : " << topoPtr().nPoly() << endl
336 else if (state == fvMesh::POINTS_MOVED)
338 // points exists for time step, let's read them
339 Info<< " Points file detected - updating points" << endl;
342 const fieldviewTopology& topo = topoPtr();
346 // Create file and write header
351 fvPath/runTime.caseName() + "_" + Foam::name(timeI) + ".uns"
354 Info<< " file:" << fvFileName.c_str() << endl;
357 std::ofstream fvFile(fvFileName.c_str());
359 //Info<< "Writing header ..." << endl;
361 // Output the magic number.
362 writeInt(fvFile, FV_MAGIC);
364 // Output file header and version number.
365 writeStr80(fvFile, "FIELDVIEW");
367 // This version of the FIELDVIEW unstructured file is "3.0".
368 // This is written as two integers.
373 // File type code. Grid and results.
374 writeInt(fvFile, FV_COMBINED_FILE);
376 // Reserved field, always zero
379 // Output constants for time, fsmach, alpha and re.
381 fBuf[0] = runTime.value();
385 fvFile.write(reinterpret_cast<char*>(fBuf), 4*sizeof(float));
388 // Output the number of grids
395 //Info<< "Writing boundary table ..." << endl;
398 writeInt(fvFile, mesh.boundary().size());
400 forAll(mesh.boundary(), patchI)
402 const fvPatch& currPatch = mesh.boundary()[patchI];
404 writeInt(fvFile, 1); // data present
405 writeInt(fvFile, 1); // normals ok
408 writeStr80(fvFile, currPatch.name().c_str());
414 // volFieldPtrs : List of ptrs to all volScalar/Vector fields
415 // (null if field not present at current time)
416 // volFieldNames : FieldView compatible names of volFields
417 // surfFieldPtrs : same for surfaceScalar/Vector
419 # include "createFields.H"
424 // Write Variables table
427 //Info<< "Writing variables table ..." << endl;
429 writeInt(fvFile, volFieldNames.size());
430 forAll(volFieldNames, fieldI)
432 if (volFieldPtrs[fieldI] == NULL)
434 Info<< " dummy field for "
435 << volFieldNames[fieldI].c_str() << endl;
438 writeStr80(fvFile, volFieldNames[fieldI].c_str());
442 // Write Boundary Variables table = vol + surface fields
445 //Info<< "Writing boundary variables table ..." << endl;
450 volFieldNames.size() + surfFieldNames.size()
452 forAll(volFieldNames, fieldI)
454 writeStr80(fvFile, volFieldNames[fieldI].c_str());
456 forAll(surfFieldNames, fieldI)
458 if (surfFieldPtrs[fieldI] == NULL)
460 Info<< " dummy surface field for "
461 << surfFieldNames[fieldI].c_str() << endl;
464 writeStr80(fvFile, surfFieldNames[fieldI].c_str());
474 //Info<< "Writing points ..." << endl;
476 const pointField& points = mesh.points();
477 label nPoints = points.size();
479 writeInt(fvFile, FV_NODES);
480 writeInt(fvFile, nPoints);
482 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
484 floatField fField(nPoints);
486 for (label pointi = 0; pointi<nPoints; pointi++)
488 fField[pointi] = float(points[pointi][cmpt]);
493 reinterpret_cast<char*>(fField.begin()),
494 fField.size()*sizeof(float)
499 // Boundary Faces - regular
502 //Info<< "Writing regular boundary faces ..." << endl;
504 forAll(mesh.boundary(), patchI)
506 label nQuadFaces = topo.quadFaceLabels()[patchI].size()/4;
510 writeInt(fvFile, FV_FACES);
511 writeInt(fvFile, patchI + 1); // patch number
512 writeInt(fvFile, nQuadFaces); // number of faces in patch
515 reinterpret_cast<const char*>
516 (topo.quadFaceLabels()[patchI].begin()),
517 nQuadFaces*4*sizeof(int)
523 // Boundary Faces - arbitrary polygon
526 //Info<< "Write polygonal boundary faces ..." << endl;
528 forAll(mesh.boundary(), patchI)
530 if (topo.nPolyFaces()[patchI] > 0)
532 writeInt(fvFile, FV_ARB_POLY_FACES);
533 writeInt(fvFile, patchI + 1);
535 // number of arb faces in patch
536 writeInt(fvFile, topo.nPolyFaces()[patchI]);
538 const polyPatch& patchFaces = mesh.boundary()[patchI].patch();
540 forAll(patchFaces, faceI)
542 const face& f = patchFaces[faceI];
546 writeInt(fvFile, f.size());
550 writeInt(fvFile, f[fp] + 1);
559 // Write regular topology
562 //Info<< "Writing regular elements ..." << endl;
564 writeInt(fvFile, FV_ELEMENTS);
565 writeInt(fvFile, topo.nTet());
566 writeInt(fvFile, topo.nHex());
567 writeInt(fvFile, topo.nPrism());
568 writeInt(fvFile, topo.nPyr());
571 reinterpret_cast<const char*>(topo.tetLabels().begin()),
572 topo.nTet()*(1+4)*sizeof(int)
576 reinterpret_cast<const char*>(topo.hexLabels().begin()),
577 topo.nHex()*(1+8)*sizeof(int)
581 reinterpret_cast<const char*>(topo.prismLabels().begin()),
582 topo.nPrism()*(1+6)*sizeof(int)
586 reinterpret_cast<const char*>(topo.pyrLabels().begin()),
587 topo.nPyr()*(1+5)*sizeof(int)
592 // Write arbitrary polyhedra
595 //Info<< "Writing polyhedral elements ..." << endl;
598 const cellShapeList& cellShapes = mesh.cellShapes();
599 const cellModel& unknown = *(cellModeller::lookup("unknown"));
601 if (topo.nPoly() > 0)
603 writeInt(fvFile, FV_ARB_POLY_ELEMENTS);
604 writeInt(fvFile, topo.nPoly());
606 forAll(cellShapes, celli)
608 if (cellShapes[celli].model() == unknown)
610 const cell& cll = mesh.cells()[celli];
613 writeInt(fvFile, cll.size());
614 // number of vertices used (no cell centre)
615 writeInt(fvFile, countVerts(mesh, celli));
616 // cell centre node id
617 writeInt(fvFile, -1);
619 forAll(cll, cellFacei)
621 label faceI = cll[cellFacei];
623 const face& f = mesh.faces()[faceI];
625 // Not a wall for now
626 writeInt(fvFile, NOT_A_WALL);
628 writeInt(fvFile, f.size());
630 if (mesh.faceOwner()[faceI] == celli)
634 writeInt(fvFile, f[fp]+1);
639 for (label fp = f.size()-1; fp >= 0; fp--)
641 writeInt(fvFile, f[fp]+1);
645 // Number of hanging nodes
657 //Info<< "Writing variables data ..." << endl;
659 volPointInterpolation pInterp(mesh);
661 writeInt(fvFile, FV_VARIABLES);
664 forAll(volFieldPtrs, fieldI)
666 if (volFieldPtrs[fieldI] != NULL)
668 const volScalarField& vField = *volFieldPtrs[fieldI];
670 // Interpolate to points
671 pointScalarField psf(pInterp.interpolate(vField));
673 floatField fField(nPoints);
675 for (label pointi = 0; pointi<nPoints; pointi++)
677 fField[pointi] = float(psf[pointi]);
682 reinterpret_cast<char*>(fField.begin()),
683 fField.size()*sizeof(float)
688 // Create dummy field
689 floatField dummyField(nPoints, 0.0);
693 reinterpret_cast<char*>(dummyField.begin()),
694 dummyField.size()*sizeof(float)
701 // Boundary variables data
705 //Info<< "Writing regular boundary elements data ..." << endl;
707 writeInt(fvFile, FV_BNDRY_VARS);
709 forAll(volFieldPtrs, fieldI)
711 if (volFieldPtrs[fieldI] != NULL)
713 const volScalarField& vsf = *volFieldPtrs[fieldI];
715 forAll(mesh.boundary(), patchI)
722 vsf.boundaryField()[patchI],
730 forAll(mesh.boundaryMesh(), patchI)
735 mesh.boundaryMesh()[patchI].size()
736 - topo.nPolyFaces()[patchI],
742 reinterpret_cast<char*>(fField.begin()),
743 fField.size()*sizeof(float)
750 forAll(surfFieldPtrs, fieldI)
752 if (surfFieldPtrs[fieldI] != NULL)
754 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
756 forAll(mesh.boundary(), patchI)
763 ssf.boundaryField()[patchI],
771 forAll(mesh.boundaryMesh(), patchI)
776 mesh.boundaryMesh()[patchI].size()
777 - topo.nPolyFaces()[patchI],
783 reinterpret_cast<char*>(fField.begin()),
784 fField.size()*sizeof(float)
791 // Polygonal faces boundary data
795 //Info<< "Writing polygonal boundary elements data ..." << endl;
797 writeInt(fvFile, FV_ARB_POLY_BNDRY_VARS);
798 forAll(volFieldPtrs, fieldI)
800 if (volFieldPtrs[fieldI] != NULL)
802 const volScalarField& vsf = *volFieldPtrs[fieldI];
804 // All non-empty patches
805 forAll(mesh.boundary(), patchI)
812 vsf.boundaryField()[patchI],
820 forAll(mesh.boundary(), patchI)
823 floatField fField(topo.nPolyFaces()[patchI], 0.0);
827 reinterpret_cast<char*>(fField.begin()),
828 fField.size()*sizeof(float)
835 forAll(surfFieldPtrs, fieldI)
837 if (surfFieldPtrs[fieldI] != NULL)
839 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
841 // All non-empty patches
842 forAll(mesh.boundary(), patchI)
849 ssf.boundaryField()[patchI],
857 forAll(mesh.boundaryMesh(), patchI)
862 mesh.boundaryMesh()[patchI].size()
863 - topo.nPolyFaces()[patchI],
869 reinterpret_cast<char*>(fField.begin()),
870 fField.size()*sizeof(float)
878 // Cleanup volume and surface fields
880 forAll(volFieldPtrs, fieldI)
882 delete volFieldPtrs[fieldI];
884 forAll(surfFieldPtrs, fieldI)
886 delete surfFieldPtrs[fieldI];
897 // Read/create fields:
898 // sprayScalarFieldPtrs: List of ptrs to lagrangian scalfields
899 // sprayVectorFieldPtrs: ,, vec ,,
900 # include "createSprayFields.H"
905 // Time index (FieldView: has to start from 1)
906 writeInt(fvParticleFile, fieldViewTime + 1);
909 writeFloat(fvParticleFile, runTime.value());
912 Cloud<passiveParticle> parcels(mesh);
915 writeInt(fvParticleFile, parcels.size());
917 Info<< " Writing " << parcels.size() << " particles." << endl;
921 // Output data parcelwise
929 Cloud<passiveParticle>::iterator elmnt = parcels.begin();
930 elmnt != parcels.end();
934 writeInt(fvParticleFile, parcelNo+1);
936 writeFloat(fvParticleFile, elmnt().position().x());
937 writeFloat(fvParticleFile, elmnt().position().y());
938 writeFloat(fvParticleFile, elmnt().position().z());
940 forAll(sprayScalarFieldPtrs, fieldI)
942 if (sprayScalarFieldPtrs[fieldI] != NULL)
944 const IOField<scalar>& sprayField =
945 *sprayScalarFieldPtrs[fieldI];
954 writeFloat(fvParticleFile, 0.0);
957 forAll(sprayVectorFieldPtrs, fieldI)
959 if (sprayVectorFieldPtrs[fieldI] != NULL)
961 const IOField<vector>& sprayVectorField =
962 *sprayVectorFieldPtrs[fieldI];
964 sprayVectorField[parcelNo];
966 writeFloat(fvParticleFile, val.x());
967 writeFloat(fvParticleFile, val.y());
968 writeFloat(fvParticleFile, val.z());
972 writeFloat(fvParticleFile, 0.0);
973 writeFloat(fvParticleFile, 0.0);
974 writeFloat(fvParticleFile, 0.0);
979 // increment fieldView particle time
984 // Cleanup spray fields
986 forAll(sprayScalarFieldPtrs, fieldI)
988 delete sprayScalarFieldPtrs[fieldI];
990 forAll(sprayVectorFieldPtrs, fieldI)
992 delete sprayVectorFieldPtrs[fieldI];
995 } // end of hasLagrangian
1000 rm(fvParticleFileName);
1003 Info<< "End\n" << endl;
1009 // ************************************************************************* //