1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2008 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
26 Write out the FOAM 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 "volFields.H"
35 #include "surfaceFields.H"
36 #include "pointFields.H"
37 #include "scalarIOField.H"
38 #include "volPointInterpolation.H"
39 #include "wallFvPatch.H"
40 #include "symmetryFvPatch.H"
43 #include "passiveParticle.H"
45 #include "IOobjectList.H"
47 #include "stringList.H"
48 #include "DynamicList.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::validOptions.insert("noWall", "");
181 # include "addTimeOptions.H"
182 # include "setRootCase.H"
183 # include "createTime.H"
185 instantList Times = runTime.times();
187 # include "checkTimeOptions.H"
189 runTime.setTime(Times[startTime], startTime);
191 # include "createMesh.H"
194 // Initialize name mapping table
195 FieldviewNames.insert("alpha", "aalpha");
196 FieldviewNames.insert("Alpha", "AAlpha");
197 FieldviewNames.insert("fsmach", "ffsmach");
198 FieldviewNames.insert("FSMach", "FFSMach");
199 FieldviewNames.insert("re", "rre");
200 FieldviewNames.insert("Re", "RRe");
201 FieldviewNames.insert("time", "ttime");
202 FieldviewNames.insert("Time", "TTime");
203 FieldviewNames.insert("pi", "ppi");
204 FieldviewNames.insert("PI", "PPI");
205 FieldviewNames.insert("x", "xx");
206 FieldviewNames.insert("X", "XX");
207 FieldviewNames.insert("y", "yy");
208 FieldviewNames.insert("Y", "YY");
209 FieldviewNames.insert("z", "zz");
210 FieldviewNames.insert("Z", "ZZ");
211 FieldviewNames.insert("rcyl", "rrcyl");
212 FieldviewNames.insert("Rcyl", "RRcyl");
213 FieldviewNames.insert("theta", "ttheta");
214 FieldviewNames.insert("Theta", "TTheta");
215 FieldviewNames.insert("rsphere", "rrsphere");
216 FieldviewNames.insert("Rsphere", "RRsphere");
217 FieldviewNames.insert("k", "kk");
218 FieldviewNames.insert("K", "KK");
221 // Scan for all available fields, in all timesteps
222 // volScalarNames : all scalar fields
223 // volVectorNames : ,, vector ,,
224 // surfScalarNames : surface fields
225 // surfVectorNames : ,,
226 // sprayScalarNames: spray fields
227 // sprayVectorNames: ,,
228 # include "getFieldNames.H"
230 bool hasLagrangian = false;
231 if ((sprayScalarNames.size() > 0) || (sprayVectorNames.size() > 0))
233 hasLagrangian = true;
236 Info<< "All fields: Foam/Fieldview" << endl;
237 Info<< " volScalar :";
238 printNames(volScalarNames, Info);
240 Info<< " volVector :";
241 printNames(volVectorNames, Info);
243 Info<< " surfScalar :";
244 printNames(surfScalarNames, Info);
246 Info<< " surfVector :";
247 printNames(surfVectorNames, Info);
249 Info<< " sprayScalar :";
250 printNames(sprayScalarNames, Info);
252 Info<< " sprayVector :";
253 printNames(sprayVectorNames, Info);
261 // make a directory called FieldView in the case
262 fileName fvPath(runTime.path()/"Fieldview");
271 fileName fvParticleFileName(fvPath/runTime.caseName() + ".fvp");
274 Info<< "Opening particle file " << fvParticleFileName << endl;
276 std::ofstream fvParticleFile(fvParticleFileName.c_str());
278 // Write spray file header
281 # include "writeSprayHeader.H"
284 // Current mesh. Start off from unloaded mesh.
285 autoPtr<fieldviewTopology> topoPtr(NULL);
287 label fieldViewTime = 0;
289 for (label i=startTime; i<endTime; i++)
291 runTime.setTime(Times[i], i);
293 Info<< "Time " << Times[i].name() << endl;
295 fvMesh::readUpdateState state = mesh.readUpdate();
300 || state == fvMesh::TOPO_CHANGE
301 || state == fvMesh::TOPO_PATCH_CHANGE
304 // Mesh topo changed. Update Fieldview topo.
308 new fieldviewTopology
311 !args.options().found("noWall")
315 Info<< " Mesh read:" << endl
316 << " tet : " << topoPtr().nTet() << endl
317 << " hex : " << topoPtr().nHex() << endl
318 << " prism : " << topoPtr().nPrism() << endl
319 << " pyr : " << topoPtr().nPyr() << endl
320 << " poly : " << topoPtr().nPoly() << endl
323 else if (state == fvMesh::POINTS_MOVED)
325 // points exists for time step, let's read them
326 Info<< " Points file detected - updating points" << endl;
329 const fieldviewTopology& topo = topoPtr();
333 // Create file and write header
338 fvPath/runTime.caseName() + "_" + Foam::name(i) + ".uns"
341 Info<< " file:" << fvFileName.c_str() << endl;
344 std::ofstream fvFile(fvFileName.c_str());
346 //Info<< "Writing header ..." << endl;
348 // Output the magic number.
349 writeInt(fvFile, FV_MAGIC);
351 // Output file header and version number.
352 writeStr80(fvFile, "FIELDVIEW");
354 // This version of the FIELDVIEW unstructured file is "3.0".
355 // This is written as two integers.
360 // File type code. Grid and results.
361 writeInt(fvFile, FV_COMBINED_FILE);
363 // Reserved field, always zero
366 // Output constants for time, fsmach, alpha and re.
368 fBuf[0] = Times[i].value();
372 fvFile.write(reinterpret_cast<char*>(fBuf), 4*sizeof(float));
375 // Output the number of grids
382 //Info<< "Writing boundary table ..." << endl;
385 writeInt(fvFile, mesh.boundary().size());
387 forAll (mesh.boundary(), patchI)
389 const fvPatch& currPatch = mesh.boundary()[patchI];
391 writeInt(fvFile, 1); // data present
392 writeInt(fvFile, 1); // normals ok
395 writeStr80(fvFile, currPatch.name().c_str());
401 // volFieldPtrs : List of ptrs to all volScalar/Vector fields
402 // (null if field not present at current time)
403 // volFieldNames : FieldView compatible names of volFields
404 // surfFieldPtrs : same for surfaceScalar/Vector
406 # include "createFields.H"
411 // Write Variables table
414 //Info<< "Writing variables table ..." << endl;
416 writeInt(fvFile, volFieldNames.size());
417 forAll(volFieldNames, fieldI)
419 if (volFieldPtrs[fieldI] == NULL)
421 Info<< " dummy field for "
422 << volFieldNames[fieldI].c_str() << endl;
425 writeStr80(fvFile, volFieldNames[fieldI].c_str());
429 // Write Boundary Variables table = vol + surface fields
432 //Info<< "Writing boundary variables table ..." << endl;
437 volFieldNames.size() + surfFieldNames.size()
439 forAll(volFieldNames, fieldI)
441 writeStr80(fvFile, volFieldNames[fieldI].c_str());
443 forAll(surfFieldNames, fieldI)
445 if (surfFieldPtrs[fieldI] == NULL)
447 Info<< " dummy surface field for "
448 << surfFieldNames[fieldI].c_str() << endl;
451 writeStr80(fvFile, surfFieldNames[fieldI].c_str());
461 //Info<< "Writing points ..." << endl;
463 const pointField& points = mesh.points();
464 label nPoints = points.size();
466 writeInt(fvFile, FV_NODES);
467 writeInt(fvFile, nPoints);
469 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
471 floatField fField(nPoints);
473 for (label pointi = 0; pointi<nPoints; pointi++)
475 fField[pointi] = float(points[pointi][cmpt]);
480 reinterpret_cast<char*>(fField.begin()),
481 fField.size()*sizeof(float)
486 // Boundary Faces - regular
489 //Info<< "Writing regular boundary faces ..." << endl;
491 forAll(mesh.boundary(), patchI)
493 label nQuadFaces = topo.quadFaceLabels()[patchI].size()/4;
497 writeInt(fvFile, FV_FACES);
498 writeInt(fvFile, patchI + 1); // patch number
499 writeInt(fvFile, nQuadFaces); // number of faces in patch
502 reinterpret_cast<const char*>
503 (topo.quadFaceLabels()[patchI].begin()),
504 nQuadFaces*4*sizeof(int)
510 // Boundary Faces - arbitrary polygon
513 //Info<< "Write polygonal boundary faces ..." << endl;
515 forAll(mesh.boundary(), patchI)
517 if (topo.nPolyFaces()[patchI] > 0)
519 writeInt(fvFile, FV_ARB_POLY_FACES);
520 writeInt(fvFile, patchI + 1);
522 // number of arb faces in patch
523 writeInt(fvFile, topo.nPolyFaces()[patchI]);
525 const polyPatch& patchFaces = mesh.boundary()[patchI].patch();
527 forAll(patchFaces, faceI)
529 const face& f = patchFaces[faceI];
533 writeInt(fvFile, f.size());
537 writeInt(fvFile, f[fp] + 1);
546 // Write regular topology
549 //Info<< "Writing regular elements ..." << endl;
551 writeInt(fvFile, FV_ELEMENTS);
552 writeInt(fvFile, topo.nTet());
553 writeInt(fvFile, topo.nHex());
554 writeInt(fvFile, topo.nPrism());
555 writeInt(fvFile, topo.nPyr());
558 reinterpret_cast<const char*>(topo.tetLabels().begin()),
559 topo.nTet()*(1+4)*sizeof(int)
563 reinterpret_cast<const char*>(topo.hexLabels().begin()),
564 topo.nHex()*(1+8)*sizeof(int)
568 reinterpret_cast<const char*>(topo.prismLabels().begin()),
569 topo.nPrism()*(1+6)*sizeof(int)
573 reinterpret_cast<const char*>(topo.pyrLabels().begin()),
574 topo.nPyr()*(1+5)*sizeof(int)
579 // Write arbitrary polyhedra
582 //Info<< "Writing polyhedral elements ..." << endl;
585 const cellShapeList& cellShapes = mesh.cellShapes();
586 const cellModel& unknown = *(cellModeller::lookup("unknown"));
588 if (topo.nPoly() > 0)
590 writeInt(fvFile, FV_ARB_POLY_ELEMENTS);
591 writeInt(fvFile, topo.nPoly());
593 forAll(cellShapes, celli)
595 if (cellShapes[celli].model() == unknown)
597 const cell& cll = mesh.cells()[celli];
600 writeInt(fvFile, cll.size());
601 // number of vertices used (no cell centre)
602 writeInt(fvFile, countVerts(mesh, celli));
603 // cell centre node id
604 writeInt(fvFile, -1);
606 forAll(cll, cellFacei)
608 label faceI = cll[cellFacei];
610 const face& f = mesh.faces()[faceI];
612 // Not a wall for now
613 writeInt(fvFile, NOT_A_WALL);
615 writeInt(fvFile, f.size());
617 if (mesh.faceOwner()[faceI] == celli)
621 writeInt(fvFile, f[fp]+1);
626 for (label fp = f.size()-1; fp >= 0; fp--)
628 writeInt(fvFile, f[fp]+1);
632 // Number of hanging nodes
644 //Info<< "Writing variables data ..." << endl;
646 pointMesh pMesh(mesh);
647 volPointInterpolation pInterp(mesh, pMesh);
649 writeInt(fvFile, FV_VARIABLES);
652 forAll(volFieldPtrs, fieldI)
654 if (volFieldPtrs[fieldI] != NULL)
656 const volScalarField& vField = *volFieldPtrs[fieldI];
658 // Interpolate to points
659 pointScalarField psf(pInterp.interpolate(vField));
661 floatField fField(nPoints);
663 for (label pointi = 0; pointi<nPoints; pointi++)
665 fField[pointi] = float(psf[pointi]);
670 reinterpret_cast<char*>(fField.begin()),
671 fField.size()*sizeof(float)
676 // Create dummy field
677 floatField dummyField(nPoints, 0.0);
681 reinterpret_cast<char*>(dummyField.begin()),
682 dummyField.size()*sizeof(float)
689 // Boundary variables data
693 //Info<< "Writing regular boundary elements data ..." << endl;
695 writeInt(fvFile, FV_BNDRY_VARS);
697 forAll(volFieldPtrs, fieldI)
699 if (volFieldPtrs[fieldI] != NULL)
701 const volScalarField& vsf = *volFieldPtrs[fieldI];
703 forAll (mesh.boundary(), patchI)
710 vsf.boundaryField()[patchI],
718 forAll (mesh.boundaryMesh(), patchI)
723 mesh.boundaryMesh()[patchI].size()
724 - topo.nPolyFaces()[patchI],
730 reinterpret_cast<char*>(fField.begin()),
731 fField.size()*sizeof(float)
738 forAll(surfFieldPtrs, fieldI)
740 if (surfFieldPtrs[fieldI] != NULL)
742 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
744 forAll (mesh.boundary(), patchI)
751 ssf.boundaryField()[patchI],
759 forAll (mesh.boundaryMesh(), patchI)
764 mesh.boundaryMesh()[patchI].size()
765 - topo.nPolyFaces()[patchI],
771 reinterpret_cast<char*>(fField.begin()),
772 fField.size()*sizeof(float)
779 // Polygonal faces boundary data
783 //Info<< "Writing polygonal boundary elements data ..." << endl;
785 writeInt(fvFile, FV_ARB_POLY_BNDRY_VARS);
786 forAll(volFieldPtrs, fieldI)
788 if (volFieldPtrs[fieldI] != NULL)
790 const volScalarField& vsf = *volFieldPtrs[fieldI];
792 // All non-empty patches
793 forAll (mesh.boundary(), patchI)
800 vsf.boundaryField()[patchI],
808 forAll (mesh.boundary(), patchI)
811 floatField fField(topo.nPolyFaces()[patchI], 0.0);
815 reinterpret_cast<char*>(fField.begin()),
816 fField.size()*sizeof(float)
823 forAll(surfFieldPtrs, fieldI)
825 if (surfFieldPtrs[fieldI] != NULL)
827 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
829 // All non-empty patches
830 forAll(mesh.boundary(), patchI)
837 ssf.boundaryField()[patchI],
845 forAll (mesh.boundaryMesh(), patchI)
850 mesh.boundaryMesh()[patchI].size()
851 - topo.nPolyFaces()[patchI],
857 reinterpret_cast<char*>(fField.begin()),
858 fField.size()*sizeof(float)
866 // Cleanup volume and surface fields
868 forAll(volFieldPtrs, fieldI)
870 delete volFieldPtrs[fieldI];
872 forAll(surfFieldPtrs, fieldI)
874 delete surfFieldPtrs[fieldI];
885 // Read/create fields:
886 // sprayScalarFieldPtrs: List of ptrs to lagrangian scalfields
887 // sprayVectorFieldPtrs: ,, vec ,,
888 # include "createSprayFields.H"
893 // Time index (FieldView: has to start from 1)
894 writeInt(fvParticleFile, fieldViewTime + 1);
897 writeFloat(fvParticleFile, Times[i].value());
900 Cloud<passiveParticle> parcels(mesh);
903 writeInt(fvParticleFile, parcels.size());
905 Info<< " Writing " << parcels.size() << " particles." << endl;
909 // Output data parcelwise
917 Cloud<passiveParticle>::iterator elmnt = parcels.begin();
918 elmnt != parcels.end();
922 writeInt(fvParticleFile, parcelNo+1);
924 writeFloat(fvParticleFile, elmnt().position().x());
925 writeFloat(fvParticleFile, elmnt().position().y());
926 writeFloat(fvParticleFile, elmnt().position().z());
928 forAll(sprayScalarFieldPtrs, fieldI)
930 if (sprayScalarFieldPtrs[fieldI] != NULL)
932 const IOField<scalar>& sprayField =
933 *sprayScalarFieldPtrs[fieldI];
942 writeFloat(fvParticleFile, 0.0);
945 forAll(sprayVectorFieldPtrs, fieldI)
947 if (sprayVectorFieldPtrs[fieldI] != NULL)
949 const IOField<vector>& sprayVectorField =
950 *sprayVectorFieldPtrs[fieldI];
952 sprayVectorField[parcelNo];
954 writeFloat(fvParticleFile, val.x());
955 writeFloat(fvParticleFile, val.y());
956 writeFloat(fvParticleFile, val.z());
960 writeFloat(fvParticleFile, 0.0);
961 writeFloat(fvParticleFile, 0.0);
962 writeFloat(fvParticleFile, 0.0);
967 // increment fieldView particle time
972 // Cleanup spray fields
974 forAll(sprayScalarFieldPtrs, fieldI)
976 delete sprayScalarFieldPtrs[fieldI];
978 forAll(sprayVectorFieldPtrs, fieldI)
980 delete sprayVectorFieldPtrs[fieldI];
983 } // end of hasLagrangian
988 rm(fvParticleFileName);
991 Info << "End\n" << endl;
997 // ************************************************************************* //