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-2024 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 (!Foam::isDir(outputFile.path()))
96  {
97  Foam::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  Foam::mkDir(dataDir);
135 
136 
137  const fileName geomFile(baseDir/geometryName);
138 
139  if (!Foam::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  osGeom.beginGeometry();
155  writeGeometry(osGeom, elemOutput);
156  }
157 
158 
159  // Write field
160  ensightFile osField
161  (
162  dataDir,
163  varName,
164  caseOpts_.format()
165  );
166 
167  if (verbose_)
168  {
169  Info<< "Writing field file to " << osField.name() << endl;
170  }
171 
172 
173  // Write field (serial only)
174  writeTrackField<Type>(osField, fieldPtrs);
175 
176 
177  // Update case file
178  if (stateChanged)
179  {
180  OFstream osCase
181  (
183  outputFile,
185  );
186  ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
187 
188  if (verbose_)
189  {
190  Info<< "Writing case file to " << osCase.name() << endl;
191  }
192 
193 
194  // The geometry can be any of the following:
195  // 0: constant/static
196  // 1: moving, with the same frequency as the data
197  // 2: moving, with different frequency as the data
198 
199  const label tsGeom = caching_.geometryTimeset();
200 
201  osCase
202  << "FORMAT" << nl
203  << "type: ensight gold" << nl
204  << nl
205  << "GEOMETRY" << nl;
206 
207  if (tsGeom)
208  {
209  // moving
210  osCase
211  << "model: " << tsGeom << " " // time-set (1|2)
212  << mask << geometryName.name() << nl;
213  }
214  else
215  {
216  // steady
217  osCase
218  << "model: "
219  << geometryName.c_str() << nl;
220  }
221 
222  osCase
223  << nl
224  << "VARIABLE" << nl;
225 
226 
227  for (const entry& dEntry : caching_.fieldsDict())
228  {
229  const dictionary& subDict = dEntry.dict();
230 
231  const string varType(subDict.get<string>("type"));
232  const word varName
233  (
234  subDict.getOrDefault<word>
235  (
236  "name",
237  dEntry.keyword() // fieldName as fallback
238  )
239  );
240 
241  osCase
242  << varType.c_str()
243  <<
244  (
245  true // this->isPointData()
246  ? " per node: 1 " // time-set 1
247  : " per element: 1 " // time-set 1
248  )
249  << setw(15) << varName << ' '
250  << mask << ensight::FileName(varName).c_str() << nl;
251  }
252 
253  osCase
254  << nl
255  << "TIME" << nl;
256 
257  ensightCase::printTimeset(osCase, 1, caching_.times());
258  if (tsGeom == 2)
259  {
261  (
262  osCase,
263  tsGeom,
264  caching_.times(),
265  caching_.geometries()
266  );
267  }
268 
269  osCase << "# end" << nl;
270  }
271 
272  // Timestamp in the directory for future reference
273  {
274  OFstream timeStamp(dataDir/"time");
275  timeStamp
276  << "# timestep time" << nl
277  << dataDir.name() << ' ' << timeValue << nl;
278  }
279  }
280 
281  wroteGeom_ = true;
282  return outputFile;
283 }
284 
285 
286 // ************************************************************************* //
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:101
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:63
writer writeGeometry()
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:80
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.
static word padded(const int nwidth, const label index)
Stringified zero-padded integer value of specified width.
Definition: ensightCase.C:48
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