FreeFOAM The Cross-Platform CFD Toolkit
foamToEnsight.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
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 FOAM data to EnSight format.
29 
30  An Ensight part is created for the internalMesh and for each patch.
31 
32 Usage
33  - foamToEnsight [OPTION] \n
34  Translates OpenFOAM data to Ensight format
35 
36  @param -ascii \n
37  Write Ensight data in ASCII format instead of "C Binary"
38 
39  @param -patches patchList \n
40  Specify particular patches to write.
41  Specifying an empty list suppresses writing the internalMesh.
42 
43  @param -noPatches \n
44  Suppress writing any patches.
45 
46  @param -case <dir> \n
47  Case directory.
48 
49  @param -noZero \n
50  Ignore time step 0.
51 
52  @param -constant \n
53  Include the constant directory.
54 
55  @param -latestTime \n
56  Only apply to the latest time step.
57 
58  @param -parallel \n
59  Run in parallel.
60 
61  @param -time <time>\n
62  Apply only to specified time.
63 
64  @param -help \n
65  Display help message.
66 
67  @param -doc \n
68  Display Doxygen API documentation page for this application.
69 
70  @param -srcDoc \n
71  Display Doxygen source documentation page for this application.
72 
73 Note
74  Parallel support for cloud data is not supported
75  - writes to @a EnSight directory to avoid collisions with foamToEnsightParts
76 
77 \*---------------------------------------------------------------------------*/
78 
79 #include <OpenFOAM/argList.H>
80 #include <OpenFOAM/timeSelector.H>
81 #include <OpenFOAM/IOobjectList.H>
82 #include <OpenFOAM/IOmanip.H>
83 #include <OpenFOAM/OFstream.H>
84 
85 #include <finiteVolume/volFields.H>
86 
87 #include <OpenFOAM/labelIOField.H>
88 #include <OpenFOAM/scalarIOField.H>
89 #include <OpenFOAM/tensorIOField.H>
90 
91 #include "ensightMesh.H"
92 #include "ensightField.H"
93 
95 #include "ensightCloudField.H"
96 
97 #include <finiteVolume/fvc.H>
98 
99 using namespace Foam;
100 
101 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
102 
103 bool inFileNameList
104 (
105  const fileNameList& nameList,
106  const word& name
107 )
108 {
109  forAll(nameList, i)
110  {
111  if (nameList[i] == name)
112  {
113  return true;
114  }
115  }
116 
117  return false;
118 }
119 
120 
121 // Main program:
122 
123 int main(int argc, char *argv[])
124 {
125  argList::validOptions.insert("ascii", "" );
126  argList::validOptions.insert("patches", "patchList");
127  argList::validOptions.insert("noPatches", "");
128 
129 # include <OpenFOAM/addTimeOptions.H>
130 # include <OpenFOAM/addRegionOption.H>
131 # include <OpenFOAM/setRootCase.H>
132 
133  // Check options
134  bool binary = !args.optionFound("ascii");
135 
136 # include <OpenFOAM/createTime.H>
137 
138  // get the available time-steps
139  instantList Times = runTime.times();
140 
141 # include <OpenFOAM/checkTimeOptions.H>
142 
143  runTime.setTime(Times[startTime], startTime);
144 
145 # include <OpenFOAM/createNamedMesh.H>
146 
147  // Mesh instance (region0 gets filtered out)
148  fileName regionPrefix = "";
149 
151  {
152  regionPrefix = regionName;
153  }
154 
155  const label nVolFieldTypes = 5;
156  const word volFieldTypes[] =
157  {
163  };
164 
165  // Path to EnSight folder at case level only
166  // - For parallel cases, data only written from master
167  fileName ensightDir = args.rootPath()/args.globalCaseName()/"EnSight";
168 
169  if (Pstream::master())
170  {
171  if (isDir(ensightDir))
172  {
173  rmDir(ensightDir);
174  }
175 
176  mkDir(ensightDir);
177  }
178 
179  // Start of case file header output
180  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181 
182  const word prepend = args.globalCaseName() + '.';
183 
184  OFstream *ensightCaseFilePtr = NULL;
185  if (Pstream::master())
186  {
187  fileName caseFileName = prepend + "case";
188  Info<< nl << "write case: " << caseFileName.c_str() << endl;
189 
190  // the case file is always ASCII
191  ensightCaseFilePtr = new OFstream
192  (
193  ensightDir/caseFileName,
195  );
196 
197  *ensightCaseFilePtr
198  << "FORMAT" << nl
199  << "type: ensight gold" << nl << nl;
200  }
201 
202  OFstream& ensightCaseFile = *ensightCaseFilePtr;
203 
204  // Construct the EnSight mesh
205  ensightMesh eMesh(mesh, args, binary);
206 
207  // Set Time to the last time before looking for the lagrangian objects
208  runTime.setTime(Times[Times.size()-1], Times.size()-1);
209 
210  IOobjectList objects(mesh, runTime.timeName());
211 
212 # include "checkMeshMoving.H"
213 
214  wordHashSet allCloudNames;
215  if (Pstream::master())
216  {
217  word geomFileName = prepend + "000";
218 
219  // test pre check variable if there is a moving mesh
220  if (meshMoving)
221  {
222  geomFileName = prepend + "***";
223  }
224 
225  ensightCaseFile
226  << "GEOMETRY" << nl
227  << "model: 1 "
228  << (geomFileName + ".mesh").c_str() << nl;
229  }
230 
231  // Identify if lagrangian data exists at each time, and add clouds
232  // to the 'allCloudNames' hash set
233  for (label n=startTime; n<endTime; n++)
234  {
235  runTime.setTime(Times[n], n);
236 
237  fileNameList cloudDirs = readDir
238  (
239  runTime.timePath()/regionPrefix/cloud::prefix,
241  );
242 
243  forAll(cloudDirs, cloudI)
244  {
245  IOobjectList cloudObjs
246  (
247  mesh,
248  runTime.timeName(),
249  cloud::prefix/cloudDirs[cloudI]
250  );
251 
252  IOobject* positionsPtr = cloudObjs.lookup("positions");
253 
254  if (positionsPtr)
255  {
256  allCloudNames.insert(cloudDirs[cloudI]);
257  }
258  }
259  }
260 
261  HashTable<HashTable<word> > allCloudFields;
262  forAllConstIter(wordHashSet, allCloudNames, cloudIter)
263  {
264  // Add the name of the cloud(s) to the case file header
265  if (Pstream::master())
266  {
267  ensightCaseFile
268  << (
269  "measured: 1 "
270  + prepend
271  + "***."
272  + cloudIter.key()
273  ).c_str()
274  << nl;
275  }
276 
277  // Create a new hash table for each cloud
278  allCloudFields.insert(cloudIter.key(), HashTable<word>());
279 
280  // Identify the new cloud in the hash table
281  HashTable<HashTable<word> >::iterator newCloudIter =
282  allCloudFields.find(cloudIter.key());
283 
284  // Loop over all times to build list of fields and field types
285  // for each cloud
286  for (label n=startTime; n<endTime; n++)
287  {
288  runTime.setTime(Times[n], n);
289 
290  IOobjectList cloudObjs
291  (
292  mesh,
293  runTime.timeName(),
294  cloud::prefix/cloudIter.key()
295  );
296 
297  forAllConstIter(IOobjectList, cloudObjs, fieldIter)
298  {
299  const IOobject obj = *fieldIter();
300 
301  if (obj.name() != "positions")
302  {
303  // Add field and field type
304  newCloudIter().insert
305  (
306  obj.name(),
307  obj.headerClassName()
308  );
309  }
310  }
311  }
312  }
313 
314  label nTimeSteps = 0;
315  for (label n=startTime; n<endTime; n++)
316  {
317  nTimeSteps++;
318  runTime.setTime(Times[n], n);
319  label timeIndex = n - startTime;
320 
321  word timeName = itoa(timeIndex);
322  word timeFile = prepend + timeName;
323 
324  Info<< "Translating time = " << runTime.timeName() << nl;
325 
326 # include "moveMesh.H"
327 
328  if (timeIndex == 0 || mesh.moving())
329  {
330  eMesh.write
331  (
332  ensightDir,
333  prepend,
334  timeIndex,
335  ensightCaseFile
336  );
337  }
338 
339 
340  // Start of field data output
341  // ~~~~~~~~~~~~~~~~~~~~~~~~~~
342 
343  if (timeIndex == 0 && Pstream::master())
344  {
345  ensightCaseFile<< nl << "VARIABLE" << nl;
346  }
347 
348 
349  // Cell field data output
350  // ~~~~~~~~~~~~~~~~~~~~~~
351 
352  for (label i=0; i<nVolFieldTypes; i++)
353  {
354  wordList fieldNames = objects.names(volFieldTypes[i]);
355 
356  for (label j=0; j<fieldNames.size(); j++)
357  {
358  word fieldName = fieldNames[j];
359 
360 # include "checkData.H"
361 
362  if (!variableGood)
363  {
364  continue;
365  }
366 
368  (
369  fieldName,
370  mesh.time().timeName(),
371  mesh,
374  );
375 
376  if (volFieldTypes[i] == volScalarField::typeName)
377  {
378  ensightField<scalar>
379  (
380  fieldObject,
381  eMesh,
382  ensightDir,
383  prepend,
384  timeIndex,
385  binary,
386  ensightCaseFile
387  );
388  }
389  else if (volFieldTypes[i] == volVectorField::typeName)
390  {
391  ensightField<vector>
392  (
393  fieldObject,
394  eMesh,
395  ensightDir,
396  prepend,
397  timeIndex,
398  binary,
399  ensightCaseFile
400  );
401  }
402  else if (volFieldTypes[i] == volSphericalTensorField::typeName)
403  {
404  ensightField<sphericalTensor>
405  (
406  fieldObject,
407  eMesh,
408  ensightDir,
409  prepend,
410  timeIndex,
411  binary,
412  ensightCaseFile
413  );
414  }
415  else if (volFieldTypes[i] == volSymmTensorField::typeName)
416  {
417  ensightField<symmTensor>
418  (
419  fieldObject,
420  eMesh,
421  ensightDir,
422  prepend,
423  timeIndex,
424  binary,
425  ensightCaseFile
426  );
427  }
428  else if (volFieldTypes[i] == volTensorField::typeName)
429  {
430  ensightField<tensor>
431  (
432  fieldObject,
433  eMesh,
434  ensightDir,
435  prepend,
436  timeIndex,
437  binary,
438  ensightCaseFile
439  );
440  }
441  }
442  }
443 
444 
445  // Cloud field data output
446  // ~~~~~~~~~~~~~~~~~~~~~~~
447 
448  forAllConstIter(HashTable<HashTable<word> >, allCloudFields, cloudIter)
449  {
450  const word& cloudName = cloudIter.key();
451 
452  fileNameList currentCloudDirs = readDir
453  (
454  runTime.timePath()/regionPrefix/cloud::prefix,
456  );
457 
458  bool cloudExists = inFileNameList(currentCloudDirs, cloudName);
460  (
461  mesh,
462  ensightDir,
463  timeFile,
464  cloudName,
465  cloudExists
466  );
467 
468  forAllConstIter(HashTable<word>, cloudIter(), fieldIter)
469  {
470  const word& fieldName = fieldIter.key();
471  const word& fieldType = fieldIter();
472 
474  (
475  fieldName,
476  mesh.time().timeName(),
478  mesh,
480  );
481 
482  bool fieldExists = fieldObject.headerOk();
483  if (fieldType == scalarIOField::typeName)
484  {
485  ensightCloudField<scalar>
486  (
487  fieldObject,
488  ensightDir,
489  prepend,
490  timeIndex,
491  cloudName,
492  ensightCaseFile,
493  fieldExists
494  );
495  }
496  else if (fieldType == vectorIOField::typeName)
497  {
498  ensightCloudField<vector>
499  (
500  fieldObject,
501  ensightDir,
502  prepend,
503  timeIndex,
504  cloudName,
505  ensightCaseFile,
506  fieldExists
507  );
508  }
509  else
510  {
511  Info<< "Unable to convert field type " << fieldType
512  << " for field " << fieldName << endl;
513  }
514  }
515  }
516  }
517 
518 # include "ensightCaseTail.H"
519 
520  if (Pstream::master())
521  {
522  delete ensightCaseFilePtr;
523  }
524 
525  Info<< "End\n" << endl;
526 
527  return 0;
528 }
529 
530 
531 // ************************ vim: set sw=4 sts=4 et: ************************ //