debugSurfaceWriter.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 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 #include "debugSurfaceWriter.H"
29 #include "globalIndex.H"
30 #include "argList.H"
31 #include "OFstream.H"
32 #include "OSspecific.H"
33 #include "IOmanip.H"
34 #include "Time.H"
35 #include "pointIOField.H"
36 #include "primitivePatch.H"
37 #include "profiling.H"
38 #include "surfaceWriterMethods.H"
40 
41 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45 namespace surfaceWriters
46 {
47  defineTypeName(debugWriter);
48  addToRunTimeSelectionTable(surfaceWriter, debugWriter, word);
49  addToRunTimeSelectionTable(surfaceWriter, debugWriter, wordDict);
50 }
51 }
52 
53 
54 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
55 
56 template<class Type>
58 Foam::surfaceWriters::debugWriter::mergeField
59 (
60  const Field<Type>& fld
61 ) const
62 {
64  (
65  merge,
66  "debugWriter::merge-field"
67  );
68 
69  if (parallel_ && Pstream::parRun())
70  {
71  // Ensure geometry is also merged
72  merge();
73 
74  // Gather all values
75  auto tfield = tmp<Field<Type>>::New();
76  auto& allFld = tfield.ref();
77 
78  if (mpiGatherv_)
79  {
81  (
82  fld,
83  allFld,
85  commType_
86  );
87  }
88  else
89  {
90  const globalIndex& globIndex =
91  (
92  this->isPointData()
95  );
96 
97  globIndex.gather
98  (
99  fld,
100  allFld,
102  commType_,
104  );
105  }
106 
107  // Renumber (point data) to correspond to merged points
108  if
109  (
111  && this->isPointData()
112  && mergedSurf_.pointsMap().size()
113  )
114  {
116  allFld.resize(mergedSurf_.points().size());
117  }
118 
119  return tfield;
120  }
121 
122  // Mark that any geometry changes have been taken care of
123  upToDate_ = true;
125  return fld;
126 }
127 
128 
129 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
130 
132 :
133  surfaceWriter(),
134  mpiGatherv_(false),
135  enableWrite_(false),
136  header_(true),
137  streamOpt_(IOstreamOption::BINARY)
138 {}
139 
140 
142 (
143  const dictionary& options
144 )
145 :
146  surfaceWriter(options),
147  mpiGatherv_(options.getOrDefault("gatherv", false)),
148  enableWrite_(options.getOrDefault("write", false)),
149  header_(true),
150  streamOpt_(IOstreamOption::BINARY)
151 {
152  Info<< "Using debug surface writer ("
153  << (this->isPointData() ? "point" : "face") << " data):"
154  << " commsType=" << UPstream::commsTypeNames[commType_]
155  << " gatherv=" << Switch::name(mpiGatherv_)
156  << " write=" << Switch::name(enableWrite_) << endl;
157 }
158 
159 
161 (
162  const meshedSurf& surf,
163  const fileName& outputPath,
164  bool parallel,
165  const dictionary& options
166 )
167 :
168  debugWriter(options)
169 {
170  open(surf, outputPath, parallel);
171 }
172 
173 
175 (
176  const pointField& points,
177  const faceList& faces,
178  const fileName& outputPath,
179  bool parallel,
180  const dictionary& options
181 )
182 :
183  debugWriter(options)
184 {
185  open(points, faces, outputPath, parallel);
186 }
187 
188 
189 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
190 
191 void Foam::surfaceWriters::debugWriter::serialWriteGeometry
192 (
193  const regIOobject& iopts,
194  const meshedSurf& surf
195 )
196 {
197  const pointField& points = surf.points();
198  const faceList& faces = surf.faces();
199 
200  if (verbose_)
201  {
202  if (this->isPointData())
203  {
204  Info<< "Writing points: " << iopts.objectPath() << endl;
205  }
206  else
207  {
208  Info<< "Writing face centres: " << iopts.objectPath() << endl;
209  }
210  }
211 
212  // Like regIOobject::writeObject without instance() adaptation
213  // since this would write to e.g. 0/ instead of postProcessing/
214 
215  autoPtr<primitivePatch> ppPtr;
216 
217  {
218  OFstream os(iopts.objectPath(), streamOpt_);
219 
220  if (header_)
221  {
222  iopts.writeHeader(os);
223  }
224 
225  if (this->isPointData())
226  {
227  // Just like writeData, but without copying beforehand
228  os << points;
229  }
230  else
231  {
232  ppPtr.reset(new primitivePatch(SubList<face>(faces), points));
233 
234  // Just like writeData, but without copying beforehand
235  os << ppPtr().faceCentres();
236  }
237 
238  if (header_)
239  {
241  }
242  }
243 }
244 
245 
247 {
248  checkOpen();
249 
250  // Geometry: rootdir/surfaceName/"points"
251  // Field: rootdir/surfaceName/<TIME>/field
252 
253  fileName surfaceDir = outputPath_;
254 
255  const meshedSurf& surf = surface();
256  // const meshedSurfRef& surf = adjustSurface();
257 
258  // Dummy Time to use as objectRegistry
259  autoPtr<Time> dummyTimePtr;
260 
261  if (enableWrite_)
262  {
263  dummyTimePtr = Time::New(argList::envGlobalPath());
264  }
265  else if (verbose_)
266  {
267  Info<< "Not writing: " << surf.faces().size() << " faces" << nl;
268  }
269 
270  if (enableWrite_ && (Pstream::master() || !parallel_))
271  {
272  if (!isDir(surfaceDir))
273  {
274  mkDir(surfaceDir);
275  }
276 
277  // Write sample locations
278  pointIOField iopts
279  (
280  IOobject
281  (
282  surfaceDir/"points",
283  *dummyTimePtr,
286  false // Do not register
287  )
288  );
289  iopts.note() = (this->isPointData() ? "point data" : "face data");
290 
291  serialWriteGeometry(iopts, surf);
292  }
293 
294  wroteGeom_ = true;
295  return surfaceDir;
296 }
297 
298 
299 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
300 
301 template<class Type>
302 Foam::fileName Foam::surfaceWriters::debugWriter::writeTemplate
303 (
304  const word& fieldName,
305  const Field<Type>& localValues
306 )
307 {
308  checkOpen();
309 
310  // Geometry: rootdir/surfaceName/"points"
311  // Field: rootdir/surfaceName/<TIME>/field
312 
313  fileName surfaceDir = outputPath_;
314 
315  const fileName outputFile(surfaceDir/timeName()/fieldName);
316 
317  // Implicit geometry merge()
318  tmp<Field<Type>> tfield = mergeField(localValues);
319 
320  // Dummy Time to use as objectRegistry
321  autoPtr<Time> dummyTimePtr;
322 
323  if (enableWrite_)
324  {
325  dummyTimePtr = Time::New(argList::envGlobalPath());
326  }
327  else if (verbose_)
328  {
329  Info<< "Not writing: " << tfield().size()
330  << ' ' << pTraits<Type>::typeName
331  << " values" << nl;
332  }
333 
334  const meshedSurf& surf = surface();
335  // const meshedSurfRef& surf = adjustSurface();
336 
337  if (enableWrite_ && (Pstream::master() || !parallel_))
338  {
339  if (!isDir(outputFile.path()))
340  {
341  mkDir(outputFile.path());
342  }
343 
344  // Write sample locations
345  {
346  pointIOField iopts
347  (
348  IOobject
349  (
350  surfaceDir/"points",
351  *dummyTimePtr,
354  false // Do not register
355  )
356  );
357  iopts.note() = (this->isPointData() ? "point data" : "face data");
358 
359  serialWriteGeometry(iopts, surf);
360  }
361 
362  // Write field
363  {
364  IOField<Type> iofld
365  (
366  IOobject
367  (
368  outputFile,
369  *dummyTimePtr,
372  false // Do not register
373  )
374  );
375  iofld.note() = (this->isPointData() ? "point data" : "face data");
376 
377  OFstream os(iofld.objectPath(), streamOpt_);
378 
379  if (header_)
380  {
381  iofld.writeHeader(os);
382  }
383 
384  // Just like writeData, but without copying beforehand
385  os << tfield();
386 
387  if (header_)
388  {
390  }
391  }
392  }
393 
394  wroteGeom_ = true;
395  return surfaceDir;
396 }
397 
398 
399 // Field writing methods
401 
402 
403 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
static void mpiGatherOp(const UList< Type > &sendData, OutputContainer &allData, const label comm=UPstream::worldComm, const UPstream::commsTypes=UPstream::commsTypes::nonBlocking, const int tag=UPstream::msgType())
Use MPI_Gatherv call to collect contiguous data when possible (in serial: performs a simple copy)...
#define addProfiling(name, descr)
Define profiling trigger with specified name and description string.
const globalIndex & faceGlobalIndex() const noexcept
Const access to globalIndex used for faces gathering.
Definition: mergedSurf.H:205
A class for handling file names.
Definition: fileName.H:71
static const Enum< commsTypes > commsTypeNames
Enumerated names for the communication types.
Definition: UPstream.H:76
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
vectorIOField pointIOField
pointIOField is a vectorIOField.
Definition: pointIOField.H:38
const labelList & pointsMap() const noexcept
Map for reordered points (old-to-new)
Definition: mergedSurf.H:189
virtual void open(const fileName &outputPath)
Open for output on specified path, using existing surface.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
void inplaceReorder(const labelUList &oldToNew, ListType &input, const bool prune=false)
Inplace reorder the elements of a list.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
A traits class, which is primarily used for primitives.
Definition: pTraits.H:50
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:639
const string & note() const noexcept
Return the optional note.
Definition: IOobjectI.H:180
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:697
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:806
A simple container for options an IOstream can normally have.
static std::string path(const std::string &str)
Return directory path name (part before last /)
Definition: fileNameI.H:169
bool parallel_
Writing in parallel (via master)
Ignore writing from objectRegistry::writeObject()
static label worldComm
Default world communicator (all processors). May differ from globalComm if local worlds are in use...
Definition: UPstream.H:361
mergedSurf mergedSurf_
Surface after merging (parallel)
bool writeHeader(Ostream &os) const
Write header with current type()
UPstream::commsTypes commType_
Communication type (for field merging)
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:239
Macros for easy insertion into run-time selection tables.
virtual const pointField & points() const noexcept
Const access to (global) points used for the surface.
Definition: mergedSurf.H:157
defineSurfaceWriterWriteFields(Foam::surfaceWriters::debugWriter)
Abstract definition of a meshed surface defined by faces and points.
Definition: meshedSurf.H:43
bool isPointData() const noexcept
Are the field data to be treated as point data?
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: POSIX.C:813
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
word timeName
Definition: getTimeIndex.H:3
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
static const char * name(const bool b) noexcept
A string representation of bool as "false" / "true".
Definition: Switch.C:141
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:567
const pointField & points
Generic templated field type.
Definition: Field.H:61
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual fileName write()
Write surface geometry to file.
virtual const faceList & faces() const =0
The faces used for the surface.
const wordList surface
Standard surface field types (scalar, vector, tensor, etc)
static Ostream & writeEndDivider(Ostream &os)
Write the standard end file divider.
Istream and Ostream manipulators taking arguments.
const globalIndex & pointGlobalIndex() const noexcept
Const access to globalIndex used for points gathering.
Definition: mergedSurf.H:197
OBJstream os(runTime.globalPath()/outputName)
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
Convenience macros for instantiating surfaceWriter methods.
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
defineTypeName(abaqusWriter)
static fileName envGlobalPath()
Global case (directory) from environment variable.
Definition: argList.C:590
static bool master(const label communicator=worldComm)
Am I the master rank.
Definition: UPstream.H:672
Nothing to be read.
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition: regIOobject.H:69
messageStream Info
Information stream (stdout output on master, null elsewhere)
virtual bool merge() const
Merge surfaces if they are not already upToDate (parallel) or simply mark the surface as being up-to-...
Base class for surface writers.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
static void gather(const labelUList &offsets, const label comm, const ProcIDsContainer &procIDs, const UList< Type > &fld, List< Type > &allFld, const int tag=UPstream::msgType(), const UPstream::commsTypes=UPstream::commsTypes::nonBlocking)
Collect data in processor order on master (== procIDs[0]).
A surfaceWriter for special purpose debugging. Its definition and behaviour are subject to change at ...
A class for managing temporary objects.
Definition: HashPtrTable.H:50
addToRunTimeSelectionTable(surfaceWriter, abaqusWriter, word)
static autoPtr< surfaceWriter > New(const word &writeType)
Return a reference to the selected surfaceWriter.
Definition: surfaceWriter.C:80
bool upToDate_
The topology/surface is up-to-date?
virtual const pointField & points() const =0
The points used for the surface.
Namespace for OpenFOAM.