Bug fix supplied by Niklas Nordin:
[OpenFOAM-1.5.x.git] / src / Pstream / pvm / Pstream.C
blob5138ffd43bc2797f5dfc61a469c490423287c52b
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2008 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
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.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "Pstream.H"
28 #include "PstreamReduceOps.H"
30 #include <cstring>
31 #include <cstdlib>
32 #include <csignal>
34 #include <pvm3.h>
36 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
38 namespace Foam
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 void Pstream::addValidParOptions(HashTable<string>& validParOptions)
45     validParOptions.insert("np", "");
46     validParOptions.insert("p4pg", "PI file");
47     validParOptions.insert("p4wd", "directory");
48     validParOptions.insert("p4amslave", "");
49     validParOptions.insert("p4yourname", "hostname");
53 bool Pstream::init(int& argc, char**& argv)
55     // Set the comunications options
56     pvm_setopt(PvmRoute, PvmRouteDirect);
58     // Get the ID of this processor
59     int mytid = pvm_mytid();
61 #ifdef USECRAYSHMEM
63     // Get the size of the NULL group
64     procIDs_.setSize(pvm_gsize(NULL));
66     // For each processor of the NULL group get its ID
67     for (int proci=0; proci<ProcIDs.size(); proci++)
68     {
69         procIDs_[proci] = pvm_gettid(NULL, proci);
70     }
72 #else
74     // Initialisation message type
75     int initMsgType = 0;
77     // If this is not a slave then it must be the master.
78     // Master spawns the rest of the child processes in the same manner as MPI
79     if (string(argv[argc-1]) != "-slave")
80     {
81         // Last argument is number of processors in parallel run
82         int nProcs = atoi(argv[argc-1]);
84         // If it is less than 2 this is not a parallel run!
85         if (nProcs < 2)
86         {
87             FatalErrorIn("Pstream::init(int& argc, char**& argv)")
88                 << "Attempt to run parallel on < 2 processors ... stopping."
89                 << abort(FatalError);
90         }
93         Info<< "Starting parallel run on " << nProcs << " processors ... "
94             << nl << endl;
97         // set size of ID list
98         procIDs_.setSize(nProcs);
99         procIDs_ = 0;
101         // I am the master
102         myProcNo_ = 1;
104         // Put my ID in the list
105         procIDs_[0] = mytid;
107         // Setup arguments of children
108         typedef char* charPtr;
109         char** Argv = new charPtr[argc + 1];
111         for (int i=0; i<argc-1; i++)
112         {
113             Argv[i] = new char[strlen(argv[i+1] + 1)];
114             strcpy(Argv[i], argv[i+1]);
115         }
117         Argv[argc-1] = new char[7];
118         strcpy(Argv[argc-1], "-slave");
120         Argv[argc] = NULL;
122         // Spawn children as copies of me
123         if
124         (
125             pvm_spawn
126             (
127                 argv[0],
128                 Argv,
129                 PvmTaskDefault,
130                 "",
131                 nProcs-1,
132                 &(procIDs_[1])
133             ) != nProcs-1
134         )
135         {
136             FatalErrorIn("Pstream::init(int& argc, char**& argv)")
137                 << "Unable to spawn processes ... stopping."
138                 << abort(FatalError);
139         }
142         // Broadcast task IDs to all children
143         pvm_setopt(PvmRoute, PvmRouteDirect);
144         pvm_initsend(PvmDataDefault);
145         pvm_pkint((int*)(&nProcs), 1, 1);
146         pvm_pkint(procIDs_.begin(), nProcs, 1);
147         pvm_mcast(procIDs_.begin(), nProcs, initMsgType);
150         Info<< "nProcs : " << nProcs << endl;
151         Info<< "TIDS   : ";
152         for (int proci=0; proci<procIDs_.size(); proci++)
153         {
154             cout<< hex << procIDs_[proci] << ' ';
155         }
156         cout<< dec << nl << std::endl;
157     }
158     else
159     {
160         // Receive processor data from master
161         pvm_recv(-1, initMsgType);
163         // Should have received the number of processors in the run
164         int nProcs;
165         pvm_upkint(&nProcs, 1, 1);
167         // ... set size of ID list
168         procIDs_.setSize(nProcs);
170         // ... and unpack the processor IDs
171         pvm_upkint(procIDs_.begin(), nProcs, 1);
172     }
174 #endif
176     // Find which processor number this is
177     for (int proci=0; proci<procIDs_.size(); proci++)
178     {
179         if (procIDs_[proci] == mytid)
180         {
181             break;
182         }
183     }
185     // Set the processor numbers to start from 1
186     myProcNo_ = proci + 1;
188     /*
189     if (pvm_joingroup("foam") < 0)
190     {
191         FatalErrorIn("Pstream::init(int& argc, char**& argv)")
192             << "Pstream::init(int*, char **[]) : "
193             << "could not join group ... stopping."
194             << abort(FatalError);
195     }
197     pvm_barrier("foam", nProcs());
198     */
200     // Setup signal handler to catch an interupt (^C) and abort the run
201     // This doesn't work, it causes
202     // libpvm [t40003]: pvm_sendsig(): Not implemented
203     // libpvm [t40003]: pvm_kill(): Not implemented
204     // messages
205     //signal(SIGINT, stop);
207     if (master())
208     {
209         Sout<< "Master started successfully." << nl << endl;
210     }
211     else
212     {
213         Sout<< "Child " << myProcNo_ << " started successfully." << nl << endl;
214     }
216     setParRun();
218     // Everything is OK
219     return true;
223 void Pstream::exit(int errnum)
225     //pvm_lvgroup("foam");
227     if (errnum != 0)
228     {
229         for (int proci=1; proci<=procIDs_.size(); proci++)
230         {
231             if (proci != myProcNo())
232             {
233                 pvm_kill(procID(proci));
234             }
235         }
236     }
238     pvm_exit();
239     ::exit(errnum);
243 void Pstream::abort()
245     for (int proci=1; proci<=procIDs_.size(); proci++)
246     {
247         if (proci != myProcNo())
248         {
249             pvm_kill(procID(proci));
250         }
251     }
253     pvm_exit();
254     //::abort();
258 void reduce(scalar& Value, const sumOp<scalar>& bop)
260     if (Pstream::parRun())
261     {
262 #       ifdef PVM_REDUCE
263         if
264         (
265             pvm_reduce
266             (
267                 PvmSum,
268                 &Value,
269                 1,
270                 PVM_DOUBLE,
271                 Pstream::msgType(),
272                 "foam",
273                 0
274             ) != PvmOk
275         )
276         {
277             FatalErrorIn
278             (
279                 "reduce(scalar& Value, const sumOp<scalar>& sumOp)"
280             )   << "pvm_reduce failed"
281                 << abort(FatalError);
282         }
283 #       endif
285         if (Pstream::master())
286         {
287             for
288             (
289                 int slave=Pstream::firstSlave();
290                 slave<=Pstream::lastSlave();
291                 slave++
292             )
293             {
294                 scalar value;
295                 int atid, atag, alen;
297                 if
298                 (
299                     pvm_precv
300                     (
301                         Pstream::procID(slave),
302                         Pstream::msgType(),
303                         &value,
304                         1,
305                         PVM_DOUBLE,
306                         &atid, &atag, &alen
307                     ) != PvmOk
308                 )
309                 {
310                     FatalErrorIn
311                     (
312                         "reduce(scalar& Value, const sumOp<scalar>& sumOp)"
313                     )   << "pvm_precv failed"
314                         << abort(FatalError);
315                 }
317                 Value = bop(Value, value);
318             }
319         }
320         else
321         {
322             if
323             (
324                 pvm_psend
325                 (
326                     Pstream::procID(Pstream::masterNo()),
327                     Pstream::msgType(),
328                     &Value,
329                     1,
330                     PVM_DOUBLE
331                 ) != PvmOk
332             )
333             {
334                 FatalErrorIn
335                 (
336                     "reduce(scalar& Value, const sumOp<scalar>& sumOp)"
337                 )   << "pvm_psend failed"
338                     << abort(FatalError);
339             }
340         }
343         if (Pstream::master())
344         {
345             pvm_initsend(PvmDataDefault);
346             pvm_pkdouble(&Value, 1, 1);
348             if
349             (
350                 pvm_mcast
351                 (
352                     (int*)Pstream::procIDs().begin(),
353                     Pstream::nProcs(),
354                     Pstream::msgType()
355                 ) != PvmOk
356             )
357             {
358                 FatalErrorIn
359                 (
360                     "reduce(scalar& Value, const sumOp<scalar>& sumOp)"
361                 )   << "pvm_mcast failed"
362                     << abort(FatalError);
363             }
364         }
365         else
366         {
367             if
368             (
369                 pvm_recv
370                 (
371                     Pstream::procID(Pstream::masterNo()),
372                     Pstream::msgType()
373                 ) <= 0
374             )
375             {
376                 FatalErrorIn
377                 (
378                     "reduce(scalar& Value, const sumOp<scalar>& sumOp)"
379                 )   << "pvm_psend failed"
380                     << abort(FatalError);
381             }
383             pvm_upkdouble(&Value, 1, 1);
384         }
385     }
389 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
391 } // End namespace Foam
393 // ************************************************************************* //