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-------------------------------------------------------------------------------
10License
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
37namespace Foam
38{
40}
41
43
44
45// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
46
47namespace 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//
60static 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 {
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,
84 );
85 }
86
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
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
246}
247
248
251{
252 if (!initialized())
253 {
254 useMaster(); // was not initialized
255 }
256
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
275 {
276 // Found 'done' - slave should not wait for master
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
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// ************************************************************************* //
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
#define Log
Definition: PDRblock.C:35
Inter-processor communication reduction functions.
EnumType lookup(const word &enumName, const EnumType deflt) const
The enumeration corresponding to the given name.
Definition: Enum.C:92
static void scatter(const List< commsStruct > &comms, T &value, const int tag, const label comm)
Broadcast data: Distribute without modification.
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:78
static const Enum< stopAtControls > stopAtControlNames
Names for stopAtControls.
Definition: Time.H:119
stopAtControls
Definition: Time.H:98
@ saUnknown
Dummy no-op. Do not change current value.
Definition: Time.H:103
@ saEndTime
Stop when Time reaches prescribed endTime.
Definition: Time.H:99
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
T getOrDefault(const word &keyword, const T &deflt, enum keyType::option matchOpt=keyType::REGEX) const
bool readEntry(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX, bool mandatory=true) const
Encapsulates the logic for coordinating between OpenFOAM and an external application.
enum Time::stopAtControls useSlave(const bool wait=false) const
Remove lock file to indicate that the external program is in charge.
virtual void writeDataMaster() const
Write data files from master (OpenFOAM)
virtual void removeDataSlave() const
Remove data files written by slave (external program)
enum Time::stopAtControls useMaster(const bool wait=false) const
Create lock file to indicate that OpenFOAM is in charge.
virtual ~externalFileCoupler()
Destructor.
bool readDict(const dictionary &dict)
Read communication settings from dictionary.
static word lockName
Name of the lock file.
virtual void readDataSlave()
Read data files on slave (external program).
enum Time::stopAtControls waitForMaster() const
Wait for master to complete.
virtual void writeDataSlave() const
Write data files from slave (external program)
virtual void readDataMaster()
Read data files on master (OpenFOAM).
virtual void removeDataMaster() const
Remove data files written by master (OpenFOAM)
enum Time::stopAtControls waitForSlave() const
Wait for slave to complete.
void shutdown() const
Generate status=done in lock (only when run-state = master)
externalFileCoupler()
Construct using standard defaults.
A class for handling file names.
Definition: fileName.H:76
static bool clean(std::string &str)
Definition: fileName.C:199
virtual void validate()
Validate the turbulence fields after construction.
Definition: kkLOmega.C:597
splitCell * master() const
Definition: splitCell.H:113
string & expand(const bool allowEmpty=false)
Definition: string.C:173
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
OBJstream os(runTime.globalPath()/outputName)
Namespace for OpenFOAM.
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: MSwindows.C:1012
static enum Time::stopAtControls getStopAction(const std::string &filename)
Definition: abort.C:68
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:515
messageStream Info
Information stream (stdout output on master, null elsewhere)
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1114
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
dimensionedScalar log(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
errorManip< error > abort(error &err)
Definition: errorManip.H:144
double highResLastModified(const fileName &, const bool followLink=true)
Return time of last file modification.
Definition: MSwindows.C:707
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:666
error FatalError
bool isDir(const fileName &name, const bool followLink=true)
Does the name exist as a DIRECTORY in the file system?
Definition: MSwindows.C:651
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
dictionary dict