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-2024 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 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
30 
31 Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated()
32 {
33  // Collated?
34  // ========
35  // CaseFile: rootdir/surfaceName/surfaceName.case
36  // Geometry: rootdir/surfaceName/surfaceName.mesh
37 
38  wroteGeom_ = true;
39  return fileName::null;
40 }
41 
42 
43 template<class Type>
44 Foam::fileName Foam::surfaceWriters::ensightWriter::writeCollated
45 (
46  const word& fieldName,
47  const Field<Type>& localValues
48 )
49 {
50  // Geometry changed since last output? Capture now before any merging.
51  const bool geomChanged = (!upToDate_);
52 
53  checkOpen();
54 
55  const ensight::FileName surfName(outputPath_.name());
56  const ensight::VarName varName(fieldName);
57 
58 
59  // Collated
60  // ========
61  // CaseFile: rootdir/surfaceName/surfaceName.case
62  // Geometry: rootdir/surfaceName/data/<index>/geometry
63  // Field: rootdir/surfaceName/data/<index>/field
64 
65  // Use surface name as sub-directory for results. Eg,
66  // - SURF1/SURF1.case
67  // - SURF1/data/00000000/geometry
68  // - SURF1/data/00000000/VAR1
69  // - SURF1/data/00000000/VAR2
70 
71  // Names "data" and "geometry" as per ensightCase:
72  const int maskWidth = 8;
73  const char* mask = "data/********/";
74 
75 
76  // Ignore the useTimeDir setting - manage ourselves
77  const fileName baseDir = outputPath_;
78 
79  const word timeDir = timeName();
80  const scalar timeValue = currTime_.value();
81 
82  const fileName outputFile = baseDir / surfName + ".case";
83 
84  if (verbose_)
85  {
86  Info<< "Writing case file to " << outputFile << nl;
87  }
88 
89  // Implicit geometry merge()
90  tmp<Field<Type>> tfield = adjustField(fieldName, mergeField(localValues));
91 
92  if (verbose_)
93  {
94  Info<< endl;
95  }
96 
97  // const meshedSurf& surf = surface();
98  const meshedSurfRef& surf = adjustSurface();
99 
100  if (UPstream::master() || !parallel_)
101  {
102  if (!Foam::isDir(outputFile.path()))
103  {
104  Foam::mkDir(outputFile.path());
105  }
106 
107  const bool stateChanged =
108  caching_.update
109  (
110  baseDir,
111  timeValue,
112  geomChanged,
113  fieldName,
115  varName
116  );
117 
118 
119  // The most current time and geometry indices
120  const label timeIndex = caching_.latestTimeIndex();
121  const label geomIndex = caching_.latestGeomIndex();
122 
123 
124  // This will be used for the name of a static geometry,
125  // or just the masking part for moving geometries.
126  const fileName geometryName
127  (
128  "data"
129  / ensightCase::padded(maskWidth, geomIndex)
131  );
132 
133 
134  // Location for data (and possibly the geometry as well)
135  const fileName dataDir
136  (
137  baseDir/"data"/ensightCase::padded(maskWidth, timeIndex)
138  );
139 
140  // As per mkdir -p "data/00000000"
141  Foam::mkDir(dataDir);
142 
143 
144  const fileName geomFile(baseDir/geometryName);
145 
146  // Ensight Geometry
147  ensightOutputSurface part
148  (
149  surf.points(),
150  surf.faces(),
151  geomFile.name()
152  );
153 
154  if (!Foam::exists(geomFile))
155  {
156  if (verbose_)
157  {
158  Info<< "Writing geometry to " << geomFile.name() << endl;
159  }
160 
161  // Two-argument form for path-name to avoid validating base-dir
162  ensightGeoFile osGeom
163  (
164  geomFile.path(),
165  geomFile.name(),
166  caseOpts_.format()
167  );
168 
169  osGeom.beginGeometry();
170  part.write(osGeom); // serial
171  }
172 
173  // Write field
174  ensightFile osField
175  (
176  dataDir,
177  varName,
178  caseOpts_.format()
179  );
180 
181  if (verbose_)
182  {
183  Info<< "Writing field file to " << osField.name() << endl;
184  }
185 
186  // Write field (serial only)
188  osField.newline();
189  part.writeData(osField, tfield(), this->isPointData());
190 
191 
192  // Update case file
193  if (stateChanged)
194  {
195  OFstream osCase
196  (
198  outputFile,
200  );
201  ensightCase::setTimeFormat(osCase, caseOpts_); // time-format
202 
203  if (verbose_)
204  {
205  Info<< "Writing case file to " << osCase.name() << endl;
206  }
207 
208  // The geometry can be any of the following:
209  // 0: constant/static
210  // 1: moving, with the same frequency as the data
211  // 2: moving, with different frequency as the data
212 
213  const label tsGeom = caching_.geometryTimeset();
214 
215  osCase
216  << "FORMAT" << nl
217  << "type: ensight gold" << nl
218  << nl
219  << "GEOMETRY" << nl;
220 
221 
222  if (tsGeom)
223  {
224  // moving
225  osCase
226  << "model: " << tsGeom << " " // time-set (1|2)
227  << mask << geometryName.name() << nl;
228  }
229  else
230  {
231  // steady
232  osCase
233  << "model: "
234  << geometryName.c_str() << nl;
235  }
236 
237  osCase
238  << nl
239  << "VARIABLE" << nl;
240 
241 
242  for (const entry& dEntry : caching_.fieldsDict())
243  {
244  const dictionary& subDict = dEntry.dict();
245 
246  const string varType(subDict.get<string>("type"));
247  const word varName
248  (
249  subDict.getOrDefault<word>
250  (
251  "name",
252  dEntry.keyword() // fieldName as fallback
253  )
254  );
255 
256  osCase
257  << varType.c_str()
258  <<
259  (
260  this->isPointData()
261  ? " per node: 1 " // time-set 1
262  : " per element: 1 " // time-set 1
263  )
264  << setw(15) << varName << ' '
265  << mask << ensight::FileName(varName).c_str() << nl;
266  }
267 
268  osCase
269  << nl
270  << "TIME" << nl;
271 
272  ensightCase::printTimeset(osCase, 1, caching_.times());
273  if (tsGeom == 2)
274  {
276  (
277  osCase,
278  tsGeom,
279  caching_.times(),
280  caching_.geometries()
281  );
282  }
283 
284  osCase << "# end" << nl;
285  }
286 
287  // Timestamp in the directory for future reference
288  {
289  OFstream timeStamp(dataDir/"time");
290  timeStamp
291  << "# timestep time" << nl
292  << dataDir.name() << ' ' << timeValue << nl;
293  }
294  }
295 
296  wroteGeom_ = true;
297  return outputFile;
298 }
299 
300 
301 // ************************************************************************* //
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
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 wroteGeom_
Track if geometry has been written since the last open.
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
virtual bool write(const token &tok)=0
Write token to stream or otherwise handle it.
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
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
messageStream Info
Information stream (stdout output on master, null elsewhere)
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
A class for managing temporary objects.
Definition: HashPtrTable.H:50
label timeIndex
Definition: getTimeIndex.H:24