dune-fem  2.4.1-rc
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 { return (verboseRank == MPIManager::rank()); }
59 
60  mutable std::map< std::string, Value > map;
61  std::set< std::string > deprecated;
62  int verboseRank = -1;
63  };
64 
65 
66 
67  // ParameterContainer
68  // ------------------
69 
71  : public BasicParameterReader< ParameterContainerData >
72  {
74 
75  struct DGFBlock;
76 
77  static std::string stripComment ( const std::string &line );
78 
79  const std::string &insert ( const std::string &key, const std::string &value );
80  bool insert ( const std::string &s, std::queue< std::string > &includes );
81 
82  void processFile ( const std::string &filename );
83  void processIncludes( std::queue< std::string > &includes );
84 
85  public:
86 
88  operator ParameterReader () const { return ParameterReader( std::ref( parameter_ ) ); }
89 
97  int setVerboseRank( int verboseRank );
98 
109  void append ( int &argc, char **argv );
110 
116  void append ( const std::string &filename )
117  {
118  processFile( filename );
119  }
120 
127  void append ( const std::string &key, const std::string &value )
128  {
129  if( key != "paramfile" )
130  {
131  curFileName_ = "program code";
132  insert( key, value );
133  }
134  else
135  append( value );
136  }
137 
146  void appendDGF ( const std::string &filename );
147 
149  void clear () { parameter_.map.clear(); }
150 
152  bool verbose () const { return parameter_.verbose(); }
153 
154  std::string commonInputPath () const
155  {
156  return getValue( "fem.prefix.input", std::string( "." ) );
157  }
158 
159  std::string commonOutputPath () const
160  {
161  return getValue( "fem.prefix", std::string( "." ) );
162  }
163 
178  void write ( std::ostream &out, bool writeAll = true ) const;
179 
180  private:
181  std::string curFileName_;
182  int curLineNumber_;
183  };
184 
185 
186 
187  // ParameterContainer::DGFBlock
188  // ----------------------------
189 
191  : dgf::BasicBlock
192  {
193  explicit DGFBlock ( std::istream &in ) : BasicBlock( in, "FemParameter" ) {}
194 
195  bool advance () { return getnextline(); }
196  std::string getLine () const { return line.str(); }
197  };
198 
199 
200 
201  // Implementation of ParameterContainerData
202  // ----------------------------------------
203 
204  inline const std::string *ParameterContainerData::operator() ( const std::string &key, const std::string *defaultValue ) const
205  {
206  if( deprecated.find( key ) != deprecated.end() )
207  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' deprecated" );
208 
209  std::map< std::string, Value >::iterator pos;
210  if( defaultValue )
211  {
212  auto info = map.insert( std::make_pair( key, Value( *defaultValue, "default" ) ) );
213  if( info.second && verbose() )
214  std::cout << "Adding default: " << key << " = " << *defaultValue << std::endl;
215  pos = info.first;
216  }
217  else
218  pos = map.find( key );
219 
220  if( pos == map.end() )
221  return nullptr;
222  Value &val = pos->second;
223 
224  if( val.used )
225  {
226  if( val.hasDefault != static_cast< bool >( defaultValue ) )
227  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' used with and without default" );
228  if( defaultValue && (val.defaultValue != *defaultValue) )
229  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' used with different default values" );
230  }
231  else
232  {
233  val.used = true;
234  val.hasDefault = static_cast< bool >( defaultValue );
235  if( defaultValue )
236  val.defaultValue = *defaultValue;
237  }
238 
239  resolveShadows( key, val );
240  return &val.value;
241  }
242 
243 
244  inline std::string ParameterContainerData::resolveEscape ( const std::string &key, std::string &value ) const
245  {
246  if( value.empty() )
247  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' contains trailing '$'." );
248 
249  const char escapedChar = value[ 0 ];
250  value.replace( 0, 1, "" );
251 
252  switch( escapedChar )
253  {
254  case '$':
255  case '%':
256  case '#':
257  return std::string( "" ) + escapedChar;
258 
259  case '(':
260  {
261  auto pos = map.find( getShadowKey( key, ')', value ) );
262  if( pos == map.end() )
263  DUNE_THROW( ParameterNotFound, "Parameter '" << key << "' not found" );
264  resolveShadows( pos->first, pos->second );
265  return pos->second.value;
266  }
267 
268  case '[':
269  return trim( executeCommand( getShadowKey( key, ']', value ) ) );
270 
271  default:
272  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid." );
273  }
274  }
275 
276 
277  inline void ParameterContainerData::resolveShadows ( const std::string &key, Value &val ) const
278  {
279  std::string &realValue = val.value;
280  if( val.shadowStatus == Value::resolved )
281  return;
282 
283  if ( val.shadowStatus == Value::resolving )
284  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid, contains infinite loop" );
285 
287  std::string realValueHelper;
288  realValue.swap( realValueHelper );
289 
290  while( !realValueHelper.empty() )
291  {
292  std::size_t startPoint = realValueHelper.find_first_of( '$' );
293  realValue += realValueHelper.substr( 0, startPoint );
294 
295  if( startPoint == std::string::npos )
296  break;
297 
298  realValueHelper.replace( 0, startPoint+1, "" );
299 
300  realValue += resolveEscape( key, realValueHelper );
301  }
303  }
304 
305 
306  inline std::string ParameterContainerData::getShadowKey ( const std::string key, const char delimiter, std::string &value ) const
307  {
308  std::string shadowKey;
309 
310  while( true )
311  {
312  std::size_t startPoint = value.find_first_of( std::string( "$" ) + delimiter );
313 
314  if( startPoint == std::string::npos )
315  DUNE_THROW( ParameterInvalid, "Parameter '" << key << "' invalid." );
316 
317  shadowKey += value.substr( 0, startPoint );
318  const char startChar = value[ startPoint ];
319 
320  value.replace( 0, startPoint+1, "" );
321 
322  if( startChar == delimiter )
323  return shadowKey;
324  assert( startChar == '$' );
325 
326  shadowKey += resolveEscape( key, value );
327  }
328  }
329 
330 
331 
332  // Implementation of ParameterContainer
333  // ------------------------------------
334 
335  inline const std::string &ParameterContainer::insert ( const std::string &key, const std::string &value )
336  {
337  auto info = parameter_.map.insert( std::make_pair( key, Value( value, curFileName_ ) ) );
338  Value &val = info.first->second;
339 
340  if( verbose() )
341  {
342  std::cout << curFileName_ << "[" << curLineNumber_ << "]: ";
343  if( info.second )
344  std::cout << "Adding " << key << " = " << value << std::endl;
345  else
346  std::cout << "Ignored " << key << " = " << value << ", using " << val.value << std::endl;
347  }
348 
349  return val.value;
350  }
351 
352 
353  inline std::string ParameterContainer::stripComment ( const std::string &line )
354  {
355  std::size_t size = line.size();
356  std::size_t end = line.find_first_of ( "%#$" );
357 
358  while( (end != std::string::npos) && (line[end] =='$') )
359  {
360  if( end+2 < size )
361  end = line.find_first_of ( "%#$", end+2 );
362  else
363  end = std::string::npos;
364  }
365 
366  return ParameterContainerData::trim( line.substr( 0, end ) );
367  }
368 
369 
370  inline bool ParameterContainer::insert ( const std::string &s, std::queue< std::string > &includes )
371  {
372  const std::size_t size = s.size();
373 
374  std::size_t key_start = 0;
375  for( ; key_start < size; ++key_start )
376  {
377  if( (s[ key_start ] != ' ') && (s[ key_start ] != '\t') )
378  break;
379  }
380 
381  std::size_t key_end = key_start;
382  for( ; key_end < size; ++key_end )
383  {
384  const char &c = s[ key_end ];
385  if( (c == ' ') || (c == '\t') || (c == ':') )
386  break;
387  }
388 
389  std::size_t value_start = key_end;
390  for( ; value_start < size ; ++value_start )
391  {
392  if( s[ value_start ] == ':' )
393  break;
394  }
395  ++value_start;
396 
397  for( ; value_start < size; ++value_start )
398  {
399  if( (s[ value_start ] != ' ') && (s[ value_start ] != '\t') )
400  break;
401  }
402 
403  std::size_t value_end = value_start;
404  for( std::size_t i = 0; i < size; ++i )
405  {
406  if( (s[ i ] != ' ') && (s[ i ] != '\t') )
407  value_end = i+1;
408  }
409 
410  if( value_start >= size )
411  return false;
412 
413  std::string key = s.substr( key_start, key_end - key_start );
414  std::string value = s.substr( value_start, value_end - value_start );
415 
416  if( key == "paramfile" )
417  includes.push( commonInputPath() + "/" + value );
418  else if( key == "deprecated" )
419  parameter_.deprecated.insert( value );
420  else
421  {
422  const std::string &actual_value = insert( key, value );
423  if( key == "fem.verboserank" )
424  {
425  ParameterParser< int >::parse( actual_value, parameter_.verboseRank );
426  if( (parameter_.verboseRank < -1) || (parameter_.verboseRank >= MPIManager::size() ) )
427  std::cout << "Warning: Parameter 'fem.verboserank' is neither a " << "valid rank nor -1." << std::endl;
428  }
429  }
430  return true;
431  }
432 
434  {
435  int old = parameter_.verboseRank;
436  parameter_.verboseRank = verboseRank;
437  return old;
438  }
439 
440  inline void ParameterContainer::processFile ( const std::string &filename )
441  {
442  if( verbose() )
443  std::cout << "Parameter: Processing '" << filename << "'..." << std::endl;
444 
445  std::ifstream file( filename );
446  if( !file.is_open() )
447  {
448  std::cerr << "Warning: Unable to read parameter file '" << filename << "'" << std::endl;
449  return;
450  }
451 
452  curFileName_ = filename;
453  curLineNumber_ = 0;
454  std::queue< std::string > includes;
455 
456  while( !file.eof() )
457  {
458  std::string line;
459  std::getline( file, line );
460  curLineNumber_++;
461  line = stripComment( line );
462  if( !line.empty() )
463  insert( line, includes );
464  }
465  file.close();
466 
467  processIncludes( includes );
468  }
469 
470 
471  inline void ParameterContainer::processIncludes( std::queue< std::string > &includes )
472  {
473  while( !includes.empty() )
474  {
475  Value val;
476  val.value = includes.front();
477  includes.pop();
478  parameter_.resolveShadows( "paramfile", val );
479  processFile( val.value );
480  }
481  }
482 
483 
484  inline void ParameterContainer::append ( int &argc, char **argv )
485  {
486  std::queue< std::string > includes;
487  curFileName_ = "program arguments";
488  curLineNumber_ = 0;
489  for( int i = 1 ; i < argc; ++i )
490  {
491  ++curLineNumber_;
492  if( !insert( std::string( argv[ i ] ), includes ) )
493  continue;
494 
495  std::copy( argv + (i+1), argv + argc, argv + i );
496  --i;
497  --argc;
498  }
499 
500  processIncludes( includes );
501  }
502 
503 
504  inline void ParameterContainer::appendDGF ( const std::string &filename )
505  {
506  if( verbose() )
507  std::cout << "Parameter: Processing DGF '" << filename << "'..." << std::endl;
508 
509  std::ifstream file( filename );
510  if( !file.is_open() )
511  {
512  std::cerr << "Warning: Unable to read DGF file '" << filename << "'" << std::endl;
513  return;
514  }
515 
516  if( !DuneGridFormatParser::isDuneGridFormat( file ) )
517  return;
518 
519  DGFBlock block( file );
520  if( !block.isactive() )
521  return;
522 
523  curFileName_ = filename;
524  curLineNumber_ = 0;
525  std::queue< std::string > includes;
526 
527  while( block.advance() )
528  {
529  ++curLineNumber_;
530  const std::string line = stripComment( block.getLine() );
531  if( !line.empty() )
532  insert( line, includes );
533  }
534 
535  processIncludes( includes );
536  }
537 
538 
539  inline void ParameterContainer::write ( std::ostream &out, bool writeAll ) const
540  {
541  std::map< std::string, std::map<std::string, std::string> > writeMap;
542  for( const auto &param : parameter_.map )
543  {
544  const Value &val = param.second;
545  if( writeAll || !val.hasDefault || (val.used && (val.value != val.defaultValue)) )
546  writeMap[ val.fileName ][ (val.used ? "": "# " ) + param.first ] = val.value;
547  }
548 
549  for( const auto &source : writeMap )
550  {
551  out << "# from " << source.first << std::endl;
552  for( const auto &param : source.second )
553  out << param.first << ": " << param.second << std::endl;
554  out << std::endl;
555  }
556  }
557 
558  } // namespace Fem
559 
560 } // namespace Dune
561 
562 #endif // #ifndef DUNE_FEM_IO_PARAMETER_CONTAINER_HH
Value(std::string v, std::string fn)
Definition: container.hh:39
void write(std::ostream &out, bool writeAll=true) const
write the parameter database to a stream
Definition: container.hh:539
static int rank()
Definition: mpimanager.hh:116
int verboseRank
Definition: container.hh:62
Definition: container.hh:190
BasicParameterReader< std::function< const std::string *(const std::string &, const std::string *) > > ParameterReader
Definition: reader.hh:264
static int size()
Definition: mpimanager.hh:121
Definition: io/parameter/exceptions.hh:24
void resolveShadows(const std::string &key, Value &val) const
Definition: container.hh:277
static std::string trim(const std::string &s)
Definition: container.hh:48
ShadowStatus
Definition: container.hh:35
DGFBlock(std::istream &in)
Definition: container.hh:193
std::string fileName
Definition: container.hh:41
const std::string * operator()(const std::string &key, const std::string *defaultValue) const
Definition: container.hh:204
Definition: reader.hh:24
std::string commonInputPath() const
Definition: container.hh:154
Definition: container.hh:33
void appendDGF(const std::string &filename)
add parameters from a DGF file
Definition: container.hh:504
static bool parse(const std::string &s, T &value)
Definition: parser.hh:22
void append(int &argc, char **argv)
add parameters from the command line
Definition: container.hh:484
Definition: coordinate.hh:4
Definition: container.hh:31
std::string getShadowKey(const std::string key, const char delimter, std::string &value) const
Definition: container.hh:306
std::map< std::string, Value > map
Definition: container.hh:60
STL namespace.
std::string resolveEscape(const std::string &key, std::string &value) const
Definition: container.hh:244
void append(const std::string &key, const std::string &value)
add a single parameter to the container
Definition: container.hh:127
void move(ArrayInterface< T > &array, const unsigned int oldOffset, const unsigned int newOffset, const unsigned int length)
Definition: array_inline.hh:38
std::string getLine() const
Definition: container.hh:196
bool verbose() const
obtain the cached value for fem.verbose
Definition: container.hh:152
void append(const std::string &filename)
add parameters from a file
Definition: container.hh:116
Definition: io/parameter/exceptions.hh:15
ShadowStatus shadowStatus
Definition: container.hh:43
bool used
Definition: container.hh:42
bool advance()
Definition: container.hh:195
std::string defaultValue
Definition: container.hh:41
std::string value
Definition: container.hh:41
Definition: container.hh:70
bool hasDefault
Definition: container.hh:42
std::string commonOutputPath() const
Definition: container.hh:159
std::set< std::string > deprecated
Definition: container.hh:61
std::string executeCommand(const std::string &command)
executes a command and return the output
Definition: io.cc:69
bool verbose() const
Definition: container.hh:58
void clear()
clear all parameters
Definition: container.hh:149
int setVerboseRank(int verboseRank)
set the rank for verbose output
Definition: container.hh:433