probes.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 "probes.H"
27 #include "volFields.H"
28 #include "polyTopoChangeMap.H"
29 #include "OSspecific.H"
30 #include "writeFile.H"
31 #include "meshSearch.H"
33 
34 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
39 
41  (
43  probes,
45  );
46 }
47 
48 
49 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
50 
52 {
53  if (debug)
54  {
55  Info<< "probes: resetting sample locations" << endl;
56  }
57 
58  const meshSearch& searchEngine = meshSearch::New(mesh_);
59 
62 
63  faceList_.clear();
65 
66  forAll(*this, probei)
67  {
68  const vector& location = operator[](probei);
69 
70  const label celli = searchEngine.findCell(location);
71 
72  elementList_[probei] = celli;
73 
74  if (celli != -1)
75  {
76  const labelList& cellFaces = mesh.cells()[celli];
77  const vector& cellCentre = mesh.cellCentres()[celli];
78  scalar minDistance = great;
79  label minFaceID = -1;
80  forAll(cellFaces, i)
81  {
82  label facei = cellFaces[i];
83  vector dist = mesh.faceCentres()[facei] - cellCentre;
84  if (mag(dist) < minDistance)
85  {
86  minDistance = mag(dist);
87  minFaceID = facei;
88  }
89  }
90  faceList_[probei] = minFaceID;
91  }
92  else
93  {
94  faceList_[probei] = -1;
95  }
96 
97  if (debug && (elementList_[probei] != -1 || faceList_[probei] != -1))
98  {
99  Pout<< "probes : found point " << location
100  << " in cell " << elementList_[probei]
101  << " and face " << faceList_[probei] << endl;
102  }
103  }
104 
105 
106  // Check if all probes have been found.
107  forAll(elementList_, probei)
108  {
109  const vector& location = operator[](probei);
110  label celli = elementList_[probei];
111  label facei = faceList_[probei];
112 
113  // Check at least one processor with cell.
114  reduce(celli, maxOp<label>());
115  reduce(facei, maxOp<label>());
116 
117  if (celli == -1)
118  {
119  if (Pstream::master())
120  {
122  << "Did not find location " << location
123  << " in any cell. Skipping location." << endl;
124  }
125  }
126  else if (facei == -1)
127  {
128  if (Pstream::master())
129  {
131  << "Did not find location " << location
132  << " in any face. Skipping location." << endl;
133  }
134  }
135  else
136  {
137  // Make sure location not on two domains.
138  if (elementList_[probei] != -1 && elementList_[probei] != celli)
139  {
141  << "Location " << location
142  << " seems to be on multiple domains:"
143  << " cell " << elementList_[probei]
144  << " on my domain " << Pstream::myProcNo()
145  << " and cell " << celli << " on some other domain."
146  << endl
147  << "This might happen if the probe location is on"
148  << " a processor patch. Change the location slightly"
149  << " to prevent this." << endl;
150  }
151 
152  if (faceList_[probei] != -1 && faceList_[probei] != facei)
153  {
155  << "Location " << location
156  << " seems to be on multiple domains:"
157  << " cell " << faceList_[probei]
158  << " on my domain " << Pstream::myProcNo()
159  << " and face " << facei << " on some other domain."
160  << endl
161  << "This might happen if the probe location is on"
162  << " a processor patch. Change the location slightly"
163  << " to prevent this." << endl;
164  }
165  }
166  }
167 }
168 
169 
171 {
172  const label nFields = classifyFields();
173 
174  // adjust file streams
175  if (Pstream::master())
176  {
177  wordHashSet currentFields;
178 
179  currentFields.insert(scalarFields_);
180  currentFields.insert(vectorFields_);
181  currentFields.insert(sphericalTensorFields_);
182  currentFields.insert(symmTensorFields_);
183  currentFields.insert(tensorFields_);
184 
185  currentFields.insert(surfaceScalarFields_);
186  currentFields.insert(surfaceVectorFields_);
187  currentFields.insert(surfaceSphericalTensorFields_);
188  currentFields.insert(surfaceSymmTensorFields_);
189  currentFields.insert(surfaceTensorFields_);
190 
191  if (debug)
192  {
193  Info<< "Probing fields: " << currentFields << nl
194  << "Probing locations: " << *this << nl
195  << endl;
196  }
197 
198  const fileName probeDir =
199  mesh_.time().globalPath()
201  /(mesh_.name() != polyMesh::defaultRegion ? mesh_.name() : word())
202  /name()
203  /mesh_.time().name();
204 
205  // ignore known fields, close streams for fields that no longer exist
206  forAllIter(HashPtrTable<OFstream>, probeFilePtrs_, iter)
207  {
208  if (!currentFields.erase(iter.key()))
209  {
210  if (debug)
211  {
212  Info<< "close probe stream: " << iter()->name() << endl;
213  }
214 
215  delete probeFilePtrs_.remove(iter);
216  }
217  }
218 
219  // currentFields now just has the new fields - open streams for them
220  forAllConstIter(wordHashSet, currentFields, iter)
221  {
222  const word& fieldName = iter.key();
223 
224  // Create directory if does not exist.
225  mkDir(probeDir);
226 
227  OFstream* fPtr = new OFstream(probeDir/fieldName);
228  OFstream& os = *fPtr;
229 
230  if (debug)
231  {
232  Info<< "open probe stream: " << os.name() << endl;
233  }
234 
235  probeFilePtrs_.insert(fieldName, fPtr);
236 
237  const unsigned int w = IOstream::defaultPrecision() + 7;
238  os << setf(ios_base::left);
239 
240  forAll(*this, probei)
241  {
242  os<< "# Probe " << probei << ' ' << operator[](probei)
243  << endl;
244  }
245 
246  os << setw(w) << "# Time";
247 
248  forAll(*this, probei)
249  {
250  os<< ' ' << setw(w) << probei;
251  }
252  os<< endl;
253  }
254  }
255 
256  return nFields;
257 }
258 
259 
260 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
261 
263 (
264  const word& name,
265  const Time& t,
266  const dictionary& dict
267 )
268 :
269  functionObject(name, t),
270  pointField(0),
271  mesh_
272  (
273  refCast<const fvMesh>
274  (
275  t.lookupObject<objectRegistry>
276  (
277  dict.lookupOrDefault("region", polyMesh::defaultRegion)
278  )
279  )
280  ),
281  fields_(),
282  fixedLocations_(true),
283  interpolationScheme_("cell")
284 {
285  read(dict);
286 }
287 
288 
289 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
290 
292 {}
293 
294 
295 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
296 
298 {
299  dict.lookup("probeLocations") >> *this;
300  dict.lookup("fields") >> fields_;
301 
302  dict.readIfPresent("fixedLocations", fixedLocations_);
303  if (dict.readIfPresent("interpolationScheme", interpolationScheme_))
304  {
305  if (!fixedLocations_ && interpolationScheme_ != "cell")
306  {
308  << "Only cell interpolation can be applied when "
309  << "not using fixedLocations. InterpolationScheme "
310  << "entry will be ignored";
311  }
312  }
313 
314  // Initialise cells to sample from supplied locations
315  findElements(mesh_);
316 
317  prepare();
318 
319  return true;
320 }
321 
322 
324 {
325  return fields_;
326 }
327 
328 
330 {
331  return true;
332 }
333 
334 
336 {
337  if (size() && prepare())
338  {
339  sampleAndWrite(scalarFields_);
340  sampleAndWrite(vectorFields_);
341  sampleAndWrite(sphericalTensorFields_);
342  sampleAndWrite(symmTensorFields_);
343  sampleAndWrite(tensorFields_);
344 
345  sampleAndWriteSurfaceFields(surfaceScalarFields_);
346  sampleAndWriteSurfaceFields(surfaceVectorFields_);
347  sampleAndWriteSurfaceFields(surfaceSphericalTensorFields_);
348  sampleAndWriteSurfaceFields(surfaceSymmTensorFields_);
349  sampleAndWriteSurfaceFields(surfaceTensorFields_);
350  }
351 
352  return true;
353 }
354 
355 
357 {
358  DebugInfo<< "probes: movePoints" << endl;
359 
360  if (fixedLocations_ && &mesh == &mesh_)
361  {
362  findElements(mesh_);
363  }
364 }
365 
366 
368 {
369  DebugInfo<< "probes: topoChange" << endl;
370 
371  if (&map.mesh() != &mesh_)
372  {
373  return;
374  }
375 
376  if (fixedLocations_)
377  {
378  findElements(mesh_);
379  }
380  else
381  {
382  if (debug)
383  {
384  Info<< "probes: remapping sample locations" << endl;
385  }
386 
387  // 1. Update cells
388  if (!map.reverseCellMap().empty())
389  {
390  DynamicList<label> elems(elementList_.size());
391 
392  const labelList& reverseMap = map.reverseCellMap();
393  forAll(elementList_, i)
394  {
395  const label celli = elementList_[i];
396  const label newCelli = reverseMap[celli];
397 
398  if (newCelli == -1)
399  {
400  // cell removed
401  }
402  else if (newCelli < -1)
403  {
404  // cell merged
405  elems.append(-newCelli - 2);
406  }
407  else
408  {
409  // valid new cell
410  elems.append(newCelli);
411  }
412  }
413 
414  elementList_.transfer(elems);
415  }
416 
417  // 2. Update faces
418  if (!map.reverseFaceMap().empty())
419  {
420  DynamicList<label> elems(faceList_.size());
421 
422  const labelList& reverseMap = map.reverseFaceMap();
423  forAll(faceList_, i)
424  {
425  const label facei = faceList_[i];
426  const label newFacei = reverseMap[facei];
427 
428  if (newFacei == -1)
429  {
430  // face removed
431  }
432  else if (newFacei < -1)
433  {
434  // face merged
435  elems.append(-newFacei - 2);
436  }
437  else
438  {
439  // valid new face
440  elems.append(newFacei);
441  }
442  }
443 
444  faceList_.transfer(elems);
445  }
446  }
447 }
448 
449 
451 {
452  DebugInfo<< "probes: mapMesh" << endl;
453 
454  findElements(mesh_);
455 }
456 
457 
458 // ************************************************************************* //
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 forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:458
#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.
DynamicList< T, SizeInc, SizeMult, SizeDiv > & append(const T &)
Append an element at the end of the list.
Definition: DynamicListI.H:296
A HashTable specialisation for hashing pointers.
Definition: HashPtrTable.H:67
A HashTable with keys but without contents.
Definition: HashSet.H:62
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:109
bool erase(const iterator &)
Erase a hashedEntry specified by given iterator.
Definition: HashTable.C:445
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:473
label size() const
Return the number of elements in the UList.
Definition: ListI.H:171
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:125
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output to file stream.
Definition: OFstream.H:87
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:121
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:76
bool empty() const
Return true if the UList is empty (ie, size() is zero)
Definition: UListI.H:325
T & operator[](const label)
Return element of UList.
Definition: UListI.H:167
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:740
bool readIfPresent(const word &, T &, bool recursive=false, bool patternMatch=true) const
Find an entry if present, and assign to T.
A class for handling file names.
Definition: fileName.H:82
Abstract base-class for Time/database functionObjects.
static const word outputPrefix
Directory prefix.
Definition: writeFile.H:72
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
Mesh object that implements searches within the local cells and faces.
Definition: meshSearch.H:59
label findCell(const point &p, const pointInCellShapes=pointInCellShapes::tets) const
Find the cell containing the given point.
Definition: meshSearch.C:173
static const meshSearch & New(const polyMesh &mesh, const pointInCellShapes=pointInCellShapes::tets)
Lookup or construct from mesh and cell decomposition option.
Definition: meshSearch.C:61
Registry of regIOobjects.
Class containing mesh-to-mesh mapping information.
Definition: polyMeshMap.H:51
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:251
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
const labelList & reverseCellMap() const
Reverse cell map.
const labelList & reverseFaceMap() const
Reverse face map.
const polyMesh & mesh() const
Return polyMesh.
const vectorField & faceCentres() const
const vectorField & cellCentres() const
const cellList & cells() const
Set of locations to sample.
Definition: probes.H:68
virtual ~probes()
Destructor.
Definition: probes.C:291
const fvMesh & mesh_
Const reference to fvMesh.
Definition: probes.H:91
virtual wordList fields() const
Return the list of fields required.
Definition: probes.C:323
virtual void topoChange(const polyTopoChangeMap &)
Update topology using the given map.
Definition: probes.C:367
label prepare()
Classify field type and Open/close file streams,.
Definition: probes.C:170
probes(const word &name, const Time &time, const dictionary &dict)
Construct from Time and dictionary.
Definition: probes.C:263
labelList elementList_
Definition: probes.H:126
virtual void findElements(const fvMesh &)
Find cells and faces containing probes.
Definition: probes.C:51
virtual void mapMesh(const polyMeshMap &)
Update from another mesh using the given map.
Definition: probes.C:450
virtual void movePoints(const polyMesh &)
Update topology using the given map.
Definition: probes.C:356
labelList faceList_
Definition: probes.H:129
virtual bool execute()
Execute, currently does nothing.
Definition: probes.C:329
virtual bool write()
Sample and write.
Definition: probes.C:335
virtual bool read(const dictionary &)
Read the probes.
Definition: probes.C:297
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)
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
Smanip< ios_base::fmtflags > setf(const ios_base::fmtflags flags)
Definition: IOmanip.H:164
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
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
To & refCast(From &r)
Reference type cast template function.
Definition: typeInfo.H:134
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
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
messageStream Info
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
defineTypeNameAndDebug(combustionModel, 0)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
static const char nl
Definition: Ostream.H:267
dictionary dict