functionObjectSurface.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) 2015-2019 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 // OpenFOAM includes
29 #include "functionObjectSurface.H"
30 #include "runTimePostProcessing.H"
32 
33 // VTK includes
34 #include "vtkActor.h"
35 #include "vtkCellData.h"
36 #include "vtkCellDataToPointData.h"
37 #include "vtkCompositeDataGeometryFilter.h"
38 #include "vtkCompositeDataSet.h"
39 #include "vtkCompositePolyDataMapper.h"
40 #include "vtkMultiPieceDataSet.h"
41 #include "vtkPointData.h"
42 #include "vtkPolyData.h"
43 #include "vtkPolyDataMapper.h"
44 #include "vtkProperty.h"
45 #include "vtkRenderer.h"
46 #include "vtkSmartPointer.h"
47 
48 // VTK Readers
49 #include "vtkPolyDataReader.h"
50 #include "vtkXMLPolyDataReader.h"
51 
52 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
53 
54 namespace Foam
55 {
56 namespace functionObjects
57 {
58 namespace runTimePostPro
59 {
60  defineTypeName(functionObjectSurface);
61  addToRunTimeSelectionTable(surface, functionObjectSurface, dictionary);
62 }
63 }
64 }
65 
66 
67 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
68 
69 namespace
70 {
71 
72 static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName)
73 {
74  // Not extremely elegant...
76 
77  if ("vtk" == fName.ext())
78  {
80 
81  reader->SetFileName(fName.c_str());
82  reader->Update();
83  dataset = reader->GetOutput();
84 
85  return dataset;
86  }
87 
88  if ("vtp" == fName.ext())
89  {
91 
92  reader->SetFileName(fName.c_str());
93  reader->Update();
94  dataset = reader->GetOutput();
95 
96  return dataset;
97  }
98 
99  return dataset;
100 }
101 
102 } // End anonymous namespace
103 
104 
105 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
106 
109 (
110  const runTimePostProcessing& parent,
111  const dictionary& dict,
112  const HashPtrTable<Function1<vector>>& colours
113 )
114 :
115  geometrySurface(parent, dict, colours, List<fileName>()),
116  functionObjectBase(parent, dict, colours)
117 {}
118 
119 
120 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
121 
124 (
125  const scalar position,
126  vtkRenderer* renderer
127 )
128 {
129  if (!visible_)
130  {
131  return false;
132  }
133 
134  DebugInfo
135  << " Find surface " << functionObjectName_ << endl;
136 
137  const polySurface* surf =
138  (
139  geometryBase::parent_.storedObjects()
140  .cfindObject<polySurface>(functionObjectName_)
141  );
142 
143  // Treat surface with no faces/points like a missing surface
144  surf = ((surf && surf->nPoints()) ? surf : nullptr);
145 
146  bool hasSurface = surf;
147 
148 
149  // Retrieve the field association (CELL, POINT) for the given field
150 
151  unsigned fieldAssociation(0u);
152  if (surf)
153  {
154  unsigned queried = surf->queryFieldAssociation(fieldName_);
155 
156  if (queried & polySurface::FACE_DATA)
157  {
158  fieldAssociation |= FieldAssociation::CELL_DATA;
159  }
160  if (queried & polySurface::POINT_DATA)
161  {
162  fieldAssociation |= FieldAssociation::POINT_DATA;
163  }
164  }
165 
166  // Reduce the information
167  if (Pstream::parRun())
168  {
169  if (!hasSurface)
170  {
171  // No geometry - set all field association bits ON to ensure
172  // it does not affect bitwise reduction.
173  fieldAssociation = (~0u);
174  }
175 
176  reduce(hasSurface, orOp<bool>());
177  reduce(fieldAssociation, bitAndOp<unsigned>());
178  }
179 
180  if (!hasSurface)
181  {
183  << "No functionObject surface, or has no faces: "
184  << functionObjectName_
185  << endl;
186 
187  DebugInfo
188  << " Available surfaces:" << nl
189  << geometryBase::parent_.storedObjects()
190  .sortedNames<polySurface>() << endl;
191 
192  return false;
193  }
194 
196 
197 
198  // Create a vtkMultiPieceDataSet with vtkPolyData on the leaves
200 
201  // Requesting glyphs on the surface AND only have face data?
202  // - just use the faceCentres directly and attach fields as CellData
203  // (not PointData).
204 
205  if
206  (
207  representation_ == rtGlyph
208  && (fieldAssociation == FieldAssociation::CELL_DATA)
209  )
210  {
211  multiPiece = gatherFaceCentres(surf);
212  }
213  else
214  {
215  multiPiece = gatherSurfacePieces(surf);
216  }
217 
218 
219  // Add the field (the information is consistent after last reduction).
220 
221  // Need field(s) for glyphs or colourByField:
222 
223  if (representation_ == rtGlyph || colourBy_ == cbField)
224  {
225  if (fieldAssociation == FieldAssociation::CELL_DATA)
226  {
227  addDimField<polySurfaceGeoMesh>
228  (
229  multiPiece,
230  surf,
231  fieldName_
232  );
233  }
234  else if (fieldAssociation & FieldAssociation::POINT_DATA)
235  {
236  addDimField<polySurfacePointGeoMesh>
237  (
238  multiPiece,
239  surf,
240  fieldName_
241  );
242  }
243  }
244 
245 
246  // Now have a multi-piece dataset that is one of the following:
247  //
248  // - one-piece per processor (OpenFOAM = parallel, VTK=parallel)
249  // - all pieces on master only (OpenFOAM = parallel, VTK=serial)
250 
251  // Re-query field information - we may have stored it differently
252  // than the original source.
253 
254  fieldSummary fieldInfo = queryFieldSummary(fieldName_, multiPiece);
255  fieldInfo.reduce();
256 
257  DebugInfo
258  << " Field " << fieldName_ << ' ' << fieldInfo.info() << endl;
259 
260 
261  // Not rendered on this processor?
262  // This is where we stop, but could also have an MPI barrier
263  if (!renderer)
264  {
265  return true;
266  }
267 
268 
269  // Rendering
270 
271  {
273 
274  polyData->SetInputData(multiPiece);
275  polyData->Update();
276 
277  if (representation_ == rtGlyph)
278  {
279  addGlyphs
280  (
281  position,
282  fieldName_, fieldInfo, // scaling
283  fieldName_, fieldInfo, // colouring
284  maxGlyphLength_,
285  polyData->GetOutput(),
286  surfaceActor_,
287  renderer
288  );
289  }
290  else
291  {
293 
294  // CellData - Need a cell->point filter
295  if (smooth_ && !fieldInfo.hasPointData())
296  {
298  cellToPoint->SetInputData(multiPiece);
299 
300  polyData->SetInputConnection(cellToPoint->GetOutputPort());
301  }
302  else
303  {
304  polyData->SetInputData(multiPiece);
305  }
306  polyData->Update();
307 
308 
309  if (!smooth_)
310  {
311  addFeatureEdges(renderer, polyData);
312  }
313 
315  mapper->SetInputConnection(polyData->GetOutputPort());
316 
317  setField
318  (
319  position,
320  fieldName_,
321  (
322  smooth_
324  : FieldAssociation(fieldInfo.association_)
325  ),
326  mapper,
327  renderer
328  );
329 
330  surfaceActor_->SetMapper(mapper);
331 
332  setRepresentation(surfaceActor_);
333 
334  renderer->AddActor(surfaceActor_);
335  }
336  }
337 
338  return true;
339 }
340 
341 
344 (
345  const scalar position,
346  vtkRenderer* renderer
347 )
348 {
349  if (!visible_)
350  {
351  return false;
352  }
353 
355 
356  bool good = true;
357 
358  // File reading is serial (master only)
359  if (Pstream::master())
360  {
361  fileName fName = getFileName("file", fieldName_);
362 
363  if (fName.size())
364  {
365  polyData = getPolyDataFile(fName);
366 
367  if (!polyData || polyData->GetNumberOfPoints() == 0)
368  {
369  good = false;
370 
372  << "Could not read "<< fName << nl
373  << "Only VTK (.vtp, .vtk) files are supported"
374  << endl;
375  }
376  else
377  {
378  DebugInfo
379  << " Resolved surface " << fName << endl;
380  }
381  }
382  else
383  {
384  good = false;
385 
387  << "Unable to read file name from function object "
388  << functionObjectName_ << " for field " << fieldName_
389  << ". Surface will not be processed"
390  << endl;
391  }
392  }
393 
394  reduce(good, andOp<bool>());
395 
396  if (!good)
397  {
398  return false;
399  }
400 
401  // Only render on master
402  if (!renderer || !Pstream::master())
403  {
404  return true;
405  }
406 
407  fieldSummary fieldInfo = queryFieldSummary(fieldName_, polyData);
408  // No reduction (serial)
409 
410  DebugInfo
411  << " Field " << fieldName_ << ' ' << fieldInfo.info() << endl;
412 
413 
414  // Render
415 
416  if (representation_ == rtGlyph)
417  {
418  addGlyphs
419  (
420  position,
421  fieldName_, fieldInfo, // scaling
422  fieldName_, fieldInfo, // colouring
423  maxGlyphLength_,
424  polyData,
425  surfaceActor_,
426  renderer
427  );
428  }
429  else
430  {
431  addFeatureEdges(renderer, polyData);
432 
434  mapper->SetInputData(polyData);
435 
436  setField
437  (
438  position,
439  fieldName_,
440  queryFieldAssociation(fieldName_, polyData),
441  mapper,
442  renderer
443  );
444 
445  surfaceActor_->SetMapper(mapper);
446 
447  setRepresentation(surfaceActor_);
448 
449  renderer->AddActor(surfaceActor_);
450  }
451 
452  return true;
453 }
454 
455 
458 (
459  const scalar position,
460  vtkRenderer* renderer
461 )
462 {
463  if (!visible_)
464  {
465  return;
466  }
467 
468  if (liveObject_)
469  {
470  // Live source
471  if (addGeometry(position, renderer))
472  {
473  return;
474  }
475 
477  << "No functionObject live source, or is empty: "
478  << functionObjectName_
479  << " ... attempting with file source"
480  << endl;
481  }
482  else
483  {
484  DebugInfo
485  << "Using file source only" << nl;
486  }
487 
488  // File source
489  addGeometryFromFile(position, renderer);
490 }
491 
492 
494 {
496  {
497  // Even for a "live" data source we allow file cleanup
498  // (eg, from a previous run, etc)
499  return removeFile("file", fieldName_);
500  }
501 
502  return false;
503 }
504 
505 
506 // ************************************************************************* //
Foam::functionObjects::runTimePostPro::functionObjectSurface::addGeometryFromFile
bool addGeometryFromFile(const scalar position, vtkRenderer *renderer)
Add functionObjectSurface to scene (using file source)
Definition: functionObjectSurface.C:344
Foam::functionObjects::runTimePostPro::addToRunTimeSelectionTable
addToRunTimeSelectionTable(surface, contourFilter, dictionary)
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::functionObjects::runTimePostPro::fieldVisualisationBase::fieldSummary
General field characteristics.
Definition: fieldVisualisationBase.H:172
Foam::functionObjects::runTimePostPro::fieldVisualisationBase::fieldName_
word fieldName_
Field name.
Definition: fieldVisualisationBase.H:228
Foam::expressions::patchExpr::POINT_DATA
Point data.
Definition: patchExprFwd.H:60
Foam::functionObjects::runTimePostPro::functionObjectSurface::clear
virtual bool clear()
Clear files used to create the object(s)
Definition: functionObjectSurface.C:493
Foam::cellToPoint
A topoSetPointSource to select points based on usage in cells.
Definition: cellToPoint.H:83
Foam::functionObjects::fieldInfo
Helper class to store a wordRe and label used by Foam::functionObjects::fieldSelection.
Definition: fieldInfo.H:56
Foam::functionObjects::runTimePostPro::functionObjectSurface::functionObjectSurface
functionObjectSurface(const functionObjectSurface &)=delete
No copy construct.
vtkSmartPointer
Definition: runTimePostProcessing.H:148
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:337
functionObjectSurface.H
Foam::Function1
Top level data entry class for use in dictionaries. Provides a mechanism to specify a variable as a c...
Definition: Function1.H:56
Foam::functionObjects::runTimePostPro::functionObjectBase
Base class for function object visualisation.
Definition: functionObjectBase.H:86
Foam::expressions::patchExpr::FieldAssociation
FieldAssociation
The field association for patch expressions (mutually exclusive)
Definition: patchExprFwd.H:57
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::polySurface
A surface mesh consisting of general polygon faces and capable of holding fields.
Definition: polySurface.H:67
Foam::functionObjects::runTimePostProcessing
Generate images during run-time.
Definition: runTimePostProcessing.H:170
Foam::andOp
Definition: ops.H:233
setField
surfacesMesh setField(triSurfaceToAgglom)
Foam::functionObjects::runTimePostPro::functionObjectBase::clear
virtual bool clear()
Clear files used to create the object(s)
Definition: functionObjectBase.C:88
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Foam::functionObjects::runTimePostPro::functionObjectBase::removeFile
bool removeFile(const word &keyword, const word &subDictName)
Remove file used to create the scene object.
Definition: functionObjectBase.C:53
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::fileName::ext
word ext() const
Return file name extension (part after last .)
Definition: fileNameI.H:228
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::polySurface::queryFieldAssociation
FieldAssociation queryFieldAssociation(const word &fieldName) const
Query the field association (FACE or POINT)
Definition: polySurface.C:212
Foam::functionObjects::runTimePostPro::functionObjectSurface::addGeometryToScene
virtual void addGeometryToScene(const scalar position, vtkRenderer *renderer)
Add functionObjectSurface(s) to scene.
Definition: functionObjectSurface.C:458
Foam::New
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh >> &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
Definition: DimensionedFieldReuseFunctions.H:105
Foam::functionObjects::runTimePostPro::functionObjectSurface::addGeometry
bool addGeometry(const scalar position, vtkRenderer *renderer)
Add functionObjectSurface to scene (using simulation source)
Definition: functionObjectSurface.C:124
runTimePostProcessing.H
DebugInfo
#define DebugInfo
Report an information message using Foam::Info.
Definition: messageStream.H:350
Foam::nl
constexpr char nl
Definition: Ostream.H:372
Foam::HashPtrTable
A HashTable of pointers to objects of type <T>.
Definition: HashPtrTable.H:54
Foam::List< fileName >
Foam::functionObjects::runTimePostPro::defineTypeName
defineTypeName(contourFilter)
Foam::functionObjects::runTimePostPro::geometrySurface
Read and visualize surface geometry files.
Definition: geometrySurface.H:83
Foam::bitAndOp
Definition: ops.H:229
Foam::orOp
Definition: ops.H:234
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:294
Foam::polySurface::nPoints
virtual label nPoints() const
Return the number of points.
Definition: polySurface.H:219