regIOobject.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2018-2023 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 Note
28  Included by global/globals.C
29 
30 \*---------------------------------------------------------------------------*/
31 
32 #include "regIOobject.H"
33 #include "Time.H"
34 #include "polyMesh.H"
35 #include "dictionary.H"
36 #include "fileOperation.H"
37 
38 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
42  defineTypeNameAndDebug(regIOobject, 0);
43 }
44 
46 
47 
48 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
49 
50 Foam::regIOobject::regIOobject(const IOobject& io, const bool isTimeObject)
51 :
52  IOobject(io),
53  registered_(false),
54  ownedByRegistry_(false),
55  eventNo_(isTimeObject ? 0 : db().getEvent()), // No event for top-level Time
56  metaDataPtr_(nullptr),
57  isPtr_(nullptr)
58 {
60  {
61  // Register (check-in) with objectRegistry if requested
62  checkIn();
63  }
64 }
65 
66 
67 Foam::regIOobject::regIOobject(const regIOobject& rio)
68 :
69  IOobject(rio),
70  registered_(false),
71  ownedByRegistry_(false),
72  eventNo_(db().getEvent()),
73  watchFiles_(rio.watchFiles_),
74  watchIndices_(rio.watchIndices_),
75  metaDataPtr_(rio.metaDataPtr_.clone()),
76  isPtr_(nullptr)
77 {
78  // Do not register copy with objectRegistry
79 }
80 
81 
82 Foam::regIOobject::regIOobject(const regIOobject& rio, bool registerCopy)
83 :
84  IOobject(rio),
85  registered_(false),
86  ownedByRegistry_(false),
87  eventNo_(db().getEvent()),
88  metaDataPtr_(rio.metaDataPtr_.clone()),
89  isPtr_(nullptr)
90 {
91  if (registerCopy)
92  {
93  if (rio.registered_)
94  {
95  // Unregister the original object
96  const_cast<regIOobject&>(rio).checkOut();
97  }
98  checkIn();
99  }
100 }
101 
102 
104 (
105  const word& newName,
106  const regIOobject& rio,
107  bool registerCopy
108 )
109 :
110  IOobject(newName, rio.instance(), rio.local(), rio.db()),
111  registered_(false),
112  ownedByRegistry_(false),
113  eventNo_(db().getEvent()),
114  metaDataPtr_(rio.metaDataPtr_.clone()),
115  isPtr_(nullptr)
116 {
117  if (registerCopy)
118  {
119  // NOTE: could also unregister the original object
120  // if (rio.registered_ && newName == rio.name()) ...
122  checkIn();
123  }
124 }
125 
126 
128 (
129  const IOobject& io,
130  const regIOobject& rio
131 )
132 :
133  IOobject(io),
134  registered_(false),
135  ownedByRegistry_(false),
136  eventNo_(db().getEvent()),
137  metaDataPtr_(rio.metaDataPtr_.clone()),
138  isPtr_(nullptr)
139 {
141  {
143  }
144 }
145 
146 
147 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
148 
150 {
152  {
153  Pout<< "Destroy regIOobject: " << name()
154  << " type=" << type()
155  << " registered=" << registered_
156  << " owned=" << ownedByRegistry_
157  << " directory=" << path()
158  << endl;
159  }
160 
161  // Deletion of a regIOobject should remove itself from its registry
162  // (ie, checkOut), but there are different paths for destruction to occur.
163  // The complications are only when the object is ownedByRegistry.
164  //
165  // 1. The objectRegistry clear()/erase() is called (and object is
166  // 'ownedByRegistry').
167  //
168  // - Mark as unowned/unregistered prior to deletion.
169  // This ensures that this checkOut() only clears file watches and
170  // does nothing else.
171  //
172  // 2. The regIOobject is deleted directly (and also 'ownedByRegistry').
173  //
174  // - Mark as unowned (but keep as registered) prior to triggering
175  // checkOut(). By being 'unowned', the registry will not attempt a
176  // second deletion when the object name is removed from the registry.
177 
178  // Reset the cache state (if any)
179  db().resetCacheTemporaryObject(this);
180 
181  // Revoke any registry ownership: we are already deleting
182  ownedByRegistry_ = false;
183 
184  // Remove registered object from objectRegistry
185  checkOut();
186 }
187 
188 
189 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
190 
192 {
193  if (!registered_)
194  {
195  // multiple checkin of same object is disallowed - this would mess up
196  // any mapping
197  registered_ = db().checkIn(this);
198 
199  // check-in on defaultRegion is allowed to fail, since subsetted meshes
200  // are created with the same name as their originating mesh
201  if (!registered_ && debug && name() != polyMesh::defaultRegion)
202  {
203  if (debug == 2)
204  {
205  // for ease of finding where attempted duplicate check-in
206  // originated
208  << "Failed to register: " << name() << ' '
209  << objectRelPath()
210  << " : the name already exists in the registry" << nl
211  << "Contents:" << db().sortedToc() << endl
212  << abort(FatalError);
213  }
214  else
215  {
217  << "Failed to register: " << name() << ' '
218  << objectRelPath()
219  << " : the name already exists in the registry" << endl;
220  }
221  }
222  }
223 
224  return registered_;
225 }
226 
227 
229 {
230  forAllReverse(watchIndices_, i)
231  {
232  fileHandler().removeWatch(watchIndices_[i]);
233  }
234  watchIndices_.clear();
235  watchFiles_.clear();
236 
237  if (registered_)
238  {
239  registered_ = false;
240 
241  return db().checkOut(this);
242  }
243 
244  return false;
245 }
246 
247 
248 Foam::label Foam::regIOobject::addWatch(const fileName& f)
249 {
250  label index = -1;
251 
252  if
253  (
254  registered_
255  && readOpt() == IOobjectOption::READ_MODIFIED
256  && time().runTimeModifiable()
257  )
258  {
259  //- 1. Directly add to fileHandler
260  //index = fileHandler().findWatch(watchIndices_, f);
261  //
262  //if (index == -1)
263  //{
264  // index = watchIndices_.size();
265  // watchIndices_.push_back(fileHandler().addWatch(f));
266  //}
267 
268  //- 2. Delay adding; add to list and handle in addWatch() later on
269  // Note: what do we return?
270  index = watchFiles_.size();
271  watchFiles_.push_back(f);
272  }
273 
274  return index;
275 }
276 
279 {
280  // Everyone or just master
281  const bool masterOnly
282  (
283  global()
284  && (
287  )
288  );
289 
290  // if (debug)
291  // {
292  // Pout<< "regIOobject::addWatch " << watchIndices_.size()
293  // << " indices master-only:" << masterOnly
294  // << " watchFiles: " << watchFiles_ << endl;
295  // }
296 
297  if
298  (
299  registered_
300  && readOpt() == IOobjectOption::READ_MODIFIED
301  && time().runTimeModifiable()
302  )
303  {
304  fileName f = filePath();
305  if (f.empty())
306  {
307  // We don't have this file but would like to re-read it.
308  // Possibly if master-only reading mode.
309  f = objectPath();
310  }
311 
312  label index = fileHandler().findWatch(watchIndices_, f);
313  if (index != -1)
314  {
316  << "Object " << objectPath() << " of type " << type()
317  << " already watched with index " << watchIndices_[index]
318  << abort(FatalError);
319  }
320 
321  // If master-only reading only the master will have all dependencies
322  // so broadcast these to other ranks
323 
324  if (masterOnly && UPstream::parRun())
325  {
326  // Get all files watched on master, and broadcast at once
327  fileNameList filesToWatch;
328  if (UPstream::master())
329  {
330  const bool oldParRun = UPstream::parRun(false);
331 
332  filesToWatch.resize(watchIndices_.size());
333  forAll(watchIndices_, i)
334  {
335  filesToWatch[i] = fileHandler().getFile(watchIndices_[i]);
336  }
337 
338  UPstream::parRun(oldParRun);
339  }
340 
342  (
344  filesToWatch,
345  watchFiles_
346  );
347 
348  // Add master files in same order
349  if (!UPstream::master())
350  {
351  const bool oldParRun = UPstream::parRun(false);
352 
353  // Unregister current watched indices
354  forAllReverse(watchIndices_, i)
355  {
356  fileHandler().removeWatch(watchIndices_[i]);
357  }
358 
359  // Insert the ones from master, in master order
360  watchIndices_.clear();
361  for (const auto& file : filesToWatch)
362  {
363  watchIndices_.push_back(fileHandler().addWatch(file));
364  }
365 
366  UPstream::parRun(oldParRun);
367  }
368 
369 
370  // Files that were explicitly added via addWatch(const fileName&)
371  // (e.g. through #include)
372  for (const auto& file : watchFiles_)
373  {
374  watchIndices_.push_back(fileHandler().addWatch(file));
375  }
376 
377  // Append the local file
378  watchIndices_.push_back(fileHandler().addWatch(f));
379  }
380  else
381  {
382  DynamicList<fileName> filesToWatch
383  (
384  watchIndices_.size()+watchFiles_.size()+1
385  );
386 
387  // Get existing watched files from fileHandler
388  for (const label index : watchIndices_)
389  {
390  filesToWatch.push_back(fileHandler().getFile(index));
391  }
392 
393  // The files explicitly added from addWatch(const fileName&)
394  // (e.g. through #include)
395  filesToWatch.push_back(std::move(watchFiles_));
396 
397  // The local file
398  filesToWatch.push_back(f);
399 
400  // Re-do all watches
401  fileHandler().addWatches(*this, filesToWatch);
402  }
403  }
404 }
405 
407 bool Foam::regIOobject::upToDate(const regIOobject& a) const
408 {
409  label da = a.eventNo()-eventNo_;
410 
411  // In case of overflow *this.event() might be 2G but a.event() might
412  // have overflowed to 0.
413  // Detect this by detecting a massive difference (labelMax/2) between
414  // the two events.
415  //
416  // a *this return
417  // - ----- ------
418  // normal operation:
419  // 11 10 false
420  // 11 11 false
421  // 10 11 true
422  // overflow situation:
423  // 0 big false
424  // big 0 true
425 
426  if (da > labelMax/2)
427  {
428  // *this.event overflowed but a.event not yet
429  return true;
430  }
431  else if (da < -labelMax/2)
432  {
433  // a.event overflowed but *this not yet
434  return false;
435  }
436  else if (da < 0)
437  {
438  // My event number higher than a
439  return true;
440  }
441 
442  return false;
443 }
444 
445 
447 (
448  const regIOobject& a,
449  const regIOobject& b
450 ) const
451 {
452  return upToDate(a) && upToDate(b);
453 }
454 
455 
457 (
458  const regIOobject& a,
459  const regIOobject& b,
460  const regIOobject& c
461 ) const
462 {
463  return upToDate(a) && upToDate(b) && upToDate(c);
464 }
465 
466 
468 (
469  const regIOobject& a,
470  const regIOobject& b,
471  const regIOobject& c,
472  const regIOobject& d
473 ) const
474 {
475  return upToDate(a) && upToDate(b) && upToDate(c) && upToDate(d);
476 }
477 
480 {
481  eventNo_ = db().getEvent();
482 }
483 
485 void Foam::regIOobject::rename(const word& newName)
486 {
487  // Check out of objectRegistry
488  checkOut();
489 
490  IOobject::rename(newName);
491 
493  {
494  // Re-register object with objectRegistry
495  checkIn();
496  }
497 }
498 
501 {
502  return localFilePath(type());
503 }
504 
507 {
508  // Note: Should be consistent with IOobject::typeHeaderOk(false)
509 
510  bool ok = true;
511 
512  fileName fName(filePath());
513 
514  ok = Foam::fileHandler().readHeader(*this, fName, type());
515 
516  if (!ok && IOobject::debug)
517  {
518  IOWarningInFunction(fName)
519  << "failed to read header of file " << objectPath()
520  << endl;
521  }
522 
523  return ok;
524 }
525 
528 {
529  // Close any file
530  isPtr_.reset(nullptr);
531 
532  // Check out of objectRegistry
533  checkOut();
534 
536 
538  {
539  // Re-register object with objectRegistry
540  checkIn();
541  }
542 }
543 
544 
545 // ************************************************************************* //
bool upToDate(const regIOobject &) const
Return true if up-to-date with respect to given object.
Definition: regIOobject.C:406
A class for handling file names.
Definition: fileName.H:72
void operator=(const IOobject &io)
Copy assignment, copies all values (except the registry)
Definition: IOobject.C:603
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void setUpToDate()
Set as up-to-date.
Definition: regIOobject.C:478
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
label eventNo() const noexcept
Event number at last update.
Definition: regIOobjectI.H:186
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:666
virtual void rename(const word &newName)
Rename the object.
Definition: IOobject.H:677
regIOobject(const IOobject &io, const bool isTimeObject=false)
Construct from IOobject. The optional flag adds special handling if the object is the top-level regIO...
Definition: regIOobject.C:43
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
bool headerOk()
Read and check header info. Does not check the headerClassName.
Definition: regIOobject.C:505
refPtr< fileOperation > fileHandler(std::nullptr_t)
Delete current file handler - forwards to fileOperation::handler()
virtual fileName filePath() const
Return complete path + object name if the file exists.
Definition: regIOobject.C:499
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:409
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
A class for handling words, derived from Foam::string.
Definition: word.H:63
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:405
bool local
Definition: EEqn.H:20
errorManip< error > abort(error &err)
Definition: errorManip.H:139
bool checkOut()
Remove all file watches and remove object from registry.
Definition: regIOobject.C:221
int debug
Static debugging option.
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
defineTypeNameAndDebug(combustionModel, 0)
static fileCheckTypes fileModificationChecking
Type of file modification checking.
Definition: IOobject.H:343
virtual void addWatch()
Add file watch on object (if registered and READ_IF_MODIFIED)
Definition: regIOobject.C:277
virtual void rename(const word &newName)
Rename.
Definition: regIOobject.C:484
labelList f(nPoints)
void push_back(const T &val)
Copy append an element to the end of this list.
Definition: DynamicListI.H:555
static void broadcasts(const label comm, Type &arg1, Args &&... args)
Broadcast multiple items to all communicator ranks. Does nothing in non-parallel. ...
static bool masterOnlyReading
To flag master-only reading of objects.
Definition: regIOobject.H:84
#define WarningInFunction
Report a warning using Foam::Warning.
void operator=(const regIOobject &)=delete
No copy assignment.
const dimensionedScalar c
Speed of light in a vacuum.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1082
regIOobject is an abstract class derived from IOobject to handle automatic object registration with t...
Definition: regIOobject.H:66
constexpr label labelMax
Definition: label.H:55
bool registerObject() const noexcept
Should objects created with this IOobject be registered?
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:437
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
bool checkIn()
Add object to registry, if not already registered.
Definition: regIOobject.C:184
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.
virtual ~regIOobject()
Destructor.
Definition: regIOobject.C:142