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