dune-fem  2.8-git
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 
22 namespace 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 
41  std::string value, fileName, defaultValue;
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
Definition: bindguard.hh:11
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
static const std::string & checkParameterExistsString()
Definition: reader.hh:20
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:160
static int rank()
Definition: mpimanager.hh:155