ensightCoordSetWriterCollated.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) 2022-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
29 
30 Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
31 (
32  const bool writeTracks
33 )
34 {
35  // Collated?
36  // ========
37  // CaseFile: rootdir/NAME/NAME.case
38  // Geometry: rootdir/NAME/NAME.mesh
39 
40  wroteGeom_ = true;
41  return fileName::null;
42 }
43 
44 
45 template<class Type>
46 Foam::fileName Foam::coordSetWriters::ensightWriter::writeCollated
47 (
48  const word& fieldName,
49  const UPtrList<const Field<Type>>& fieldPtrs,
50  elemOutputType elemOutput
51 )
52 {
53  // Geometry changed since last output? Capture now
54  const bool geomChanged = (!upToDate_);
55 
56  checkOpen();
57 
58  const ensight::FileName baseName(outputPath_.name());
59  const ensight::VarName varName(fieldName);
60 
61 
62  // Collated
63  // ========
64  // CaseFile: rootdir/NAME/NAME.case
65  // Geometry: rootdir/NAME/data/<index>/geometry
66  // Field: rootdir/NAME/data/<index>/field
67 
68  // Use geometry name as sub-directory for results. Eg,
69  // - NAME1/NAME1.case
70  // - NAME1/data/00000000/geometry
71  // - NAME1/data/00000000/VAR1
72  // - NAME1/data/00000000/VAR2
73 
74  // Names "data" and "geometry" as per ensightCase:
75  const int maskWidth = 8;
76  const char* mask = "data/********/";
77 
78  // Ignore the useTimeDir setting - manage ourselves
79  const fileName baseDir = outputPath_;
80 
81  const word timeDir = timeName();
82  const scalar timeValue = currTime_.value();
83 
84  const fileName outputFile = baseDir / baseName + ".case";
85 
86  if (verbose_)
87  {
88  Info<< "Writing case file to " << outputFile << endl;
89  }
90 
91  // Update geometry
92  merge();
93 
94  {
95  if (!isDir(outputFile.path()))
96  {
97  mkDir(outputFile.path());
98  }
99 
100  const bool stateChanged =
101  caching_.update
102  (
103  baseDir,
104  timeValue,
105  geomChanged,
106  fieldName,
108  varName
109  );
110 
111 
112  // The most current time and geometry indices
113  const label timeIndex = caching_.latestTimeIndex();
114  const label geomIndex = caching_.latestGeomIndex();
115 
116 
117  // This will be used for the name of a static geometry,
118  // or just the masking part for moving geometries.
119  const fileName geometryName
120  (
121  "data"
122  / ensightCase::padded(maskWidth, geomIndex)
124  );
125 
126 
127  // Location for data (and possibly the geometry as well)
128  const fileName dataDir
129  (
130  baseDir/"data"/ensightCase::padded(maskWidth, timeIndex)
131  );
132 
133  // As per mkdir -p "data/00000000"
134  mkDir(dataDir);
135 
136 
137  const fileName geomFile(baseDir/geometryName);
138 
139  if (!exists(geomFile))
140  {
141  if (verbose_)
142  {
143  Info<< "Writing geometry to " << geomFile.name() << endl;
144  }
145 
146  // Two-argument form for path-name to avoid validating base-dir
147  ensightGeoFile osGeom
148  (
149  geomFile.path(),
150  geomFile.name(),
151  caseOpts_.format()
152  );
153 
154  writeGeometry(osGeom, elemOutput);
155  }
156 
157 
158  // Write field
159  ensightFile osField
160  (
161  dataDir,
162  varName,
163  caseOpts_.format()
164  );
165 
166  if (verbose_)
167  {
168  Info<< "Writing field file to " << osField.name() << endl;
169  }
170 
171 
172  // Write field (serial only)
173  writeTrackField<Type>(osField, fieldPtrs);
174 
175 
176  // Update case file
177  if (stateChanged)
178  {
179  OFstream osCase(outputFile, IOstreamOption::ASCII);
180  ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
181 
182  if (verbose_)
183  {
184  Info<< "Writing case file to " << osCase.name() << endl;
185  }
186 
187 
188  // The geometry can be any of the following:
189  // 0: constant/static
190  // 1: moving, with the same frequency as the data
191  // 2: moving, with different frequency as the data
192 
193  const label tsGeom = caching_.geometryTimeset();
194 
195  osCase
196  << "FORMAT" << nl
197  << "type: ensight gold" << nl
198  << nl
199  << "GEOMETRY" << nl;
200 
201  if (tsGeom)
202  {
203  // moving
204  osCase
205  << "model: " << tsGeom << " " // time-set (1|2)
206  << mask << geometryName.name() << nl;
207  }
208  else
209  {
210  // steady
211  osCase
212  << "model: "
213  << geometryName.c_str() << nl;
214  }
215 
216  osCase
217  << nl
218  << "VARIABLE" << nl;
219 
220 
221  for (const entry& dEntry : caching_.fieldsDict())
222  {
223  const dictionary& subDict = dEntry.dict();
224 
225  const word varType(subDict.get<word>("type"));
226  const word varName
227  (
228  subDict.getOrDefault<word>
229  (
230  "name",
231  dEntry.keyword() // fieldName as fallback
232  )
233  );
234 
235  osCase
236  << varType
237  <<
238  (
239  true // this->isPointData()
240  ? " per node: 1 " // time-set 1
241  : " per element: 1 " // time-set 1
242  )
243  << setw(15) << varName << ' '
244  << mask << ensight::FileName(varName).c_str() << nl;
245  }
246 
247  osCase
248  << nl
249  << "TIME" << nl;
250 
251  ensightCase::printTimeset(osCase, 1, caching_.times());
252  if (tsGeom == 2)
253  {
255  (
256  osCase,
257  tsGeom,
258  caching_.times(),
259  caching_.geometries()
260  );
261  }
262 
263  osCase << "# end" << nl;
264  }
265 
266  // Timestamp in the directory for future reference
267  {
268  OFstream timeStamp(dataDir/"time");
269  timeStamp
270  << "# timestep time" << nl
271  << dataDir.name() << ' ' << timeValue << nl;
272  }
273  }
274 
275  wroteGeom_ = true;
276  return outputFile;
277 }
278 
279 
280 // ************************************************************************* //
static void printTimeset(OSstream &os, const label ts, const scalar timeValue)
Print time-set for ensight case file with a single time.
Definition: ensightCase.C:91
A class for handling file names.
Definition: fileName.H:72
static void setTimeFormat(OSstream &os, IOstreamOption::floatFormat timeFmt, const int timePrec)
Set output time format for ensight case file.
Definition: ensightCase.C:53
writer writeGeometry()
static word padded(const int nwidth, const label value)
Stringified zero-padded integer value.
Definition: ensightCase.C:38
bool wroteGeom_
Track if geometry has been written since the last open.
Specification of a valid Ensight file-name.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
"ascii" (normal default)
static const fileName null
An empty fileName.
Definition: fileName.H:111
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:860
word timeName
Definition: getTimeIndex.H:3
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:614
Generic templated field type.
Definition: Field.H:62
A class for handling words, derived from Foam::string.
Definition: word.H:63
static const char * geometryName
The name for geometry files: "geometry".
Definition: ensightCase.H:82
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: POSIX.C:835
A list of pointers to objects of type <T>, without allocation/deallocation management of the pointers...
Definition: HashTable.H:106
const char *const typeName
Specification of a valid Ensight variable-name.
messageStream Info
Information stream (stdout output on master, null elsewhere)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
label timeIndex
Definition: getTimeIndex.H:24