timeVaryingMappedFixedValuePointPatchField.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) 2012-2026 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 
27 #include "Time.H"
28 #include "AverageField.H"
29 #include "IFstream.H"
30 
31 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
32 
33 template<class Type>
36 (
37  const pointPatch& p,
39  const dictionary& dict
40 )
41 :
42  fixedValuePointPatchField<Type>(p, iF, dict, false),
43  fieldTableName_(iF.name()),
44  setAverage_(dict.lookupOrDefault("setAverage", false)),
45  perturb_(dict.lookupOrDefault("perturb", 1e-5)),
46  mapMethod_
47  (
48  dict.lookupOrDefault<word>
49  (
50  "mapMethod",
51  "planarInterpolation"
52  )
53  ),
54  mapperPtr_(nullptr),
55  sampleTimes_(0),
56  startSampleTime_(-1),
57  startSampledValues_(0),
58  startAverage_(Zero),
59  endSampleTime_(-1),
60  endSampledValues_(0),
61  endAverage_(Zero),
62  offset_()
63 {
64  if (dict.found("offset"))
65  {
66  offset_ = Function1<Type>::New
67  (
68  "offset",
69  this->time().userUnits(),
70  iF.dimensions(),
71  dict
72  );
73  }
74 
75  if
76  (
77  mapMethod_ != "planarInterpolation"
78  && mapMethod_ != "nearest"
79  )
80  {
82  (
83  dict
84  ) << "mapMethod should be one of 'planarInterpolation'"
85  << ", 'nearest'" << exit(FatalIOError);
86  }
87 
88  dict.readIfPresent("fieldTableName", fieldTableName_);
89 
90  if (dict.found("value"))
91  {
93  (
94  Field<Type>("value", iF.dimensions(), dict, p.size())
95  );
96  }
97  else
98  {
99  // Note: use evaluate to do updateCoeffs followed by a reset
100  // of the pointPatchField::updated_ flag. This is
101  // so if first use is in the next time step it retriggers
102  // a new update.
104  }
105 }
106 
107 
108 template<class Type>
111 (
113  const pointPatch& p,
115  const fieldMapper& mapper
116 )
117 :
118  fixedValuePointPatchField<Type>(ptf, p, iF, mapper),
119  fieldTableName_(ptf.fieldTableName_),
120  setAverage_(ptf.setAverage_),
121  perturb_(ptf.perturb_),
122  mapMethod_(ptf.mapMethod_),
123  mapperPtr_(nullptr),
124  sampleTimes_(0),
125  startSampleTime_(-1),
126  startSampledValues_(0),
127  startAverage_(Zero),
128  endSampleTime_(-1),
129  endSampledValues_(0),
130  endAverage_(Zero),
131  offset_(ptf.offset_, false)
132 {}
133 
134 
135 template<class Type>
138 (
141 )
142 :
143  fixedValuePointPatchField<Type>(ptf, iF),
144  fieldTableName_(ptf.fieldTableName_),
145  setAverage_(ptf.setAverage_),
146  perturb_(ptf.perturb_),
147  mapMethod_(ptf.mapMethod_),
148  mapperPtr_(ptf.mapperPtr_),
149  sampleTimes_(ptf.sampleTimes_),
150  startSampleTime_(ptf.startSampleTime_),
151  startSampledValues_(ptf.startSampledValues_),
152  startAverage_(ptf.startAverage_),
153  endSampleTime_(ptf.endSampleTime_),
154  endSampledValues_(ptf.endSampledValues_),
155  endAverage_(ptf.endAverage_),
156  offset_(ptf.offset_, false)
157 {}
158 
159 
160 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
161 
162 template<class Type>
164 (
165  const pointPatchField<Type>& ptf,
166  const fieldMapper& mapper
167 )
168 {
169  reset(ptf);
170 }
171 
172 
173 template<class Type>
175 (
176  const pointPatchField<Type>& ptf
177 )
178 {
180 
182  refCast<const timeVaryingMappedFixedValuePointPatchField<Type>>(ptf);
183 
184  if (this != &tiptf)
185  {
186  startSampledValues_.reset(tiptf.startSampledValues_);
187  endSampledValues_.reset(tiptf.endSampledValues_);
188  }
189 
190  // Clear interpolator
191  mapperPtr_.clear();
192  startSampleTime_ = -1;
193  endSampleTime_ = -1;
194 }
195 
196 
197 template<class Type>
199 {
200  // Initialise
201  if (startSampleTime_ == -1 && endSampleTime_ == -1)
202  {
203  const polyMesh& pMesh = this->patch().mesh()();
204 
205  // Read the initial point position
206  pointField meshPts;
207 
208  if (pMesh.pointsInstance() == pMesh.facesInstance())
209  {
210  meshPts = pointField(pMesh.points(), this->patch().meshPoints());
211  }
212  else
213  {
214  // Load points from facesInstance
215  if (debug)
216  {
217  Info<< "Reloading points0 from " << pMesh.facesInstance()
218  << endl;
219  }
220 
221  pointIOField points0
222  (
223  IOobject
224  (
225  "points",
226  pMesh.facesInstance(),
228  pMesh,
231  false
232  )
233  );
234  meshPts = pointField(points0, this->patch().meshPoints());
235  }
236 
237  // Reread values and interpolate
238  fileName samplePointsFile
239  (
240  this->time().constant()
241  /"boundaryData"
242  /this->patch().name()
243  /"points"
244  );
245 
246  pointField samplePoints((IFstream(samplePointsFile)()));
247 
248  // tbd: run-time selection
249  bool nearestOnly =
250  (
251  !mapMethod_.empty()
252  && mapMethod_ != "planarInterpolation"
253  );
254 
255  // Allocate the interpolator
256  mapperPtr_.reset
257  (
259  (
260  samplePoints,
261  meshPts,
262  perturb_,
263  nearestOnly
264  )
265  );
266 
267  // Read the times for which data is available
268 
269  const fileName samplePointsDir = samplePointsFile.path();
270  sampleTimes_ = this->time().findTimes(samplePointsDir);
271 
272  if (debug)
273  {
274  Info<< "timeVaryingMappedFixedValuePointPatchField : In directory "
275  << samplePointsDir << " found times "
277  << endl;
278  }
279  }
280 
281  // Find current time in sampleTimes
282  label lo = -1;
283  label hi = -1;
284 
285  bool foundTime = mapperPtr_().findTime
286  (
287  sampleTimes_,
288  startSampleTime_,
289  this->time().userTimeValue(),
290  lo,
291  hi
292  );
293 
294  if (!foundTime)
295  {
297  << "Cannot find starting sampling values for current time "
298  << this->time().userTimeValue() << nl
299  << "Have sampling values for times "
301  << "In directory "
302  << this->time().constant()/"boundaryData"/this->patch().name()
303  << "\n on patch " << this->patch().name()
304  << " of field " << fieldTableName_
305  << exit(FatalError);
306  }
307 
308 
309  // Update sampled data fields.
310 
311  if (lo != startSampleTime_)
312  {
313  startSampleTime_ = lo;
314 
315  if (startSampleTime_ == endSampleTime_)
316  {
317  // No need to reread since are end values
318  if (debug)
319  {
320  Pout<< "checkTable : Setting startValues to (already read) "
321  << "boundaryData"
322  /this->patch().name()
323  /sampleTimes_[startSampleTime_].name()
324  << endl;
325  }
326  startSampledValues_ = endSampledValues_;
327  startAverage_ = endAverage_;
328  }
329  else
330  {
331  if (debug)
332  {
333  Pout<< "checkTable : Reading startValues from "
334  << "boundaryData"
335  /this->patch().name()
336  /sampleTimes_[lo].name()
337  << endl;
338  }
339 
340  // Reread values and interpolate
341  fileName valsFile
342  (
343  this->time().constant()
344  /"boundaryData"
345  /this->patch().name()
346  /sampleTimes_[startSampleTime_].name()
347  /fieldTableName_
348  );
349 
350  Field<Type> vals;
351 
352  if (setAverage_)
353  {
354  AverageField<Type> avals((IFstream(valsFile)()));
355  vals = avals;
356  startAverage_ = avals.average();
357  }
358  else
359  {
360  (IFstream(valsFile)()) >> vals;
361  }
362 
363  if (vals.size() != mapperPtr_().sourceSize())
364  {
366  << "Number of values (" << vals.size()
367  << ") differs from the number of points ("
368  << mapperPtr_().sourceSize()
369  << ") in file " << valsFile << exit(FatalError);
370  }
371 
372  startSampledValues_ = mapperPtr_().interpolate(vals);
373  }
374  }
375 
376  if (hi != endSampleTime_)
377  {
378  endSampleTime_ = hi;
379 
380  if (endSampleTime_ == -1)
381  {
382  // endTime no longer valid. Might as well clear endValues.
383  if (debug)
384  {
385  Pout<< "checkTable : Clearing endValues" << endl;
386  }
387  endSampledValues_.clear();
388  }
389  else
390  {
391  if (debug)
392  {
393  Pout<< "checkTable : Reading endValues from "
394  << "boundaryData"
395  /this->patch().name()
396  /sampleTimes_[endSampleTime_].name()
397  << endl;
398  }
399 
400  // Reread values and interpolate
401  fileName valsFile
402  (
403  this->time().constant()
404  /"boundaryData"
405  /this->patch().name()
406  /sampleTimes_[endSampleTime_].name()
407  /fieldTableName_
408  );
409 
410  Field<Type> vals;
411 
412  if (setAverage_)
413  {
414  AverageField<Type> avals((IFstream(valsFile)()));
415  vals = avals;
416  endAverage_ = avals.average();
417  }
418  else
419  {
420  (IFstream(valsFile)()) >> vals;
421  }
422 
423  if (vals.size() != mapperPtr_().sourceSize())
424  {
426  << "Number of values (" << vals.size()
427  << ") differs from the number of points ("
428  << mapperPtr_().sourceSize()
429  << ") in file " << valsFile << exit(FatalError);
430  }
431 
432  endSampledValues_ = mapperPtr_().interpolate(vals);
433  }
434  }
435 }
436 
437 
438 template<class Type>
440 {
441  if (this->updated())
442  {
443  return;
444  }
445 
446  checkTable();
447 
448  // Interpolate between the sampled data
449 
450  Type wantedAverage;
451 
452  if (endSampleTime_ == -1)
453  {
454  // only start value
455  if (debug)
456  {
457  Pout<< "updateCoeffs : Sampled, non-interpolated values"
458  << " from start time:"
459  << sampleTimes_[startSampleTime_].name() << nl;
460  }
461 
462  this->operator==(startSampledValues_);
463  wantedAverage = startAverage_;
464  }
465  else
466  {
467  scalar start = sampleTimes_[startSampleTime_].value();
468  scalar end = sampleTimes_[endSampleTime_].value();
469 
470  scalar s = (this->time().userTimeValue()-start)/(end-start);
471 
472  if (debug)
473  {
474  Pout<< "updateCoeffs : Sampled, interpolated values"
475  << " between start time:"
476  << sampleTimes_[startSampleTime_].name()
477  << " and end time:" << sampleTimes_[endSampleTime_].name()
478  << " with weight:" << s << endl;
479  }
480 
481  this->operator==((1 - s)*startSampledValues_ + s*endSampledValues_);
482  wantedAverage = (1 - s)*startAverage_ + s*endAverage_;
483  }
484 
485  // Enforce average. Either by scaling (if scaling factor > 0.5) or by
486  // offsetting.
487  if (setAverage_)
488  {
489  const Field<Type>& fld = *this;
490 
491  Type averagePsi = gAverage(fld);
492 
493  if (debug)
494  {
495  Pout<< "updateCoeffs :"
496  << " actual average:" << averagePsi
497  << " wanted average:" << wantedAverage
498  << endl;
499  }
500 
501  if (mag(averagePsi) < vSmall)
502  {
503  // Field too small to scale. Offset instead.
504  const Type offset = wantedAverage - averagePsi;
505  if (debug)
506  {
507  Pout<< "updateCoeffs :"
508  << " offsetting with:" << offset << endl;
509  }
510  this->operator==(fld + offset);
511  }
512  else
513  {
514  const scalar scale = mag(wantedAverage)/mag(averagePsi);
515 
516  if (debug)
517  {
518  Pout<< "updateCoeffs :"
519  << " scaling with:" << scale << endl;
520  }
521  this->operator==(scale*fld);
522  }
523  }
524 
525  // Apply offset to mapped values
526  if (offset_.valid())
527  {
528  this->operator==
529  (
530  *this + offset_->value(this->time().value())
531  );
532  }
533 
534  if (debug)
535  {
536  Pout<< "updateCoeffs : set fixedValue to min:" << gMin(*this)
537  << " max:" << gMax(*this)
538  << " avg:" << gAverage(*this) << endl;
539  }
540 
542 }
543 
544 
545 template<class Type>
547 (
548  Ostream& os
549 ) const
550 {
552 
553  writeEntryIfDifferent(os, "setAverage", Switch(false), setAverage_);
554 
555  writeEntryIfDifferent(os, "perturb", scalar(1e-5), perturb_);
556 
558  (
559  os,
560  "fieldTable",
561  this->internalField().name(),
562  fieldTableName_
563  );
564 
566  (
567  os,
568  "mapMethod",
569  word("planarInterpolation"),
570  mapMethod_
571  );
572 
573  if (offset_.valid())
574  {
575  writeEntry(os, offset_());
576  }
577 }
578 
579 
580 // ************************************************************************* //
A primitive field with a separate average value.
Definition: AverageField.H:52
const Type & average() const
Definition: AverageField.C:61
Field with dimensions and associated with geometry type GeoMesh which is used to size the field and a...
const dimensionSet & dimensions() const
Return dimensions.
Pre-declare SubField and related Field type.
Definition: Field.H:83
static autoPtr< Function1< Type > > New(const word &name, const Function1s::unitSets &units, const dictionary &dict)
Select from dictionary.
Definition: Function1New.C:32
Input from file stream.
Definition: IFstream.H:85
A primitive field of type <Type> with automated input and output.
Definition: IOField.H:53
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:99
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:85
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
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 field mapping.
Definition: fieldMapper.H:48
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
fileName path() const
Return directory path name (part before last /)
Definition: fileName.C:284
A FixedValue boundary condition for pointField.
Abstract base class for point-mesh patch fields.
virtual void evaluate(const Pstream::commsTypes commsType=Pstream::commsTypes::blocking)
Evaluate the patch field.
const Time & time() const
Return time.
Basic pointPatch represents a set of points from the mesh.
Definition: pointPatch.H:61
Interpolates between two sets of unstructured points using 2D Delaunay triangulation....
static wordList timeNames(const instantList &)
Helper: extract words of times.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:78
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:1012
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:1006
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:263
A time-varying form of a mapped fixed value boundary condition.
timeVaryingMappedFixedValuePointPatchField(const pointPatch &, const DimensionedField< Type, pointMesh > &, const dictionary &)
Construct from patch, internal field and dictionary.
virtual void updateCoeffs()
Update the coefficients associated with the patch field.
void checkTable()
Find boundary data in between current time and interpolate.
virtual void reset(const pointPatchField< Type > &)
Reset the pointPatchField to the given pointPatchField.
virtual void map(const pointPatchField< Type > &, const fieldMapper &)
Map the given pointPatchField onto this pointPatchField.
virtual void write(Ostream &) const
Write.
virtual void updateCoeffs()
Update the coefficients associated with the patch field.
virtual void reset(const pointPatchField< Type > &)
Reset the pointPatchField to the given pointPatchField.
A class for handling words, derived from string.
Definition: word.H:63
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:346
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
gmvFile<< "tracers "<< particles.size()<< nl;{ pointField positions(particles.size());label particlei=0;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter) { positions[particlei++]=iter().position(mesh);} for(i=0;i< pTraits< point >::nComponents;i++) { forAll(positions, particlei) { gmvFile<< component(positions[particlei], i)<< ' ';} gmvFile<< nl;}}forAll(lagrangianScalarNames, i){ const word &name=lagrangianScalarNames[i];IOField< scalar > fld(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
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))
const dimensionedScalar e
Elementary charge.
const dimensionSet time
Type gMin(const UList< Type > &f, const label comm)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
const doubleScalar e
Definition: doubleScalar.H:106
void writeEntryIfDifferent(Ostream &os, const word &entryName, const EntryType &value1, const EntryType &value2)
Helper function to write the keyword and entry only if the.
Type gAverage(const UList< Type > &f, const label comm)
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
tmp< fvMatrix< Type > > operator==(const fvMatrix< Type > &, const fvMatrix< Type > &)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
IOerror FatalIOError
Type gMax(const UList< Type > &f, const label comm)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
error FatalError
void offset(label &lst, const label o)
void writeEntry(Ostream &os, const word &key, const DimensionedFieldFunction< DimensionedFieldType > &f)
static const char nl
Definition: Ostream.H:297
dictionary dict
volScalarField & p