parameters.hh 18.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
7
8
9
10
11
12
 *                                                                           *
 *   This program 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 2 of the License, or       *
 *   (at your option) any later version.                                     *
 *                                                                           *
 *   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
18
19
 *   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/>.   *
 *****************************************************************************/
/*!
20
 * \ingroup Parameter
21
22
23
24
25
26
27
28
29
 * \file
 *
 * \brief The infrastructure to retrieve run-time parameters from
 *        Dune::ParameterTrees with the defaul value taken from the
 *        property system.
 */
#ifndef DUMUX_PARAMETERS_HH
#define DUMUX_PARAMETERS_HH

30
31
32
33
#include <iostream>
#include <list>
#include <sstream>
#include <unordered_map>
34

35
36
#include <dune/common/parametertree.hh>

37
38
#include <dumux/common/propertysystem.hh>
#include <dumux/common/exceptions.hh>
39

40
/*!
41
 * \ingroup Parameter
42
43
44
 * \brief Retrieve a runtime parameter which _does_ have a default value taken from
 *        the Dumux property system.
 *
45
 * Example:
46
 *
47
48
49
 * \code 
 * // -> retrieves scalar value UpwindWeight, default 
 * // is taken from the property UpwindWeight 
50
 * GET_PARAM(TypeTag, Scalar, UpwindWeight);
51
 * \endcode
52
53
 */
#define GET_PARAM(TypeTag, ParamType, ParamName)                        \
54
    ::Dumux::Parameters::get<TypeTag,                                   \
55
                           ParamType,                                   \
56
                           PTAG_(ParamName)>(#ParamName, #ParamName)
57
58
59
60
61
62
63
64
65
66

/*!
 * \ingroup Parameter
 * \brief Retrieve a runtime parameter which _does_ have a default value taken from
 *        the Dumux property system.
 *
 * The third argument is group name which must be the prefix to the
 * property name which provides the default value for the parameter
 *
 * Example:
67
 *
68
 * \code 
69
70
 * // -> retrieves Boolean value Newton.WriteConvergence, default
 * // is taken from the property NewtonWriteConvergence
71
 * GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence);
72
 * \endcode
73
 */
74
#define GET_PARAM_FROM_GROUP(TypeTag, ParamType, GroupName, ParamName)  \
75
    ::Dumux::Parameters::get<TypeTag,                                   \
76
                           ParamType,                                   \
77
                           PTAG_(GroupName##ParamName)>(#GroupName#ParamName, #GroupName, #ParamName)
78

79
/*!
80
 * \ingroup Parameter
81
82
83
 * \brief Retrieve a runtime parameter which _does not_ have a default value taken from
 *        the Dumux property system.
 *
84
 * Example:
85
 *
86
 * \code 
87
88
 * // -> retrieves global integer value NumberOfCellsX
 * GET_RUNTIME_PARAM(TypeTag, int, NumberOfCellsX);
89
 * \endcode
90
91
 */
#define GET_RUNTIME_PARAM(TypeTag, ParamType, ParamName) \
92
    ::Dumux::Parameters::getRuntime<TypeTag, ParamType>(#ParamName)
93
94
95
96
97
98
99
100
101

/*!
 * \ingroup Parameter
 * \brief Retrieve a runtime parameter which _does not_ have a default value taken from
 *        the Dumux property system.
 *
 * The third argument is group name.
 *
 * Example:
102
 *
103
 * \code 
104
105
106
 * // -> retrieves global integer value "NumberOfCellsX" which is
 * // located in the parameter group "Grid"
 * GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, int, Grid, NumberOfCellsX);
107
 * \endcode
108
 */
109
#define GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, ParamType, GroupName, ParamName) \
110
    ::Dumux::Parameters::getRuntime<TypeTag, ParamType>(#GroupName, #ParamName)
111
112
113
114
115
116

namespace Dumux
{
namespace Properties
{
NEW_PROP_TAG(ParameterTree);
117
NEW_PROP_TAG(ModelParameterGroup);
118
119
120
} // namespace Properties

namespace Parameters {
121
122

template <class TypeTag>
123
void findUnusedKeys_(std::list<std::string> &unusedParams,
124
125
126
                     const Dune::ParameterTree &tree,
                     const std::string prefix="")
{
127
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
128
    const Dune::ParameterTree &rt = Params::runTimeParams();
129
    const Dune::ParameterTree &drt = Params::deprecatedRunTimeParams();
130
131

    // loop over all keys of the current tree
132
    const Dune::ParameterTree::KeyVector &keys =
133
        tree.getValueKeys();
134
    for (unsigned int i = 0; i < keys.size(); ++i) {
135
136
        std::string canonicalName = prefix + keys[i];

137
138
139
140
141
        // store keys which were not accessed
        if (!rt.hasKey(canonicalName) && !drt.hasKey(canonicalName))
        {
            unusedParams.push_back(canonicalName);
        }
142
143
144
    }

    // loop over all subtrees
145
    const Dune::ParameterTree::KeyVector &subKeys =
146
        tree.getSubKeys();
147
    for (unsigned int i = 0; i < subKeys.size(); ++i) {
148
149
        std::string newPrefix = prefix + subKeys[i] + ".";

150
        findUnusedKeys_<TypeTag>(unusedParams,
151
152
153
                                 tree.sub(subKeys[i]),
                                 newPrefix);
    }
154

155
156
}

157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
template <class TypeTag>
bool hasDeprecatedKeys_(const Dune::ParameterTree &tree)
{
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
    const Dune::ParameterTree &drt = Params::deprecatedRunTimeParams();

    // loop over all keys of the current tree
    const Dune::ParameterTree::KeyVector &keys =
        tree.getValueKeys();
    for (unsigned int i = 0; i < keys.size(); ++i) {
        std::string canonicalName = keys[i];

        // check whether the key was accessed
        if (drt.hasKey(canonicalName))
            return true;
    }
    return false;
}

176
177
178
179
/*!
 * \ingroup Parameter
 * \brief Print the run- and compile-time parameters.
 */
180
181
182
template <class TypeTag>
void print(std::ostream &os = std::cout)
{
183
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
184
185
186
187

    const Dune::ParameterTree &tree = Params::tree();
    const Dune::ParameterTree &rt = Params::runTimeParams();
    const Dune::ParameterTree &ct = Params::compileTimeParams();
188
189
    const Dune::ParameterTree &drt = Params::deprecatedRunTimeParams();
    const Dune::ParameterTree &unrt = Params::unusedNewRunTimeParams();
190

191
    os << "# Run-time specified parameters:" << std::endl;
192
    rt.report(os);
193

194
    if (hasDeprecatedKeys_<TypeTag>(tree)) 
195
    {
196
197
198
199
        os << "# DEPRECATED Run-time specified parameters:" << std::endl;
        drt.report(os);
        os << "# Replace by:" << std::endl;
        unrt.report(os);
200
201
    }

202
    os << "# Compile-time specified parameters:" << std::endl;
203
204
205
    ct.report(os);

    std::list<std::string> unusedParams;
206
    findUnusedKeys_<TypeTag>(unusedParams, tree);
207

208
209
210
211
212
213
    if (unusedParams.size() > 0)
    {
        os << "# UNUSED PARAMETERS:" << std::endl;
        for (auto it = unusedParams.begin(); it != unusedParams.end(); ++it)
        {
            os << *it << " = \"" << tree.get(*it, "") << "\"" << std::endl;
214
        }
215
    }
216
}
217

218
219
const char *getString_(const char *foo = 0)
{ return foo; }
220

221
template <class TypeTag>
222
223
class Param
{
224
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
225
public:
226
    template <class ParamType, class PropTag>
227
228
    static const ParamType &get(const char *propertyName,
                                const char *groupOrParamName,
229
                                const char *paramNameOrNil = 0)
230
    {
231
        static const ParamType &value = retrieve_<ParamType, PropTag>(propertyName, groupOrParamName, paramNameOrNil);
232
233
234
235
        return value;
    }

    template <class ParamType>
236
    static const ParamType &getRuntime(const char *groupOrParamName,
237
238
239
240
241
242
243
244
245
246
247
                                       const char *paramNameOrNil = 0)
    {
#ifndef NDEBUG
        // make sure that the parameter is used consistently. since
        // this is potentially quite expensive, it is only done if
        // debugging code is not explicitly turned off.
        const char *paramName, *groupName;
        static const std::string propertyName("");
        if (paramNameOrNil && strlen(paramNameOrNil) > 0) {
            groupName = groupOrParamName;
            paramName = paramNameOrNil;
248
        }
249
250
251
252
253
        else {
            groupName = "";
            paramName = groupOrParamName;
        }

254
        check_(Dune::className<ParamType>(), propertyName, groupName, paramName);
255
256
#endif

257
        return retrieveRuntime_<ParamType>(groupOrParamName, paramNameOrNil);
258
259
260
    }

private:
261
262
263
264
265
266
267
268
269
270
271
    struct Blubb {
        std::string propertyName;
        std::string paramTypeName;
        std::string groupName;

        Blubb &operator=(const Blubb &b)
        {
            propertyName = b.propertyName;
            paramTypeName = b.paramTypeName;
            groupName = b.groupName;
            return *this;
272
        }
273
274
    };

275
276
    static void check_(const std::string &paramTypeName,
                       const std::string &propertyName,
277
                       const char *groupName,
278
279
                       const char *paramName)
    {
280
        typedef std::unordered_map<std::string, Blubb> StaticData;
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
        static StaticData staticData;

        typename StaticData::iterator it = staticData.find(paramName);
        Blubb *b;
        if (it == staticData.end())
        {
            Blubb a;
            a.propertyName = propertyName;
            a.paramTypeName = paramTypeName;
            a.groupName = groupName;
            staticData[paramName] = a;
            b = &staticData[paramName];
        }
        else
            b = &(it->second);
296

297
298
299
        if (b->groupName != groupName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName
300
                       << "' called for at least two different groups ('"
301
302
303
304
305
306
                       << b->groupName << "' and '" << groupName << "')");
        }

        if (b->propertyName != propertyName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName
307
                       << "' called for at least two different properties ('"
308
309
310
311
312
313
                       << b->propertyName << "' and '" << propertyName << "')");
        }

        if (b->paramTypeName != paramTypeName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName << "' in group '"
314
                       << groupName << "' called with at least two different types ("
315
316
317
                       << b->paramTypeName << " and " << paramTypeName << ")");
        }
    }
318

319
    template <class ParamType, class PropTag>
320
    static const ParamType &retrieve_(const char *propertyName,
Andreas Lauser's avatar
Andreas Lauser committed
321
                                      const char *groupOrParamName,
322
                                      const char *paramNameOrNil = 0)
323
    {
324
        const char *paramName, *groupName;
325
        if (paramNameOrNil && strlen(paramNameOrNil) > 0) {
326
327
328
329
            groupName = groupOrParamName;
            paramName = paramNameOrNil;
        }
        else {
330
            groupName = "";
331
332
333
            paramName = groupOrParamName;
        }

334
335
336
337
338
339
340
#ifndef NDEBUG
        // make sure that the parameter is used consistently. since
        // this is potentially quite expensive, it is only done if
        // debugging code is not explicitly turned off.
        check_(Dune::className<ParamType>(), propertyName, groupName, paramName);
#endif

341
342
343
344
345
346
347
348
        // prefix the parameter name by 'GroupName.'. E.g. 'Newton'
        // and 'WriteConvergence' becomes 'Newton.WriteConvergence'
        // with the default value specified by the
        // 'NewtonWriteConvergence' property. in an INI file this
        // would look like:
        //
        // [Newton]
        // WriteConvergence = true
349
        std::string canonicalName(paramName);
350
        if (strlen(groupName) > 0) {
351
352
            canonicalName.insert(0, ".");
            canonicalName.insert(0, groupName);
353
        }
354

355
        std::string modelParamGroup(GET_PROP_VALUE(TypeTag, ModelParameterGroup));
356
357
358
359
360
361
362
363
        // prefix the parameter with the parameter group of the
        // model. this allows things like sub-model specific parameters like
        //
        // [Stokes.Newton]
        // WriteConvergence = false
        // [Darcy.Newton]
        // WriteConvergence = true
        if (modelParamGroup.size()) {
364
365
            canonicalName.insert(0, ".");
            canonicalName.insert(0, modelParamGroup);
366
        }
367

368
        static ParamType value;
369
        // retrieve actual parameter from the parameter tree
370
        ParamType defaultValue = GET_PROP_VALUE_(TypeTag, PropTag);
371
372
373
374
375
376
377
        if (!Params::tree().hasKey(canonicalName) && Params::tree().hasKey(paramName))//functionality to catch deprecated params
        {
            value = Params::tree().template get<ParamType>(paramName, defaultValue);
//            std::cout<<"\nWarning: Using the parameter: "<<paramName<<" without group name: "<<groupName<<" is deprecated!"<<"\n\n";
        }
        else
            value = Params::tree().template get<ParamType>(canonicalName, defaultValue);
378

379
380
        // remember whether the parameter was taken from the parameter
        // tree or the default from the property system was taken.
381
382
        Dune::ParameterTree &rt = Params::runTimeParams();
        Dune::ParameterTree &ct = Params::compileTimeParams();
383
384
        Dune::ParameterTree &drt = Params::deprecatedRunTimeParams();
        Dune::ParameterTree &unrt = Params::unusedNewRunTimeParams();
385
386
        if (Params::tree().hasKey(canonicalName)) {
            rt[canonicalName] = Params::tree()[canonicalName];
387
        }
388
389
390
391
392
        else if (Params::tree().hasKey(paramName))//functionality to catch deprecated params
        {
            drt[paramName] = Params::tree()[paramName];
            unrt[canonicalName] = Params::tree()[paramName];
        }
393
394
395
396
        else {
            std::string s;
            std::ostringstream oss(s);
            oss << defaultValue;
397
            ct[canonicalName] = oss.str();
398
        }
399
400
401
        return value;
    }

402
403
    template <class ParamType>
    static const ParamType &retrieveRuntime_(const char *groupOrParamName, const char *paramNameOrNil = 0)
404
    {
405
        const char *paramName, *groupName;
406
        if (paramNameOrNil && paramNameOrNil[0] != '\0') {
407
408
409
410
            groupName = groupOrParamName;
            paramName = paramNameOrNil;
        }
        else {
411
            groupName = "";
412
413
            paramName = groupOrParamName;
        }
414

415
        static std::string modelParamGroup(GET_PROP(TypeTag, ModelParameterGroup)::value);
416

417
        std::string canonicalName(modelParamGroup);
418

419
420
421
422
423
424
425
426
        // prefix the parameter with the parameter group of the
        // model. this allows things like sub-model specific parameters like
        //
        // [Stokes.Newton]
        // WriteConvergence = false
        // [Darcy.Newton]
        // WriteConvergence = true
        if (modelParamGroup.size()) {
427
            canonicalName.push_back('.');
428
        }
429

430
431
432
433
434
435
436
437
        // prefix the parameter name by 'GroupName.'. E.g. 'Newton'
        // and 'WriteConvergence' becomes 'Newton.WriteConvergence'
        // with the default value specified by the
        // 'NewtonWriteConvergence' property. in an INI file this
        // would look like:
        //
        // [Newton]
        // WriteConvergence = true
438
        if (strlen(groupName) > 0) {
439
440
441
442
443
444
445
446
            canonicalName.append(groupName);
            canonicalName.push_back('.');
        }

        // append the name of the parameter
        canonicalName.append(paramName);

        // cache parameters using a hash_map (Dune::Parameter tree is slow!)
447
        typedef std::unordered_map<std::string, ParamType> ParamCache;
448
        static ParamCache paramCache;
449
        typename ParamCache::iterator it = paramCache.find(canonicalName);
450
451
452
        if (it != paramCache.end())
            return it->second;

453
454
455
456
        it = paramCache.find(paramName);
        if (it != paramCache.end())
                    return it->second;

457
        // retrieve actual parameter from the parameter tree
458
        if (!Params::tree().hasKey(canonicalName) && !Params::tree().hasKey(paramName)) {
459
            print<TypeTag>();
460
            DUNE_THROW(::Dumux::ParameterException,
461
                       "Mandatory parameter '" << canonicalName
462
                       << "' was not specified");
463
464
        }

465
        // update the cache
466
467
468
469
470
        ParamType value;
        if (!Params::tree().hasKey(canonicalName) && Params::tree().hasKey(paramName))//functionality to catch deprecated params
        {
            value = Params::tree().template get<ParamType>(paramName);
            paramCache[paramName] = value;
471

472
473
474
475
            // remember whether the parameter was taken from the parameter
            // tree or the default from the property system was taken.
            Dune::ParameterTree &drt = Params::deprecatedRunTimeParams();
            Dune::ParameterTree &unrt = Params::unusedNewRunTimeParams();
476

477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
            drt[paramName] = Params::tree()[paramName];
            unrt[canonicalName] = Params::tree()[paramName];
            return paramCache[paramName];
        }
        else
        {
            value = Params::tree().template get<ParamType>(canonicalName);
            paramCache[canonicalName] = value;

            // remember whether the parameter was taken from the parameter
            // tree or the default from the property system was taken.
            Dune::ParameterTree &rt = Params::runTimeParams();

            rt[canonicalName] = Params::tree()[canonicalName];
            return paramCache[canonicalName];
        }
493
494
    }
};
495

496
template <class TypeTag, class ParamType, class PropTag>
497
498
const ParamType &get(const char *propertyName,
                     const char *paramOrGroupName,
499
500
                     const char *paramNameOrNil = 0)
{
501
502
    return Param<TypeTag>::template get<ParamType, PropTag>(propertyName,
                                                            paramOrGroupName,
503
504
505
506
                                                            paramNameOrNil);
}

template <class TypeTag, class ParamType>
507
const ParamType &getRuntime(const char *paramOrGroupName,
508
509
                            const char *paramNameOrNil = 0)
{
510
    return Param<TypeTag>::template getRuntime<ParamType>(paramOrGroupName,
511
512
513
                                                          paramNameOrNil);
}

514
515
516
517
518
519
} // namespace Parameters

} // namespace Dumux


#endif