start.hh 15.4 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
/*****************************************************************************
 *   Copyright (C) 2010 by Andreas Lauser                                    *
Andreas Lauser's avatar
Andreas Lauser committed
5
 *   Institute for Modelling Hydraulic and Environmental Systems             *
6
7
8
 *   University of Stuttgart, Germany                                        *
 *   email: <givenname>.<name>@iws.uni-stuttgart.de                          *
 *                                                                           *
9
 *   This program is free software: you can redistribute it and/or modify    *
10
 *   it under the terms of the GNU General Public License as published by    *
11
12
 *   the Free Software Foundation, either version 2 of the License, or       *
 *   (at your option) any later version.                                     *
13
 *                                                                           *
14
15
16
17
18
19
20
 *   This program 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       *
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
21
22
23
 *****************************************************************************/
/*!
 * \file
24
 * \brief Provides a few default main functions for convenience.
25
26
27
28
29
 */
#ifndef DUMUX_START_HH
#define DUMUX_START_HH

#include <iostream>
30

Christoph Grueninger's avatar
Christoph Grueninger committed
31
32
33
34
35
#include "propertysystem.hh"
#include "parameters.hh"
#include "valgrind.hh"

#include <dune/common/mpihelper.hh>
36
37
#include <dune/common/version.hh>
#include <dune/common/parametertreeparser.hh>
38

Christoph Grueninger's avatar
Christoph Grueninger committed
39
#include <dune/grid/io/file/dgfparser.hh>
40

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);
Andreas Lauser's avatar
Andreas Lauser committed
47
NEW_PROP_TAG(Grid);
48
NEW_PROP_TAG(GridCreator);
Andreas Lauser's avatar
Andreas Lauser committed
49
50
51
52
NEW_PROP_TAG(Problem);
NEW_PROP_TAG(TimeManager);
}

53
/*!
54
 * \brief Print a usage string for simulations using
55
56
57
58
 *        Dumux::startFromDGF() as their main() function.
 *
 * \param progname The name of the executable
 */
59
DUMUX_DEPRECATED_MSG("Not needed if Dumux::start() is used")
60
void printUsageDGF(const char *progname)
61
{
62
    std::cout << "usage: " << progname << " [--restart restartTime] gridfile.dgf tEnd dt\n";
63
    exit(1);
64
}
65

66
/*!
67
 * \brief Print a usage string for simulations using
68
69
70
71
 *        Dumux::startWithGrid() as their main() function.
 *
 * \param progname The name of the executable
 */
72
DUMUX_DEPRECATED_MSG("Not needed if Dumux::start() is used")
73
74
75
76
void printUsageGrid(const char *progname)
{
    std::cout << "usage: " << progname << " [--restart restartTime] tEnd dt\n";
    exit(1);
77
78
}

79
80
81
82
83
84
85
86
87
88
/*!
 * \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.
 */
89
90
std::string readOptions_(int argc, char **argv, Dune::ParameterTree &paramTree)
{
91
    // All command line options need to start with '-'
92
93
94
    for (int i = 1; i < argc; ++i) {
        if (argv[i][0] != '-') {
            std::ostringstream oss;
95
            oss << "\n -> Command line argument " << i << " (='" << argv[i] << "') is invalid. <- \n\n\n\n";
96
97
            return oss.str();
        }
Andreas Lauser's avatar
Andreas Lauser committed
98

99
100
        std::string paramName, paramValue;

101
102
103
        // read a --my-opt=abc option. This gets transformed
        // into the parameter "myOpt" with the value being
        // "abc"
104
105
        if (argv[i][1] == '-') {
            std::string s(argv[i] + 2);
106
            // There is nothing after the '='
107
108
109
            if (s.size() == 0 || s[0] == '=')
            {
                std::ostringstream oss;
110
111
                oss << "\n -> Parameter name of argument " << i << " (='" << argv[i] << "')"
                    << " is empty. <- \n\n\n\n";
112
113
114
115
                return oss.str();
            }

            // parse argument
116
            unsigned int j = 0;
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
            while (true) {
                if (j >= s.size()) {
                    // encountered the end of the string, i.e. we
                    // have a parameter where the argument is empty
                    paramName = s;
                    paramValue = "";
                    break;
                }
                else if (s[j] == '=') {
                    // we encountered a '=' character. everything
                    // before is the name of the parameter,
                    // everything after is the value.
                    paramName = s.substr(0, j);
                    paramValue = s.substr(j+1);
                    break;
                }
                else if (s[j] == '-') {
                    // remove all "-" characters and capitalize the
                    // character after them
                    s.erase(j, 1);
                    if (s.size() == j)
                    {
                        std::ostringstream oss;
140
141
                        oss << "\n -> Parameter name of argument " << i << " ('" << argv[i] << "')"
                            << " is invalid (ends with a '-' character). <- \n\n\n\n";
142
143
144
145
146
                        return oss.str();
                    }
                    else if (s[j] == '-')
                    {
                        std::ostringstream oss;
147
148
                        oss << "\n -> Malformed parameter name name in argument " << i << " ('" << argv[i] << "'): "
                            << "'--' in parameter name. <- \n\n\n\n";
149
150
                        return oss.str();
                    }
151
                    s[j] = toupper(s[j]);
152
                }
153
154
155
156
157

                ++j;
            }
        }
        else {
158
159
            // read a -myOpt abc option
            paramName = argv[i] + 1;
Andreas Lauser's avatar
Andreas Lauser committed
160

161
162
            if (argc == i + 1 || argv[i+1][0] == '-') {
                std::ostringstream oss;
163
                oss << "\n -> No argument given for parameter '" << argv[i] << "'! <- \n\n\n\n";
164
165
                return oss.str();
            }
Andreas Lauser's avatar
Andreas Lauser committed
166

167
            paramValue = argv[i+1];
168
            ++i; // In the case of '-myOpt abc' each pair counts as two arguments
169
170
171
172
173
174
175
176
        }

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

177
178
179
180
181
182
183
184
185
186

/*!
 * \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()
{
187
188
    return  "Options have to be specified with this syntax: \n"
            "\t-tEnd ENDTIME                    The time of the end of the simulation [s]\n"
189
            "Alternativ supported syntax:\n"
190
191
192
193
194
195
            "\t--t-end=ENDTIME                  The time of the end of the simulation [s]\n"
            "\n"
            "If -parameterFile is specified parameters can also be defined there. In this case,\n"
            "camel case is used for the parameters (e.g.: tEnd=100). \n"
            "\n"
            "Parameters specified on the command line have priority over those in the parameter file.\n"
196
197
            "\n"
            "Important optional options include:\n"
198
199
200
201
202
203
204
            "\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"
            "\t-parameterFile FILENAME           File with parameter definitions\n"
            "\t-restart RESTARTTIME              Restart simulation from a restart file\n"
205
            "\n"
206
            "For the case of no arguments given, the input parameter file is expected to be named './<programname>.input' \n"
207
208
209
            "\n";
}

210
211
212
213
214
215
216
217
218
219
220
221
/*!
 * \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
 */
222
template <class TypeTag>
223
224
225
int start_(int argc,
           char **argv,
           void (*usage)(const char *, const std::string &))
226
227
228
{
    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
    typedef typename GET_PROP_TYPE(TypeTag, Grid) Grid;
229
230
    // Set by default (dumux/common/basicproperties.hh) to DgfGridCreator (dumux/common/dgfgridcreator.hh)
    typedef typename GET_PROP_TYPE(TypeTag, GridCreator) GridCreator;
231
232
    typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
    typedef typename GET_PROP_TYPE(TypeTag, TimeManager) TimeManager;
Andreas Lauser's avatar
Andreas Lauser committed
233

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

237
238
239
240
241
242
243
    ////////////////////////////////////////////////////////////
    // parse the command line arguments
    ////////////////////////////////////////////////////////////

    // check whether the user did not specify any parameter. in this
    // case print the usage message
    if (argc == 1) {
244
        std::cout<< "\nNo parameter file given. \n"
245
246
247
                 << "Defaulting to '"
                 <<argv[0]
                 <<".input' for input file.\n";
248
249
        std::ifstream parameterFile;
        // check whether the parameter file exists.
250
251
        std::string defaultName = argv[0];
                    defaultName += ".input";
252
                    parameterFile.open(defaultName.c_str());
253
        if (not parameterFile.is_open()){
254
255
256
            std::cout<< "\n\t -> Could not open file '"
                     <<defaultName
                     <<"'. <- \n\n\n\n";
257
            usage(argv[0], usageTextBlock());
258
            return 1;
259
260
        }
        parameterFile.close();
261
262
263
264
265
266
267
    }


    // check whether the user wanted to see the help message
    for (int i = 1; i < argc; ++i) {
        if (std::string("--help") == argv[i] || std::string("-h") == argv[i])
        {
268
            usage(argv[0], usageTextBlock());
269
270
271
            return 0;
        }
    }
Andreas Lauser's avatar
Andreas Lauser committed
272

273
    // fill the parameter tree with the options from the command line
274
275
    typedef typename GET_PROP(TypeTag, ParameterTree) ParameterTree;
    std::string s = readOptions_(argc, argv, ParameterTree::tree());
276
    if (!s.empty()) {
277
278
279
        std::string usageMessage = s ;
                    usageMessage += usageTextBlock();
        usage(argv[0], usageMessage);
280
        return 1;
281
282
283
    }

    if (ParameterTree::tree().hasKey("parameterFile") or argc==1) {
284
        // read input file, but do not overwrite options specified
285
286
        // on the command line, since the latter have precedence.
        std::string inputFileName ;
287
288
289
290
291
        if(argc==1) // if there are no arguments given (and there is a file ./<programname>.input) we use it as input file
        {
            inputFileName = argv[0];
            inputFileName += ".input";
        }
292
293
294
295
296
297
        else
            inputFileName = GET_RUNTIME_PARAM(TypeTag, std::string, parameterFile); // otherwise we read from the command line

        std::ifstream parameterFile;

        // check whether the parameter file exists.
298
        parameterFile.open(inputFileName.c_str());
299
        if (not parameterFile.is_open()){
300
            std::cout<< "\n\t -> Could not open file"
301
                     << inputFileName
302
303
                     << ". <- \n\n\n\n";
            usage(argv[0], usageTextBlock());
304
            return 1;
305
306
307
        }
        parameterFile.close();

Andreas Lauser's avatar
Andreas Lauser committed
308
        Dune::ParameterTreeParser::readINITree(inputFileName,
309
                                               ParameterTree::tree(),
310
311
312
                                               /*overwrite=*/false);
    }

313
    bool printProps = false;
314
    if (ParameterTree::tree().hasKey("PrintProperties"))
315
        printProps = GET_RUNTIME_PARAM(TypeTag, bool, PrintProperties);
316
317
318
319

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

321
322
323
    // deal with the restart stuff
    bool restart = false;
    Scalar restartTime = 0;
324
    if (ParameterTree::tree().hasKey("restart")) {
325
        restart = true;
326
        restartTime = GET_RUNTIME_PARAM(TypeTag, Scalar, restart);
327
    }
Andreas Lauser's avatar
Andreas Lauser committed
328

329
330
    // read the PrintParams parameter
    bool printParams = true;
331
    if (ParameterTree::tree().hasKey("PrintParameters"))
332
        printParams = GET_RUNTIME_PARAM(TypeTag, bool, PrintParameters);
Andreas Lauser's avatar
Andreas Lauser committed
333

334
    // try to create a grid (from the given grid file)
335
    try { GridCreator::makeGrid(); }
336
337
338
339
340
341
    catch (...) {
        std::string usageMessage = "\n\t -> Creation of the grid failed! <- \n\n\n\n";
                    usageMessage += usageTextBlock();
        usage(argv[0], usageMessage);
        throw;
    }
342
    GridCreator::loadBalance();
Andreas Lauser's avatar
Andreas Lauser committed
343

344
345
346
347
    // read the initial time step and the end time
    double tEnd;
    double dt;

348
349
350
351
352
353
354
    try { tEnd = GET_RUNTIME_PARAM(TypeTag, Scalar, tEnd); }
    catch (...) {
        std::string usageMessage = "\n\t -> Mandatory parameter '--t-end' not specified! <- \n\n\n\n";
                    usageMessage += usageTextBlock();
        usage(argv[0], usageMessage);
        throw;
    }
355

356
357
358
359
360
361
362
    try { dt = GET_RUNTIME_PARAM(TypeTag, Scalar, dtInitial); }
    catch (...) {
        std::string usageMessage = "\n\t -> Mandatory parameter '--dt-initial' not specified! <- \n\n\n\n";
                    usageMessage += usageTextBlock();
        usage(argv[0], usageMessage);
        throw;
    }
363
364
365

    // instantiate and run the concrete problem
    TimeManager timeManager;
366
    Problem problem(timeManager, GridCreator::grid().leafView());
367
    timeManager.init(problem, restartTime, dt, tEnd, restart);
368
369
370
371
372
    timeManager.run();

    if (printParams && mpiHelper.rank() == 0) {
        Dumux::Parameters::print<TypeTag>();
    }
373
    return 0;
374
375
376
377
378
379
380
}

/*!
 * \ingroup Start
 *
 * \brief Provides a main function which reads in parameters from the
 *        command line and a parameter file.
381
 *
382
383
384
 *        In this function only the differentiation between debugger
 *        or not is made.
 *
385
 * \tparam TypeTag  The type tag of the problem which needs to be solved
386
 *
387
388
 * \param argc  The number of command line arguments of the program
 * \param argv  The contents of the command line arguments of the program
389
 * \param usage Callback function for printing the usage message
390
 */
391
template <class TypeTag>
392
393
394
int start(int argc,
          char **argv,
          void (*usage)(const char *, const std::string &))
395
{
Andreas Lauser's avatar
Andreas Lauser committed
396
    try {
397
        return start_<TypeTag>(argc, argv, usage);
Andreas Lauser's avatar
Andreas Lauser committed
398
399
400
401
402
403
404
405
406
407
408
409
410
    }
    catch (Dumux::ParameterException &e) {
        std::cerr << e << ". Abort!\n";
        return 1;
    }
    catch (Dune::Exception &e) {
        std::cerr << "Dune reported error: " << e << std::endl;
        return 2;
    }
    catch (...) {
        std::cerr << "Unknown exception thrown!\n";
        return 3;
    }
411
}
412

413
} // namespace Dumux
414
415

#endif