streamlines.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-2022 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 "Pstream.H"
27 #include "functionObjectList.H"
28 #include "streamlines.H"
29 #include "streamlinesCloud.H"
30 #include "ReadFields.H"
31 #include "meshSearch.H"
32 #include "sampledSet.H"
33 #include "globalIndex.H"
34 #include "distributionMap.H"
35 #include "interpolationCellPoint.H"
36 #include "PatchTools.H"
37 #include "writeFile.H"
38 #include "polyTopoChangeMap.H"
39 #include "polyMeshMap.H"
41 
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46 
47 template<class Type>
49 {
50  List<List<Type>> gatheredField(Pstream::nProcs());
51  gatheredField[Pstream::myProcNo()] = field;
52  Pstream::gatherList(gatheredField);
53 
54  field =
55  ListListOps::combine<List<Type>>
56  (
57  gatheredField,
59  );
60 }
61 
62 }
63 
64 
65 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
66 
67 namespace Foam
68 {
69  template<>
70  const char*
72  {"forward", "backward", "both"};
73 
74  namespace functionObjects
75  {
76  defineTypeNameAndDebug(streamlines, 0);
78 
81  }
82 }
83 
84 
85 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
86 
88 (
89  const word& name,
90  const Time& runTime,
91  const dictionary& dict
92 )
93 :
94  fvMeshFunctionObject(name, runTime, dict),
95  dict_(dict),
96  nSubCycle_(0)
97 {
98  read(dict_);
99 }
100 
101 
102 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
103 
105 {}
106 
107 
108 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
109 
111 {
112  if (dict != dict_)
113  {
114  dict_ = dict;
115  }
116 
117  Info<< type() << " " << name() << ":" << nl;
118 
119  dict.lookup("fields") >> fields_;
120 
121  UName_ = dict.lookupOrDefault("U", word("U"));
122 
123  writeAge_ = dict.lookupOrDefault<Switch>("writeAge", true);
124 
125  trackDirection_ = trackDirectionNames_[word(dict.lookup("direction"))];
126 
127  trackOutside_ = dict.lookupOrDefault<Switch>("outside", false);
128 
129  dict.lookup("lifeTime") >> lifeTime_;
130 
131  if (lifeTime_ < 1)
132  {
134  << "Illegal value " << lifeTime_ << " for lifeTime"
135  << exit(FatalError);
136  }
137 
138  bool subCycling = dict.found("nSubCycle");
139  bool fixedLength = dict.found("trackLength");
140  if (subCycling && fixedLength)
141  {
143  << "Cannot both specify automatic time stepping (through '"
144  << "nSubCycle' specification) and fixed track length (through '"
145  << "trackLength')"
146  << exit(FatalIOError);
147  }
148  if (subCycling)
149  {
150  nSubCycle_ = max(dict.lookup<scalar>("nSubCycle"), 1);
151  trackLength_ = vGreat;
152  Info<< " automatic track length specified through"
153  << " number of sub cycles : " << nSubCycle_ << nl << endl;
154  }
155  else
156  {
157  nSubCycle_ = 1;
158  dict.lookup("trackLength") >> trackLength_;
159  Info<< " fixed track length specified : "
160  << trackLength_ << nl << endl;
161  }
162 
163  interpolationScheme_ =
164  dict.lookupOrDefault
165  (
166  "interpolationScheme",
168  );
169 
170  cloudName_ = dict.lookupOrDefault<word>("cloudName", "streamlines");
171 
172  meshSearchPtr_.reset(new meshSearch(mesh_));
173 
174  sampledSetPtr_ = sampledSet::New
175  (
176  "seedSampleSet",
177  mesh_,
178  meshSearchPtr_(),
179  dict.subDict("seedSampleSet")
180  );
181 
182  formatterPtr_ = setWriter::New(dict.lookup("setFormat"), dict);
183 
184  return true;
185 }
186 
187 
189 {
190  wordList allFields(fields_);
191  allFields.append(UName_);
192 
193  return allFields;
194 }
195 
196 
198 {
199  return true;
200 }
201 
202 
204 {
205  Info<< type() << " " << name() << " write:" << nl;
206 
207  // Create list of available fields
209  forAll(fields_, fieldi)
210  {
211  if
212  (
213  false
214  #define FoundTypeField(Type, nullArg) \
215  || foundObject<VolField<Type>>(fields_[fieldi])
217  #undef FoundTypeField
218  )
219  {
220  fieldNames.append(fields_[fieldi]);
221  }
222  else
223  {
224  cannotFindObject(fields_[fieldi]);
225  }
226  }
227 
228  // Lookup fields and construct interpolators
229  #define DeclareTypeInterpolator(Type, nullArg) \
230  PtrList<interpolation<Type>> Type##Interp(fieldNames.size());
232  #undef DeclareTypeInterpolator
233  forAll(fieldNames, fieldi)
234  {
235  #define ConstructTypeInterpolator(Type, nullArg) \
236  if (mesh_.foundObject<VolField<Type>>(fieldNames[fieldi])) \
237  { \
238  Type##Interp.set \
239  ( \
240  fieldi, \
241  interpolation<Type>::New \
242  ( \
243  interpolationScheme_, \
244  mesh_.lookupObject<VolField<Type>>(fieldNames[fieldi]) \
245  ) \
246  ); \
247  }
249  #undef ConstructTypeInterpolator
250  }
251 
252  // Create a velocity interpolator if it is not already available
253  const label UIndex = findIndex(fieldNames, UName_);
254  tmpNrc<interpolation<vector>> UInterp(nullptr);
255  if (UIndex == -1)
256  {
257  UInterp =
259  (
261  (
262  interpolationScheme_,
263  mesh_.lookupObject<volVectorField>(UName_)
264  ).ptr()
265  );
266  }
267 
268  // Do tracking to create sampled data
269  DynamicField<point> allPositions;
270  DynamicField<label> allTracks;
271  DynamicField<label> allTrackParts;
272  DynamicField<scalar> allAges;
273  #define DeclareAllTypes(Type, nullArg) \
274  List<DynamicField<Type>> all##Type##s(fieldNames.size());
276  #undef DeclareAllTypes
277  {
278  // Create a cloud and initialise with points from the sampled set
279  globalIndex gi(sampledSetPtr_().size());
281  (
282  mesh_,
283  cloudName_,
285  );
286  forAll(sampledSetPtr_(), i)
287  {
288  particles.addParticle
289  (
291  (
292  mesh_,
293  sampledSetPtr_().positions()[i],
294  sampledSetPtr_().cells()[i],
295  lifeTime_,
296  gi.toGlobal(i)
297  )
298  );
299  }
300 
301  // Report the number of successful seeds
302  const label nSeeds = returnReduce(particles.size(), sumOp<label>());
303  Info << " Seeded " << nSeeds << " particles" << endl;
304 
305  // Create tracking data
307  (
308  particles,
309  #define TypeInterpolatorParameter(Type, nullArg) \
310  Type##Interp,
313  UIndex != -1 ? vectorInterp[UIndex] : UInterp(),
314  trackDirection_ == trackDirection::forward,
315  trackOutside_,
316  nSubCycle_,
317  trackLength_,
318  allPositions,
319  allTracks,
320  allTrackParts,
321  allAges
322  #define AllTypesParameter(Type, nullArg) \
323  , all##Type##s
325  #undef AllTypesParameter
326  );
327 
328  // Track
329  IDLList<streamlinesParticle> initialParticles;
330  if (trackDirection_ == trackDirection::both)
331  {
332  initialParticles = particles;
333  }
334 
335  particles.move(particles, td, rootGreat);
336 
337  if (trackDirection_ == trackDirection::both)
338  {
339  particles.IDLList<streamlinesParticle>::operator=(initialParticles);
340  td.trackForward_ = !td.trackForward_;
341  particles.move(particles, td, rootGreat);
342  }
343  }
344 
345  // Gather data on the master
346  if (Pstream::parRun())
347  {
348  gatherAndFlatten(allPositions);
349  gatherAndFlatten(allTracks);
350  gatherAndFlatten(allTrackParts);
351  gatherAndFlatten(allAges);
352  forAll(fieldNames, fieldi)
353  {
354  #define GatherAndFlattenAllTypes(Type, nullArg) \
355  if (Type##Interp.set(fieldi)) \
356  { \
357  gatherAndFlatten(all##Type##s[fieldi]); \
358  }
360  #undef GatherAndFlattenAllTypes
361  }
362  }
363 
364  // Report the total number of samples
365  Info<< " Sampled " << allPositions.size() << " locations" << endl;
366 
367  // Bin-sort by track and trackPart to build an ordering
368  labelList order(allPositions.size());
369  if (Pstream::master())
370  {
371  const label nTracks = max(allTracks) + 1;
372  const label trackParti0 = min(allTrackParts);
373  const label trackParti1 = max(allTrackParts) + 1;
374 
375  labelListList trackPartCounts
376  (
377  nTracks,
378  labelList(trackParti1 - trackParti0, 0)
379  );
380  forAll(allPositions, samplei)
381  {
382  const label tracki = allTracks[samplei];
383  const label trackParti = -trackParti0 + allTrackParts[samplei];
384  trackPartCounts[tracki][trackParti] ++;
385  }
386 
387  label offset = 0;
388  labelListList trackPartOffsets
389  (
390  nTracks,
391  labelList(trackParti1 - trackParti0, 0)
392  );
393  forAll(trackPartOffsets, tracki)
394  {
395  forAll(trackPartOffsets[tracki], trackParti)
396  {
397  trackPartOffsets[tracki][trackParti] += offset;
398  offset += trackPartCounts[tracki][trackParti];
399  }
400  }
401 
402  forAll(trackPartCounts, tracki)
403  {
404  trackPartCounts[tracki] = 0;
405  }
406 
407  forAll(allPositions, samplei)
408  {
409  const label tracki = allTracks[samplei];
410  const label trackParti = -trackParti0 + allTrackParts[samplei];
411 
412  order[samplei] =
413  trackPartOffsets[tracki][trackParti]
414  + trackPartCounts[tracki][trackParti];
415 
416  trackPartCounts[tracki][trackParti] ++;
417  }
418  }
419 
420  //auto reportTrackParts = [&]()
421  //{
422  // Info<< nl;
423  // forAll(allPositions, samplei)
424  // {
425  // if
426  // (
427  // samplei == 0
428  // || allTracks[samplei] != allTracks[samplei - 1]
429  // || allTrackParts[samplei] != allTrackParts[samplei - 1]
430  // )
431  // {
432  // Info<< "track #" << allTracks[samplei]
433  // << " part #" << allTrackParts[samplei]
434  // << " from i=" << samplei << " to ";
435  // }
436  // if
437  // (
438  // samplei == allPositions.size() - 1
439  // || allTracks[samplei + 1] != allTracks[samplei]
440  // || allTrackParts[samplei + 1] != allTrackParts[samplei]
441  // )
442  // {
443  // Info<< "i=" << samplei << nl;
444  // }
445  // }
446  //};
447 
448  //reportTrackParts();
449 
450  // Reorder
451  if (Pstream::master())
452  {
453  allPositions.rmap(allPositions, order);
454  allTracks.rmap(allTracks, order);
455  allTrackParts.rmap(allTrackParts, order);
456  allAges.rmap(allAges, order);
457  forAll(fieldNames, fieldi)
458  {
459  #define RMapAllTypes(Type, nullArg) \
460  if (Type##Interp.set(fieldi)) \
461  { \
462  all##Type##s[fieldi].rmap(all##Type##s[fieldi], order); \
463  }
465  #undef RMapAllTypes
466  }
467  }
468 
469  //reportTrackParts();
470 
471  // Relabel tracks and track parts into track labels only, and join the
472  // forward and backward track parts that are connected to the seed
473  if (Pstream::master())
474  {
475  label samplei = 0, tracki = 0;
476  forAll(allPositions, samplej)
477  {
478  const label trackj = allTracks[samplej];
479  const label trackPartj = allTrackParts[samplej];
480 
481  allPositions[samplei] = allPositions[samplej];
482  allTracks[samplei] = tracki;
483  allTrackParts[samplei] = 0;
484  allAges[samplei] = allAges[samplej];
485  forAll(fieldNames, fieldi)
486  {
487  #define ShuffleUpAllTypes(Type, nullArg) \
488  if (Type##Interp.set(fieldi)) \
489  { \
490  all##Type##s[fieldi][samplei] = \
491  all##Type##s[fieldi][samplej]; \
492  }
494  #undef ShuffleUpAllTypes
495  }
496 
497  const bool joinNewParts =
498  samplej != allPositions.size() - 1
499  && trackPartj == -1
500  && allTrackParts[samplej + 1] == 0;
501 
502  if (!joinNewParts) samplei ++;
503 
504  const bool newPart =
505  samplej == allPositions.size() - 1
506  || trackj != allTracks[samplej + 1]
507  || trackPartj != allTrackParts[samplej + 1];
508 
509  if (!joinNewParts && newPart) tracki ++;
510  }
511 
512  allPositions.resize(samplei);
513  allTracks.resize(samplei);
514  allTrackParts.resize(samplei);
515  allAges.resize(samplei);
516  forAll(fieldNames, fieldi)
517  {
518  #define ResizeAllTypes(Type, nullArg) \
519  if (Type##Interp.set(fieldi)) \
520  { \
521  all##Type##s[fieldi].resize(samplei); \
522  }
524  #undef ResizeAllTypes
525  }
526  }
527 
528  //reportTrackParts();
529 
530  // Write
531  if (Pstream::master() && allPositions.size())
532  {
533  // Make output directory
534  fileName outputPath
535  (
536  mesh_.time().globalPath()/writeFile::outputPrefix/name()
537  );
538  if (mesh_.name() != fvMesh::defaultRegion)
539  {
540  outputPath = outputPath/mesh_.name();
541  }
542  outputPath = outputPath/mesh_.time().timeName();
543  mkDir(outputPath);
544 
545  // Pass data to the formatter to write
546  const label nValueSets = fieldNames.size() + writeAge_;
547  wordList valueSetNames(nValueSets);
548  #define DeclareTypeValueSets(Type, nullArg) \
549  UPtrList<const Field<Type>> Type##ValueSets(nValueSets);
551  #undef DeclareTypeValueSets
552  if (writeAge_)
553  {
554  valueSetNames[0] = "age";
555  scalarValueSets.set(0, &allAges);
556  }
557  forAll(fieldNames, fieldi)
558  {
559  valueSetNames[fieldi + writeAge_] = fieldNames[fieldi];
560 
561  #define SetTypeValueSetPtr(Type, nullArg) \
562  if (Type##Interp.set(fieldi)) \
563  { \
564  Type##ValueSets.set \
565  ( \
566  fieldi + writeAge_, \
567  &all##Type##s[fieldi] \
568  ); \
569  }
571  #undef SetTypeValueSetPtr
572  }
573  formatterPtr_->write
574  (
575  outputPath,
576  "tracks",
577  coordSet(allTracks, word::null, allPositions),
578  valueSetNames
579  #define TypeValueSetsParameter(Type, nullArg) , Type##ValueSets
582  );
583  }
584 
585  return true;
586 }
587 
588 
590 {
591  if (&mesh == &mesh_)
592  {
593  // Moving mesh affects the search tree
594  read(dict_);
595  }
596 }
597 
598 
600 (
601  const polyTopoChangeMap& map
602 )
603 {
604  if (&map.mesh() == &mesh_)
605  {
606  read(dict_);
607  }
608 }
609 
610 
612 (
613  const polyMeshMap& map
614 )
615 {
616  if (&map.mesh() == &mesh_)
617  {
618  read(dict_);
619  }
620 }
621 
622 
623 // ************************************************************************* //
static autoPtr< setWriter > New(const word &writeType, const IOstream::streamFormat writeFormat=IOstream::ASCII, const IOstream::compressionType writeCompression=IOstream::UNCOMPRESSED)
Select given write options.
Definition: setWriter.C:279
Template class for intrusive linked lists.
Definition: ILList.H:50
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search...
Definition: meshSearch.H:57
dictionary dict
bool found(const word &, bool recursive=false, bool patternMatch=true) const
Search dictionary for given keyword.
Definition: dictionary.C:663
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
A class for handling file names.
Definition: fileName.H:79
void gatherAndFlatten(DynamicField< Type > &field)
Definition: streamlines.C:48
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
#define SetTypeValueSetPtr(Type, nullArg)
#define TypeValueSetsParameter(Type, nullArg)
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
static autoPtr< sampledSet > New(const word &name, const polyMesh &mesh, const meshSearch &searchEngine, const dictionary &dict)
Return a reference to the selected sampledSet.
Definition: sampledSet.C:190
void resize(const label)
Alter the addressed list size.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
streamlines(const word &name, const Time &runTime, const dictionary &dict)
Construct from Time and dictionary.
Definition: streamlines.C:88
#define DeclareTypeValueSets(Type, nullArg)
static autoPtr< interpolation< Type > > New(const word &interpolationType, const GeometricField< Type, fvPatchField, volMesh > &psi)
Return a reference to the specified interpolation scheme.
Definition: interpolation.C:48
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
addToRunTimeSelectionTable(functionObject, Qdot, dictionary)
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:325
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none/any.
Definition: Switch.H:60
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
#define FoundTypeField(Type, nullArg)
Generic GeometricField class.
label size() const
Return the number of particles in the cloud.
Definition: Cloud.H:190
Field reading functions for post-processing utilities.
Abstract base-class for Time/database functionObjects.
fvMesh & mesh
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:51
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
Macros for easy insertion into run-time selection tables.
#define AllTypesParameter(Type, nullArg)
static List< word > fieldNames
Definition: globalFoam.H:46
virtual bool execute()
Do nothing.
Definition: streamlines.C:197
const dictionary & subDict(const word &) const
Find and return a sub-dictionary.
Definition: dictionary.C:1002
This functionObject tracks a particle cloud in the specified velocity field of an incompressible flow...
Definition: particles.H:108
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
bool read(const char *, int32_t &)
Definition: int32IO.C:85
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
void addParticle(ParticleType *pPtr)
Transfer particle to cloud.
Definition: Cloud.C:220
Holds list of sampling positions.
Definition: coordSet.H:50
const cellShapeList & cells
static const word outputPrefix
Directory prefix.
Definition: writeFile.H:72
A class for handling words, derived from string.
Definition: word.H:59
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
#define TypeInterpolatorParameter(Type, nullArg)
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
A Cloud of streamlines particles.
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
static const word null
An empty word.
Definition: word.H:77
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
#define ShuffleUpAllTypes(Type, nullArg)
Dynamically sized Field.
Definition: DynamicField.H:49
List< label > labelList
A List of labels.
Definition: labelList.H:56
Particle class that samples fields as it passes through. Used in streamlines calculation.
const polyMesh & mesh() const
Return polyMesh.
static const char nl
Definition: Ostream.H:260
virtual bool write()
Calculate and write the streamlines.
Definition: streamlines.C:203
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
bool mkDir(const fileName &, mode_t=0777)
Make a directory and return an error if it could not be created.
Definition: POSIX.C:290
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
defineTypeNameAndDebug(Qdot, 0)
#define DeclareAllTypes(Type, nullArg)
A class for managing temporary objects without reference counting.
Definition: tmpNrc.H:52
virtual void movePoints(const polyMesh &)
Update for mesh point-motion.
Definition: streamlines.C:589
virtual wordList fields() const
Return the list of fields required.
Definition: streamlines.C:188
virtual ~streamlines()
Destructor.
Definition: streamlines.C:104
label toGlobal(const label i) const
From local to global.
Definition: globalIndexI.H:82
void rmap(const UList< T > &mapF, const labelUList &mapAddressing)
1 to 1 reverse-map from the given field
Definition: Field.C:362
void move(TrackCloudType &cloud, typename ParticleType::trackingData &td, const scalar trackTime)
Move the particles.
Definition: Cloud.C:265
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
Given cell centre values and point (vertex) values decompose into tetrahedra and linear interpolate w...
#define ConstructTypeInterpolator(Type, nullArg)
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
#define GatherAndFlattenAllTypes(Type, nullArg)
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:318
#define DeclareTypeInterpolator(Type, nullArg)
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
messageStream Info
FOR_ALL_FIELD_TYPES(DefineFvWallInfoType)
#define RMapAllTypes(Type, nullArg)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
virtual bool read(const dictionary &)
Read the field average data.
Definition: streamlines.C:110
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
Definition: streamlines.C:612
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
Specialisation of Foam::functionObject for an Foam::fvMesh, providing a reference to the Foam::fvMesh...
rDeltaTY field()
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:50
const polyMesh & mesh() const
Return polyMesh.
Definition: polyMeshMap.H:72
static const NamedEnum< trackDirection, 3 > trackDirectionNames_
Track direction enumeration names.
Definition: streamlines.H:230
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
#define ResizeAllTypes(Type, nullArg)
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
Definition: streamlines.C:600
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:864
IOerror FatalIOError