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/>.
25 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 "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"
43 #include "CloudTemplate.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::validOptions.insert("noWall", "");
180 timeSelector::addOptions(true, false);
182 # include "setRootCase.H"
183 # include "createTime.H"
185 instantList timeDirs = timeSelector::select0(runTime, args);
187 # include "createMesh.H"
189 // Initialize name mapping table
190 FieldviewNames.insert("alpha", "aalpha");
191 FieldviewNames.insert("Alpha", "AAlpha");
192 FieldviewNames.insert("fsmach", "ffsmach");
193 FieldviewNames.insert("FSMach", "FFSMach");
194 FieldviewNames.insert("re", "rre");
195 FieldviewNames.insert("Re", "RRe");
196 FieldviewNames.insert("time", "ttime");
197 FieldviewNames.insert("Time", "TTime");
198 FieldviewNames.insert("pi", "ppi");
199 FieldviewNames.insert("PI", "PPI");
200 FieldviewNames.insert("x", "xx");
201 FieldviewNames.insert("X", "XX");
202 FieldviewNames.insert("y", "yy");
203 FieldviewNames.insert("Y", "YY");
204 FieldviewNames.insert("z", "zz");
205 FieldviewNames.insert("Z", "ZZ");
206 FieldviewNames.insert("rcyl", "rrcyl");
207 FieldviewNames.insert("Rcyl", "RRcyl");
208 FieldviewNames.insert("theta", "ttheta");
209 FieldviewNames.insert("Theta", "TTheta");
210 FieldviewNames.insert("rsphere", "rrsphere");
211 FieldviewNames.insert("Rsphere", "RRsphere");
212 FieldviewNames.insert("k", "kk");
213 FieldviewNames.insert("K", "KK");
216 // Scan for all available fields, in all timesteps
217 // volScalarNames : all scalar fields
218 // volVectorNames : ,, vector ,,
219 // surfScalarNames : surface fields
220 // surfVectorNames : ,,
221 // sprayScalarNames: spray fields
222 // sprayVectorNames: ,,
223 # include "getFieldNames.H"
225 bool hasLagrangian = false;
226 if (sprayScalarNames.size() || sprayVectorNames.size())
228 hasLagrangian = true;
231 Info<< "All fields: Foam/Fieldview" << endl;
232 Info<< " volScalar :";
233 printNames(volScalarNames, Info);
235 Info<< " volVector :";
236 printNames(volVectorNames, Info);
238 Info<< " surfScalar :";
239 printNames(surfScalarNames, Info);
241 Info<< " surfVector :";
242 printNames(surfVectorNames, Info);
244 Info<< " sprayScalar :";
245 printNames(sprayScalarNames, Info);
247 Info<< " sprayVector :";
248 printNames(sprayVectorNames, Info);
256 // make a directory called FieldView in the case
257 fileName fvPath(runTime.path()/"Fieldview");
266 fileName fvParticleFileName(fvPath/runTime.caseName() + ".fvp");
269 Info<< "Opening particle file " << fvParticleFileName << endl;
271 std::ofstream fvParticleFile(fvParticleFileName.c_str());
273 // Write spray file header
276 # include "writeSprayHeader.H"
279 // Current mesh. Start off from unloaded mesh.
280 autoPtr<fieldviewTopology> topoPtr(NULL);
282 label fieldViewTime = 0;
284 forAll(timeDirs, timeI)
286 runTime.setTime(timeDirs[timeI], timeI);
287 Info<< "Time: " << runTime.timeName() << endl;
289 fvMesh::readUpdateState state = mesh.readUpdate();
294 || state == fvMesh::TOPO_CHANGE
295 || state == fvMesh::TOPO_PATCH_CHANGE
298 // Mesh topo changed. Update Fieldview topo.
302 new fieldviewTopology
305 !args.optionFound("noWall")
309 Info<< " Mesh read:" << endl
310 << " tet : " << topoPtr().nTet() << endl
311 << " hex : " << topoPtr().nHex() << endl
312 << " prism : " << topoPtr().nPrism() << endl
313 << " pyr : " << topoPtr().nPyr() << endl
314 << " poly : " << topoPtr().nPoly() << endl
317 else if (state == fvMesh::POINTS_MOVED)
319 // points exists for time step, let's read them
320 Info<< " Points file detected - updating points" << endl;
323 const fieldviewTopology& topo = topoPtr();
327 // Create file and write header
332 fvPath/runTime.caseName() + "_" + Foam::name(timeI) + ".uns"
335 Info<< " file:" << fvFileName.c_str() << endl;
338 std::ofstream fvFile(fvFileName.c_str());
340 //Info<< "Writing header ..." << endl;
342 // Output the magic number.
343 writeInt(fvFile, FV_MAGIC);
345 // Output file header and version number.
346 writeStr80(fvFile, "FIELDVIEW");
348 // This version of the FIELDVIEW unstructured file is "3.0".
349 // This is written as two integers.
354 // File type code. Grid and results.
355 writeInt(fvFile, FV_COMBINED_FILE);
357 // Reserved field, always zero
360 // Output constants for time, fsmach, alpha and re.
362 fBuf[0] = runTime.value();
366 fvFile.write(reinterpret_cast<char*>(fBuf), 4*sizeof(float));
369 // Output the number of grids
376 //Info<< "Writing boundary table ..." << endl;
379 writeInt(fvFile, mesh.boundary().size());
381 forAll (mesh.boundary(), patchI)
383 const fvPatch& currPatch = mesh.boundary()[patchI];
385 writeInt(fvFile, 1); // data present
386 writeInt(fvFile, 1); // normals ok
389 writeStr80(fvFile, currPatch.name().c_str());
395 // volFieldPtrs : List of ptrs to all volScalar/Vector fields
396 // (null if field not present at current time)
397 // volFieldNames : FieldView compatible names of volFields
398 // surfFieldPtrs : same for surfaceScalar/Vector
400 # include "createFields.H"
405 // Write Variables table
408 //Info<< "Writing variables table ..." << endl;
410 writeInt(fvFile, volFieldNames.size());
411 forAll(volFieldNames, fieldI)
413 if (volFieldPtrs[fieldI] == NULL)
415 Info<< " dummy field for "
416 << volFieldNames[fieldI].c_str() << endl;
419 writeStr80(fvFile, volFieldNames[fieldI].c_str());
423 // Write Boundary Variables table = vol + surface fields
426 //Info<< "Writing boundary variables table ..." << endl;
431 volFieldNames.size() + surfFieldNames.size()
433 forAll(volFieldNames, fieldI)
435 writeStr80(fvFile, volFieldNames[fieldI].c_str());
437 forAll(surfFieldNames, fieldI)
439 if (surfFieldPtrs[fieldI] == NULL)
441 Info<< " dummy surface field for "
442 << surfFieldNames[fieldI].c_str() << endl;
445 writeStr80(fvFile, surfFieldNames[fieldI].c_str());
455 //Info<< "Writing points ..." << endl;
457 const pointField& points = mesh.points();
458 label nPoints = points.size();
460 writeInt(fvFile, FV_NODES);
461 writeInt(fvFile, nPoints);
463 for (direction cmpt=0; cmpt<vector::nComponents; cmpt++)
465 floatField fField(nPoints);
467 for (label pointi = 0; pointi<nPoints; pointi++)
469 fField[pointi] = float(points[pointi][cmpt]);
474 reinterpret_cast<char*>(fField.begin()),
475 fField.size()*sizeof(float)
480 // Boundary Faces - regular
483 //Info<< "Writing regular boundary faces ..." << endl;
485 forAll(mesh.boundary(), patchI)
487 label nQuadFaces = topo.quadFaceLabels()[patchI].size()/4;
491 writeInt(fvFile, FV_FACES);
492 writeInt(fvFile, patchI + 1); // patch number
493 writeInt(fvFile, nQuadFaces); // number of faces in patch
496 reinterpret_cast<const char*>
497 (topo.quadFaceLabels()[patchI].begin()),
498 nQuadFaces*4*sizeof(int)
504 // Boundary Faces - arbitrary polygon
507 //Info<< "Write polygonal boundary faces ..." << endl;
509 forAll(mesh.boundary(), patchI)
511 if (topo.nPolyFaces()[patchI] > 0)
513 writeInt(fvFile, FV_ARB_POLY_FACES);
514 writeInt(fvFile, patchI + 1);
516 // number of arb faces in patch
517 writeInt(fvFile, topo.nPolyFaces()[patchI]);
519 const polyPatch& patchFaces = mesh.boundary()[patchI].patch();
521 forAll(patchFaces, faceI)
523 const face& f = patchFaces[faceI];
527 writeInt(fvFile, f.size());
531 writeInt(fvFile, f[fp] + 1);
540 // Write regular topology
543 //Info<< "Writing regular elements ..." << endl;
545 writeInt(fvFile, FV_ELEMENTS);
546 writeInt(fvFile, topo.nTet());
547 writeInt(fvFile, topo.nHex());
548 writeInt(fvFile, topo.nPrism());
549 writeInt(fvFile, topo.nPyr());
552 reinterpret_cast<const char*>(topo.tetLabels().begin()),
553 topo.nTet()*(1+4)*sizeof(int)
557 reinterpret_cast<const char*>(topo.hexLabels().begin()),
558 topo.nHex()*(1+8)*sizeof(int)
562 reinterpret_cast<const char*>(topo.prismLabels().begin()),
563 topo.nPrism()*(1+6)*sizeof(int)
567 reinterpret_cast<const char*>(topo.pyrLabels().begin()),
568 topo.nPyr()*(1+5)*sizeof(int)
573 // Write arbitrary polyhedra
576 //Info<< "Writing polyhedral elements ..." << endl;
579 const cellShapeList& cellShapes = mesh.cellShapes();
580 const cellModel& unknown = *(cellModeller::lookup("unknown"));
582 if (topo.nPoly() > 0)
584 writeInt(fvFile, FV_ARB_POLY_ELEMENTS);
585 writeInt(fvFile, topo.nPoly());
587 forAll(cellShapes, celli)
589 if (cellShapes[celli].model() == unknown)
591 const cell& cll = mesh.cells()[celli];
594 writeInt(fvFile, cll.size());
595 // number of vertices used (no cell centre)
596 writeInt(fvFile, countVerts(mesh, celli));
597 // cell centre node id
598 writeInt(fvFile, -1);
600 forAll(cll, cellFacei)
602 label faceI = cll[cellFacei];
604 const face& f = mesh.faces()[faceI];
606 // Not a wall for now
607 writeInt(fvFile, NOT_A_WALL);
609 writeInt(fvFile, f.size());
611 if (mesh.faceOwner()[faceI] == celli)
615 writeInt(fvFile, f[fp]+1);
620 for (label fp = f.size()-1; fp >= 0; fp--)
622 writeInt(fvFile, f[fp]+1);
626 // Number of hanging nodes
638 //Info<< "Writing variables data ..." << endl;
640 volPointInterpolation pInterp(mesh);
642 writeInt(fvFile, FV_VARIABLES);
645 forAll(volFieldPtrs, fieldI)
647 if (volFieldPtrs[fieldI] != NULL)
649 const volScalarField& vField = *volFieldPtrs[fieldI];
651 // Interpolate to points
652 pointScalarField psf(pInterp.interpolate(vField));
654 floatField fField(nPoints);
656 for (label pointi = 0; pointi<nPoints; pointi++)
658 fField[pointi] = float(psf[pointi]);
663 reinterpret_cast<char*>(fField.begin()),
664 fField.size()*sizeof(float)
669 // Create dummy field
670 floatField dummyField(nPoints, 0.0);
674 reinterpret_cast<char*>(dummyField.begin()),
675 dummyField.size()*sizeof(float)
682 // Boundary variables data
686 //Info<< "Writing regular boundary elements data ..." << endl;
688 writeInt(fvFile, FV_BNDRY_VARS);
690 forAll(volFieldPtrs, fieldI)
692 if (volFieldPtrs[fieldI] != NULL)
694 const volScalarField& vsf = *volFieldPtrs[fieldI];
696 forAll (mesh.boundary(), patchI)
703 vsf.boundaryField()[patchI],
711 forAll (mesh.boundaryMesh(), patchI)
716 mesh.boundaryMesh()[patchI].size()
717 - topo.nPolyFaces()[patchI],
723 reinterpret_cast<char*>(fField.begin()),
724 fField.size()*sizeof(float)
731 forAll(surfFieldPtrs, fieldI)
733 if (surfFieldPtrs[fieldI] != NULL)
735 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
737 forAll (mesh.boundary(), patchI)
744 ssf.boundaryField()[patchI],
752 forAll (mesh.boundaryMesh(), patchI)
757 mesh.boundaryMesh()[patchI].size()
758 - topo.nPolyFaces()[patchI],
764 reinterpret_cast<char*>(fField.begin()),
765 fField.size()*sizeof(float)
772 // Polygonal faces boundary data
776 //Info<< "Writing polygonal boundary elements data ..." << endl;
778 writeInt(fvFile, FV_ARB_POLY_BNDRY_VARS);
779 forAll(volFieldPtrs, fieldI)
781 if (volFieldPtrs[fieldI] != NULL)
783 const volScalarField& vsf = *volFieldPtrs[fieldI];
785 // All non-empty patches
786 forAll (mesh.boundary(), patchI)
793 vsf.boundaryField()[patchI],
801 forAll (mesh.boundary(), patchI)
804 floatField fField(topo.nPolyFaces()[patchI], 0.0);
808 reinterpret_cast<char*>(fField.begin()),
809 fField.size()*sizeof(float)
816 forAll(surfFieldPtrs, fieldI)
818 if (surfFieldPtrs[fieldI] != NULL)
820 const surfaceScalarField& ssf = *surfFieldPtrs[fieldI];
822 // All non-empty patches
823 forAll(mesh.boundary(), patchI)
830 ssf.boundaryField()[patchI],
838 forAll (mesh.boundaryMesh(), patchI)
843 mesh.boundaryMesh()[patchI].size()
844 - topo.nPolyFaces()[patchI],
850 reinterpret_cast<char*>(fField.begin()),
851 fField.size()*sizeof(float)
859 // Cleanup volume and surface fields
861 forAll(volFieldPtrs, fieldI)
863 delete volFieldPtrs[fieldI];
865 forAll(surfFieldPtrs, fieldI)
867 delete surfFieldPtrs[fieldI];
878 // Read/create fields:
879 // sprayScalarFieldPtrs: List of ptrs to lagrangian scalfields
880 // sprayVectorFieldPtrs: ,, vec ,,
881 # include "createSprayFields.H"
886 // Time index (FieldView: has to start from 1)
887 writeInt(fvParticleFile, fieldViewTime + 1);
890 writeFloat(fvParticleFile, runTime.value());
893 Cloud<passiveParticle> parcels(mesh);
896 writeInt(fvParticleFile, parcels.size());
898 Info<< " Writing " << parcels.size() << " particles." << endl;
902 // Output data parcelwise
910 Cloud<passiveParticle>::iterator elmnt = parcels.begin();
911 elmnt != parcels.end();
915 writeInt(fvParticleFile, parcelNo+1);
917 writeFloat(fvParticleFile, elmnt().position().x());
918 writeFloat(fvParticleFile, elmnt().position().y());
919 writeFloat(fvParticleFile, elmnt().position().z());
921 forAll(sprayScalarFieldPtrs, fieldI)
923 if (sprayScalarFieldPtrs[fieldI] != NULL)
925 const IOField<scalar>& sprayField =
926 *sprayScalarFieldPtrs[fieldI];
935 writeFloat(fvParticleFile, 0.0);
938 forAll(sprayVectorFieldPtrs, fieldI)
940 if (sprayVectorFieldPtrs[fieldI] != NULL)
942 const IOField<vector>& sprayVectorField =
943 *sprayVectorFieldPtrs[fieldI];
945 sprayVectorField[parcelNo];
947 writeFloat(fvParticleFile, val.x());
948 writeFloat(fvParticleFile, val.y());
949 writeFloat(fvParticleFile, val.z());
953 writeFloat(fvParticleFile, 0.0);
954 writeFloat(fvParticleFile, 0.0);
955 writeFloat(fvParticleFile, 0.0);
960 // increment fieldView particle time
965 // Cleanup spray fields
967 forAll(sprayScalarFieldPtrs, fieldI)
969 delete sprayScalarFieldPtrs[fieldI];
971 forAll(sprayVectorFieldPtrs, fieldI)
973 delete sprayVectorFieldPtrs[fieldI];
976 } // end of hasLagrangian
981 rm(fvParticleFileName);
984 Info << "End\n" << endl;
990 // ************************************************************************* //