sampledSurfaces.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2025 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "sampledSurfaces.H"
27 #include "PatchTools.H"
28 #include "polyTopoChangeMap.H"
29 #include "polyMeshMap.H"
30 #include "polyDistributionMap.H"
31 #include "OSspecific.H"
32 #include "writeFile.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39 namespace functionObjects
40 {
42 
44  (
48  );
49 }
50 }
51 
52 Foam::scalar Foam::functionObjects::sampledSurfaces::mergeTol_ = 1e-10;
53 
54 
55 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
56 
57 bool Foam::functionObjects::sampledSurfaces::needsUpdate() const
58 {
59  forAll(*this, si)
60  {
61  if (operator[](si).needsUpdate())
62  {
63  return true;
64  }
65  }
66 
67  return false;
68 }
69 
70 
71 bool Foam::functionObjects::sampledSurfaces::expire()
72 {
73  bool justExpired = false;
74 
75  forAll(*this, si)
76  {
77  if (operator[](si).expire())
78  {
79  justExpired = true;
80  }
81 
82  // Clear merge information
83  if (Pstream::parRun())
84  {
85  mergeList_[si].clear();
86  }
87  }
88 
89  // true if any surfaces just expired
90  return justExpired;
91 }
92 
93 
94 bool Foam::functionObjects::sampledSurfaces::update()
95 {
96  bool updated = false;
97 
98  if (!needsUpdate())
99  {
100  return updated;
101  }
102 
103  // Serial: quick and easy, no merging required
104  if (!Pstream::parRun())
105  {
106  forAll(*this, si)
107  {
108  if (operator[](si).update())
109  {
110  updated = true;
111  }
112  }
113 
114  return updated;
115  }
116 
117  // Dimension as fraction of mesh bounding box
118  scalar mergeDim = mergeTol_*mesh_.bounds().mag();
119 
120  if (Pstream::master() && debug)
121  {
122  Pout<< nl << "Merging all points within "
123  << mergeDim << " metre" << endl;
124  }
125 
126  forAll(*this, si)
127  {
128  sampledSurface& s = operator[](si);
129 
130  if (s.update())
131  {
132  updated = true;
133  }
134  else
135  {
136  continue;
137  }
138 
140  (
141  mergeDim,
143  (
144  SubList<face>(s.faces(), s.faces().size()),
145  s.points()
146  ),
147  mergeList_[si].points,
148  mergeList_[si].faces,
149  mergeList_[si].pointsMap
150  );
151  }
152 
153  return updated;
154 }
155 
156 
157 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
158 
160 (
161  const word& name,
162  const Time& t,
163  const dictionary& dict
164 )
165 :
168  outputPath_
169  (
170  mesh_.time().globalPath()
171  /writeFile::outputPrefix
172  /(mesh_.name() != polyMesh::defaultRegion ? mesh_.name() : word())
173  /name
174  ),
175  fields_(),
176  interpolationScheme_(word::null),
177  writeEmpty_(false),
178  mergeList_(),
179  formatter_(nullptr)
180 {
181  read(dict);
182 }
183 
184 
185 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
186 
188 {}
189 
190 
191 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
192 
194 {
195  bool surfacesFound = dict.found("surfaces");
196 
197  if (surfacesFound)
198  {
199  dict.lookup("fields") >> fields_;
200 
201  dict.lookup("interpolationScheme") >> interpolationScheme_;
202 
203  dict.readIfPresent("writeEmpty", writeEmpty_);
204 
205  const word writeType(dict.lookup("surfaceFormat"));
206 
207  // Define the surface formatter
208  formatter_ = surfaceWriter::New(writeType, dict);
209 
210  if (dict.isDict("surfaces"))
211  {
212  const dictionary& surfacesDict = dict.subDict("surfaces");
213 
214  setSize(surfacesDict.size());
215 
216  label i = 0;
217 
218  forAllConstIter(dictionary, surfacesDict, iter)
219  {
220  set
221  (
222  i++,
223  sampledSurface::New(iter().keyword(), mesh_, iter().dict())
224  );
225  }
226  }
227  else
228  {
230  (
231  dict.lookup("surfaces"),
232  sampledSurface::iNew(mesh_)
233  );
234  transfer(newList);
235  }
236 
237  if (Pstream::parRun())
238  {
239  mergeList_.setSize(size());
240  }
241 
242  // Ensure all surfaces and merge information are expired
243  expire();
244 
245  if (this->size())
246  {
247  Info<< "Reading surface description:" << nl;
248  forAll(*this, si)
249  {
250  Info<< " " << operator[](si).name() << nl;
251  }
252  Info<< endl;
253  }
254  }
255 
256  if (Pstream::master() && debug)
257  {
258  Pout<< "sample fields:" << fields_ << nl
259  << "sample surfaces:" << nl << "(" << nl;
260 
261  forAll(*this, si)
262  {
263  Pout<< " " << operator[](si) << endl;
264  }
265  Pout<< ")" << endl;
266  }
267 
268  return true;
269 }
270 
271 
273 {
274  wordList fields(fields_);
275 
276  forAll(*this, si)
277  {
278  fields.append(operator[](si).fields());
279  }
280 
281  return fields;
282 }
283 
284 
286 {
287  return true;
288 }
289 
290 
292 {
293  if (size())
294  {
295  // Finalise surfaces, merge points etc.
296  update();
297 
298  // Create the output directory
299  if (Pstream::master())
300  {
301  if (debug)
302  {
303  Pout<< "Creating directory "
304  << outputPath_/mesh_.time().name() << nl << endl;
305 
306  }
307 
308  mkDir(outputPath_/mesh_.time().name());
309  }
310 
311  // Create a list of names of fields that are actually available
313  forAll(fields_, fieldi)
314  {
315  #define FoundFieldType(Type, nullArg) \
316  || foundObject<VolField<Type>>(fields_[fieldi]) \
317  || foundObject<SurfaceField<Type>>(fields_[fieldi])
319  {
320  fieldNames.append(fields_[fieldi]);
321  }
322  else
323  {
324  cannotFindObject(fields_[fieldi]);
325  }
326  #undef FoundFieldType
327  }
328 
329  // Create table of cached interpolations, to prevent unnecessary work
330  // when interpolating fields over multiple surfaces
331  #define DeclareInterpolations(Type, nullArg) \
332  HashPtrTable<interpolation<Type>> interpolation##Type##s;
334  #undef DeclareInterpolations
335 
336  // Sample and write the surfaces
337  forAll(*this, surfi)
338  {
339  const sampledSurface& s = operator[](surfi);
340 
341  #define GenerateFieldTypeValues(Type, nullArg) \
342  PtrList<Field<Type>> field##Type##Values = \
343  sampleType<Type>(surfi, fieldNames, interpolation##Type##s);
345  #undef GenerateFieldTypeValues
346 
347  if (Pstream::parRun())
348  {
349  if
350  (
352  && (mergeList_[surfi].faces.size() || writeEmpty_)
353  )
354  {
355  formatter_->write
356  (
357  outputPath_/mesh_.time().name(),
358  s.name(),
359  mergeList_[surfi].points,
360  mergeList_[surfi].faces,
361  fieldNames,
362  s.interpolate()
363  #define FieldTypeValuesParameter(Type, nullArg) \
364  , field##Type##Values
367  );
368  }
369  }
370  else
371  {
372  if (s.faces().size() || writeEmpty_)
373  {
374  formatter_->write
375  (
376  outputPath_/mesh_.time().name(),
377  s.name(),
378  s.points(),
379  s.faces(),
380  fieldNames,
381  s.interpolate()
382  #define FieldTypeValuesParameter(Type, nullArg) \
383  , field##Type##Values
386  );
387  }
388  }
389  }
390  }
391 
392  return true;
393 }
394 
395 
397 {
398  if (&mesh == &mesh_)
399  {
400  expire();
401  }
402 }
403 
404 
406 (
407  const polyTopoChangeMap& map
408 )
409 {
410  if (&map.mesh() == &mesh_)
411  {
412  expire();
413  }
414 }
415 
416 
418 (
419  const polyMeshMap& map
420 )
421 {
422  if (&map.mesh() == &mesh_)
423  {
424  expire();
425  }
426 }
427 
428 
430 (
431  const polyDistributionMap& map
432 )
433 {
434  if (&map.mesh() == &mesh_)
435  {
436  expire();
437  }
438 }
439 
440 
441 // ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
Macros for easy insertion into run-time selection tables.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:85
static void gatherAndMerge(const scalar mergeDist, const PrimitivePatch< FaceList, PointField > &p, Field< typename PrimitivePatch< FaceList, PointField >::PointType > &mergedPoints, List< typename PrimitivePatch< FaceList, PointField >::FaceType > &mergedFaces, labelList &pointMergeMap)
Gather points and faces onto master and merge into single patch.
const Field< PointType > & points() const
Return reference to global points.
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: PtrList.H:75
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:76
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Abstract base-class for Time/database functionObjects.
Specialisation of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
virtual wordList fields() const
Return the list of fields required.
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map - expires the surfaces.
virtual void distribute(const polyDistributionMap &)
Redistribute or update using the given distribution map.
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
virtual void movePoints(const polyMesh &)
Update for mesh point-motion - expires the surfaces.
sampledSurfaces(const word &name, const Time &time, const dictionary &dict)
Construct from Time and dictionary.
virtual bool execute()
Execute, currently does nothing.
virtual bool write()
Sample and write.
virtual bool read(const dictionary &)
Read the sampledSurfaces dictionary.
Writes run time, CPU time and clock time and optionally the CPU and clock times per time step.
functionObject base class for writing single files
Definition: writeFile.H:56
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
const polyMesh & mesh() const
Return polyMesh.
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:51
const polyMesh & mesh() const
Return polyMesh.
Definition: polyMeshMap.H:75
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:80
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const polyMesh & mesh() const
Return polyMesh.
Class used for the PtrLists read-construction.
An abstract class for surfaces with sampling.
static autoPtr< sampledSurface > New(const word &name, const polyMesh &, const dictionary &)
Return a reference to the selected surface.
static autoPtr< surfaceWriter > New(const word &writeType, const IOstream::streamFormat writeFormat, const IOstream::compressionType writeCompression)
Select given write options.
Definition: surfaceWriter.C:75
A class for handling words, derived from string.
Definition: word.H:62
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
static List< word > fieldNames
Definition: globalFoam.H:46
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Info<< "Calculating turbulent flame speed field St\n"<< endl;volScalarField St(IOobject("St", runTime.name(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), flameWrinkling->Xi() *Su);multivariateSurfaceInterpolationScheme< scalar >::fieldTable fields
Definition: createFields.H:234
const dimensionedScalar e
Elementary charge.
defineTypeNameAndDebug(adjustTimeStepToCombustion, 0)
addToRunTimeSelectionTable(functionObject, adjustTimeStepToCombustion, dictionary)
Namespace for OpenFOAM.
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
messageStream Info
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
Addressing for a faceList slice.
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
FOR_ALL_FIELD_TYPES(makeFieldSourceTypedef)
static const char nl
Definition: Ostream.H:267
points setSize(newPointi)
#define FoundFieldType(Type, nullArg)
#define FieldTypeValuesParameter(Type, nullArg)
#define DeclareInterpolations(Type, nullArg)
#define GenerateFieldTypeValues(Type, nullArg)
dictionary dict