argList.C 38.4 KB
Newer Older
1
2
3
4
/*---------------------------------------------------------------------------*\
  =========                 |
  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
   \\    /   O peration     |
5
    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
6
     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
7
8
9
10
-------------------------------------------------------------------------------
License
    This file is part of OpenFOAM.

11
12
13
14
    OpenFOAM is free software: you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
15
16
17
18
19
20
21

    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    for more details.

    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
26
27
28
29
30
31
32
33

\*---------------------------------------------------------------------------*/

#include "argList.H"
#include "OSspecific.H"
#include "clock.H"
#include "IFstream.H"
#include "dictionary.H"
#include "IOobject.H"
#include "JobInfo.H"
#include "labelList.H"
mattijs's avatar
mattijs committed
34
#include "regIOobject.H"
35
#include "dynamicCode.H"
36
37
38
39
#include "sigFpe.H"
#include "sigInt.H"
#include "sigQuit.H"
#include "sigSegv.H"
40
#include "foamVersion.H"
41
42
#include "uncollatedFileOperation.H"
#include "masterUncollatedFileOperation.H"
43

44
#include <cctype>
45

46
47
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //

48
bool Foam::argList::bannerEnabled_ = true;
49
bool Foam::argList::checkProcessorDirectories_ = true;
Mark Olesen's avatar
Mark Olesen committed
50
51
52
Foam::SLList<Foam::string>    Foam::argList::validArgs;
Foam::HashTable<Foam::string> Foam::argList::validOptions;
Foam::HashTable<Foam::string> Foam::argList::validParOptions;
Mark Olesen's avatar
Mark Olesen committed
53
Foam::HashTable<Foam::string> Foam::argList::optionUsage;
54
Foam::SLList<Foam::string>    Foam::argList::notes;
55
Foam::string::size_type Foam::argList::usageMin = 20;
56
Foam::string::size_type Foam::argList::usageMax = 80;
57
Foam::word Foam::argList::postProcessOptionName("postProcess");
58
59
60

Foam::argList::initValidTables::initValidTables()
{
Mark Olesen's avatar
Mark Olesen committed
61
62
    argList::addOption
    (
63
        "case", "dir",
Mark Olesen's avatar
Mark Olesen committed
64
65
66
        "specify alternate case directory, default is the cwd"
    );
    argList::addBoolOption("parallel", "run in parallel");
Mark Olesen's avatar
Mark Olesen committed
67
    validParOptions.set("parallel", "");
68
69
    argList::addOption
    (
70
        "roots", "(dir1 .. dirN)",
71
72
        "slave root directories for distributed running"
    );
73
    validParOptions.set("roots", "(dir1 .. dirN)");
74

75
76
77
78
79
80
81
82
83
84
85
    argList::addOption
    (
        "decomposeParDict", "file",
        "read decomposePar dictionary from specified location"
    );
    validParOptions.set
    (
        "decomposeParDict",
        "file"
    );

86
87
88
89
90
91
    argList::addBoolOption
    (
        "noFunctionObjects",
        "do not execute functionObjects"
    );

92
93
94
95
96
97
98
    argList::addOption
    (
        "fileHandler",
        "handler",
        "override the fileHandler"
     );

99
100
101
102
103
104
    Pstream::addValidParOptions(validParOptions);
}


Foam::argList::initValidTables dummyInitValidTables;

105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //

namespace Foam
{

// Counted per machine name
// Does not include any sorting since we wish to know the ordering according to
// mpi rank.
//
// Always include the master too.
// This provides a better overview of the subscription
static void printHostsSubscription(const UList<string>& slaveProcs)
{
    Info<< "Hosts  :" << nl << "(" << nl;

    std::string prev = hostName();
    int count = 1;

    for (const auto& str : slaveProcs)
    {
Mark OLESEN's avatar
Mark OLESEN committed
125
        std::string curr(str.substr(0, str.rfind('.')));
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150

        if (prev != curr)
        {
            if (count)
            {
                // Finish previous
                Info<<"    (" << prev.c_str() << " " << count << ")" << nl;
                count = 0;
            }

            prev = std::move(curr);
        }
        ++count;
    }

    if (count)
    {
        // Finished last one
        Info<<"    (" << prev.c_str() << " " << count << ")" << nl;
    }

    Info<< ")" << nl;
}

}
151

Mark Olesen's avatar
Mark Olesen committed
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //

void Foam::argList::addBoolOption
(
    const word& opt,
    const string& usage
)
{
    addOption(opt, "", usage);
}


void Foam::argList::addOption
(
    const word& opt,
    const string& param,
    const string& usage
)
{
    validOptions.set(opt, param);
    if (!usage.empty())
    {
        optionUsage.set(opt, usage);
    }
}


void Foam::argList::addUsage
(
    const word& opt,
    const string& usage
)
{
    if (usage.empty())
    {
        optionUsage.erase(opt);
    }
    else
    {
        optionUsage.set(opt, usage);
    }
}


196
197
198
199
200
201
202
203
204
void Foam::argList::addNote(const string& note)
{
    if (!note.empty())
    {
        notes.append(note);
    }
}


Mark Olesen's avatar
Mark Olesen committed
205
206
207
208
209
210
211
212
213
void Foam::argList::removeOption(const word& opt)
{
    validOptions.erase(opt);
    optionUsage.erase(opt);
}


void Foam::argList::noBanner()
{
214
215
216
217
218
219
220
    bannerEnabled_ = false;
}


bool Foam::argList::bannerEnabled()
{
    return bannerEnabled_;
Mark Olesen's avatar
Mark Olesen committed
221
222
223
}


224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
void Foam::argList::noFunctionObjects(bool addWithOption)
{
    removeOption("noFunctionObjects");

    if (addWithOption)
    {
        addBoolOption
        (
            "withFunctionObjects",
            "execute functionObjects"
        );
    }
}


239
240
241
242
243
244
void Foam::argList::noJobInfo()
{
    JobInfo::writeJobInfo = false;
}


Mark Olesen's avatar
Mark Olesen committed
245
246
void Foam::argList::noParallel()
{
247
248
    removeOption("parallel");
    removeOption("roots");
249
    removeOption("decomposeParDict");
Mark Olesen's avatar
Mark Olesen committed
250
251
252
253
    validParOptions.clear();
}


254
255
256
257
258
259
void Foam::argList::noCheckProcessorDirectories()
{
    checkProcessorDirectories_ = false;
}


Mark Olesen's avatar
Mark Olesen committed
260
261
262
263
264
265
void Foam::argList::printOptionUsage
(
    const label location,
    const string& str
)
{
266
267
268
269
    const string::size_type textWidth = usageMax - usageMin;
    const string::size_type strLen = str.size();

    if (strLen)
Mark Olesen's avatar
Mark Olesen committed
270
    {
271
        // Minimum of 2 spaces between option and usage:
272
        if (string::size_type(location) + 2 <= usageMin)
Mark Olesen's avatar
Mark Olesen committed
273
        {
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
            for (string::size_type i = location; i < usageMin; ++i)
            {
                Info<<' ';
            }
        }
        else
        {
            // or start a new line
            Info<< nl;
            for (string::size_type i = 0; i < usageMin; ++i)
            {
                Info<<' ';
            }
        }

289
        // Text wrap
290
        string::size_type pos = 0;
291
        while (pos != string::npos && pos + textWidth < strLen)
292
        {
293
            // Potential end point and next point
294
            string::size_type curr = pos + textWidth - 1;
295
296
            string::size_type next = string::npos;

297
            if (isspace(str[curr]))
298
            {
299
                // We were lucky: ended on a space
300
301
302
303
                next = str.find_first_not_of(" \t\n", curr);
            }
            else if (isspace(str[curr+1]))
            {
304
                // The next one is a space - so we are okay
305
306
                curr++;  // otherwise the length is wrong
                next = str.find_first_not_of(" \t\n", curr);
307
308
309
            }
            else
            {
310
                // Search for end of a previous word break
311
                string::size_type prev = str.find_last_of(" \t\n", curr);
312

313
                // Reposition to the end of previous word if possible
314
                if (prev != string::npos && prev > pos)
315
                {
316
                    curr = prev;
317
318
319
                }
            }

320
321
322
323
324
            if (next == string::npos)
            {
                next = curr + 1;
            }

325
            // Indent following lines (not the first one)
326
            if (pos)
327
            {
328
                for (string::size_type i = 0; i < usageMin; ++i)
329
                {
330
                    Info<<' ';
331
332
                }
            }
333
334
335

            Info<< str.substr(pos, (curr - pos)).c_str() << nl;
            pos = next;
336
337
        }

338
        // Output the remainder of the string
339
340
        if (pos != string::npos)
        {
341
            // Indent following lines (not the first one)
342
343
344
345
346
347
348
349
350
            if (pos)
            {
                for (string::size_type i = 0; i < usageMin; ++i)
                {
                    Info<<' ';
                }
            }

            Info<< str.substr(pos).c_str() << nl;
Mark Olesen's avatar
Mark Olesen committed
351
352
        }
    }
353
354
355
356
    else
    {
        Info<< nl;
    }
Mark Olesen's avatar
Mark Olesen committed
357
358
359
}


360
361
362
363
364
365
366
367
368
369
370
371
372
373
bool Foam::argList::postProcess(int argc, char *argv[])
{
    bool postProcessOption = false;

    for (int i=1; i<argc; i++)
    {
        postProcessOption = argv[i] == '-' + postProcessOptionName;
        if (postProcessOption) break;
    }

    return postProcessOption;
}


Mark Olesen's avatar
Mark Olesen committed
374
375
// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //

376
377
bool Foam::argList::regroupArgv(int& argc, char**& argv)
{
378
379
    int nArgs = 1;
    unsigned listDepth = 0;
380
381
    string tmpString;

382
    // Note: we rewrite directly into args_
383
    // and use a second pass to sort out args/options
384
385
386

    args_[0] = fileName(argv[0]);
    for (int argI = 1; argI < argc; ++argI)
387
    {
388
        if (strcmp(argv[argI], "(") == 0)
389
        {
Mark Olesen's avatar
Mark Olesen committed
390
            ++listDepth;
391
392
            tmpString += "(";
        }
393
        else if (strcmp(argv[argI], ")") == 0)
394
        {
Mark Olesen's avatar
Mark Olesen committed
395
            if (listDepth)
396
            {
Mark Olesen's avatar
Mark Olesen committed
397
                --listDepth;
398
                tmpString += ")";
399
                if (!listDepth)
400
401
402
403
404
405
406
                {
                    args_[nArgs++] = tmpString;
                    tmpString.clear();
                }
            }
            else
            {
407
                args_[nArgs++] = argv[argI];
408
409
            }
        }
Mark Olesen's avatar
Mark Olesen committed
410
        else if (listDepth)
411
        {
412
            // Quote each string element
413
            tmpString += "\"";
414
            tmpString += argv[argI];
415
416
417
418
            tmpString += "\"";
        }
        else
        {
419
            args_[nArgs++] = argv[argI];
420
421
422
423
424
        }
    }

    if (tmpString.size())
    {
425
        // Group(s) not closed, but flush anything still pending
426
427
428
429
430
        args_[nArgs++] = tmpString;
    }

    args_.setSize(nArgs);

431
432
433
434
435
436
437
438
439
    std::string::size_type len = (nArgs-1); // Spaces between args
    forAll(args_, argi)
    {
        len += args_[argi].size();
    }

    // Length needed for regrouped command-line
    argListStr_.reserve(len);

440
441
442
443
444
445
446
447
448
    return nArgs < argc;
}


void Foam::argList::getRootCase()
{
    fileName casePath;

    // [-case dir] specified
449
    auto optIter = options_.cfind("case");
450

451
    if (optIter.found())
452
    {
453
        casePath = optIter.object();
454
        casePath.clean();
Mark Olesen's avatar
Mark Olesen committed
455
456
457

        if (casePath.empty() || casePath == ".")
        {
458
            // Handle degenerate form and '-case .' like no -case specified
Mark Olesen's avatar
Mark Olesen committed
459
460
461
            casePath = cwd();
            options_.erase("case");
        }
462
        else if (!casePath.isAbsolute() && casePath.name() == "..")
463
        {
464
            // Avoid relative cases ending in '..' - makes for very ugly names
465
466
467
            casePath = cwd()/casePath;
            casePath.clean();
        }
468
469
470
    }
    else
    {
471
        // Nothing specified, use the current dir
472
473
474
475
476
477
        casePath = cwd();
    }

    rootPath_   = casePath.path();
    globalCase_ = casePath.name();
    case_       = globalCase_;
Mark Olesen's avatar
Mark Olesen committed
478

479
480
    // The name of the executable, unless already present in the environment
    setEnv("FOAM_EXECUTABLE", executable_, false);
Mark Olesen's avatar
Mark Olesen committed
481
482

    // Set the case and case-name as an environment variable
483
    if (rootPath_.isAbsolute())
Mark Olesen's avatar
Mark Olesen committed
484
    {
485
        // Absolute path - use as-is
Mark Olesen's avatar
Mark Olesen committed
486
487
488
489
490
        setEnv("FOAM_CASE", rootPath_/globalCase_, true);
        setEnv("FOAM_CASENAME", globalCase_, true);
    }
    else
    {
491
        // Qualify relative path
492
        casePath = cwd()/rootPath_/globalCase_;
Mark Olesen's avatar
Mark Olesen committed
493
494
495
496
497
        casePath.clean();

        setEnv("FOAM_CASE", casePath, true);
        setEnv("FOAM_CASENAME", casePath.name(), true);
    }
498
499
500
501
502
503
504
505
506
507
}


// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //

Foam::argList::argList
(
    int& argc,
    char**& argv,
    bool checkArgs,
andy's avatar
andy committed
508
509
    bool checkOpts,
    const bool initialise
510
511
512
)
:
    args_(argc),
513
514
    options_(argc),
    distributed_(false)
515
516
{
    // Check if this run is a parallel run by searching for any parallel option
Mark Olesen's avatar
Mark Olesen committed
517
    // If found call runPar which might filter argv
518
    for (int argI = 1; argI < argc; ++argI)
519
    {
520
        if (argv[argI][0] == '-')
521
        {
522
            const char *optionName = &argv[argI][1];
523
524
525
526
527
528
529
530
531

            if (validParOptions.found(optionName))
            {
                parRunControl_.runPar(argc, argv);
                break;
            }
        }
    }

532
    // Convert argv -> args_ and capture ( ... ) lists
533
    regroupArgv(argc, argv);
534
    argListStr_ += args_[0];
535

536
    // Check arguments and options, argv[0] was already handled
537
    int nArgs = 1;
538
    HashTable<string>::const_iterator optIter;
539
    for (int argI = 1; argI < args_.size(); ++argI)
540
    {
andy's avatar
andy committed
541
542
        argListStr_ += ' ';
        argListStr_ += args_[argI];
543

544
        if (args_[argI][0] == '-')
545
        {
546
            const char *optionName = &args_[argI][1];
547

548
549
550
551
552
553
            if (!*optionName)
            {
                Warning
                    <<"Ignoring lone '-' on the command-line" << endl;
            }
            else if
554
555
            (
                (
556
557
                    (optIter = validOptions.cfind(optionName)).found()
                 && !optIter.object().empty()
558
559
                )
             || (
560
561
                    (optIter = validParOptions.cfind(optionName)).found()
                 && !optIter.object().empty()
562
563
564
                )
            )
            {
565
566
567
                // If the option is known to require an argument,
                // get it or emit a FatalError.

Mark Olesen's avatar
Mark Olesen committed
568
                ++argI;
569
                if (argI >= args_.size())
570
571
                {
                    FatalError
Mark Olesen's avatar
Mark Olesen committed
572
573
574
575
                        <<"Option '-" << optionName
                        << "' requires an argument" << endl;
                    printUsage();
                    FatalError.exit();
576
577
                }

andy's avatar
andy committed
578
579
                argListStr_ += ' ';
                argListStr_ += args_[argI];
580
581
                // Handle duplicates by taking the last -option specified
                options_.set(optionName, args_[argI]);
582
583
584
            }
            else
            {
585
586
587
                // All other options (including unknown ones) are simply
                // registered as existing.

588
589
590
591
592
                options_.insert(optionName, "");
            }
        }
        else
        {
593
            if (nArgs != argI)
594
            {
595
                args_[nArgs] = args_[argI];
596
            }
Mark Olesen's avatar
Mark Olesen committed
597
            ++nArgs;
598
599
600
601
602
        }
    }

    args_.setSize(nArgs);

603
604
605
    // Set executable name
    executable_ = fileName(args_[0]).name();

andy's avatar
andy committed
606
607
608
609
610
611
612
613
614
615
616
617
618
    parse(checkArgs, checkOpts, initialise);
}


Foam::argList::argList
(
    const argList& args,
    const HashTable<string>& options,
    bool checkArgs,
    bool checkOpts,
    bool initialise
)
:
619
    parRunControl_(args.parRunControl_),
andy's avatar
andy committed
620
621
622
623
624
625
    args_(args.args_),
    options_(options),
    executable_(args.executable_),
    rootPath_(args.rootPath_),
    globalCase_(args.globalCase_),
    case_(args.case_),
626
    argListStr_(args.argListStr_)
andy's avatar
andy committed
627
628
629
630
631
632
633
634
635
636
637
638
{
    parse(checkArgs, checkOpts, initialise);
}


void Foam::argList::parse
(
    bool checkArgs,
    bool checkOpts,
    bool initialise
)
{
639
640
641
642
    // Help/documentation options:
    //   -help    print the usage
    //   -doc     display application documentation in browser
    //   -srcDoc  display source code in browser
643
    {
644
645
        bool quickExit = false;

646
647
648
        if (options_.found("help"))
        {
            printUsage();
649
            quickExit = true;
650
651
        }

652
        // Only display one or the other
653
654
655
        if (options_.found("srcDoc"))
        {
            displayDoc(true);
656
            quickExit = true;
657
658
        }
        else if (options_.found("doc"))
659
        {
660
            displayDoc(false);
661
            quickExit = true;
662
663
        }

664
665
666
667
        if (quickExit)
        {
            ::exit(0);
        }
668
669
670
671
672
673
674
675
676
    }

    // Print the usage message and exit if the number of arguments is incorrect
    if (!check(checkArgs, checkOpts))
    {
        FatalError.exit();
    }


andy's avatar
andy committed
677
    if (initialise)
678
    {
679
680
        const string dateString = clock::date();
        const string timeString = clock::clockTime();
681

andy's avatar
andy committed
682
        // Print the banner once only for parallel runs
683
        if (Pstream::master() && bannerEnabled_)
684
        {
andy's avatar
andy committed
685
686
            IOobject::writeBanner(Info, true)
                << "Build  : " << Foam::FOAMbuild << nl
687
                << "Arch   : " << Foam::FOAMbuildArch << nl
andy's avatar
andy committed
688
689
690
691
692
                << "Exec   : " << argListStr_.c_str() << nl
                << "Date   : " << dateString.c_str() << nl
                << "Time   : " << timeString.c_str() << nl
                << "Host   : " << hostName() << nl
                << "PID    : " << pid() << endl;
693
694
        }

andy's avatar
andy committed
695
696
697
        jobInfo.add("startDate", dateString);
        jobInfo.add("startTime", timeString);
        jobInfo.add("userName", userName());
698
        jobInfo.add("foamVersion", word(Foam::FOAMversion));
andy's avatar
andy committed
699
700
701
702
703
704
        jobInfo.add("code", executable_);
        jobInfo.add("argList", argListStr_);
        jobInfo.add("currentDir", cwd());
        jobInfo.add("PPID", ppid());
        jobInfo.add("PGID", pgid());

705
        // Add build information - only use the first word
andy's avatar
andy committed
706
707
        {
            std::string build(Foam::FOAMbuild);
708
709
            std::string::size_type space = build.find(' ');
            if (space != std::string::npos)
andy's avatar
andy committed
710
            {
711
                build.resize(space);
andy's avatar
andy committed
712
713
714
715
            }
            jobInfo.add("foamBuild", build);
        }
    }
716

717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747

    // Set fileHandler. In increasing order of priority:
    // 1. default = uncollated
    // 2. environment var FOAM_FILEHANDLER
    // 3. etc/controlDict optimisationSwitches 'fileHandler'
    // 4. system/controlDict 'fileHandler' (not handled here; done in TimeIO.C)

    {
        word handlerType(getEnv("FOAM_FILEHANDLER"));
        HashTable<string>::const_iterator iter = options_.find("fileHandler");
        if (iter != options_.end())
        {
            handlerType = iter();
        }

        if (handlerType.empty())
        {
            handlerType = fileOperation::defaultFileHandler;
        }

        autoPtr<fileOperation> handler
        (
            fileOperation::New
            (
                handlerType,
                bannerEnabled_
            )
        );
        Foam::fileHandler(handler);
    }

748
749
750
    // Case is a single processor run unless it is running parallel
    int nProcs = 1;

751
752
753
    // Roots if running distributed
    fileNameList roots;

754
755
756
757
758
759
    // If this actually is a parallel run
    if (parRunControl_.parRun())
    {
        // For the master
        if (Pstream::master())
        {
760
            // Establish rootPath_/globalCase_/case_ for master
761
762
            getRootCase();

763
764
765
766
767
768
            // Establish location of decomposeParDict, allow override with
            // the -decomposeParDict option.
            fileName source = rootPath_/globalCase_/"system"/"decomposeParDict";
            if (options_.found("decomposeParDict"))
            {
                bool adjustOpt = false;
769

770
771
772
773
                source = options_["decomposeParDict"];
                if (isDir(source))
                {
                    source = source/"decomposeParDict";
774
                    adjustOpt = true;
775
                }
776

777
778
                // Case-relative if not absolute and not "./" etc
                if (!source.isAbsolute() && !source.startsWith("."))
779
780
781
782
783
                {
                    source = rootPath_/globalCase_/source;
                    adjustOpt = true;
                }

784
785
786
787
788
789
790
791
792
793
                // Could also check for absolute path, but shouldn't be needed
                if (adjustOpt)
                {
                    source.clean();
                    options_.set("decomposeParDict", source);
                }
            }

            // If running distributed (different roots for different procs)
            label dictNProcs = -1;
794
            if (options_.found("roots"))
795
            {
796
                distributed_ = true;
797
                source = "-roots";
798
799
800
801
802
803
804
                IStringStream is(options_["roots"]);
                roots = readList<fileName>(is);

                if (roots.size() != 1)
                {
                    dictNProcs = roots.size()+1;
                }
805
            }
806
            else if (checkProcessorDirectories_)
807
            {
808
809
                // Use values from decomposeParDict, the location was already
                // established above.
810

811
                IFstream decompDictStream(source);
812

813
814
815
                if (!decompDictStream.good())
                {
                    FatalError
816
                        << "Cannot read decomposeParDict from "
817
818
819
                        << decompDictStream.name()
                        << exit(FatalError);
                }
820

821
822
823
                dictionary decompDict(decompDictStream);

                dictNProcs = readLabel
824
                (
Mark Olesen's avatar
Mark Olesen committed
825
                    decompDict.lookup("numberOfSubdomains")
826
827
                );

828
                if (decompDict.lookupOrDefault("distributed", false))
829
                {
830
                    distributed_ = true;
831
832
833
                    decompDict.lookup("roots") >> roots;
                }
            }
834

835
            // Convenience:
836
837
838
839
840
841
842
843
844
845
846
847
848
849
            // when a single root is specified, use it for all processes
            if (roots.size() == 1)
            {
                const fileName rootName(roots[0]);
                roots.setSize(Pstream::nProcs()-1, rootName);

                // adjust dictNProcs for command-line '-roots' option
                if (dictNProcs < 0)
                {
                    dictNProcs = roots.size()+1;
                }
            }


Mark Olesen's avatar
Mark Olesen committed
850
851
852
853
854
            // Check number of processors.
            // nProcs     => number of actual procs
            // dictNProcs => number of procs specified in decompositionDict
            // nProcDirs  => number of processor directories
            //               (n/a when running distributed)
855
856
            //
            // - normal running : nProcs = dictNProcs = nProcDirs
Mark Olesen's avatar
Mark Olesen committed
857
858
            // - decomposition to more  processors : nProcs = dictNProcs
            // - decomposition to fewer processors : nProcs = nProcDirs
859
            if (checkProcessorDirectories_ && dictNProcs > Pstream::nProcs())
860
861
            {
                FatalError
862
                    << source
863
864
865
866
867
868
                    << " specifies " << dictNProcs
                    << " processors but job was started with "
                    << Pstream::nProcs() << " processors."
                    << exit(FatalError);
            }

869

870
            // Distributed data
871
            if (roots.size())
872
            {
Mark Olesen's avatar
Mark Olesen committed
873
                if (roots.size() != Pstream::nProcs()-1)
874
875
                {
                    FatalError
876
877
                        << "number of entries in roots "
                        << roots.size()
Mark Olesen's avatar
Mark Olesen committed
878
879
                        << " is not equal to the number of slaves "
                        << Pstream::nProcs()-1
880
881
882
                        << exit(FatalError);
                }

883
884
885
886
887
                forAll(roots, i)
                {
                    roots[i].expand();
                }

888
                // Distribute the master's argument list (with new root)
889
                const bool hadCaseOpt = options_.found("case");
890
891
                for
                (
Mark Olesen's avatar
Mark Olesen committed
892
893
                    int slave = Pstream::firstSlave();
                    slave <= Pstream::lastSlave();
894
895
896
                    slave++
                )
                {
897
                    options_.set("case", roots[slave-1]/globalCase_);
898

899
                    OPstream toSlave(Pstream::commsTypes::scheduled, slave);
900
                    toSlave << args_ << options_ << roots.size();
901
902
903
                }
                options_.erase("case");

904
                // Restore [-case dir]
Mark Olesen's avatar
Mark Olesen committed
905
                if (hadCaseOpt)
906
                {
Mark Olesen's avatar
Mark Olesen committed
907
                    options_.set("case", rootPath_/globalCase_);
908
909
910
911
                }
            }
            else
            {
Mark Olesen's avatar
Mark Olesen committed
912
913
                // Possibly going to fewer processors.
                // Check if all procDirs are there.
914
915
916
917
918
                if
                (
                    checkProcessorDirectories_
                 && dictNProcs < Pstream::nProcs()
                )
Mark Olesen's avatar
Mark Olesen committed
919
920
921
922
                {
                    label nProcDirs = 0;
                    while
                    (
923
                        isDir
Mark Olesen's avatar
Mark Olesen committed
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
                        (
                            rootPath_/globalCase_/"processor"
                          + name(++nProcDirs)
                        )
                    )
                    {}

                    if (nProcDirs != Pstream::nProcs())
                    {
                        FatalError
                            << "number of processor directories = "
                            << nProcDirs
                            << " is not equal to the number of processors = "
                            << Pstream::nProcs()
                            << exit(FatalError);
                    }
                }

942
943
944
                // Distribute the master's argument list (unaltered)
                for
                (
Mark Olesen's avatar
Mark Olesen committed
945
946
                    int slave = Pstream::firstSlave();
                    slave <= Pstream::lastSlave();
947
948
949
                    slave++
                )
                {
950
                    OPstream toSlave(Pstream::commsTypes::scheduled, slave);
951
                    toSlave << args_ << options_ << roots.size();
952
953
954
955
956
957
                }
            }
        }
        else
        {
            // Collect the master's argument list
958
959
960
961
962
            IPstream fromMaster
            (
                Pstream::commsTypes::scheduled,
                Pstream::masterNo()
            );
963
            fromMaster >> args_ >> options_ >> distributed_;
964

965
            // Establish rootPath_/globalCase_/case_ for slave
966
967
968
969
970
971
972
973
            getRootCase();
        }

        nProcs = Pstream::nProcs();
        case_ = globalCase_/(word("processor") + name(Pstream::myProcNo()));
    }
    else
    {
974
        // Establish rootPath_/globalCase_/case_
975
976
977
978
        getRootCase();
        case_ = globalCase_;
    }

979
    stringList slaveProcs;
980
    const int writeHostsSwitch = debug::infoSwitch("writeHosts", 1);
981

982
    // Collect slave machine/pid, and check that the build is identical
983
984
985
986
987
    if (parRunControl_.parRun())
    {
        if (Pstream::master())
        {
            slaveProcs.setSize(Pstream::nProcs() - 1);
988
            label proci = 0;
989
990
            for
            (
Mark Olesen's avatar
Mark Olesen committed
991
992
                int slave = Pstream::firstSlave();
                slave <= Pstream::lastSlave();
993
994
995
                slave++
            )
            {
996
                IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
997
998
999
1000

                string slaveBuild;
                string slaveMachine;
                label slavePid;
For faster browsing, not all history is shown. View entire blame