dune-fem 2.8.0
Loading...
Searching...
No Matches
container.hh
Go to the documentation of this file.
1#ifndef DUNE_FEM_IO_PARAMETER_CONTAINER_HH
2#define DUNE_FEM_IO_PARAMETER_CONTAINER_HH
3
4#include <cassert>
5#include <cstddef>
6
7#include <fstream>
8#include <iostream>
9#include <map>
10#include <queue>
11#include <set>
12#include <string>
13#include <utility>
14
15#include <dune/grid/io/file/dgfparser/dgfparser.hh>
16
17#include <dune/fem/io/io.hh>
21
22namespace Dune
23{
24
25 namespace Fem
26 {
27
28 // ParameterContainerData
29 // ----------------------
30
32 {
33 struct Value
34 {
36
37 Value () = default;
38
39 Value ( std::string v, std::string fn ) : value( std::move( v ) ), fileName( std::move( fn ) ) {}
40
42 bool used = false, hasDefault = false;
44 };
45
46 const std::string *operator() ( const std::string &key, const std::string *defaultValue ) const;
47
48 static std::string trim ( const std::string &s )
49 {
50 const std::size_t first = s.find_first_not_of( " \t\n" );
51 return (first != s.npos ? s.substr( first, s.find_last_not_of( " \t\n" ) + 1 - first ) : std::string());
52 }
53
54 std::string resolveEscape ( const std::string &key, std::string &value ) const;
55 void resolveShadows ( const std::string &key, Value &val ) const;
56 std::string getShadowKey ( const std::string key, const char delimter, std::string &value ) const;
57
58 bool verbose () const {
59 return (verboseRank == MPIManager::rank());
60 }
61
62 mutable std::map< std::string, Value > map;
63 std::set< std::string > deprecated;
64 int verboseRank = -1;
65 };
66
67
68
69 // ParameterContainer
70 // ------------------
71
73 : public BasicParameterReader< ParameterContainerData >
74 {
76
77 struct DGFBlock;
78
79 static std::string stripComment ( const std::string &line );
80
81 const std::string &insert ( const std::string &key, const std::string &value, bool force );
82 bool insert ( const std::string &s, std::queue< std::string > &includes );
83
84 void processFile ( const std::string &filename );
85 void processIncludes( std::queue< std::string > &includes );
86
87 public:
88
90 operator ParameterReader () const { return ParameterReader( std::ref( parameter_ ) ); }
91
102 void append ( int &argc, char **argv );
103
109 void append ( const std::string &filename )
110 {
111 processFile( filename );
112 }
113
121 void append ( const std::string &key, const std::string &value, bool force = false )
122 {
123 if( key != "paramfile" )
124 {
125 curFileName_ = "program code";
126 insert( key, value, force );
127 }
128 else
129 append( value );
130 }
131
132
138 template <class T>
139 std::string toString( const T& value )
140 {
141 std::stringstream str;
142 str << std::scientific;
143 str << value;
144 return str.str();
145 }
146
154 template<class NumberType, std::enable_if_t< std::is_floating_point< NumberType >::value || std::is_integral< NumberType >::value, int> = 0 >
155 void append ( const std::string &key, NumberType value, bool force = false )
156 {
157 assert( key != "paramfile" );
158 curFileName_ = "program code";
159 std::string valueString = toString( value );
160 insert( key, valueString, force );
161 }
162
171 void appendDGF ( const std::string &filename );
172
174 void clear () { parameter_.map.clear(); }
175
177 bool verbose () const { return parameter_.verbose(); }
178
179 std::string commonInputPath () const
180 {
181 return getValue( "fem.prefix.input", std::string( "." ) );
182 }
183
184 std::string commonOutputPath () const
185 {
186 return getValue( "fem.prefix", std::string( "." ) );
187 }
188
203 void write ( std::ostream &out, bool writeAll = true ) const;
204
205 private:
206 std::string curFileName_;
207 int curLineNumber_;
208 };
209
210
211
212 // ParameterContainer::DGFBlock
213 // ----------------------------
214
216 : dgf::BasicBlock
217 {
218 explicit DGFBlock ( std::istream &in ) : BasicBlock( in, "FemParameter" ) {}
219
220 bool advance () { return getnextline(); }
221 std::string getLine () const { return line.str(); }
222 };
223
224
225
226 // Implementation of ParameterContainerData
227 // ----------------------------------------
228
229 inline const std::string *ParameterContainerData::operator() ( const std::string &key, const std::string *defaultValue ) const
230 {
231 if( deprecated.find( key ) != deprecated.end() )
232 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' deprecated" );
233
234 std::map< std::string, Value >::iterator pos;
235 if( defaultValue )
236 {
237 const std::string& defaultValueStr = *defaultValue;
238 // only check existence, do not check default values and the like
239 // when the default string has the value of checkParameterExistsString
240 // this is to avoid problems with default and non-default parameters
241 if( defaultValueStr == checkParameterExistsString() )
242 {
243 pos = map.find( key );
244 if( pos == map.end() )
245 return nullptr;
246 else
247 {
248 Value &val = pos->second;
249 return &val.value ;
250 }
251 }
252
253 auto info = map.insert( std::make_pair( key, Value( *defaultValue, "default" ) ) );
254 if( info.second && verbose() )
255 std::cout << "Adding default: " << key << ": " << *defaultValue << std::endl;
256 pos = info.first;
257 }
258 else
259 pos = map.find( key );
260
261 if( pos == map.end() )
262 return nullptr;
263 Value &val = pos->second;
264
265 if( val.used )
266 {
267 if( val.hasDefault != static_cast< bool >( defaultValue ) )
268 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' used with and without default" );
269 if( defaultValue && (val.defaultValue != *defaultValue) )
270 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' used with different default values" );
271 }
272 else
273 {
274 val.used = true;
275 val.hasDefault = static_cast< bool >( defaultValue );
276 if( defaultValue )
277 val.defaultValue = *defaultValue;
278 }
279
280 resolveShadows( key, val );
281 return &val.value;
282 }
283
284
285 inline std::string ParameterContainerData::resolveEscape ( const std::string &key, std::string &value ) const
286 {
287 if( value.empty() )
288 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' contains trailing '$'." );
289
290 const char escapedChar = value[ 0 ];
291 value.replace( 0, 1, "" );
292
293 switch( escapedChar )
294 {
295 case '$':
296 case '%':
297 case '#':
298 return std::string( "" ) + escapedChar;
299
300 case '(':
301 {
302 auto pos = map.find( getShadowKey( key, ')', value ) );
303 if( pos == map.end() )
304 DUNE_THROW( ParameterNotFound, "Parameter '" << key << "' not found" );
305 resolveShadows( pos->first, pos->second );
306 return pos->second.value;
307 }
308
309 case '[':
310 return trim( executeCommand( getShadowKey( key, ']', value ) ) );
311
312 default:
313 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid." );
314 }
315 }
316
317
318 inline void ParameterContainerData::resolveShadows ( const std::string &key, Value &val ) const
319 {
320 std::string &realValue = val.value;
321 if( val.shadowStatus == Value::resolved )
322 return;
323
324 if ( val.shadowStatus == Value::resolving )
325 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid, contains infinite loop" );
326
328 std::string realValueHelper;
329 realValue.swap( realValueHelper );
330
331 while( !realValueHelper.empty() )
332 {
333 std::size_t startPoint = realValueHelper.find_first_of( '$' );
334 realValue += realValueHelper.substr( 0, startPoint );
335
336 if( startPoint == std::string::npos )
337 break;
338
339 realValueHelper.replace( 0, startPoint+1, "" );
340
341 realValue += resolveEscape( key, realValueHelper );
342 }
344 }
345
346
347 inline std::string ParameterContainerData::getShadowKey ( const std::string key, const char delimiter, std::string &value ) const
348 {
349 std::string shadowKey;
350
351 while( true )
352 {
353 std::size_t startPoint = value.find_first_of( std::string( "$" ) + delimiter );
354
355 if( startPoint == std::string::npos )
356 DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid." );
357
358 shadowKey += value.substr( 0, startPoint );
359 const char startChar = value[ startPoint ];
360
361 value.replace( 0, startPoint+1, "" );
362
363 if( startChar == delimiter )
364 return shadowKey;
365 assert( startChar == '$' );
366
367 shadowKey += resolveEscape( key, value );
368 }
369 }
370
371
372
373 // Implementation of ParameterContainer
374 // ------------------------------------
375
376 inline const std::string &ParameterContainer::insert ( const std::string &key, const std::string &value, bool force = false)
377 {
378 auto pos = parameter_.map.find( key );
379 bool paramExists = ( pos != parameter_.map.end() );
380 std::string paramValue;
381 if( force && paramExists )
382 {
383 paramValue = pos->second.value;
384 if( paramValue == value )
385 return value;
386 parameter_.map.erase( key );
387 }
388 auto info = parameter_.map.insert( std::make_pair( key, Value( value, curFileName_ ) ) );
389 Value &val = info.first->second;
390 if( key == "fem.verboserank" )
391 {
394 std::cout << "Warning: Parameter 'fem.verboserank' is neither a " << "valid rank nor -1." << std::endl;
395 }
396
397 if( verbose() )
398 {
399 std::cout << curFileName_ << "[" << curLineNumber_ << "]: ";
400 if( !paramExists )
401 std::cout << "Adding " << key << " = " << value << std::endl;
402 else if ( !force )
403 std::cout << "Ignored " << key << " = " << value << ", using " << val.value << std::endl;
404 else
405 std::cout << "Replacing " << key << " = " << paramValue << " by " << value << std::endl;
406 }
407
408 return force ? value : val.value;
409 }
410
411
412 inline std::string ParameterContainer::stripComment ( const std::string &line )
413 {
414 std::size_t size = line.size();
415 std::size_t end = line.find_first_of ( "%#$" );
416
417 while( (end != std::string::npos) && (line[end] =='$') )
418 {
419 if( end+2 < size )
420 end = line.find_first_of ( "%#$", end+2 );
421 else
422 end = std::string::npos;
423 }
424
425 return ParameterContainerData::trim( line.substr( 0, end ) );
426 }
427
428
429 inline bool ParameterContainer::insert ( const std::string &s, std::queue< std::string > &includes )
430 {
431 const std::size_t size = s.size();
432
433 std::size_t key_start = 0;
434 for( ; key_start < size; ++key_start )
435 {
436 if( (s[ key_start ] != ' ') && (s[ key_start ] != '\t') )
437 break;
438 }
439
440 std::size_t key_end = key_start;
441 for( ; key_end < size; ++key_end )
442 {
443 const char &c = s[ key_end ];
444 if( (c == ' ') || (c == '\t') || (c == ':') )
445 break;
446 }
447
448 std::size_t value_start = key_end;
449 for( ; value_start < size ; ++value_start )
450 {
451 if( s[ value_start ] == ':' )
452 break;
453 }
454 ++value_start;
455
456 for( ; value_start < size; ++value_start )
457 {
458 if( (s[ value_start ] != ' ') && (s[ value_start ] != '\t') )
459 break;
460 }
461
462 std::size_t value_end = value_start;
463 for( std::size_t i = 0; i < size; ++i )
464 {
465 if( (s[ i ] != ' ') && (s[ i ] != '\t') )
466 value_end = i+1;
467 }
468
469 if( value_start >= size )
470 return false;
471
472 std::string key = s.substr( key_start, key_end - key_start );
473 std::string value = s.substr( value_start, value_end - value_start );
474
475 if( key == "paramfile" )
476 includes.push( commonInputPath() + "/" + value );
477 else if( key == "deprecated" )
478 parameter_.deprecated.insert( value );
479 else
480 insert( key, value );
481 return true;
482 }
483
484
485 inline void ParameterContainer::processFile ( const std::string &filename )
486 {
487 if( verbose() )
488 std::cout << "Parameter: Processing '" << filename << "'..." << std::endl;
489
490 std::ifstream file( filename );
491 if( !file.is_open() )
492 {
493 std::cerr << "Warning: Unable to read parameter file '" << filename << "'" << std::endl;
494 return;
495 }
496
497 curFileName_ = filename;
498 curLineNumber_ = 0;
499 std::queue< std::string > includes;
500
501 while( !file.eof() )
502 {
503 std::string line;
504 std::getline( file, line );
505 curLineNumber_++;
506 line = stripComment( line );
507 if( !line.empty() )
508 insert( line, includes );
509 }
510 file.close();
511
512 processIncludes( includes );
513 }
514
515
516 inline void ParameterContainer::processIncludes( std::queue< std::string > &includes )
517 {
518 while( !includes.empty() )
519 {
520 Value val;
521 val.value = includes.front();
522 includes.pop();
523 parameter_.resolveShadows( "paramfile", val );
524 processFile( val.value );
525 }
526 }
527
528
529 inline void ParameterContainer::append ( int &argc, char **argv )
530 {
531 std::queue< std::string > includes;
532 curFileName_ = "program arguments";
533 curLineNumber_ = 0;
534 for( int i = 1 ; i < argc; ++i )
535 {
536 ++curLineNumber_;
537 if( !insert( std::string( argv[ i ] ), includes ) )
538 continue;
539
540 std::copy( argv + (i+1), argv + argc, argv + i );
541 --i;
542 --argc;
543 }
544
545 processIncludes( includes );
546 }
547
548
549 inline void ParameterContainer::appendDGF ( const std::string &filename )
550 {
551 if( verbose() )
552 std::cout << "Parameter: Processing DGF '" << filename << "'..." << std::endl;
553
554 std::ifstream file( filename );
555 if( !file.is_open() )
556 {
557 std::cerr << "Warning: Unable to read DGF file '" << filename << "'" << std::endl;
558 return;
559 }
560
561 if( !DuneGridFormatParser::isDuneGridFormat( file ) )
562 return;
563
564 DGFBlock block( file );
565 if( !block.isactive() )
566 return;
567
568 curFileName_ = filename;
569 curLineNumber_ = 0;
570 std::queue< std::string > includes;
571
572 while( block.advance() )
573 {
574 ++curLineNumber_;
575 const std::string line = stripComment( block.getLine() );
576 if( !line.empty() )
577 insert( line, includes );
578 }
579
580 processIncludes( includes );
581 }
582
583
584 inline void ParameterContainer::write ( std::ostream &out, bool writeAll ) const
585 {
586 std::map< std::string, std::map<std::string, std::string> > writeMap;
587 for( const auto &param : parameter_.map )
588 {
589 const Value &val = param.second;
590 if( writeAll || !val.hasDefault || (val.used && (val.value != val.defaultValue)) )
591 writeMap[ val.fileName ][ (val.used ? "": "# " ) + param.first ] = val.value;
592 }
593
594 for( const auto &source : writeMap )
595 {
596 out << "# from " << source.first << std::endl;
597 for( const auto &param : source.second )
598 out << param.first << ": " << param.second << std::endl;
599 out << std::endl;
600 }
601 }
602
603 } // namespace Fem
604
605} // namespace Dune
606
607#endif // #ifndef DUNE_FEM_IO_PARAMETER_CONTAINER_HH
STL namespace.
Definition: bindguard.hh:11
static const std::string & checkParameterExistsString()
Definition: reader.hh:20
std::string executeCommand(const std::string &command)
executes a command and return the output
Definition: io.cc:70
BasicParameterReader< std::function< const std::string *(const std::string &, const std::string *) > > ParameterReader
Definition: reader.hh:315
Definition: container.hh:32
void resolveShadows(const std::string &key, Value &val) const
Definition: container.hh:318
std::string getShadowKey(const std::string key, const char delimter, std::string &value) const
Definition: container.hh:347
static std::string trim(const std::string &s)
Definition: container.hh:48
int verboseRank
Definition: container.hh:64
const std::string * operator()(const std::string &key, const std::string *defaultValue) const
Definition: container.hh:229
std::string resolveEscape(const std::string &key, std::string &value) const
Definition: container.hh:285
bool verbose() const
Definition: container.hh:58
std::map< std::string, Value > map
Definition: container.hh:62
std::set< std::string > deprecated
Definition: container.hh:63
Definition: container.hh:34
std::string value
Definition: container.hh:41
ShadowStatus
Definition: container.hh:35
@ resolved
Definition: container.hh:35
@ resolving
Definition: container.hh:35
@ unresolved
Definition: container.hh:35
bool hasDefault
Definition: container.hh:42
Value(std::string v, std::string fn)
Definition: container.hh:39
std::string defaultValue
Definition: container.hh:41
ShadowStatus shadowStatus
Definition: container.hh:43
bool used
Definition: container.hh:42
std::string fileName
Definition: container.hh:41
Definition: container.hh:74
std::string commonInputPath() const
Definition: container.hh:179
void clear()
clear all parameters
Definition: container.hh:174
void append(const std::string &filename)
add parameters from a file
Definition: container.hh:109
void write(std::ostream &out, bool writeAll=true) const
write the parameter database to a stream
Definition: container.hh:584
std::string toString(const T &value)
A helper function to convert numbers to scientific strings.
Definition: container.hh:139
bool verbose() const
obtain the cached value for fem.verbose
Definition: container.hh:177
void append(const std::string &key, const std::string &value, bool force=false)
add a single parameter to the container
Definition: container.hh:121
void append(const std::string &key, NumberType value, bool force=false)
add a single Floating number parameter to the container
Definition: container.hh:155
void append(int &argc, char **argv)
add parameters from the command line
Definition: container.hh:529
void appendDGF(const std::string &filename)
add parameters from a DGF file
Definition: container.hh:549
std::string commonOutputPath() const
Definition: container.hh:184
Definition: container.hh:217
bool advance()
Definition: container.hh:220
DGFBlock(std::istream &in)
Definition: container.hh:218
std::string getLine() const
Definition: container.hh:221
Definition: io/parameter/exceptions.hh:17
Definition: io/parameter/exceptions.hh:26
static bool parse(const std::string &s, T &value)
Definition: parser.hh:22
Definition: reader.hh:31
T getValue(const std::string &key) const
get mandatory parameter
Definition: reader.hh:159
ParameterContainerData parameter_
Definition: reader.hh:307
Definition: grcommon.hh:31
static int size()
Definition: mpimanager.hh:406
static int rank()
Definition: mpimanager.hh:401