foamToEnsightParts.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-2022 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  foamToEnsightParts
26 
27 Description
28  Translates OpenFOAM data to Ensight format.
29  An Ensight part is created for each cellZone and patch.
30 
31 Usage
32  \b foamToEnsightParts [OPTION]
33 
34  Options:
35  - \par -ascii
36  Write Ensight data in ASCII format instead of "C Binary"
37 
38  - \par -name <subdir>
39  Define sub-directory name to use for Ensight data (default: "Ensight")
40 
41  - \par -noZero
42  Exclude the often incomplete initial conditions.
43 
44  - \par -index <start>
45  Ignore the time index contained in the time file and use a
46  simple indexing when creating the \c Ensight/data/######## files.
47 
48  - \par -noMesh
49  Suppress writing the geometry. Can be useful for converting partial
50  results for a static geometry.
51 
52  - \par -width <n>
53  Width of Ensight data subdir
54 
55  Note:
56  - no parallel data.
57  - writes to \a Ensight directory to avoid collisions with foamToEnsight.
58 
59 \*---------------------------------------------------------------------------*/
60 
61 #include "argList.H"
62 #include "timeSelector.H"
63 
64 #include "volFields.H"
65 #include "OFstream.H"
66 #include "IOmanip.H"
67 #include "IOobjectList.H"
68 #include "scalarIOField.H"
69 #include "tensorIOField.H"
70 
71 #include "ensightParts.H"
72 #include "ensightOutputFunctions.H"
73 
74 using namespace Foam;
75 
76 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
77 
78 
79 int main(int argc, char *argv[])
80 {
81  // enable -constant
82  // probably don't need -withZero though, since the fields are vetted
83  // afterwards anyhow
84  timeSelector::addOptions(true, false);
87  (
88  "ascii",
89  "write in ASCII format instead of 'C Binary'"
90  );
92  (
93  "index",
94  "start",
95  "ignore the time index contained in the uniform/time file "
96  "and use simple indexing when creating the files"
97  );
99  (
100  "noMesh",
101  "suppress writing the geometry. "
102  "Can be useful for converting partial results for a static geometry"
103  );
105  (
106  "name",
107  "subdir",
108  "define sub-directory name to use for Ensight data "
109  "(default: \"Ensight\")"
110  );
112  (
113  "width",
114  "n",
115  "width of Ensight data subdir"
116  );
117 
118  // the volume field types that we handle
119  wordHashSet volFieldTypes;
120  volFieldTypes.insert(volScalarField::typeName);
121  volFieldTypes.insert(volVectorField::typeName);
123  volFieldTypes.insert(volSymmTensorField::typeName);
124  volFieldTypes.insert(volTensorField::typeName);
125 
126  // the lagrangian field types that we handle
127  wordHashSet cloudFieldTypes;
128  cloudFieldTypes.insert(scalarIOField::typeName);
129  cloudFieldTypes.insert(vectorIOField::typeName);
130  cloudFieldTypes.insert(tensorIOField::typeName);
131 
132  const char* geometryName = "geometry";
133 
134  #include "setRootCase.H"
135  #include "createTime.H"
136 
137  // get times list
138  instantList timeDirs = timeSelector::select0(runTime, args);
139 
140  // default to binary output, unless otherwise specified
142  if (args.optionFound("ascii"))
143  {
144  format = IOstream::ASCII;
145  }
146 
147  // control for renumbering iterations
148  label indexingNumber = 0;
149  bool optIndex = args.optionReadIfPresent("index", indexingNumber);
150 
151  // always write the geometry, unless the -noMesh option is specified
152  bool optNoMesh = args.optionFound("noMesh");
153 
154  // adjust output width
155  if (args.optionFound("width"))
156  {
158  }
159 
160  // define sub-directory name to use for Ensight data
161  fileName ensightDir = "Ensight";
162  args.optionReadIfPresent("name", ensightDir);
163 
164  if (!ensightDir.isAbsolute())
165  {
166  ensightDir = args.rootPath()/args.globalCaseName()/ensightDir;
167  }
168 
169  fileName dataDir = ensightDir/"data";
170  fileName caseFileName = "Ensight.case";
171  fileName dataMask = fileName("data")/ensightFile::mask();
172 
173  // Ensight and Ensight/data directories must exist
174  // do not remove old data - we might wish to convert new results
175  // or a particular time interval
176  if (isDir(ensightDir))
177  {
178  Info<<"Warning: re-using existing directory" << nl
179  << " " << ensightDir << endl;
180  }
181  mkDir(ensightDir);
182  mkDir(dataDir);
183 
184  #include "createNamedMesh.H"
185 
186  // Mesh instance (region0 gets filtered out)
187  fileName regionPrefix;
188 
190  {
191  regionPrefix = regionName;
192  }
193 
194  // Construct the list of ensight parts for the entire mesh
195  ensightParts partsList(mesh);
196 
197  // write summary information
198  {
199  OFstream partsInfoFile(ensightDir/"partsInfo");
200 
201  partsInfoFile
202  << "// summary of ensight parts" << nl << nl;
203  partsList.writeSummary(partsInfoFile);
204  }
205 
206  #include "checkHasMovingMesh.H"
207  #include "findFields.H"
208 
209  if (hasMovingMesh && optNoMesh)
210  {
211  Info<< "mesh is moving: ignoring '-noMesh' option" << endl;
212  optNoMesh = false;
213  }
214 
215 
216  // map times used
217  Map<scalar> timeIndices;
218 
219  // Track the time indices used by the volume fields
220  DynamicList<label> fieldTimesUsed;
221 
222  // Track the time indices used by each cloud
223  HashTable<DynamicList<label>> cloudTimesUsed;
224 
225  // Create a new DynamicList for each cloud
227  {
228  cloudTimesUsed.insert(cloudIter.key(), DynamicList<label>());
229  }
230 
231 
232  forAll(timeDirs, timeI)
233  {
234  runTime.setTime(timeDirs[timeI], timeI);
235 
236  #include "getTimeIndex.H"
237 
238  // remember the time index
239  fieldTimesUsed.append(timeIndex);
240 
241  // the data/ITER subdirectory must exist
243  mkDir(dataDir/subDir);
244 
245  // place a timestamp in the directory for future reference
246  {
247  OFstream timeStamp(dataDir/subDir/"time");
248  timeStamp
249  << "# timestep time" << nl
250  << subDir.c_str() << " " << runTime.timeName() << nl;
251  }
252 
253  #include "moveMesh.H"
254 
255  if (timeI == 0 || mesh.moving())
256  {
257  if (mesh.moving())
258  {
259  partsList.recalculate(mesh);
260  }
261 
262  if (!optNoMesh)
263  {
264  fileName geomDir;
265  if (hasMovingMesh)
266  {
267  geomDir = dataDir/subDir;
268  }
269 
270  ensightGeoFile geoFile(ensightDir/geomDir/geometryName, format);
271  partsList.writeGeometry(geoFile);
272  Info<< nl;
273  }
274  }
275 
276  Info<< "write volume field (" << flush;
277 
279  {
280  const word& fieldName = fieldIter.key();
281  const word& fieldType = fieldIter();
282 
284  (
285  fieldName,
286  mesh.time().timeName(),
287  mesh,
290  );
291 
292  if (fieldType == volScalarField::typeName)
293  {
294  ensightVolField<scalar>
295  (
296  partsList,
297  fieldObject,
298  mesh,
299  dataDir,
300  subDir,
301  format
302  );
303 
304  }
305  else if (fieldType == volVectorField::typeName)
306  {
307  ensightVolField<vector>
308  (
309  partsList,
310  fieldObject,
311  mesh,
312  dataDir,
313  subDir,
314  format
315  );
316 
317  }
318  else if (fieldType == volSphericalTensorField::typeName)
319  {
320  ensightVolField<sphericalTensor>
321  (
322  partsList,
323  fieldObject,
324  mesh,
325  dataDir,
326  subDir,
327  format
328  );
329 
330  }
331  else if (fieldType == volSymmTensorField::typeName)
332  {
333  ensightVolField<symmTensor>
334  (
335  partsList,
336  fieldObject,
337  mesh,
338  dataDir,
339  subDir,
340  format
341  );
342  }
343  else if (fieldType == volTensorField::typeName)
344  {
345  ensightVolField<tensor>
346  (
347  partsList,
348  fieldObject,
349  mesh,
350  dataDir,
351  subDir,
352  format
353  );
354  }
355  }
356  Info<< " )" << endl;
357 
358  // check for clouds
360  {
361  const word& cloudName = cloudIter.key();
362 
363  if
364  (
365  !isDir
366  (
367  runTime.timePath()/regionPrefix/
369  )
370  )
371  {
372  continue;
373  }
374 
375  IOobjectList cloudObjs
376  (
377  mesh,
378  runTime.timeName(),
380  );
381 
382  // check that the positions field is present for this time
383  IOobject* positionPtr = cloudObjs.lookup(word("positions"));
384  if (positionPtr != nullptr)
385  {
387  (
388  mesh,
389  dataDir,
390  subDir,
391  cloudName,
392  format
393  );
394  }
395  else
396  {
397  continue;
398  }
399 
400  Info<< "write " << cloudName << " (" << flush;
401 
402  forAllConstIter(HashTable<word>, cloudIter(), fieldIter)
403  {
404  const word& fieldName = fieldIter.key();
405  const word& fieldType = fieldIter();
406 
407  IOobject *fieldObject = cloudObjs.lookup(fieldName);
408 
409  if (!fieldObject)
410  {
411  Info<< "missing "
412  << runTime.timeName()/cloud::prefix/cloudName
413  / fieldName
414  << endl;
415  continue;
416  }
417 
418  if (fieldType == scalarIOField::typeName)
419  {
420  ensightLagrangianField<scalar>
421  (
422  *fieldObject,
423  dataDir,
424  subDir,
425  cloudName,
426  format
427  );
428 
429  }
430  else if (fieldType == vectorIOField::typeName)
431  {
432  ensightLagrangianField<vector>
433  (
434  *fieldObject,
435  dataDir,
436  subDir,
437  cloudName,
438  format
439  );
440 
441  }
442  else if (fieldType == tensorIOField::typeName)
443  {
444  ensightLagrangianField<tensor>
445  (
446  *fieldObject,
447  dataDir,
448  subDir,
449  cloudName,
450  format
451  );
452 
453  }
454  }
455 
456  Info<< " )" << endl;
457 
458  // remember the time index
459  cloudTimesUsed[cloudName].append(timeIndex);
460  }
461  }
462 
463  #include "ensightOutputCase.H"
464 
465  Info<< "\nEnd\n"<< endl;
466 
467  return 0;
468 }
469 
470 
471 // ************************************************************************* //
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
Foam::word regionName
A collection of several ensightPart elements.
Definition: ensightParts.H:59
A class for handling file names.
Definition: fileName.H:79
List of IOobjects with searching and retrieving facilities.
Definition: IOobjectList.H:50
bool moving() const
Is mesh moving.
Definition: polyMesh.H:525
const fileName & globalCaseName() const
Return case name.
Definition: argListI.H:54
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:477
static const char *const typeName
Definition: Field.H:105
const fileName & rootPath() const
Return root path.
Definition: argListI.H:42
Output to file stream.
Definition: OFstream.H:82
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:325
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
Specialised Ensight output with extra geometry file header.
void ensightParticlePositions(const polyMesh &mesh, const fileName &dataDir, const fileName &subDir, const word &cloudName, IOstream::streamFormat format)
static void noParallel()
Remove the parallel options.
Definition: argList.C:175
static string subDir(const label)
Consistent zero-padded numbers for subdirectories.
Definition: ensightFile.C:49
word format(conversionProperties.lookup("format"))
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:372
IOobject fieldObject(fieldNames[var2field[nVar]], runTime.timeName(), mesh, IOobject::MUST_READ, IOobject::NO_WRITE)
fvMesh & mesh
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:111
HashTable< word > volumeFields
Definition: findFields.H:4
bool optionReadIfPresent(const word &opt, T &) const
Read a value from the named option if present.
Definition: argListI.H:204
bool insert(const Key &, const T &newElmt)
Insert a new hashedEntry.
Definition: HashTableI.H:80
HashTable< HashTable< word > > cloudFields
Definition: findFields.H:7
T optionRead(const word &opt) const
Read a value from the named option.
Definition: argListI.H:193
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
static word timeName(const scalar, const int precision=curPrecision_)
Return time name of given scalar time.
Definition: Time.C:666
bool isAbsolute() const
Return true if file name is absolute.
Definition: fileName.C:73
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
Miscellaneous collection of functions and template related to Ensight data.
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
streamFormat
Enumeration for the format of data in the stream.
Definition: IOstream.H:86
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
static string mask()
The &#39;*&#39; mask appropriate for subDir.
Definition: ensightFile.C:43
An STL-conforming hash table.
Definition: HashTable.H:61
Istream and Ostream manipulators taking arguments.
static const char nl
Definition: Ostream.H:260
static const word prefix
The prefix to local: lagrangian.
Definition: cloud.H:62
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
Ostream & flush(Ostream &os)
Flush stream.
Definition: Ostream.H:243
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
bool hasMovingMesh
Foam::argList args(argc, argv)
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:98
static label subDirWidth()
Return current width of subDir and mask.
Definition: ensightFile.C:76
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.
A HashTable to objects of type <T> with a label key.
Definition: Map.H:49