externalFileCoupler.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) 2015-2020 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "externalFileCoupler.H"
29 #include "Pstream.H"
30 #include "PstreamReduceOps.H"
31 #include "OSspecific.H"
32 #include "Switch.H"
33 #include <fstream>
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
39  defineTypeNameAndDebug(externalFileCoupler, 0);
40 }
41 
43 
44 
45 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
46 
47 namespace Foam
48 {
49 
50 // Read file contents and return a stop control as follows:
51 // - contains "done" (should actually be status=done, but we are generous) :
52 // The master (OpenFOAM) has signalled that it is done. Report as <endTime>
53 //
54 // - action=writeNow, action=nextWrite action=noWriteNow :
55 // The slave has signalled that it is done and wants the master to exit with
56 // the specified type of action. Report as corresponding <action>.
57 //
58 // Anything else (empty file, no action=, etc) is reported as <unknown>.
59 //
60 static enum Time::stopAtControls getStopAction(const std::string& filename)
61 {
62  // Slurp entire input file (must exist) as a single string
63  std::string fileContent;
64 
65  std::ifstream is(filename);
66  std::getline(is, fileContent, '\0');
67 
68  if (fileContent.find("done") != std::string::npos)
69  {
70  return Time::stopAtControls::saEndTime;
71  }
72 
73  const auto equals = fileContent.find('=');
74 
75  if (equals != std::string::npos)
76  {
77  const word actionName(word::validate(fileContent.substr(equals+1)));
78 
79  return
81  (
82  actionName,
83  Time::stopAtControls::saUnknown
84  );
85  }
86 
87  return Time::stopAtControls::saUnknown;
88 }
89 
90 } // End namespace Foam
91 
92 
93 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
94 
96 :
97  runState_(NONE),
98  commsDir_("<case>/comms"),
99  statusDone_("done"),
100  waitInterval_(1u),
101  timeOut_(100u),
102  slaveFirst_(false),
103  log(false)
104 {
105  commsDir_.expand();
106  commsDir_.clean(); // Remove unneeded ".."
107 }
108 
109 
111 :
112  runState_(NONE),
113  commsDir_(commsDir),
114  statusDone_("done"),
115  waitInterval_(1u),
116  timeOut_(100u),
117  slaveFirst_(false),
118  log(false)
119 {
120  commsDir_.expand();
121  commsDir_.clean(); // Remove unneeded ".."
122 
123  if (Pstream::master())
124  {
125  mkDir(commsDir_);
126  }
127 }
128 
129 
131 :
133 {
134  readDict(dict);
135 
136  if (Pstream::master())
137  {
138  mkDir(commsDir_);
139  }
140 }
141 
142 
143 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
144 
146 {
147  shutdown();
148 }
149 
150 
151 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
152 
154 {
155  // Normally cannot change directory or initialization
156  // if things have already been initialized
157  if (!initialized())
158  {
159  dict.readEntry("commsDir", commsDir_);
160  commsDir_.expand();
161  commsDir_.clean(); // Remove unneeded ".."
162  statusDone_ = dict.getOrDefault<word>("statusDone", "done");
163  slaveFirst_ = dict.getOrDefault("initByExternal", false);
164 
165  Info<< type() << ": initialize" << nl
166  << " directory: " << commsDir_ << nl
167  << " slave-first: " << Switch(slaveFirst_) << endl;
168  }
169 
170  waitInterval_ = dict.getOrDefault("waitInterval", 1u);
171  if (!waitInterval_)
172  {
173  // Enforce non-zero sleep
174  waitInterval_ = 1u;
175  }
176 
177  timeOut_ = dict.getOrDefault("timeOut", 100*waitInterval_);
178 
179  log = dict.getOrDefault("log", false);
180 
181  return true;
182 }
183 
184 
187 {
188  const bool wasInit = initialized();
189  runState_ = MASTER;
190 
191  if (Pstream::master())
192  {
193  if (!wasInit)
194  {
195  // First time
196  mkDir(commsDir_);
197  }
198 
199  const fileName lck(lockFile());
200 
201  // Create lock file - only if it doesn't already exist
202  if (!Foam::isFile(lck))
203  {
204  Log << type()
205  << ": creating lock file with status=openfoam" << endl;
206 
207  std::ofstream os(lck);
208  os << "status=openfoam\n";
209  }
210  }
211 
212  if (wait)
213  {
214  return waitForMaster();
215  }
216 
217  return Time::stopAtControls::saUnknown;
218 }
219 
220 
223 {
224  const bool wasInit = initialized();
225  runState_ = SLAVE;
226 
227  if (Pstream::master())
228  {
229  if (!wasInit)
230  {
231  // First time
232  mkDir(commsDir_);
233  }
234 
235  Log << type() << ": removing lock file" << endl;
236 
237  Foam::rm(lockFile());
238  }
239 
240  if (wait)
241  {
242  return waitForSlave();
243  }
244 
245  return Time::stopAtControls::saUnknown;
246 }
247 
248 
251 {
252  if (!initialized())
253  {
254  useMaster(); // was not initialized
255  }
256 
257  auto action = Time::stopAtControls::saUnknown;
258 
259  if (Pstream::master())
260  {
261  const fileName lck(lockFile());
262 
263  double prevTime = 0;
264  double modTime = 0;
265 
266  // Wait until file disappears (modTime == 0)
267  // But also check for status=done content in the file
268  while ((modTime = highResLastModified(lck)) > 0)
269  {
270  if (prevTime < modTime)
271  {
272  prevTime = modTime;
273 
274  if (Time::stopAtControls::saEndTime == getStopAction(lck))
275  {
276  // Found 'done' - slave should not wait for master
277  action = Time::stopAtControls::saEndTime;
278  break;
279  }
280  }
281  sleep(waitInterval_);
282  }
283  }
284 
285  label intAction(action);
286 
287  Pstream::scatter(intAction); // Also acts as MPI barrier
288 
289  return Time::stopAtControls(intAction);
290 }
291 
292 
295 {
296  if (!initialized())
297  {
298  useSlave(); // was not initialized
299  }
300 
301  auto action = Time::stopAtControls::saUnknown;
302 
303  if (Pstream::master())
304  {
305  const fileName lck(lockFile());
306  unsigned totalTime = 0;
307 
308  Log << type() << ": waiting for lock file to appear " << lck << endl;
309 
310  while (!Foam::isFile(lck))
311  {
312  sleep(waitInterval_);
313 
314  if (timeOut_ && (totalTime += waitInterval_) > timeOut_)
315  {
317  << "Wait time exceeded timeout of " << timeOut_
318  << " s" << abort(FatalError);
319  }
320 
321  Log << type() << ": wait time = " << totalTime << endl;
322  }
323 
324  action = getStopAction(lck);
325 
326  Log << type() << ": found lock file " << lck << endl;
327  }
328 
329  label intAction(action);
330 
331  Pstream::scatter(intAction); // Also acts as MPI barrier
332 
333  return Time::stopAtControls(intAction);
334 }
335 
336 
338 {}
339 
340 
342 {}
343 
344 
346 {}
347 
348 
350 {}
351 
352 
354 {}
355 
356 
358 {}
359 
360 
362 {
363  if (Pstream::master() && runState_ == MASTER && Foam::isDir(commsDir_))
364  {
365  Log << type() << ": lock file status=" << statusDone_ << endl;
366 
367  std::ofstream os(lockFile());
368  os << "status=" << statusDone_ << nl;
369  }
370 
371  runState_ = DONE; // Avoid re-triggering in destructor
372 }
373 
374 
375 // ************************************************************************* //
Foam::externalFileCoupler::writeDataSlave
virtual void writeDataSlave() const
Write data files from slave (external program)
Definition: externalFileCoupler.C:349
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::Switch
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:77
Log
#define Log
Definition: PDRblock.C:35
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
Foam::externalFileCoupler::removeDataMaster
virtual void removeDataMaster() const
Remove data files written by master (OpenFOAM)
Definition: externalFileCoupler.C:353
Foam::fileName
A class for handling file names.
Definition: fileName.H:73
Foam::externalFileCoupler::writeDataMaster
virtual void writeDataMaster() const
Write data files from master (OpenFOAM)
Definition: externalFileCoupler.C:345
Foam::externalFileCoupler::useMaster
enum Time::stopAtControls useMaster(const bool wait=false) const
Create lock file to indicate that OpenFOAM is in charge.
Definition: externalFileCoupler.C:186
Foam::word::validate
static word validate(const std::string &s, const bool prefix=false)
Construct validated word (no invalid characters).
Definition: word.C:45
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:150
Foam::isFile
bool isFile(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist as a FILE in the file system?
Definition: MSwindows.C:658
Foam::rm
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: MSwindows.C:1004
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::externalFileCoupler::waitForMaster
enum Time::stopAtControls waitForMaster() const
Wait for master to complete.
Definition: externalFileCoupler.C:250
Foam::externalFileCoupler::readDataMaster
virtual void readDataMaster()
Read data files on master (OpenFOAM).
Definition: externalFileCoupler.C:337
Foam::Time::stopAtControlNames
static const Enum< stopAtControls > stopAtControlNames
Names for stopAtControls.
Definition: Time.H:119
Foam::getStopAction
static enum Time::stopAtControls getStopAction(const std::string &filename)
Definition: abort.C:68
Foam::externalFileCoupler::removeDataSlave
virtual void removeDataSlave() const
Remove data files written by slave (external program)
Definition: externalFileCoupler.C:357
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::externalFileCoupler::~externalFileCoupler
virtual ~externalFileCoupler()
Destructor.
Definition: externalFileCoupler.C:145
externalFileCoupler.H
Foam::externalFileCoupler::readDataSlave
virtual void readDataSlave()
Read data files on slave (external program).
Definition: externalFileCoupler.C:341
Switch.H
Foam::dictionary::readEntry
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
Definition: dictionaryTemplates.C:302
Foam::highResLastModified
double highResLastModified(const fileName &, const bool followLink=true)
Return time of last file modification.
Definition: MSwindows.C:699
Foam::Enum::lookup
EnumType lookup(const word &enumName, const EnumType deflt) const
The enumeration corresponding to the given name.
Definition: Enum.C:92
Foam::externalFileCoupler::lockName
static word lockName
Name of the lock file.
Definition: externalFileCoupler.H:166
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::log
dimensionedScalar log(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:262
os
OBJstream os(runTime.globalPath()/outputName)
Pstream.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
PstreamReduceOps.H
Inter-processor communication reduction functions.
Foam::externalFileCoupler::useSlave
enum Time::stopAtControls useSlave(const bool wait=false) const
Remove lock file to indicate that the external program is in charge.
Definition: externalFileCoupler.C:222
Foam::externalFileCoupler
Encapsulates the logic for coordinating between OpenFOAM and an external application.
Definition: externalFileCoupler.H:107
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::type
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:590
Foam::string::expand
string & expand(const bool allowEmpty=false)
Definition: string.C:173
Foam::externalFileCoupler::waitForSlave
enum Time::stopAtControls waitForSlave() const
Wait for slave to complete.
Definition: externalFileCoupler.C:294
Foam::externalFileCoupler::shutdown
void shutdown() const
Generate status=done in lock (only when run-state = master)
Definition: externalFileCoupler.C:361
Foam::fileName::clean
static bool clean(std::string &str)
Definition: fileName.C:199
Foam::externalFileCoupler::readDict
bool readDict(const dictionary &dict)
Read communication settings from dictionary.
Definition: externalFileCoupler.C:153
Foam::Time::stopAtControls
stopAtControls
Definition: Time.H:97
Foam::externalFileCoupler::externalFileCoupler
externalFileCoupler()
Construct using standard defaults.
Definition: externalFileCoupler.C:95
Foam::dictionary::getOrDefault
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
Definition: dictionaryTemplates.C:148
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::sleep
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1106
Foam::isDir
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:643