initial commit for version 1.5.x patch release
[OpenFOAM-1.5.x.git] / applications / utilities / postProcessing / graphics / fieldview9Reader / fieldview9Reader.C
blobc4568f101e3097a513716264bd0bd6ec23c75a2a
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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
25 Description
26     Reader module for Fieldview9 to read Foam mesh&data.
27     Creates new 'fvbin' type executable which needs to be installed in place
28     of bin/fvbin.
30     Implements a reader for combined mesh&results on an unstructured mesh.
32     See Fieldview Release 9 Reference Manual and coding in user/ directory
33     of the Fieldview release.
35 \*---------------------------------------------------------------------------*/
37 #include "fvCFD.H"
38 #include "IOobjectList.H"
39 #include "GeometricField.H"
40 #include "pointFields.H"
41 #include "volPointInterpolation.H"
42 #include "readerDatabase.H"
43 #include "wallPolyPatch.H"
44 #include "ListOps.H"
45 #include "cellModeller.H"
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 extern "C"
51 // Define various Fieldview constants and prototypes
53 #include "fv_reader_tags.h"
55 static const int FVHEX     = 2;
56 static const int FVPRISM   = 3;
57 static const int FVPYRAMID = 4;
58 static const int FVTET     = 1;
59 static const int ITYPE     = 1;
61 unsigned int fv_encode_elem_header(int elem_type, int wall_info[]);
62 void time_step_get_value(float*, int, int*, float*, int*);
63 void fv_error_msg(const char*, const char*);
65 void reg_single_unstruct_reader
67     char *,
68     void
69     (
70         char*, int*, int*, int*, int*, int*, int*,
71         int[], int*, char[][80], int[], int*, char[][80], int*
72     ),
73     void
74     (
75         int*, int*, int*, float[], int*, float[], int*
76     )
79 int create_tet(const int, const int[8], const int[]);
80 int create_pyramid(const int, const int[8], const int[]);
81 int create_prism(const int, const int[8], const int[]);
82 int create_hex(const int, const int[8], const int[]);
84 typedef unsigned char uChar;
85 extern uChar create_bndry_face_buffered
87     int bndry_type,
88     int num_verts,
89     int verts[],
90     int *normals_flags,
91     int num_grid_nodes
95  * just define empty readers here for ease of linking.
96  * Comment out if you have doubly defined linking error on this symbol
97  */
98 void ftn_register_data_readers()
102  * just define empty readers here for ease of linking.
103  * Comment out if you have doubly defined linking error on this symbol
104  */
105 void ftn_register_functions()
109  * just define empty readers here for ease of linking.
110  * Comment out if you have doubly defined linking error on this symbol
111  */
112 void register_functions()
116 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
120 // Storage for all Foam state (mainly database & mesh)
122 static readerDatabase db_;
125 // Write fv error message.
126 static void errorMsg(const string& msg)
128     fv_error_msg("Foam Reader", msg.c_str());
132 // Simple check if directory is valid case directory.
133 static bool validCase(const fileName& rootAndCase)
135     //if (dir(rootAndCase/"system") && dir(rootAndCase/"constant"))
136     if (dir(rootAndCase/"constant"))
137     {
138         return true;
139     }
140     else
141     {
142         return false;
143     }
147 // Check whether case has topo changes by looking back from last time
148 // to first directory with polyMesh/cells.
149 static bool hasTopoChange(const instantList& times)
151     label lastIndex = times.size()-1;
153     const Time& runTime = db_.runTime();
155     // Only set time; do not update mesh.
156     runTime.setTime(times[lastIndex], lastIndex);
158     fileName facesInst(runTime.findInstance(polyMesh::meshSubDir, "faces"));
160     // See if cellInst is constant directory. Note extra .name() is for
161     // parallel cases when runTime.constant is '../constant'
162     if (facesInst != runTime.constant().name())
163     {
164         Info<< "Found cells file in " << facesInst << " so case has "
165             << "topological changes" << endl;
167         return true;
168     }
169     else
170     {
171         Info<< "Found cells file in " << facesInst << " so case has "
172             << "no topological changes" << endl;
174         return false;
175     }
179 static bool selectTime(const instantList& times, int* iret)
181     List<float> fvTimes(2*times.size());
183     forAll(times, timeI)
184     {
185         fvTimes[2*timeI]   = float(timeI);
186         fvTimes[2*timeI+1] = float(times[timeI].value());
187     }
189     int istep;
191     float time;
193     *iret=0;
195     time_step_get_value(fvTimes.begin(), times.size(), &istep, &time, iret);
197     if (*iret == -5)
198     {
199         errorMsg("Out of memory.");
201         return false;
202     }
203     if (*iret == -15)
204     {
205         // Cancel action.
206         return false;
207     }
208     if (*iret != 0)
209     {
210         errorMsg("Unspecified error.");
212         return false;
213     }
214     Info<< "Selected timeStep:" << istep << "  time:" << scalar(time) << endl;
216     // Set time and load mesh.
217     db_.setTime(times[istep], istep);
219     return true;
223 // Gets (names of) all fields in all timesteps.
224 static void createFieldNames
226     const Time& runTime,
227     const instantList& Times,
228     const word& setName
231     // From foamToFieldView9/getFieldNames.H:
233     HashSet<word> volScalarHash;
234     HashSet<word> volVectorHash;
235     HashSet<word> surfScalarHash;
236     HashSet<word> surfVectorHash;
238     if (setName.size() == 0)
239     {
240         forAll(Times, timeI)
241         {
242             const word& timeName = Times[timeI].name();
244             // Add all fields to hashtable
245             IOobjectList objects(runTime, timeName);
247             wordList vsNames(objects.names(volScalarField::typeName));
249             forAll(vsNames, fieldI)
250             {
251                 volScalarHash.insert(vsNames[fieldI]);
252             }
254             wordList vvNames(objects.names(volVectorField::typeName));
256             forAll(vvNames, fieldI)
257             {
258                 volVectorHash.insert(vvNames[fieldI]);
259             }
260         }
261     }
262     db_.setFieldNames(volScalarHash.toc(), volVectorHash.toc());
266 // Appends interpolated values of fieldName to vars array.
267 static void storeScalarField
269     const volPointInterpolation& pInterp,
270     const word& fieldName,
271     float vars[],
272     label& pointI
275     label nPoints = db_.mesh().nPoints();
276     label nTotPoints = nPoints + db_.polys().size();
278     // Check if present
279     IOobject ioHeader
280     (
281         fieldName,
282         db_.runTime().timeName(),
283         db_.runTime(),
284         IOobject::MUST_READ,
285         IOobject::NO_WRITE
286     );
288     if (ioHeader.headerOk())
289     {
290         Info<< "Storing " << nTotPoints << " of interpolated " << fieldName
291             << endl;
293         volScalarField field(ioHeader, db_.mesh());
295         pointScalarField psf(pInterp.interpolate(field));
297         forAll(psf, i)
298         {
299             vars[pointI++] = float(psf[i]);
300         }
302         const labelList& polys = db_.polys();
304         forAll(polys, i)
305         {
306             label cellI = polys[i];
308             vars[pointI++] = float(field[cellI]);
309         }
310     }
311     else
312     {
313         Info<< "Storing " << nTotPoints << " of dummy values of " << fieldName
314             << endl;
316         for(label i = 0; i < nPoints; i++)
317         {
318             vars[pointI++] = 0.0;
319         }
321         const labelList& polys = db_.polys();
323         forAll(polys, i)
324         {
325             vars[pointI++] = 0.0;
326         }
327     }
331 // Appends interpolated values of fieldName to vars array.
332 static void storeVectorField
334     const volPointInterpolation& pInterp,
335     const word& fieldName,
336     float vars[],
337     label& pointI
340     label nPoints = db_.mesh().nPoints();
342     label nTotPoints = nPoints + db_.polys().size();
344     // Check if present
345     IOobject ioHeader
346     (
347         fieldName,
348         db_.runTime().timeName(),
349         db_.runTime(),
350         IOobject::MUST_READ,
351         IOobject::NO_WRITE
352     );
354     if (ioHeader.headerOk())
355     {
356         Info<< "Storing " << nTotPoints << " of interpolated " << fieldName
357             << endl;
359         volVectorField field(ioHeader, db_.mesh());
361         for (direction d = 0; d < vector::nComponents; d++)
362         {
363             tmp<volScalarField> tcomp = field.component(d);
364             const volScalarField& comp = tcomp();
366             pointScalarField psf(pInterp.interpolate(comp));
368             forAll(psf, i)
369             {
370                 vars[pointI++] = float(psf[i]);
371             }
373             const labelList& polys = db_.polys();
375             forAll(polys, i)
376             {
377                 label cellI = polys[i];
379                 vars[pointI++] = float(comp[cellI]);
380             }
381         }
382     }
383     else
384     {
385         Info<< "Storing " << nTotPoints << " of dummy values of " << fieldName
386             << endl;
388         for (direction d = 0; d < vector::nComponents; d++)
389         {
390             for(label i = 0; i < nPoints; i++)
391             {
392                 vars[pointI++] = 0.0;
393             }
395             const labelList& polys = db_.polys();
397             forAll(polys, i)
398             {
399                 vars[pointI++] = 0.0;
400             }
401         }
402     }
406 // Returns Fieldview face_type of mesh face faceI.
407 static label getFvType(const polyMesh& mesh, const label faceI)
409     return mesh.boundaryMesh().whichPatch(faceI) + 1;
413 // Returns Fieldview face_type of face f.
414 static label getFaceType
416     const polyMesh& mesh,
417     const labelList& faceLabels,
418     const face& f
421     // Search in subset faceLabels of faces for index of face f.
422     const faceList& faces = mesh.faces();
424     forAll(faceLabels, i)
425     {
426         label faceI = faceLabels[i];
428         if (f == faces[faceI])
429         {
430             // Convert patch to Fieldview face_type.
431             return getFvType(mesh, faceI);
432         }
433     }
435     FatalErrorIn("getFaceType")
436         << "Cannot find face " << f << " in mesh face subset " << faceLabels
437         << abort(FatalError);
439     return -1;
443 // Returns Fieldview face_types for set of faces
444 static labelList getFaceTypes
446     const polyMesh& mesh,
447     const labelList& cellFaces,
448     const faceList& cellShapeFaces
451     labelList faceLabels(cellShapeFaces.size());
453     forAll(cellShapeFaces, i)
454     {
455         faceLabels[i] = getFaceType(mesh, cellFaces, cellShapeFaces[i]);
456     }
457     return faceLabels;
462  * Callback for querying file contents. Taken from user/user_unstruct_combined.f
463  */
464 void user_query_file_function
466     /* input */
467     char* fname,        /* filename */
468     int* lenf,          /* length of fName */
469     int* iunit,         /* fortran unit to use */
470     int* max_grids,     /* maximum number of grids allowed */
471     int* max_face_types,/* maximum number of face types allowed */
472     int* max_vars,      /* maximum number of result variables allowed per */
473                         /* grid point*/
475     /* output */
476     int* num_grids,     /* number of grids that will be read from data file */
477     int  num_nodes[],   /* (array of node counts for all grids) */
478     int* num_face_types,        /* number of special face types */
479     char face_type_names[][80], /* array of face-type names */
480     int  wall_flags[],          /* array of flags for the "wall" behavior */
481     int* num_vars,              /* number of result variables per grid point */
482     char var_names[][80],       /* array of variable names */
483     int* iret                   /* return value */
486     fprintf(stderr, "\n** user_query_file_function\n");
488     string rootAndCaseString(fname, *lenf);
490     fileName rootAndCase(rootAndCaseString);
492     word setName("");
494     if (!validCase(rootAndCase))
495     {
496         setName = rootAndCase.name();
498         rootAndCase = rootAndCase.path();
500         word setDir = rootAndCase.name();
502         rootAndCase = rootAndCase.path();
504         word meshDir = rootAndCase.name();
506         rootAndCase = rootAndCase.path();
507         rootAndCase = rootAndCase.path();
509         if
510         (
511             setDir == "sets"
512          && meshDir == polyMesh::typeName
513          && validCase(rootAndCase)
514         )
515         {
516             // Valid set (hopefully - cannot check contents of setName yet).
517         }
518         else
519         {
520             errorMsg
521             (
522                 "Could not find system/ and constant/ directory in\n"
523               + rootAndCase
524               + "\nPlease select a Foam case directory."
525             );
527             *iret = 1;
529             return;
530         }
531         
532     }
534     fileName rootDir(rootAndCase.path());
536     fileName caseName(rootAndCase.name());
538     // handle trailing '/'
539     if (caseName.size() == 0)
540     {
541         caseName = rootDir.name();
542         rootDir = rootDir.path();
543     }
546     Info<< "rootDir  : " << rootDir << endl
547         << "caseName : " << caseName << endl
548         << "setName  : " << setName << endl;
550     //
551     // Get/reuse database and mesh
552     //
554     bool caseChanged = db_.setRunTime(rootDir, caseName, setName);
557     //
558     // Select time
559     //
561     instantList Times = db_.runTime().times();
563     // If topo case set database time and update mesh.
564     if (hasTopoChange(Times))
565     {
566         if (!selectTime(Times, iret))
567         {
568             return;
569         }
570     }
571     else if (caseChanged)
572     {
573         // Load mesh (if case changed) to make sure we have nPoints etc.
574         db_.loadMesh();
575     }
578     //
579     // Set output variables
580     //
582     *num_grids = 1;
584     const fvMesh& mesh = db_.mesh();
586     label nTotPoints = mesh.nPoints() + db_.polys().size();
588     num_nodes[0] = nTotPoints;
590     Info<< "setting num_nodes:" << num_nodes[0] << endl;
592     Info<< "setting num_face_types:" << mesh.boundary().size() << endl;
594     *num_face_types = mesh.boundary().size();
596     if (*num_face_types > *max_face_types)
597     {
598         errorMsg("Too many patches. FieldView limit:" + name(*max_face_types));
600         *iret = 1;
602         return;
603     }
606     forAll(mesh.boundaryMesh(), patchI)
607     {
608         const polyPatch& patch = mesh.boundaryMesh()[patchI];
610         strcpy(face_type_names[patchI], patch.name().c_str());
612         if (isType<wallPolyPatch>(patch))
613         {
614             wall_flags[patchI] = 1;
615         }
616         else
617         {
618             wall_flags[patchI] = 0;
619         }
620         Info<< "Patch " << patch.name() << " is wall:"
621             <<  wall_flags[patchI] << endl;
622     }
624     //- Find all volFields and add them to database
625     createFieldNames(db_.runTime(), Times, setName);
627     *num_vars = db_.volScalarNames().size() + 3*db_.volVectorNames().size();
629     if (*num_vars > *max_vars)
630     {
631         errorMsg("Too many variables. FieldView limit:" + name(*max_vars));
633         *iret = 1;
635         return;
636     }
639     int nameI = 0;
641     forAll(db_.volScalarNames(), i)
642     {
643         const word& fieldName = db_.volScalarNames()[i];
645         const word& fvName = db_.getFvName(fieldName);
647         strcpy(var_names[nameI++], fvName.c_str());
648     }
650     forAll(db_.volVectorNames(), i)
651     {
652         const word& fieldName = db_.volVectorNames()[i];
654         const word& fvName = db_.getFvName(fieldName);
656         strcpy(var_names[nameI++], (fvName + "x;" + fvName).c_str());
657         strcpy(var_names[nameI++], (fvName + "y").c_str());
658         strcpy(var_names[nameI++], (fvName + "z").c_str());
659     }
661     *iret = 0;
666  * Callback for reading timestep. Taken from user/user_unstruct_combined.f
667  */
668 void user_read_one_grid_function
670     int* iunit,     /* in: fortran unit number */
671     int* igrid,     /* in: grid number to read */
672     int* nodecnt,   /* in: number of nodes to read */
673     float xyz[],    /* out: coordinates of nodes: x1..xN y1..yN z1..zN */
674     int* num_vars,  /* in: number of results per node */
675     float vars[],   /* out: values per node */
676     int* iret       /* out: return value */
679     fprintf(stderr, "\n** user_read_one_grid_function\n");
681     if (*igrid != 1)
682     {
683         errorMsg("Illegal grid number " + Foam::name(*igrid));
685         *iret = 1;
687         return;
688     }
690     // Get current time
691     instantList Times = db_.runTime().times();
693     // Set database time and update mesh.
694     // Note: this should not be nessecary here. We already have the correct
695     // time set and mesh loaded. This is only nessecary because Fieldview
696     // otherwise thinks the case is non-transient.
697     if (!selectTime(Times, iret))
698     {
699         return;
700     }
703     const fvMesh& mesh = db_.mesh();
705     // With mesh now loaded check for change in number of points.
706     label nTotPoints = mesh.nPoints() + db_.polys().size();
708     if (*nodecnt != nTotPoints)
709     {
710         errorMsg
711         (
712             "nodecnt differs from number of points in mesh.\nnodecnt:"
713           + Foam::name(*nodecnt)
714           + "  mesh:"
715           + Foam::name(nTotPoints)
716         );
718         *iret = 1;
720         return;
721     }
724     if
725     (
726         *num_vars
727      != (db_.volScalarNames().size() + 3*db_.volVectorNames().size())
728     )
729     {
730         errorMsg("Illegal number of variables " + name(*num_vars));
732         *iret = 1;
734         return;
735     }
737     //
738     // Set coordinates
739     //
741     const pointField& points = mesh.points();
743     int xIndex = 0;
744     int yIndex = xIndex + nTotPoints;
745     int zIndex = yIndex + nTotPoints;
747     // Add mesh points first.
748     forAll(points, pointI)
749     {
750         xyz[xIndex++] = points[pointI].x();
751         xyz[yIndex++] = points[pointI].y();
752         xyz[zIndex++] = points[pointI].z();
753     }
755     // Add cell centres of polys
756     const pointField& ctrs = mesh.cellCentres();
758     const labelList& polys = db_.polys();
760     forAll(polys, i)
761     {
762         label cellI = polys[i];
764         xyz[xIndex++] = ctrs[cellI].x();
765         xyz[yIndex++] = ctrs[cellI].y();
766         xyz[zIndex++] = ctrs[cellI].z();
767     }
770     //
771     // Define elements by calling fv routines
772     //
774     static const cellModel& tet = *(cellModeller::lookup("tet"));
775     static const cellModel& tetWedge = *(cellModeller::lookup("tetWedge"));
776     static const cellModel& pyr = *(cellModeller::lookup("pyr"));
777     static const cellModel& prism = *(cellModeller::lookup("prism"));
778     static const cellModel& wedge = *(cellModeller::lookup("wedge"));
779     static const cellModel& hex = *(cellModeller::lookup("hex"));
780     //static const cellModel& splitHex = *(cellModeller::lookup("splitHex"));
782     int tetVerts[4];
783     int pyrVerts[5];
784     int prismVerts[6];
785     int hexVerts[8];
787     int tetFaces[4];
788     int pyrFaces[5];
789     int prismFaces[5];
790     int hexFaces[6];
792     const cellShapeList& cellShapes = mesh.cellShapes();
793     const faceList& faces = mesh.faces();
794     const cellList& cells = mesh.cells();
795     const labelList& owner = mesh.faceOwner();
796     label nPoints = mesh.nPoints();
798     // Fieldview face_types array with all faces marked as internal.
799     labelList internalFaces(6, 0);
801     // Mark all cells next to boundary so we don't have to calculate
802     // wall_types for internal cells and can just pass internalFaces.
803     boolList wallCell(mesh.nCells(), false);
805     label nWallCells = 0;
807     for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
808     {
809         label cellI = owner[faceI];
811         if (!wallCell[cellI])
812         {
813             wallCell[cellI] = true;
815             nWallCells++;
816         }
817     }
819     label nPolys = 0;
821     forAll(cellShapes, cellI)
822     {
823         const cellShape& cellShape = cellShapes[cellI];
824         const cellModel& cellModel = cellShape.model();
825         const cell& cellFaces = cells[cellI];
827         int istat = 0;
829         if (cellModel == tet)
830         {
831             tetVerts[0] = cellShape[3] + 1;
832             tetVerts[1] = cellShape[0] + 1;
833             tetVerts[2] = cellShape[1] + 1;
834             tetVerts[3] = cellShape[2] + 1;
836             if (wallCell[cellI])
837             {
838                 labelList faceTypes =
839                     getFaceTypes(mesh, cellFaces, cellShape.faces());
841                 tetFaces[0] = faceTypes[2];
842                 tetFaces[1] = faceTypes[3];
843                 tetFaces[2] = faceTypes[0];
844                 tetFaces[3] = faceTypes[1];
846                 istat = create_tet(ITYPE, tetVerts, tetFaces);
847             }
848             else
849             {
850                 // All faces internal so use precalculated zero.
851                 istat = create_tet(ITYPE, tetVerts, internalFaces.begin());
852             }
853         }
854         else if (cellModel == tetWedge)
855         {
856             prismVerts[0] = cellShape[0] + 1;
857             prismVerts[1] = cellShape[3] + 1;
858             prismVerts[2] = cellShape[4] + 1;
859             prismVerts[3] = cellShape[1] + 1;
860             prismVerts[4] = cellShape[4] + 1;
861             prismVerts[5] = cellShape[2] + 1;
863             if (wallCell[cellI])
864             {
865                 labelList faceTypes =
866                     getFaceTypes(mesh, cellFaces, cellShape.faces());
868                 prismFaces[0] = faceTypes[1];
869                 prismFaces[1] = faceTypes[2];
870                 prismFaces[2] = faceTypes[3];
871                 prismFaces[3] = faceTypes[0];
872                 prismFaces[4] = faceTypes[3];
874                 istat = create_prism(ITYPE, prismVerts, prismFaces);
875             }
876             else
877             {
878                 istat = create_prism(ITYPE, prismVerts, internalFaces.begin());
879             }
880         }
881         else if (cellModel == pyr)
882         {
883             pyrVerts[0] = cellShape[0] + 1;
884             pyrVerts[1] = cellShape[1] + 1;
885             pyrVerts[2] = cellShape[2] + 1;
886             pyrVerts[3] = cellShape[3] + 1;
887             pyrVerts[4] = cellShape[4] + 1;
889             if (wallCell[cellI])
890             {
891                 labelList faceTypes =
892                     getFaceTypes(mesh, cellFaces, cellShape.faces());
894                 pyrFaces[0] = faceTypes[0];
895                 pyrFaces[1] = faceTypes[3];
896                 pyrFaces[2] = faceTypes[2];
897                 pyrFaces[3] = faceTypes[1];
898                 pyrFaces[4] = faceTypes[4];
900                 istat = create_pyramid(ITYPE, pyrVerts, pyrFaces);
901             }
902             else
903             {
904                 istat = create_pyramid(ITYPE, pyrVerts, internalFaces.begin());
905             }
906         }
907         else if (cellModel == prism)
908         {
909             prismVerts[0] = cellShape[0] + 1;
910             prismVerts[1] = cellShape[3] + 1;
911             prismVerts[2] = cellShape[4] + 1;
912             prismVerts[3] = cellShape[1] + 1;
913             prismVerts[4] = cellShape[5] + 1;
914             prismVerts[5] = cellShape[2] + 1;
916             if (wallCell[cellI])
917             {
918                 labelList faceTypes =
919                     getFaceTypes(mesh, cellFaces, cellShape.faces());
921                 prismFaces[0] = faceTypes[4];
922                 prismFaces[1] = faceTypes[2];
923                 prismFaces[2] = faceTypes[3];
924                 prismFaces[3] = faceTypes[0];
925                 prismFaces[4] = faceTypes[1];
927                 istat = create_prism(ITYPE, prismVerts, prismFaces);
928             }
929             else
930             {
931                 istat = create_prism(ITYPE, prismVerts, internalFaces.begin());
932             }
933         }
934         else if (cellModel == wedge)
935         {
936             hexVerts[0] = cellShape[0] + 1;
937             hexVerts[1] = cellShape[1] + 1;
938             hexVerts[2] = cellShape[0] + 1;
939             hexVerts[3] = cellShape[2] + 1;
940             hexVerts[4] = cellShape[3] + 1;
941             hexVerts[5] = cellShape[4] + 1;
942             hexVerts[6] = cellShape[6] + 1;
943             hexVerts[7] = cellShape[5] + 1;
945             if (wallCell[cellI])
946             {
947                 labelList faceTypes =
948                     getFaceTypes(mesh, cellFaces, cellShape.faces());
950                 hexFaces[0] = faceTypes[2];
951                 hexFaces[1] = faceTypes[3];
952                 hexFaces[2] = faceTypes[0];
953                 hexFaces[3] = faceTypes[1];
954                 hexFaces[4] = faceTypes[4];
955                 hexFaces[5] = faceTypes[5];
957                 istat = create_hex(ITYPE, hexVerts, hexFaces);
958             }
959             else
960             {
961                 istat = create_hex(ITYPE, hexVerts, internalFaces.begin());
962             }
963         }
964         else if (cellModel == hex)
965         {
966             hexVerts[0] = cellShape[0] + 1;
967             hexVerts[1] = cellShape[1] + 1;
968             hexVerts[2] = cellShape[3] + 1;
969             hexVerts[3] = cellShape[2] + 1;
970             hexVerts[4] = cellShape[4] + 1;
971             hexVerts[5] = cellShape[5] + 1;
972             hexVerts[6] = cellShape[7] + 1;
973             hexVerts[7] = cellShape[6] + 1;
975             if (wallCell[cellI])
976             {
977                 labelList faceTypes =
978                     getFaceTypes(mesh, cellFaces, cellShape.faces());
980                 hexFaces[0] = faceTypes[0];
981                 hexFaces[1] = faceTypes[1];
982                 hexFaces[2] = faceTypes[4];
983                 hexFaces[3] = faceTypes[5];
984                 hexFaces[4] = faceTypes[2];
985                 hexFaces[5] = faceTypes[3];
987                 istat = create_hex(ITYPE, hexVerts, hexFaces);
988             }
989             else
990             {
991                 istat = create_hex(ITYPE, hexVerts, internalFaces.begin());
992             }
993         }
994         else
995         {
996             forAll(cellFaces, cFaceI)
997             {
998                 label faceI = cellFaces[cFaceI];
1000                 // Get Fieldview facetype (internal/on patch)
1001                 label fvFaceType = getFvType(mesh, faceI);
1003                 const face& f = faces[faceI];
1005                 // Indices into storage
1006                 label nQuads = 0;
1007                 label nTris = 0;
1009                 // Storage for triangles and quads created by face
1010                 // decomposition (sized for worst case)
1011                 faceList quadFaces((f.size() - 2)/2);
1012                 faceList triFaces(f.size() - 2);
1014                 f.trianglesQuads
1015                 (
1016                     points,
1017                     nTris,
1018                     nQuads,
1019                     triFaces,
1020                     quadFaces
1021                 );
1023                 // Label of cell centre in fv point list.
1024                 label polyCentrePoint = nPoints + nPolys;
1026                 for (label i=0; i<nTris; i++)
1027                 {
1028                     if (cellI == owner[faceI])
1029                     {
1030                         tetVerts[0] = triFaces[i][0] + 1;
1031                         tetVerts[1] = triFaces[i][1] + 1;
1032                         tetVerts[2] = triFaces[i][2] + 1;
1033                         tetVerts[3] = polyCentrePoint + 1;
1034                     }
1035                     else
1036                     {
1037                         tetVerts[0] = triFaces[i][2] + 1;
1038                         tetVerts[1] = triFaces[i][1] + 1;
1039                         tetVerts[2] = triFaces[i][0] + 1;
1040                         tetVerts[3] = polyCentrePoint + 1;
1041                     }
1043                     if (wallCell[cellI])
1044                     {
1045                         // Outside face is one without polyCentrePoint
1046                         tetFaces[0] = fvFaceType;
1047                         tetFaces[1] = 0;
1048                         tetFaces[2] = 0;
1049                         tetFaces[3] = 0;
1051                         istat = create_tet(ITYPE, tetVerts, tetFaces);
1052                     }
1053                     else
1054                     {
1055                         istat =
1056                             create_tet
1057                             (
1058                                 ITYPE,
1059                                 tetVerts,
1060                                 internalFaces.begin()
1061                             );
1062                     }
1063                 }
1065                 for (label i=0; i<nQuads; i++)
1066                 {
1067                     if (cellI == owner[faceI])
1068                     {
1069                         pyrVerts[0] = quadFaces[i][3] + 1;
1070                         pyrVerts[1] = quadFaces[i][2] + 1;
1071                         pyrVerts[2] = quadFaces[i][1] + 1;
1072                         pyrVerts[3] = quadFaces[i][0] + 1;
1073                         pyrVerts[4] = polyCentrePoint + 1;
1075                     }
1076                     else
1077                     {
1078                         pyrVerts[0] = quadFaces[i][0] + 1;
1079                         pyrVerts[1] = quadFaces[i][1] + 1;
1080                         pyrVerts[2] = quadFaces[i][2] + 1;
1081                         pyrVerts[3] = quadFaces[i][3] + 1;
1082                         pyrVerts[4] = polyCentrePoint + 1;
1083                     }
1085                     if (wallCell[cellI])
1086                     {
1087                         // Outside face is one without polyCentrePoint
1088                         pyrFaces[0] = fvFaceType;
1089                         pyrFaces[1] = 0;
1090                         pyrFaces[2] = 0;
1091                         pyrFaces[3] = 0;
1092                         pyrFaces[4] = 0;
1094                         istat = create_pyramid(ITYPE, pyrVerts, pyrFaces);
1095                     }
1096                     else
1097                     {
1098                         istat =
1099                             create_pyramid
1100                             (
1101                                 ITYPE,
1102                                 pyrVerts,
1103                                 internalFaces.begin()
1104                             );
1105                     }
1106                 }
1108                 if (istat != 0)
1109                 {
1110                     errorMsg("Error during adding cell " + name(cellI));
1112                     *iret = 1;
1114                     return;
1115                 }
1116             }
1118             nPolys++;
1119         }
1121         if (istat != 0)
1122         {
1123             errorMsg("Error during adding cell " + name(cellI));
1125             *iret = 1;
1127             return;
1128         }
1129     }
1133     //
1134     // Set fieldvalues
1135     //
1137     pointMesh pMesh(mesh);
1139     volPointInterpolation pInterp(mesh, pMesh);
1141     int pointI = 0;
1143     forAll(db_.volScalarNames(), i)
1144     {
1145         const word& fieldName = db_.volScalarNames()[i];
1147         storeScalarField(pInterp, fieldName, vars, pointI);
1148     }
1151     forAll(db_.volVectorNames(), i)
1152     {
1153         const word& fieldName = db_.volVectorNames()[i];
1155         storeVectorField(pInterp, fieldName, vars, pointI);
1156     }
1158     // Return without failure.
1159     *iret = 0;
1163 void register_data_readers()
1165     /*
1166     **
1167     ** You should edit this file to "register" a user-defined data
1168     ** reader with FIELDVIEW, if the user functions being registered
1169     ** here are written in C.
1170     ** You should edit "ftn_register_data_readers.f" if the user functions
1171     ** being registered are written in Fortran.
1172     ** In either case, the user functions being registered may call other
1173     ** functions written in either language (C or Fortran); only the
1174     ** language of the "query" and "read" functions referenced here matters
1175     ** to FIELDVIEW.
1176     **
1177     ** The following shows a sample user-defined data reader being
1178     ** "registered" with FIELDVIEW.
1179     **
1180     ** The "extern void" declarations should match the names of the
1181     ** query and grid-reading functions you are providing. It is
1182     ** strongly suggested that all such names begin with "user" so
1183     ** as not to conflict with global names in FIELDVIEW.
1184     **
1185     ** You may call any combination of the data reader registration
1186     ** functions shown below ("register_two_file_reader" and/or
1187     ** "register_single_file_reader" and/or "register_single_unstruct_reader"
1188     ** and/or "register_double_unstruct_reader") as many times as you like,
1189     ** in order to create several different data readers. Each data reader
1190     ** should of course have different "query" and "read" functions, all of
1191     ** which should also appear in "extern void" declarations.
1192     **
1193     */
1195     /*
1196     ** like this for combined unstructured grids & results in a single file
1197     */
1198     reg_single_unstruct_reader (
1199         "Foam Reader",                 /* title you want for data reader */
1200         user_query_file_function,      /* whatever you called this */
1201         user_read_one_grid_function    /* whatever you called this */
1202         );
1211 // ************************************************************************* //