ensightSurfaceWriterCollated.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 | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2014 OpenFOAM Foundation
9  Copyright (C) 2015-2019 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
30 
31 namespace Foam
32 {
33 
34 // Compare time values with tolerance
35 static const equalOp<scalar> equalTimes(ROOTSMALL);
36 
37 // Use ListOps findLower (with tolerance), to find the location of the next
38 // time-related index.
39 // The returned index is always 0 or larger (no negative values).
40 static label findTimeIndex(const UList<scalar>& list, const scalar val)
41 {
42  label idx =
43  findLower
44  (
45  list,
46  val,
47  0,
48  [](const scalar a, const scalar b)
49  {
50  return (a < b) && (Foam::mag(b - a) > ROOTSMALL);
51  }
52  );
53 
54  if (idx < 0 || !equalTimes(list[idx], val))
55  {
56  ++idx;
57  }
58 
59  return idx;
60 }
61 
62 } // End namespace Foam
63 
64 
65 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
66 
67 Foam::label Foam::surfaceWriters::ensightWriter::readPreviousTimes
68 (
69  const fileName& baseDir,
70  const word& dictName,
71  const scalar& timeValue
72 )
73 {
74  // In 1906 and earlier, the fieldsDict contained "meshes" and "times"
75  // entries, each with their own time values.
76  // This makes it more difficult to define the exact correspondence
77  // between geometry intervals and times.
78  //
79  // We now instead track used geometry intervals as a bitSet.
80 
81 
82  // Only called from master
83 
84  label timeIndex = 0;
85 
86  labelList geomIndices;
87  scalarList meshTimes;
88 
89  cache_.clear();
90 
91  const fileName dictFile(baseDir/dictName);
92 
93  if (isFile(dictFile))
94  {
95  IFstream is(dictFile);
96 
97  if (is.good() && cache_.read(is))
98  {
99  meshes_.clear();
100 
101  cache_.readIfPresent("times", times_);
102  timeIndex = findTimeIndex(times_, timeValue);
103 
104  if (cache_.readIfPresent("geometry", geomIndices))
105  {
106  // Convert indices to bitSet entries
107  meshes_.set(geomIndices);
108  }
109  else if (cache_.readIfPresent("meshes", meshTimes))
110  {
112  << nl
113  << "Setting geometry timeset information from time values"
114  << " (fieldsDict from an older OpenFOAM version)." << nl
115  << "This may not be fully reliable." << nl
116  << nl;
117 
118  for (const scalar& meshTime : meshTimes)
119  {
120  const label meshIndex = findTimeIndex(times_, meshTime);
121  meshes_.set(meshIndex);
122  }
123  }
124 
125  // Make length consistent with time information.
126  // We read/write the indices instead of simply dumping the bitSet.
127  // This makes the contents more human readable.
128  meshes_.resize(times_.size());
129  }
130  }
131 
132  return timeIndex;
133 }
134 
135 
136 int Foam::surfaceWriters::ensightWriter::geometryTimeset() const
137 {
138  if (meshes_.count() <= 1)
139  {
140  // Static
141  return 0;
142  }
143 
144  if (meshes_.size() == times_.size() && meshes_.all())
145  {
146  // Geometry changing is the same as fields changing
147  return 1;
148  }
149 
150  // Geometry changing differently from fields
151  return 2;
152 }
153 
154 
155 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
156 
157 Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated()
158 {
159  // Collated?
160  // ========
161  // Geometry: rootdir/surfaceName/surfaceName.case
162  // Geometry: rootdir/surfaceName/surfaceName.mesh
163 
164  wroteGeom_ = true;
165  return fileName::null;
166 }
167 
168 
169 template<class Type>
170 Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
171 (
172  const word& fieldName,
173  const Field<Type>& localValues
174 )
175 {
176  checkOpen();
177 
178  const ensight::FileName surfName(outputPath_.name());
179  const ensight::VarName varName(fieldName);
180 
181 
182  // Collated
183  // ========
184  // Geometry: rootdir/surfaceName/surfaceName.case
185  // Geometry: rootdir/surfaceName/data/<index>/geometry
186  // Field: rootdir/surfaceName/data/<index>/field
187 
188  // Use surface name as sub-directory for results. Eg,
189  // - SURF1/SURF1.case
190  // - SURF1/data/00000000/geometry
191  // - SURF1/data/00000000/VAR1
192  // - SURF1/data/00000000/VAR2
193 
194  // Names "data" and "geometry" as per ensightCase:
195  const char* fmt = "%08d";
196  const char* mask = "data/********/";
197 
198 
199  // Ignore the useTimeDir setting - manage ourselves
200  const fileName baseDir = outputPath_;
201 
202  const word timeDir = timeName();
203  const scalar timeValue = currTime_.value();
204 
205  const fileName outputFile = baseDir / surfName + ".case";
206 
207  if (verbose_)
208  {
209  Info<< "Writing case file to " << outputFile << endl;
210  }
211 
212 
213  // Mesh changed since last output? Do before any merging.
214  const bool meshChanged = (!upToDate_);
215 
216 
217  // geometry merge() implicit
218  tmp<Field<Type>> tfield = mergeField(localValues);
219 
220  const meshedSurf& surf = surface();
221 
222  if (Pstream::master() || !parallel_)
223  {
224  if (!isDir(outputFile.path()))
225  {
226  mkDir(outputFile.path());
227  }
228 
229  bool stateChanged = meshChanged;
230 
231  const label timeIndex =
232  (
233  times_.empty()
234  ? readPreviousTimes(baseDir, "fieldsDict", timeValue)
235  : findTimeIndex(times_, timeValue)
236  );
237 
238 
239  // Update stored times list and mesh index
240 
241  if (timeIndex < meshes_.size()-1)
242  {
243  // Clear old content when shrinking
244  meshes_.unset(timeIndex);
245  }
246 
247  // Extend or truncate list
248  meshes_.resize(timeIndex+1);
249  times_.resize(timeIndex+1, VGREAT);
250 
251  if (meshChanged)
252  {
253  meshes_.set(timeIndex);
254  }
255 
256  if (!equalTimes(times_[timeIndex], timeValue))
257  {
258  stateChanged = true;
259  times_[timeIndex] = timeValue;
260  }
261 
262 
263  // The most current geometry index
264  const label geomIndex(max(0, meshes_.find_last()));
265 
266 
267  // This will be used for the name of a static geometry,
268  // or just the masking part for moving geometries.
269  const fileName geometryName
270  (
271  "data"/word::printf(fmt, geomIndex)/ensightCase::geometryName
272  );
273 
274 
275  // Do case file
276  {
277  // Add time information to dictionary
278  cache_.set("geometry", meshes_.sortedToc());
279  cache_.set("times", times_);
280 
281  // Debugging, or if needed for older versions:
287 
288  // Add field information to dictionary
289  dictionary& fieldsDict = cache_.subDictOrAdd("fields");
290  dictionary& fieldDict = fieldsDict.subDictOrAdd(fieldName);
291 
292  if (fieldDict.empty())
293  {
294  fieldDict.set("type", ensightPTraits<Type>::typeName);
295  fieldDict.set("name", varName); // ensight variable name
296  stateChanged = true;
297  }
298 
299 
300  if (stateChanged)
301  {
302  if (verbose_)
303  {
304  Info<< "Writing state file to fieldsDict" << endl;
305  }
306  {
307  OFstream os(baseDir/"fieldsDict");
308  os << "// Summary of Ensight fields, times" << nl << nl;
309  cache_.write(os, false);
310  }
311 
312  OFstream osCase(outputFile, IOstream::ASCII);
313 
314  // Format options
315  osCase.setf(ios_base::left);
316  osCase.setf(ios_base::scientific, ios_base::floatfield);
317  osCase.precision(5);
318 
319  if (verbose_)
320  {
321  Info<< "Writing case file to " << osCase.name() << endl;
322  }
323 
324  // The geometry can be any of the following:
325  // 0: constant/static
326  // 1: moving, with the same frequency as the data
327  // 2: moving, with different frequency as the data
328 
329  const label tsGeom = geometryTimeset();
330 
331  osCase
332  << "FORMAT" << nl
333  << "type: ensight gold" << nl
334  << nl
335  << "GEOMETRY" << nl;
336 
337 
338  if (tsGeom)
339  {
340  // moving
341  osCase
342  << "model: " << tsGeom << " " // time-set (1|2)
343  << mask << geometryName.name() << nl;
344  }
345  else
346  {
347  // steady
348  osCase
349  << "model: "
350  << geometryName.c_str() << nl;
351  }
352 
353  osCase
354  << nl
355  << "VARIABLE" << nl;
356 
357 
358  for (const entry& dEntry : fieldsDict)
359  {
360  const dictionary& subDict = dEntry.dict();
361 
362  const word fieldType(subDict.get<word>("type"));
363  const word varName
364  (
365  subDict.getOrDefault<word>
366  (
367  "name",
368  dEntry.keyword() // fieldName as fallback
369  )
370  );
371 
372  osCase
373  << fieldType
374  <<
375  (
376  this->isPointData()
377  ? " per node: 1 " // time-set 1
378  : " per element: 1 " // time-set 1
379  )
380  << setw(15) << varName << ' '
381  << mask << varName << nl;
382  }
383 
384  osCase
385  << nl
386  << "TIME" << nl;
387 
388  printTimeset(osCase, 1, times_);
389  if (tsGeom == 2)
390  {
391  printTimeset(osCase, 2, times_, meshes_);
392  }
393 
394  osCase << "# end" << nl;
395  }
396  }
397 
398 
399  // Location for data (and possibly the geometry as well)
400  fileName dataDir = baseDir/"data"/word::printf(fmt, timeIndex);
401 
402  // As per mkdir -p "data/00000000"
403  mkDir(dataDir);
404 
405 
406  const fileName meshFile(baseDir/geometryName);
407 
408  // Write geometry
409  ensightPartFaces ensPart
410  (
411  0,
412  meshFile.name(),
413  surf.points(),
414  surf.faces(),
415  true // contiguous points
416  );
417  if (!exists(meshFile))
418  {
419  if (verbose_)
420  {
421  Info<< "Writing mesh file to " << meshFile.name() << endl;
422  }
423  // Use two-argument form for path-name to avoid validating base-dir
424  ensightGeoFile osGeom
425  (
426  meshFile.path(),
427  meshFile.name(),
428  writeFormat_
429  );
430  osGeom << ensPart;
431  }
432 
433  // Write field
434  ensightFile osField
435  (
436  dataDir,
437  varName,
438  writeFormat_
439  );
440 
441  if (verbose_)
442  {
443  Info<< "Writing field file to " << osField.name() << endl;
444  }
445 
446  // Write field
448 
449  if (this->isPointData())
450  {
452  (
453  tfield(),
454  ensPart,
455  osField
456  // serial
457  );
458  }
459  else
460  {
462  (
463  tfield(),
464  ensPart,
465  osField,
466  false // serial
467  );
468  }
469 
470  // Place a timestamp in the directory for future reference
471  {
472  OFstream timeStamp(dataDir/"time");
473  timeStamp
474  << "# timestep time" << nl
475  << dataDir.name() << ' ' << timeValue << nl;
476  }
477  }
478 
479  wroteGeom_ = true;
480  return outputFile;
481 }
482 
483 
484 // ************************************************************************* //
Foam::entry
A keyword and a list of tokens is an 'entry'.
Definition: entry.H:67
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:74
Foam::scalarList
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:64
Foam::val
label ListType::const_reference val
Definition: ListOps.H:407
Foam::exists
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: MSwindows.C:625
Foam::surfaceWriter::timeValue
scalar timeValue() const
The current time value/name.
Definition: surfaceWriterI.H:102
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::OFstream::name
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:91
Foam::fileName::path
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:186
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:59
Foam::fileName::name
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:209
Foam::meshedSurf::faces
virtual const faceList & faces() const =0
The faces used for the surface.
Foam::meshedSurf
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:49
dictName
const word dictName("blockMeshDict")
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:563
Foam::isFile
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: MSwindows.C:658
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
Foam::dictionary::get
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:81
Foam::dictionary::set
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:842
Foam::PackedList::resize
void resize(const label nElem, const unsigned int val=0u)
Reset addressable list size, does not shrink the allocated size.
Definition: PackedListI.H:388
Foam::dictionary::subDictOrAdd
dictionary & subDictOrAdd(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find and return a sub-dictionary for manipulation.
Definition: dictionary.C:563
Foam::ensightFile::writeKeyword
virtual Ostream & writeKeyword(const keyType &key)
Write element keyword with trailing newline, optionally with undef.
Definition: ensightFile.C:285
Foam::ensightPTraits
Conversion of OpenFOAM pTraits into the Ensight equivalent.
Definition: ensightPTraits.H:54
Foam::ensightGeoFile
Specialized Ensight output with extra geometry file header.
Definition: ensightGeoFile.H:48
Foam::ensight::FileName
Specification of a valid Ensight file-name.
Definition: ensightFileName.H:56
Foam::ensight::VarName
Specification of a valid Ensight variable-name.
Definition: ensightVarName.H:58
Foam::label
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:62
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::Field
Generic templated field type.
Definition: Field.H:63
Foam::findLower
label findLower(const ListType &input, const T &val, const label start, const ComparePredicate &comp)
Foam::ensightOutput::Serial::writePointField
bool writePointField(const Field< Type > &fld, const ensightFaces &part, ensightFile &os)
Write a field of point (node) values (already compacted?)
Definition: ensightOutputTemplates.C:229
Foam::Info
messageStream Info
Information stream (uses stdout - output is on the master only)
Foam::equalTimes
static const equalOp< scalar > equalTimes(ROOTSMALL)
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::meshedSurf::points
virtual const pointField & points() const =0
The points used for the surface.
timeIndex
label timeIndex
Definition: getTimeIndex.H:4
timeName
word timeName
Definition: getTimeIndex.H:3
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::ensightFile
Ensight output with specialized write() for strings, integers and floats. Correctly handles binary wr...
Definition: ensightFile.H:54
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Foam::scientific
IOstream & scientific(IOstream &io)
Definition: IOstream.H:447
Foam::fileName::null
static const fileName null
An empty fileName.
Definition: fileName.H:97
Foam::dictionary::read
bool read(Istream &is)
Read dictionary from Istream.
Definition: dictionaryIO.C:141
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:99
Foam::IOstream::setf
ios_base::fmtflags setf(const ios_base::fmtflags f)
Set flags of stream.
Definition: IOstream.H:361
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:438
Foam::OSstream::precision
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:311
Foam::findTimeIndex
static label findTimeIndex(const UList< scalar > &list, const scalar val)
Definition: ensightSurfaceWriterCollated.C:40
Foam::IOstreamOption::ASCII
"ascii"
Definition: IOstreamOption.H:66
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::UList
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:103
Foam::ensightOutput::Detail::writeFaceField
bool writeFaceField(const Field< Type > &fld, const ensightFaces &part, ensightFile &os, bool parallel)
Definition: ensightOutputTemplates.C:119
Foam::ensightPartFaces
An implementation of ensightPart to hold mesh faces.
Definition: ensightPartFaces.H:53
Foam::word::printf
static word printf(const char *fmt, const PrimitiveType &val)
Use a printf-style formatter for a primitive.
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:122
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
Foam::dictionary::clear
void clear()
Clear the dictionary.
Definition: dictionary.C:919
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::ensightCase::geometryName
static const char * geometryName
The name for geometry files.
Definition: ensightCase.H:76
Foam::PackedList::clear
void clear()
Clear the list, i.e. set addressable size to zero.
Definition: PackedListI.H:502
Foam::dictionary::readIfPresent
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:417
Foam::isDir
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:643