start.hh 21.5 KB
Newer Older
1
2
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
3
/*****************************************************************************
4
 *   See the file COPYING for full copying permissions.                      *
5
 *                                                                           *
6
 *   This program is free software: you can redistribute it and/or modify    *
7
 *   it under the terms of the GNU General Public License as published by    *
8
9
 *   the Free Software Foundation, either version 2 of the License, or       *
 *   (at your option) any later version.                                     *
10
 *                                                                           *
11
12
 *   This program is distributed in the hope that it will be useful,         *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
14
15
16
17
 *   GNU General Public License for more details.                            *
 *                                                                           *
 *   You should have received a copy of the GNU General Public License       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
18
19
20
 *****************************************************************************/
/*!
 * \file
21
 * \brief Provides a few default main functions for convenience.
22
23
24
25
 */
#ifndef DUMUX_START_HH
#define DUMUX_START_HH

26
#include <ctime>
27
#include <iostream>
28
29

#include <dune/common/parametertreeparser.hh>
30
#include <dune/common/parallel/mpihelper.hh>
31

Christoph Grueninger's avatar
Christoph Grueninger committed
32
#include <dune/grid/io/file/dgfparser.hh>
Bernd Flemisch's avatar
Bernd Flemisch committed
33
#if HAVE_DUNE_ALUGRID
34
35
#include <dune/alugrid/dgf.hh>
#endif // HAVE_DUNE_ALUGRID
36

37
38
39
40
#include "propertysystem.hh"
#include "parameters.hh"
#include "valgrind.hh"

41
42
namespace Dumux
{
Andreas Lauser's avatar
Andreas Lauser committed
43
44
45
// forward declaration of property tags
namespace Properties
{
Christoph Grueninger's avatar
Christoph Grueninger committed
46
NEW_PROP_TAG(Scalar);
47
NEW_PROP_TAG(GridCreator);
Andreas Lauser's avatar
Andreas Lauser committed
48
49
50
51
NEW_PROP_TAG(Problem);
NEW_PROP_TAG(TimeManager);
}

52
53
54
55
56
57
58
59
60
61
/*!
 * \ingroup Start
 * \brief Read the command line arguments and write them into the parameter tree.
 *        Do some syntax checks.
 *
 * \param   argc      The 'argc' argument of the main function: count of arguments (1 if there are no arguments)
 * \param   argv      The 'argv' argument of the main function: array of pointers to the argument strings
 * \param   paramTree The parameterTree. It can be filled from an input file or the command line.
 * \return            Empty string if everything worked out. Otherwise the thing that could not be read.
 */
62
63
std::string readOptions_(int argc, char **argv, Dune::ParameterTree &paramTree)
{
64
    // All command line options need to start with '-'
65
66
67
    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] != '-') {
            std::ostringstream oss;
68
            oss << "\n -> Command line argument " << i << " (='" << argv[i] << "') is invalid. <- \n\n\n\n";
69
70
            return oss.str();
        }
Andreas Lauser's avatar
Andreas Lauser committed
71

72
73
        // read a -MyOpt VALUE option
        std::string paramName = argv[i] + 1;
74

75
76
77
78
        if (argc == i + 1 || argv[i+1][0] == '-') {
            std::ostringstream oss;
            oss << "\n -> No argument given for parameter '" << argv[i] << "'! <- \n\n\n\n";
            return oss.str();
79
        }
Andreas Lauser's avatar
Andreas Lauser committed
80

81
82
        std::string paramValue = argv[i+1];
        ++i; // In the case of '-MyOpt VALUE' each pair counts as two arguments
83
84
85
86
87
88
89

        // Put the key=value pair into the parameter tree
        paramTree[paramName] = paramValue;
    }
    return "";
}

90
91
92
93
94
95
96
97
98
99

/*!
 * \ingroup Start
 *
 * \brief Provides a general text block, that is part of error/ help messages.
 *
 * \return The string that is the help / error message.
 */
std::string usageTextBlock()
{
100
101
102
    return  "Options usually are parameters given to the simulation, \n"
            "and have to be specified with this syntax: \n"
            "\t-GroupName.ParameterName VALUE, for example -TimeManager.TEnd 100\n"
103
            "\n"
104
105
106
107
108
109
110
111
112
            "If -ParameterFile is specified, parameters can also be defined there. In this case,\n"
            "lines of the form \n"
            "GroupName.ParameterName = VALUE # comment \n"
            "have to be used. More conveniently, group names can be specified in square brackets, \n"
            "such that each following parameter name belongs to that group, \n"
            "[GroupName] \n"
            "ParameterName = VALUE \n"
            "See test/boxmodels/2p/test_2p.input for an example of a parameter file \n"
            "and the Dune documentation of ParameterTreeParser for the format specification. \n"
113
114
            "\n"
            "Parameters specified on the command line have priority over those in the parameter file.\n"
115
            "If no parameter file name is given, './<programname>.input' is chosen as default.\n"
116
            "\n"
117
            "Important options include:\n"
118
119
120
121
122
            "\t-h, --help                        Print this usage message and exit\n"
            "\t-PrintParameters [true|false]     Print the run-time modifiable parameters _after_ \n"
            "\t                                  the simulation [default: true]\n"
            "\t-PrintProperties [true|false]     Print the compile-time parameters _before_ \n"
            "\t                                  the simulation [default: false]\n"
123
            "\t-ParameterFile FILENAME           File with parameter definitions\n"
124
            "\t-TimeManager.Restart RESTARTTIME  Restart simulation from a restart file\n"
125
126
127
128
            "\n"
            "\n";
}

129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*!
 * \ingroup Start
 * \brief Dumux start and end message.
 *
 * Selects random messages to write out at the start and end of a simulation run.
 * \param start Indicates if the simulation is starting (=true) or ending (=false).
 */
void dumuxMessage_(bool start)
{
    static int dice_;
    if(start)
    {
        std::srand(std::time(0));
        // roll the dice to decide which start message will be displayed:
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
143
        dice_ = std::rand() % 13; // has to be n+1
144
145
146
    }


Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
147
    std::cout << "" << std::endl;
148
149
150
151
    switch (dice_)
    {
        case 0:
            if(start)
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
152
153
                std::cout << "Welcome aboard DuMuX airlines. Please fasten your seatbelts! "
                          << "Emergency exits are near the time integration." << std::endl;
154
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
155
156
                std::cout << "We hope that you enjoyed simulating with us " << std::endl
                          << "and that you will choose us next time, too." << std::endl;
157
158
159
        break;
        case 1:
            if(start)
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
160
                std::cout << "Let's get the cow off the ice." << std::endl;
161
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
162
                std::cout << "DuMuX got the cow off the ice." << std::endl;
163
164
165
        break;
        case 2:
            if(start)
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
166
167
168
169
                std::cout << "Science, my lad, is made up of mistakes, but they are "
                          << "mistakes which it is useful to make, because they lead little "
                          << "by little to the truth." << std::endl
                          << " - Jules Verne, A journey to the center of the earth" << std::endl;
170
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
171
172
173
                std::cout << "[We see that] science is eminently perfectible, and that each theory has "
                          << "constantly to give way to a fresh one." << std::endl
                          << " - Jules Verne, Journey to the Center of the Earth" << std::endl;
174
175
176
177
178

        break;
        case 3:
            if(start)
                std::cout << "Wherever he saw a hole he always wanted to know the depth of it. "
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
179
180
                          << "To him this was important." << std::endl
                          << " - Jules Verne, A journey to the center of the earth" << std::endl;
181
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
182
183
                std::cout << "We may brave human laws, but we cannot resist natural ones." << std::endl
                          << " - Jules Verne, 20,000 Leagues Under the Sea" << std::endl;
184
185
186
        break;
        case 4:
            if(start)
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
187
                std::cout << "Silence - to delight Bernd." << std::endl;
188
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
189
                std::cout << "\n " << std::endl;
190
191
        break;
        case 5:
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
192
                std::cout << "Don't panic... !" << std::endl;
193
194
195
        break;
        case 6:
            if(start)
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
196
197
                std::cout << "You idiot! You signed the order to destroy Earth!" << std::endl
                          << " - Douglas Adams, HGttG" << std::endl;
198
            else
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
199
200
201
                std::cout << "Marvin: I've been talking to the main computer.\n Arthur: And?" << std::endl
                          << "Marvin: It hates me." << std::endl
                          << " - Douglas Adams, HGttG" << std::endl;
202
203
204
205
        break;
        case 7:
            if(start)
                std::cout << "In the beginning the Universe was created. This has made a lot of "
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
206
207
                          << "people very angry and has been widely regarded as a bad move.!" << std::endl
                          << " - Douglas Adams, HGttG " << std::endl;
208
209
            else
                std::cout << "Forty-two. I checked it very thoroughly, and that quite definitely is the answer. I think "
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
210
211
                          << "the problem, to be quite honest with you, is that you\'ve never actually known what the question is." << std::endl
                          << " - Douglas Adams, HGttG " << std::endl;
212
        break;
213
        case 8:
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
214
215
216
217
            std::cout << "                ##                  @@@@          @   @         @ @" << std::endl;
            std::cout << "             ###   #                @   @         @@ @@          @ " << std::endl;
            std::cout << "           ##       #               @   @  @   @  @ @ @  @   @  @ @" << std::endl;
            std::cout << "         ##          #              @   @  @   @  @   @  @   @     " << std::endl;
Thomas Fetzer's avatar
Thomas Fetzer committed
218
            std::cout << "        #             #             @@@@    @@@   @   @   @@@   2.7" << std::endl;
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
            std::cout << "       #               #                                           " << std::endl;
            std::cout << "      #                 #                                          " << std::endl;
            std::cout << "     #                   ##        %%%                             " << std::endl;
            std::cout << "    #                      ###    %   %  %%     %%                 " << std::endl;
            std::cout << "####                          #%%%     %%  %%%%%  %%%%%%%%%%%%%%%%%" << std::endl;
        break;
        case 9:
            std::cout << "###         #   #        # #                            " << std::endl;
            std::cout << "#  #  #  #  ## ##  #  #   #                             " << std::endl;
            std::cout << "#  #  #  #  # # #  #  #  # #                            " << std::endl;
            std::cout << "###    ##   #   #   ##                                  " << std::endl;
            std::cout << "                                                        " << std::endl;
            std::cout << "Dune for Multi-{ Phase,                                 " << std::endl;
            std::cout << "                 Component,                             " << std::endl;
            std::cout << "                 Scale,                                 " << std::endl;
            std::cout << "                 Physics,                               " << std::endl;
            std::cout << "                 ...} flow and transport in porous media" << std::endl;
        break;
        case 10:
238
239
          if(start)
            {
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
240
241
242
                std::cout << "Elliot Carver: Mr. Jones, are we ready to release our new software?" << std::endl;
                std::cout << "Jones: Yes, sir. As requested, it's full of bugs, which means people will be forced to upgrade for years." << std::endl;
                std::cout << " - James Bond, Tomorrow Never Dies" << std::endl;
243
244
245
            }
            else
            {
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
246
247
                std::cout << "Elliot Carver: Outstanding." << std::endl;
                std::cout << " - James Bond, Tomorrow Never Dies" << std::endl;
248
249
            }
        break;
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
250
        case 11:
251
252
          if(start)
            {
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
253
                std::cout << "Chuck Norris has successfully compiled DuMuX." << std::endl;
254
255
256
            }
            else
            {
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
257
                std::cout << "Chuck Norris has compiled DuMuX even two times in row!" << std::endl;
258
259
            }
        break;
Thomas Fetzer's avatar
[start]    
Thomas Fetzer committed
260
261
262
263
264
265
266
267
268
269
270
271
272
        case 12:
            std::cout << " Join the (first)" << std::endl;
            std::cout << "" << std::endl;
            std::cout << "     ____        __  ___     __ __"  << std::endl;
            std::cout << "    / __ \\__  __/  |/  /_  _ \\ \\ /" << std::endl;
            std::cout << "   / / / / / / / /|_/ / / / /_\\_\\" << std::endl;
            std::cout << "  /_____/\\__,_/_/  /_/\\__,_/        User Meeting 2015" << std::endl;
            std::cout << "" << std::endl;
            std::cout << "      11.-12.6.2015" << std::endl;
            std::cout << "                      in Stuttgart, Germany." << std::endl;
            std::cout << "" << std::endl;
            std::cout << "For more information visit dumux.org or contact the mailing list." << std::endl;
        break;
273
274
275
276
277
        //TODO: If you add a case, you have to increase the modulus at the beginning of the function!

        default:    // silence to delight Bernd
            return ;
    }
278
    std::cout << std::endl;
279
280
}

281
282
283
284
285
286
287
288
289
290
291
292
/*!
 * \ingroup Start
 *
 * \brief Provides a main function which reads in parameters from the
 *        command line and a parameter file.
 *
 * \tparam TypeTag  The type tag of the problem which needs to be solved
 *
 * \param   argc    The 'argc' argument of the main function: count of arguments (1 if there are no arguments)
 * \param   argv    The 'argv' argument of the main function: array of pointers to the argument strings
 * \param   usage   Callback function for printing the usage message
 */
293
template <class TypeTag>
294
295
296
int start_(int argc,
           char **argv,
           void (*usage)(const char *, const std::string &))
297
298
{
    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
299
    // Set by default (dumux/common/basicproperties.hh) to DgfGridCreator (dumux/io/dgfgridcreator.hh)
300
    typedef typename GET_PROP_TYPE(TypeTag, GridCreator) GridCreator;
301
302
    typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
    typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager;
Andreas Lauser's avatar
Andreas Lauser committed
303

304
305
    // initialize MPI, finalize is done automatically on exit
    const Dune::MPIHelper &mpiHelper = Dune::MPIHelper::instance(argc, argv);
Andreas Lauser's avatar
Andreas Lauser committed
306

307
308
309
310
    // print dumux start message
    if (mpiHelper.rank() == 0)
        dumuxMessage_(true);

311
312
313
314
315
316
317
    ////////////////////////////////////////////////////////////
    // parse the command line arguments
    ////////////////////////////////////////////////////////////

    // check whether the user did not specify any parameter. in this
    // case print the usage message
    if (argc == 1) {
318
319
320
        if (mpiHelper.size() > 0)
            std::cout << "Rank " << mpiHelper.rank() << ": ";
        std::cout << "No parameter file given. "
321
322
323
                  << "Defaulting to '"
                  << argv[0]
                  << ".input' for input file.\n";
324
325
        std::ifstream parameterFile;
        // check whether the parameter file exists.
326
        std::string defaultName = argv[0];
327
328
        defaultName += ".input";
        parameterFile.open(defaultName.c_str());
329
        if (not parameterFile.is_open()){
330
331
332
            if (mpiHelper.size() > 0)
                std::cout << "Rank " << mpiHelper.rank() << ": ";
            std::cout << " -> Could not open file '"
333
334
                      << defaultName
                      << "'. <- \n\n\n\n";
335
            usage(argv[0], usageTextBlock());
336
            return 1;
337
338
        }
        parameterFile.close();
339
340
341
342
    }


    // check whether the user wanted to see the help message
343
344
345
    if (mpiHelper.rank() == 0)
    {
        for (int i = 1; i < argc; ++i)
346
        {
347
348
349
350
351
            if (std::string("--help") == argv[i] || std::string("-h") == argv[i])
            {
                usage(argv[0], usageTextBlock());
                return 0;
            }
352
353
        }
    }
Andreas Lauser's avatar
Andreas Lauser committed
354

355
    // fill the parameter tree with the options from the command line
356
357
    typedef typename GET_PROP(TypeTag, ParameterTree) ParameterTree;
    std::string s = readOptions_(argc, argv, ParameterTree::tree());
358
    if (!s.empty()) {
359
        std::string usageMessage = s ;
360
        usageMessage += usageTextBlock();
361
        usage(argv[0], usageMessage);
362
        return 1;
363
364
    }

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
    // obtain the name of the parameter file
    std::string parameterFileName;
    if (ParameterTree::tree().hasKey("ParameterFile"))
    {
        // set the name to the one provided by the user
        parameterFileName = GET_RUNTIME_PARAM(TypeTag, std::string, ParameterFile); // otherwise we read from the command line        
    }
    else 
    {
        // set the name to the default ./<programname>.input
        parameterFileName = argv[0];
        parameterFileName += ".input";
    }
    
    // open and check whether the parameter file exists.
    std::ifstream parameterFile(parameterFileName.c_str());
    if (not parameterFile.is_open()) {
        // if the name of the file has been specified, 
        // this must be an error. Otherwise proceed.
        if (ParameterTree::tree().hasKey("ParameterFile"))
385
        {
386
            std::cout << "\n\t -> Could not open file '"
387
                      << parameterFileName
388
                      << "'. <- \n\n\n\n";
389
            usage(argv[0], usageTextBlock());
390
            return 1;
391
        }
392
393
394
395
396
    }
    else 
    {
        // read parameters from the file without overwriting
        Dune::ParameterTreeParser::readINITree(parameterFileName,
397
                                               ParameterTree::tree(),
398
399
                                               /*overwrite=*/false);
    }
400
    parameterFile.close();
401

402
    bool printProps = false;
403
404
    if (ParameterTree::tree().hasKey("PrintProperties") 
        || ParameterTree::tree().hasKey("TimeManager.PrintProperties"))
405
        printProps = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, bool, TimeManager, PrintProperties);
406
407
408
409

    if (printProps && mpiHelper.rank() == 0) {
        Dumux::Properties::print<TypeTag>();
    }
Andreas Lauser's avatar
Andreas Lauser committed
410

411
412
413
    // deal with the restart stuff
    bool restart = false;
    Scalar restartTime = 0;
414
415
    if (ParameterTree::tree().hasKey("Restart") 
        || ParameterTree::tree().hasKey("TimeManager.Restart")) {
416
        restart = true;
417
        restartTime = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, TimeManager, Restart);
418
    }
Andreas Lauser's avatar
Andreas Lauser committed
419

420
421
    // read the PrintParams parameter
    bool printParams = true;
422
423
    if (ParameterTree::tree().hasKey("PrintParameters") 
        || ParameterTree::tree().hasKey("TimeManager.PrintParameters"))
424
        printParams = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, bool, TimeManager, PrintParameters);
Andreas Lauser's avatar
Andreas Lauser committed
425

426
    // try to create a grid (from the given grid file)
427
    try { GridCreator::makeGrid(); }
428
429
    catch (...) {
        std::string usageMessage = "\n\t -> Creation of the grid failed! <- \n\n\n\n";
430
        usageMessage += usageTextBlock();
431
432
433
        usage(argv[0], usageMessage);
        throw;
    }
434
    GridCreator::loadBalance();
Andreas Lauser's avatar
Andreas Lauser committed
435

436
437
438
    // read the initial time step and the end time
    double tEnd;
    double dt;
439
 
440
    try { tEnd = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, TimeManager, TEnd); }
441
    catch (...) {
442
443
444
        std::string usageMessage = "\n\t -> Mandatory parameter 'TimeManager.TEnd'"
                                   " not specified! <- \n\n\n\n";
        usageMessage += usageTextBlock();
445
446
447
        usage(argv[0], usageMessage);
        throw;
    }
448

449
    try { dt = GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, Scalar, TimeManager, DtInitial); }
450
    catch (...) {
451
452
453
        std::string usageMessage = "\n\t -> Mandatory parameter 'TimeManager.DtInitial'"
                                   " not specified! <- \n\n\n\n";
        usageMessage += usageTextBlock();
454
455
456
        usage(argv[0], usageMessage);
        throw;
    }
457
458
459

    // instantiate and run the concrete problem
    TimeManager timeManager;
460
    Problem problem(timeManager, GridCreator::grid().leafGridView());
461
    timeManager.init(problem, restartTime, dt, tEnd, restart);
462
    timeManager.run();
463
464
465
    // print dumux end message
    if (mpiHelper.rank() == 0)
        dumuxMessage_(false);
466
467
468
469

    if (printParams && mpiHelper.rank() == 0) {
        Dumux::Parameters::print<TypeTag>();
    }
470
    return 0;
471
472
473
474
475
476
477
}

/*!
 * \ingroup Start
 *
 * \brief Provides a main function which reads in parameters from the
 *        command line and a parameter file.
478
 *
479
480
481
 *        In this function only the differentiation between debugger
 *        or not is made.
 *
482
 * \tparam TypeTag  The type tag of the problem which needs to be solved
483
 *
484
485
 * \param argc  The number of command line arguments of the program
 * \param argv  The contents of the command line arguments of the program
486
 * \param usage Callback function for printing the usage message
487
 */
488
template <class TypeTag>
489
490
491
int start(int argc,
          char **argv,
          void (*usage)(const char *, const std::string &))
492
{
Andreas Lauser's avatar
Andreas Lauser committed
493
    try {
494
        return start_<TypeTag>(argc, argv, usage);
Andreas Lauser's avatar
Andreas Lauser committed
495
496
497
498
499
    }
    catch (Dumux::ParameterException &e) {
        std::cerr << e << ". Abort!\n";
        return 1;
    }
500
    catch (Dune::DGFException & e) {
501
502
    std::cerr << "DGF exception thrown (" << e <<
                 "). Most likely, the DGF file name is wrong "
503
                 "or the DGF file is corrupted, "
504
505
                 "e.g. missing hash at end of file or wrong number (dimensions) of entries."
                 << std::endl;
506
507
    return 2;
    }
Andreas Lauser's avatar
Andreas Lauser committed
508
509
    catch (Dune::Exception &e) {
        std::cerr << "Dune reported error: " << e << std::endl;
510
        return 3;
Andreas Lauser's avatar
Andreas Lauser committed
511
512
513
    }
    catch (...) {
        std::cerr << "Unknown exception thrown!\n";
514
        return 4;
Andreas Lauser's avatar
Andreas Lauser committed
515
    }
516
}
517

518
} // namespace Dumux
519
520

#endif