parameters.hh 16.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
/*****************************************************************************
 *   Copyright (C) 2011 by Andreas Lauser                                    *
Andreas Lauser's avatar
Andreas Lauser committed
5
 *   Institute for Modelling Hydraulic and Environmental Systems             *
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *   University of Stuttgart, Germany                                        *
 *   email: <givenname>.<name>@iws.uni-stuttgart.de                          *
 *                                                                           *
 *   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          *
 *   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/>.   *
 *****************************************************************************/
/*!
23
 * \ingroup Parameter
24
25
26
27
28
29
30
31
32
 * \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

33
34
#include <dumux/common/propertysystem.hh>
#include <dumux/common/exceptions.hh>
35

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

38
#include <iostream>
39
#include <sstream>
40
#include <list>
41
#include <tr1/unordered_map>
42

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

/*!
 * \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:
68
69
70
 *
 * // -> retrieves Boolean value Newton.WriteConvergence, default
 * // is taken from the property NewtonWriteConvergence
71
 * GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence);
72
 */
73
#define GET_PARAM_FROM_GROUP(TypeTag, ParamType, GroupName, ParamName)  \
74
75
    Dumux::Parameters::get<TypeTag,                                     \
                           ParamType,                                   \
76
                           PTAG_(GroupName##ParamName)>(#GroupName#ParamName, #GroupName, #ParamName)
77

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

/*!
 * \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:
99
100
101
 *
 * // -> retrieves global integer value NumberOfCellsX which is
 * // located int the parameter group "Geometry"
102
 * GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, int, Geometry, NumberOfCellsX);
103
 */
104
105
#define GET_RUNTIME_PARAM_FROM_GROUP(TypeTag, ParamType, GroupName, ParamName) \
    Dumux::Parameters::getRuntime<TypeTag, ParamType>(#GroupName, #ParamName)
106
107
108
109
110
111

namespace Dumux
{
namespace Properties
{
NEW_PROP_TAG(ParameterTree);
112
NEW_PROP_TAG(ModelParameterGroup);
113
114
115
} // namespace Properties

namespace Parameters {
116
117

template <class TypeTag>
118
void findUnusedKeys_(std::list<std::string> &unusedParams,
119
120
121
                     const Dune::ParameterTree &tree,
                     const std::string prefix="")
{
122
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
123
124
125
    const Dune::ParameterTree &rt = Params::runTimeParams();

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

        // check whether the key was accessed
        if (rt.hasKey(canonicalName))
            continue;
        unusedParams.push_back(canonicalName);
    }

    // loop over all subtrees
138
    const Dune::ParameterTree::KeyVector &subKeys =
139
        tree.getSubKeys();
140
    for (unsigned int i = 0; i < subKeys.size(); ++i) {
141
142
        std::string newPrefix = prefix + subKeys[i] + ".";

143
        findUnusedKeys_<TypeTag>(unusedParams,
144
145
146
                                 tree.sub(subKeys[i]),
                                 newPrefix);
    }
147

148
149
}

150
151
152
153
/*!
 * \ingroup Parameter
 * \brief Print the run- and compile-time parameters.
 */
154
155
156
template <class TypeTag>
void print(std::ostream &os = std::cout)
{
157
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
158
159
160
161
162
163

    const Dune::ParameterTree &tree = Params::tree();
    const Dune::ParameterTree &rt = Params::runTimeParams();
    const Dune::ParameterTree &ct = Params::compileTimeParams();

    os << "###############################\n";
164
    os << "# Run-time specified parameters:\n";
165
166
167
    os << "###############################\n";
    rt.report(os);
    os << "###############################\n";
168
    os << "# Compile-time specified parameters:\n";
169
170
    os << "###############################\n";
    ct.report(os);
171
172
173
174
175
/*
    printParamTree_(ct);
    typename Dune::ParameterTree::KeyVector::const_iterator it = ct.begin();
    for (; it != ct.end(); ++it) {
        os << *it << " = \"" << ct.get(*it, "") << "\""
Andreas Lauser's avatar
Andreas Lauser committed
176
            // << " # Taken From Property: " <<
177
178
179
           << "\n";
    };
*/
180
181

    std::list<std::string> unusedParams;
182
    findUnusedKeys_<TypeTag>(unusedParams, tree);
183
184
185
186
187
188
189
190
191
192

    if (unusedParams.size() > 0) {
        os << "###############################\n";
        os << "# UNUSED PARAMETERS:\n";
        os << "###############################\n";
        std::list<std::string>::const_iterator it = unusedParams.begin();
        for (; it != unusedParams.end(); ++it) {
            os << *it << " = \"" << tree.get(*it, "") << "\"\n";
        };
    }
193
}
194

195
196
const char *getString_(const char *foo = 0)
{ return foo; }
197

198
template <class TypeTag>
199
200
class Param
{
201
    typedef typename GET_PROP(TypeTag, ParameterTree) Params;
202
public:
203
    template <class ParamType, class PropTag>
204
205
    static const ParamType &get(const char *propertyName,
                                const char *groupOrParamName,
206
                                const char *paramNameOrNil = 0)
207
    {
208
        static const ParamType &value = retrieve_<ParamType, PropTag>(propertyName, groupOrParamName, paramNameOrNil);
209
210
211
212
        return value;
    }

    template <class ParamType>
213
    static const ParamType &getRuntime(const char *groupOrParamName,
214
215
216
217
218
219
220
221
222
223
224
                                       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;
225
        }
226
227
228
229
230
        else {
            groupName = "";
            paramName = groupOrParamName;
        }

231
        check_(Dune::className<ParamType>(), propertyName, groupName, paramName);
232
233
#endif

234
        return retrieveRuntime_<ParamType>(groupOrParamName, paramNameOrNil);
235
236
237
    }

private:
238
239
240
241
242
243
244
245
246
247
248
249
250
251
    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;
        };
    };

252
253
    static void check_(const std::string &paramTypeName,
                       const std::string &propertyName,
254
                       const char *groupName,
255
256
                       const char *paramName)
    {
257
        typedef std::tr1::unordered_map<std::string, Blubb> StaticData;
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
        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);
273

274
275
276
        if (b->groupName != groupName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName
277
                       << "' called for at least two different groups ('"
278
279
280
281
282
283
                       << b->groupName << "' and '" << groupName << "')");
        }

        if (b->propertyName != propertyName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName
284
                       << "' called for at least two different properties ('"
285
286
287
288
289
290
                       << b->propertyName << "' and '" << propertyName << "')");
        }

        if (b->paramTypeName != paramTypeName) {
            DUNE_THROW(Dune::InvalidStateException,
                       "GET_*_PARAM for parameter '" << paramName << "' in group '"
291
                       << groupName << "' called with at least two different types ("
292
293
294
                       << b->paramTypeName << " and " << paramTypeName << ")");
        }
    }
295

296
    template <class ParamType, class PropTag>
297
    static const ParamType &retrieve_(const char *propertyName,
Andreas Lauser's avatar
Andreas Lauser committed
298
                                      const char *groupOrParamName,
299
                                      const char *paramNameOrNil = 0)
300
    {
301
        const char *paramName, *groupName;
302
        if (paramNameOrNil && strlen(paramNameOrNil) > 0) {
303
304
305
306
            groupName = groupOrParamName;
            paramName = paramNameOrNil;
        }
        else {
307
            groupName = "";
308
309
310
            paramName = groupOrParamName;
        }

311
312
313
314
315
316
317
#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

318
319
320
321
322
323
324
325
        // 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
326
        std::string canonicalName(paramName);
327
        if (strlen(groupName) > 0) {
328
329
            canonicalName.insert(0, ".");
            canonicalName.insert(0, groupName);
330
        }
331

332
        std::string modelParamGroup(GET_PROP_VALUE(TypeTag, ModelParameterGroup));
333
334
335
336
337
338
339
340
        // 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()) {
341
342
            canonicalName.insert(0, ".");
            canonicalName.insert(0, modelParamGroup);
343
        }
344

345
        // retrieve actual parameter from the parameter tree
346
        ParamType defaultValue = GET_PROP_VALUE_(TypeTag, PropTag);
347
        static ParamType value = Params::tree().template get<ParamType>(canonicalName, defaultValue);
348

349
350
        // remember whether the parameter was taken from the parameter
        // tree or the default from the property system was taken.
351
352
        Dune::ParameterTree &rt = Params::runTimeParams();
        Dune::ParameterTree &ct = Params::compileTimeParams();
353
354
        if (Params::tree().hasKey(canonicalName)) {
            rt[canonicalName] = Params::tree()[canonicalName];
355
356
357
358
359
        }
        else {
            std::string s;
            std::ostringstream oss(s);
            oss << defaultValue;
360
            ct[canonicalName] = oss.str();
361
        }
362
363
364
        return value;
    }

365
366
    template <class ParamType>
    static const ParamType &retrieveRuntime_(const char *groupOrParamName, const char *paramNameOrNil = 0)
367
    {
368
        const char *paramName, *groupName;
369
        if (paramNameOrNil && paramNameOrNil[0] != '\0') {
370
371
372
373
            groupName = groupOrParamName;
            paramName = paramNameOrNil;
        }
        else {
374
            groupName = "";
375
376
            paramName = groupOrParamName;
        }
377

378
        static std::string modelParamGroup(GET_PROP(TypeTag, ModelParameterGroup)::value);
379

380
        std::string canonicalName(modelParamGroup);
381

382
383
384
385
386
387
388
389
        // 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()) {
390
            canonicalName.push_back('.');
391
        }
392

393
394
395
396
397
398
399
400
        // 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
401
        if (strlen(groupName) > 0) {
402
403
404
405
406
407
408
409
            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!)
410
        typedef std::tr1::unordered_map<std::string, ParamType> ParamCache;
411
412
413
414
415
        static ParamCache paramCache;
        const typename ParamCache::iterator &it = paramCache.find(canonicalName);
        if (it != paramCache.end())
            return it->second;

416
        // retrieve actual parameter from the parameter tree
417
        if (!Params::tree().hasKey(canonicalName)) {
418
            DUNE_THROW(Dumux::ParameterException,
419
                       "Mandatory parameter '" << canonicalName
420
                       << "' was not specified");
421
422
        }

423
        // update the cache
424
        ParamType value = Params::tree().template get<ParamType>(canonicalName);
425
        paramCache[canonicalName] = value;
426
427
428
429

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

432
        return paramCache[canonicalName];
433
434
    }
};
435

436
template <class TypeTag, class ParamType, class PropTag>
437
438
const ParamType &get(const char *propertyName,
                     const char *paramOrGroupName,
439
440
                     const char *paramNameOrNil = 0)
{
441
442
    return Param<TypeTag>::template get<ParamType, PropTag>(propertyName,
                                                            paramOrGroupName,
443
444
445
446
                                                            paramNameOrNil);
}

template <class TypeTag, class ParamType>
447
const ParamType &getRuntime(const char *paramOrGroupName,
448
449
                            const char *paramNameOrNil = 0)
{
450
    return Param<TypeTag>::template getRuntime<ParamType>(paramOrGroupName,
451
452
453
                                                          paramNameOrNil);
}

454
455
456
457
458
459
} // namespace Parameters

} // namespace Dumux


#endif