foamToEnsight.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2018 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
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.
15 
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.
20 
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/>.
23 
24 Application
25  foamToEnsight
26 
27 Description
28  Translates OpenFOAM data to EnSight format.
29 
30  An Ensight part is created for the internalMesh and for each patch.
31 
32 Usage
33  \b foamToEnsight [OPTION]
34 
35  Options:
36  - \par -ascii
37  Write Ensight data in ASCII format instead of "C Binary"
38 
39  - \par -patches patchList
40  Specify particular patches to write.
41  Specifying an empty list suppresses writing the internalMesh.
42 
43  - \par -noPatches
44  Suppress writing any patches.
45 
46  - \par -faceZones zoneList
47  Specify faceZones to write, with wildcards
48 
49  - \par -cellZone zoneName
50  Specify single cellZone to write (not lagrangian)
51 
52 Note
53  Parallel support for cloud data is not supported
54  - writes to \a EnSight directory to avoid collisions with foamToEnsightParts
55 
56 \*---------------------------------------------------------------------------*/
57 
58 #include "argList.H"
59 #include "timeSelector.H"
60 #include "IOobjectList.H"
61 #include "IOmanip.H"
62 #include "OFstream.H"
63 
64 #include "volFields.H"
65 
66 #include "labelIOField.H"
67 #include "scalarIOField.H"
68 #include "tensorIOField.H"
69 
70 #include "ensightMesh.H"
71 #include "ensightField.H"
72 
74 #include "ensightCloudField.H"
75 
76 #include "fvc.H"
77 
78 #include "cellSet.H"
79 #include "fvMeshSubset.H"
80 
81 using namespace Foam;
82 
83 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
84 
85 bool inFileNameList
86 (
87  const fileNameList& nameList,
88  const word& name
89 )
90 {
91  forAll(nameList, i)
92  {
93  if (nameList[i] == name)
94  {
95  return true;
96  }
97  }
98 
99  return false;
100 }
101 
102 
103 
104 int main(int argc, char *argv[])
105 {
107  #include "addRegionOption.H"
108 
110  (
111  "ascii",
112  "write in ASCII format instead of 'C Binary'"
113  );
115  (
116  "nodeValues",
117  "write values in nodes"
118  );
120  (
121  "noPatches",
122  "suppress writing any patches"
123  );
125  (
126  "patches",
127  "wordReList",
128  "specify particular patches to write - eg '(outlet \"inlet.*\")'. "
129  "An empty list suppresses writing the internalMesh."
130  );
132  (
133  "faceZones",
134  "wordReList",
135  "specify faceZones to write - eg '( slice \"mfp-.*\" )'."
136  );
138  (
139  "fields",
140  "wordReList",
141  "specify fields to export (all by default) - eg '( \"U.*\" )'."
142  );
144  (
145  "cellZone",
146  "word",
147  "specify cellZone to write"
148  );
149 
150  #include "setRootCase.H"
151 
152  // Check options
153  const bool binary = !args.optionFound("ascii");
154  const bool nodeValues = args.optionFound("nodeValues");
155 
156  #include "createTime.H"
157 
159 
160  #include "createNamedMesh.H"
161 
162  // Mesh instance (region0 gets filtered out)
163  fileName regionPrefix = "";
164 
166  {
167  regionPrefix = regionName;
168  }
169 
170  const label nVolFieldTypes = 5;
171  const word volFieldTypes[] =
172  {
177  volTensorField::typeName
178  };
179 
180  // Path to EnSight directory at case level only
181  // - For parallel cases, data only written from master
182  fileName ensightDir = args.rootPath()/args.globalCaseName()/"EnSight";
183 
184  if (Pstream::master())
185  {
186  if (isDir(ensightDir))
187  {
188  rmDir(ensightDir);
189  }
190 
191  mkDir(ensightDir);
192  }
193 
194  // Start of case file header output
195  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
196 
197  const word prepend = args.globalCaseName() + '.';
198 
199  OFstream *ensightCaseFilePtr = nullptr;
200  if (Pstream::master())
201  {
202  fileName caseFileName = prepend + "case";
203  Info<< nl << "write case: " << caseFileName.c_str() << endl;
204 
205  // the case file is always ASCII
206  ensightCaseFilePtr = new OFstream
207  (
208  ensightDir/caseFileName,
210  );
211 
212  *ensightCaseFilePtr
213  << "FORMAT" << nl
214  << "type: ensight gold" << nl << nl;
215  }
216 
217  OFstream& ensightCaseFile = *ensightCaseFilePtr;
218 
219  // Construct the EnSight mesh
220  const bool selectedPatches = args.optionFound("patches");
221  wordReList patchPatterns;
222  if (selectedPatches)
223  {
224  patchPatterns = wordReList(args.optionLookup("patches")());
225  }
226  const bool selectedZones = args.optionFound("faceZones");
227  wordReList zonePatterns;
228  if (selectedZones)
229  {
230  zonePatterns = wordReList(args.optionLookup("faceZones")());
231  }
232 
233  const bool selectedFields = args.optionFound("fields");
234  wordReList fieldPatterns;
235  if (selectedFields)
236  {
237  fieldPatterns = wordReList(args.optionLookup("fields")());
238  }
239 
240  word cellZoneName;
241  const bool doCellZone = args.optionReadIfPresent("cellZone", cellZoneName);
242 
243  fvMeshSubset meshSubsetter(mesh);
244  if (doCellZone)
245  {
246  Info<< "Converting cellZone " << cellZoneName
247  << " only (puts outside faces into patch "
248  << mesh.boundaryMesh()[0].name()
249  << ")" << endl;
250  const cellZone& cz = mesh.cellZones()[cellZoneName];
251  cellSet c0(mesh, "c0", labelHashSet(cz));
252  meshSubsetter.setLargeCellSubset(c0, 0);
253  }
254 
255  ensightMesh eMesh
256  (
257  (
258  meshSubsetter.hasSubMesh()
259  ? meshSubsetter.subMesh()
260  : meshSubsetter.baseMesh()
261  ),
262  args.optionFound("noPatches"),
263  selectedPatches,
264  patchPatterns,
265  selectedZones,
266  zonePatterns,
267  binary
268  );
269 
270  // Set Time to the last time before looking for the lagrangian objects
271  runTime.setTime(Times.last(), Times.size()-1);
272 
274 
275  #include "checkMeshMoving.H"
276 
277  if (meshMoving)
278  {
279  Info<< "Detected a moving mesh (multiple polyMesh/points files)."
280  << " Writing meshes for every timestep." << endl;
281  }
282 
283 
284  wordHashSet allCloudNames;
285  if (Pstream::master())
286  {
287  word geomFileName = prepend + "0000";
288 
289  // test pre check variable if there is a moving mesh
290  if (meshMoving)
291  {
292  geomFileName = prepend + "****";
293  }
294 
295  ensightCaseFile
296  << "GEOMETRY" << nl
297  << "model: 1 "
298  << (geomFileName + ".mesh").c_str() << nl;
299  }
300 
301  // Identify if lagrangian data exists at each time, and add clouds
302  // to the 'allCloudNames' hash set
303  forAll(Times, timeI)
304  {
305  runTime.setTime(Times[timeI], timeI);
306 
307  fileNameList cloudDirs = readDir
308  (
309  runTime.timePath()/regionPrefix/cloud::prefix,
311  );
312 
313  forAll(cloudDirs, cloudI)
314  {
315  IOobjectList cloudObjs
316  (
317  mesh,
318  runTime.timeName(),
319  cloud::prefix/cloudDirs[cloudI]
320  );
321 
322  IOobject* positionsPtr = cloudObjs.lookup(word("positions"));
323 
324  if (positionsPtr)
325  {
326  allCloudNames.insert(cloudDirs[cloudI]);
327  }
328  }
329  }
330 
331  HashTable<HashTable<word>> allCloudFields;
332  forAllConstIter(wordHashSet, allCloudNames, cloudIter)
333  {
334  // Add the name of the cloud(s) to the case file header
335  if (Pstream::master())
336  {
337  ensightCaseFile
338  << (
339  "measured: 1 "
340  + prepend
341  + "****."
342  + cloudIter.key()
343  ).c_str()
344  << nl;
345  }
346 
347  // Create a new hash table for each cloud
348  allCloudFields.insert(cloudIter.key(), HashTable<word>());
349 
350  // Identify the new cloud in the hash table
351  HashTable<HashTable<word>>::iterator newCloudIter =
352  allCloudFields.find(cloudIter.key());
353 
354  // Loop over all times to build list of fields and field types
355  // for each cloud
356  forAll(Times, timeI)
357  {
358  runTime.setTime(Times[timeI], timeI);
359 
360  IOobjectList cloudObjs
361  (
362  mesh,
363  runTime.timeName(),
364  cloud::prefix/cloudIter.key()
365  );
366 
367  forAllConstIter(IOobjectList, cloudObjs, fieldIter)
368  {
369  const IOobject obj = *fieldIter();
370 
371  if (obj.name() != "positions")
372  {
373  // Add field and field type
374  newCloudIter().insert
375  (
376  obj.name(),
377  obj.headerClassName()
378  );
379  }
380  }
381  }
382  }
383 
384  label nTimeSteps = 0;
385  forAll(Times, timeIndex)
386  {
387  nTimeSteps++;
388  runTime.setTime(Times[timeIndex], timeIndex);
389 
390  word timeName = itoa(timeIndex);
391  word timeFile = prepend + timeName;
392 
393  Info<< "Translating time = " << runTime.timeName() << nl;
394 
396  if (timeIndex != 0 && meshSubsetter.hasSubMesh())
397  {
398  Info<< "Converting cellZone " << cellZoneName
399  << " only (puts outside faces into patch "
400  << mesh.boundaryMesh()[0].name()
401  << ")" << endl;
402  const cellZone& cz = mesh.cellZones()[cellZoneName];
403  cellSet c0(mesh, "c0", labelHashSet(cz));
404  meshSubsetter.setLargeCellSubset(c0, 0);
405  }
406 
407 
408  if (meshState != polyMesh::UNCHANGED)
409  {
410  eMesh.correct();
411  }
412 
413  if (timeIndex == 0 || meshMoving)
414  {
415  eMesh.write
416  (
417  ensightDir,
418  prepend,
419  timeIndex,
420  meshMoving,
421  ensightCaseFile
422  );
423  }
424 
425 
426  // Start of field data output
427  // ~~~~~~~~~~~~~~~~~~~~~~~~~~
428 
429  if (timeIndex == 0 && Pstream::master())
430  {
431  ensightCaseFile<< nl << "VARIABLE" << nl;
432  }
433 
434 
435  // Cell field data output
436  // ~~~~~~~~~~~~~~~~~~~~~~
437 
438  for (label i=0; i<nVolFieldTypes; i++)
439  {
440  wordList fieldNames = objects.names(volFieldTypes[i]);
441 
442  forAll(fieldNames, j)
443  {
444  const word& fieldName = fieldNames[j];
445 
446  // Check if the field has to be exported
447  if (selectedFields)
448  {
449  if (!findStrings(fieldPatterns, fieldName))
450  {
451  continue;
452  }
453  }
454 
455  #include "checkData.H"
456 
457  if (!variableGood)
458  {
459  continue;
460  }
461 
463  (
464  fieldName,
465  mesh.time().timeName(),
466  mesh,
469  );
470 
471  if (volFieldTypes[i] == volScalarField::typeName)
472  {
474  ensightField<scalar>
475  (
476  volField(meshSubsetter, vf),
477  eMesh,
478  ensightDir,
479  prepend,
480  timeIndex,
481  binary,
482  nodeValues,
483  ensightCaseFile
484  );
485  }
486  else if (volFieldTypes[i] == volVectorField::typeName)
487  {
489  ensightField<vector>
490  (
491  volField(meshSubsetter, vf),
492  eMesh,
493  ensightDir,
494  prepend,
495  timeIndex,
496  binary,
497  nodeValues,
498  ensightCaseFile
499  );
500  }
501  else if (volFieldTypes[i] == volSphericalTensorField::typeName)
502  {
504  ensightField<sphericalTensor>
505  (
506  volField(meshSubsetter, vf),
507  eMesh,
508  ensightDir,
509  prepend,
510  timeIndex,
511  binary,
512  nodeValues,
513  ensightCaseFile
514  );
515  }
516  else if (volFieldTypes[i] == volSymmTensorField::typeName)
517  {
519  ensightField<symmTensor>
520  (
521  volField(meshSubsetter, vf),
522  eMesh,
523  ensightDir,
524  prepend,
525  timeIndex,
526  binary,
527  nodeValues,
528  ensightCaseFile
529  );
530  }
531  else if (volFieldTypes[i] == volTensorField::typeName)
532  {
534  ensightField<tensor>
535  (
536  volField(meshSubsetter, vf),
537  eMesh,
538  ensightDir,
539  prepend,
540  timeIndex,
541  binary,
542  nodeValues,
543  ensightCaseFile
544  );
545  }
546  }
547  }
548 
549 
550  // Cloud field data output
551  // ~~~~~~~~~~~~~~~~~~~~~~~
552 
553  forAllConstIter(HashTable<HashTable<word>>, allCloudFields, cloudIter)
554  {
555  const word& cloudName = cloudIter.key();
556 
557  fileNameList currentCloudDirs = readDir
558  (
559  runTime.timePath()/regionPrefix/cloud::prefix,
561  );
562 
563  bool cloudExists = inFileNameList(currentCloudDirs, cloudName);
565  (
566  mesh,
567  ensightDir,
568  timeFile,
569  cloudName,
570  cloudExists
571  );
572 
573  forAllConstIter(HashTable<word>, cloudIter(), fieldIter)
574  {
575  const word& fieldName = fieldIter.key();
576  const word& fieldType = fieldIter();
577 
579  (
580  fieldName,
581  mesh.time().timeName(),
583  mesh,
585  );
586 
587  bool fieldExists = fieldObject.typeHeaderOk<IOField<scalar>>
588  (
589  false
590  );
591  if (fieldType == scalarIOField::typeName)
592  {
593  ensightCloudField<scalar>
594  (
595  fieldObject,
596  ensightDir,
597  prepend,
598  timeIndex,
599  cloudName,
600  ensightCaseFile,
601  fieldExists
602  );
603  }
604  else if (fieldType == vectorIOField::typeName)
605  {
606  ensightCloudField<vector>
607  (
608  fieldObject,
609  ensightDir,
610  prepend,
611  timeIndex,
612  cloudName,
613  ensightCaseFile,
614  fieldExists
615  );
616  }
617  else
618  {
619  Info<< "Unable to convert field type " << fieldType
620  << " for field " << fieldName << endl;
621  }
622  }
623  }
624  }
625 
626  #include "ensightCaseTail.H"
627 
628  if (Pstream::master())
629  {
630  delete ensightCaseFilePtr;
631  }
632 
633  Info<< "End\n" << endl;
634 
635  return 0;
636 }
637 
638 
639 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
A HashTable with keys but without contents.
Definition: HashSet.H:59
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
const word & name() const
Return name.
Definition: IOobject.H:303
bool typeHeaderOk(const bool checkType=true)
Read header (uses typeFilePath to find file) and check header.
A class for handling file names.
Definition: fileName.H:79
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:50
const fileName & globalCaseName() const
Return case name.
Definition: argListI.H:54
fileName timePath() const
Return current time path.
Definition: Time.H:281
static const char *const typeName
Definition: Field.H:105
const fileName & rootPath() const
Return root path.
Definition: argListI.H:42
word itoa(const label n)
Foam::word regionName
Output to file stream.
Definition: OFstream.H:82
Foam::tmp< Foam::GeometricField< Type, Foam::fvPatchField, Foam::volMesh > > volField(const Foam::fvMeshSubset &, const Foam::GeometricField< Type, Foam::fvPatchField, Foam::volMesh > &vf)
Wrapper to get hold of the field or the subsetted field.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
engineTime & runTime
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
bool optionFound(const word &opt) const
Return true if the named option is found.
Definition: argListI.H:114
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
void ensightParticlePositions(const polyMesh &mesh, const fileName &dataDir, const fileName &subDir, const word &cloudName, IOstream::streamFormat format)
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Definition: Time.C:622
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:239
IOobject fieldObject(fieldNames[var2field[nVar]], runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE)
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:204
bool findStrings(const wordReListMatcher &matcher, const std::string &str)
Return true if string matches one of the regular expressions.
Definition: stringListOps.H:52
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
iterator find(const Key &)
Find and return an iterator set at the hashedEntry.
Definition: HashTable.C:142
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:211
dynamicFvMesh & mesh
virtual readUpdateState readUpdate()
Update the mesh based on the mesh files saved in time.
Definition: fvMesh.C:489
bool isDir(const fileName &, const bool followLink=true)
Does the name exist as a directory in the file system?
Definition: POSIX.C:539
A class for handling words, derived from string.
Definition: word.H:59
const cellZoneMesh & cellZones() const
Return cell zone mesh.
Definition: polyMesh.H:482
static void addOption(const word &opt, const string &param="", const string &usage="")
Add to an option to validOptions with usage information.
Definition: argList.C:128
word timeName
Definition: getTimeIndex.H:3
virtual void setTime(const Time &)
Reset the time and time-index to those of the given time.
Definition: Time.C:879
fileNameList readDir(const fileName &, const fileType=fileType::file, const bool filterVariants=true, const bool followLink=true)
Read a directory and return the entries as a string list.
Definition: POSIX.C:662
An STL-conforming hash table.
Definition: HashTable.H:61
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
bool rmDir(const fileName &)
Remove a directory and its contents.
Definition: POSIX.C:1051
Istream and Ostream manipulators taking arguments.
static const char nl
Definition: Ostream.H:260
objects
static const word prefix
The prefix to local: lagrangian.
Definition: cloud.H:62
Post-processing mesh subset tool. Given the original mesh and the list of selected cells...
Definition: fvMeshSubset.H:73
static instantList select0(Time &runTime, const argList &args)
Return the set of times selected based on the argList options.
Definition: timeSelector.C:252
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
A subset of mesh cells.
Definition: cellZone.H:61
A collection of cell labels.
Definition: cellSet.H:48
label timeIndex
Definition: getTimeIndex.H:4
messageStream Info
const word cloudName(propsDict.lookup("cloudName"))
static void addBoolOption(const word &opt, const string &usage="")
Add to a bool option to validOptions with usage information.
Definition: argList.C:118
List< wordRe > wordReList
A List of wordRe (word or regular expression)
Definition: wordReList.H:50
readUpdateState
Enumeration defining the state of the mesh after a read update.
Definition: polyMesh.H:88
T & last()
Return the last element of the list.
Definition: UListI.H:128
Foam::argList args(argc, argv)
const word & headerClassName() const
Return name of the class name read from header.
Definition: IOobject.H:309
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
bool variableGood
Definition: checkData.H:3
A primitive field of type <T> with automated input and output.
Definition: IOField.H:50
static void addOptions(const bool constant=true, const bool withZero=false)
Add the options handled by timeSelector to argList::validOptions.
Definition: timeSelector.C:114
Namespace for OpenFOAM.
bool meshMoving
IStringStream optionLookup(const word &opt) const
Return an IStringStream from the named option.
Definition: argListI.H:120