1#ifndef DUNE_FEM_IO_PARAMETER_CONTAINER_HH
2#define DUNE_FEM_IO_PARAMETER_CONTAINER_HH
15#include <dune/grid/io/file/dgfparser/dgfparser.hh>
17#include <dune/fem/io/io.hh>
18#include <dune/fem/io/parameter/exceptions.hh>
19#include <dune/fem/io/parameter/reader.hh>
20#include <dune/fem/misc/mpimanager.hh>
31 struct ParameterContainerData
34 static const int solverStatistics = 1;
36 static const int extendedStatistics = 2;
38 static const int parameterOutput = 3;
40 static const int diagnosticsOutput = 4;
42 static const int debugOutput = 5;
46 static const int defaultVerbosityLevel = parameterOutput;
50 enum ShadowStatus { unresolved, resolved, resolving };
54 Value ( std::string v, std::string fn ) : value(
std::move( v ) ), fileName(
std::move( fn ) ) {}
56 std::string value, fileName, defaultValue;
57 bool used =
false, hasDefault =
false;
58 ShadowStatus shadowStatus = unresolved;
61 const std::string *operator() (
const std::string &key,
const std::string *defaultValue )
const;
63 static std::string trim (
const std::string &s )
65 const std::size_t first = s.find_first_not_of(
" \t\n" );
66 return (first != s.npos ? s.substr( first, s.find_last_not_of(
" \t\n" ) + 1 - first ) : std::string());
69 std::string resolveEscape (
const std::string &key, std::string &value )
const;
70 void resolveShadows (
const std::string &key, Value &val )
const;
71 std::string getShadowKey (
const std::string key,
const char delimter, std::string &value )
const;
73 bool verbose (
const int level = defaultVerbosityLevel )
const
77 return (verboseRank == MPIManager::rank() && level <= verbosityLevel);
80 mutable std::map< std::string, Value > map;
81 std::set< std::string > deprecated;
83 int verbosityLevel = 1;
84 bool verbosityLevelPresent =
false;
85 bool verbosityChangedByVerboseRank =
false;
93 class ParameterContainer
94 :
public BasicParameterReader< ParameterContainerData >
96 typedef ParameterContainerData::Value Value;
100 static std::string stripComment (
const std::string &
line );
102 const std::string &insert (
const std::string &key,
const std::string &value,
bool force );
103 bool insert (
const std::string &s, std::queue< std::string > &includes );
105 void processFile (
const std::string &filename );
106 void processIncludes( std::queue< std::string > &includes );
111 operator ParameterReader ()
const {
return ParameterReader( std::ref( parameter_ ) ); }
123 void append (
int &argc,
char **argv );
130 void append (
const std::string &filename )
132 processFile( filename );
142 void append (
const std::string &key,
const std::string &value,
bool force =
false )
144 if( key !=
"paramfile" )
146 curFileName_ =
"program code";
147 insert( key, value, force );
160 std::string
toString(
const T& value )
162 std::stringstream str;
163 str << std::scientific;
175 template<class NumberType, std::enable_if_t< std::is_floating_point< NumberType >::value || std::is_integral< NumberType >::value,
int> = 0 >
176 void append (
const std::string &key, NumberType value,
bool force =
false )
178 assert( key !=
"paramfile" );
179 curFileName_ =
"program code";
180 std::string valueString =
toString( value );
181 insert( key, valueString, force );
192 void appendDGF (
const std::string &filename );
195 void clear () { parameter_.map.clear(); }
198 bool verbose (
const int level = ParameterContainerData::defaultVerbosityLevel )
const
200 return parameter_.verbose( level );
203 std::string commonInputPath ()
const
205 return getValue(
"fem.prefix.input", std::string(
"." ) );
208 std::string commonOutputPath ()
const
210 return getValue(
"fem.prefix", std::string(
"." ) );
227 void write ( std::ostream &out,
bool writeAll =
true )
const;
228 auto write ( )
const;
230 std::map<std::string,std::set<std::pair<std::string,std::string>>> localParameterLog_;
233 std::string curFileName_;
242 struct ParameterContainer::DGFBlock
245 explicit DGFBlock ( std::istream &in ) : BasicBlock( in,
"FemParameter" ) {}
247 bool advance () {
return getnextline(); }
248 std::string getLine ()
const {
return line.str(); }
256 inline const std::string *ParameterContainerData::operator() (
const std::string &key,
const std::string *defaultValue )
const
258 if( deprecated.find( key ) != deprecated.end() )
259 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' deprecated" );
261 std::map< std::string, Value >::iterator pos;
264 const std::string& defaultValueStr = *defaultValue;
268 if( defaultValueStr == checkParameterExistsString() )
270 pos = map.find( key );
271 if( pos == map.end() )
275 Value &val = pos->second;
280 auto info = map.insert( std::make_pair( key, Value( *defaultValue,
"default" ) ) );
281 if( info.second && verbose() )
282 std::cout <<
"Adding default: " << key <<
": " << *defaultValue << std::endl;
286 pos = map.find( key );
288 if( pos == map.end() )
290 Value &val = pos->second;
294 if( val.hasDefault !=
static_cast< bool >( defaultValue ) )
295 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' used with and without default" );
296 if( defaultValue && (val.defaultValue != *defaultValue) )
297 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' used with different default values" );
302 val.hasDefault =
static_cast< bool >( defaultValue );
304 val.defaultValue = *defaultValue;
307 resolveShadows( key, val );
312 inline std::string ParameterContainerData::resolveEscape (
const std::string &key, std::string &value )
const
315 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' contains trailing '$'." );
317 const char escapedChar = value[ 0 ];
318 value.replace( 0, 1,
"" );
320 switch( escapedChar )
325 return std::string(
"" ) + escapedChar;
329 auto pos = map.find( getShadowKey( key,
')', value ) );
330 if( pos == map.end() )
331 DUNE_THROW( ParameterNotFound,
"Parameter '" << key <<
"' not found" );
332 resolveShadows( pos->first, pos->second );
333 return pos->second.value;
337 return trim( executeCommand( getShadowKey( key,
']', value ) ) );
340 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' invalid." );
345 inline void ParameterContainerData::resolveShadows (
const std::string &key, Value &val )
const
347 std::string &realValue = val.value;
348 if( val.shadowStatus == Value::resolved )
351 if ( val.shadowStatus == Value::resolving )
352 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' invalid, contains infinite loop" );
354 val.shadowStatus = Value::resolving;
355 std::string realValueHelper;
356 realValue.swap( realValueHelper );
358 while( !realValueHelper.empty() )
360 std::size_t startPoint = realValueHelper.find_first_of(
'$' );
361 realValue += realValueHelper.substr( 0, startPoint );
363 if( startPoint == std::string::npos )
366 realValueHelper.replace( 0, startPoint+1,
"" );
368 realValue += resolveEscape( key, realValueHelper );
370 val.shadowStatus = Value::resolved;
374 inline std::string ParameterContainerData::getShadowKey (
const std::string key,
const char delimiter, std::string &value )
const
376 std::string shadowKey;
380 std::size_t startPoint = value.find_first_of( std::string(
"$" ) + delimiter );
382 if( startPoint == std::string::npos )
383 DUNE_THROW( ParameterInvalid,
"Parameter '" << key <<
"' invalid." );
385 shadowKey += value.substr( 0, startPoint );
386 const char startChar = value[ startPoint ];
388 value.replace( 0, startPoint+1,
"" );
390 if( startChar == delimiter )
392 assert( startChar ==
'$' );
394 shadowKey += resolveEscape( key, value );
403 inline const std::string &ParameterContainer::insert (
const std::string &key,
const std::string &value,
bool force =
false)
405 auto pos = parameter_.map.find( key );
406 bool paramExists = ( pos != parameter_.map.end() );
407 std::string paramValue;
408 if( force && paramExists )
410 paramValue = pos->second.value;
411 if( paramValue == value )
413 parameter_.map.erase( key );
415 auto info = parameter_.map.insert( std::make_pair( key, Value( value, curFileName_ ) ) );
416 Value &val = info.first->second;
417 if( key ==
"fem.verboserank" )
419 ParameterParser< int >::parse( val.value, parameter_.verboseRank );
420 if( (parameter_.verboseRank < -1) || (parameter_.verboseRank >= MPIManager::size() ) )
421 std::cout <<
"Warning: Parameter 'fem.verboserank' is neither a " <<
"valid rank nor -1." << std::endl;
426 if( ! parameter_.verbosityLevelPresent &&
427 parameter_.verbosityLevel < ParameterContainerData::defaultVerbosityLevel )
429 parameter_.verbosityLevel = ParameterContainerData::defaultVerbosityLevel;
430 parameter_.verbosityChangedByVerboseRank =
true;
434 if( key ==
"fem.verbositylevel" )
437 if( parameter_.verbosityChangedByVerboseRank )
438 parameter_.verbosityLevel = 1;
440 parameter_.verbosityLevelPresent =
true;
442 ParameterParser< int >::parse( val.value, parameter_.verbosityLevel );
443 if( (parameter_.verbosityLevel < 0) || (parameter_.verbosityLevel >= 10 ) )
444 std::cout <<
"Warning: Parameter 'fem.verbositylevel' is neither a " <<
"valid level nor 0." << std::endl;
449 std::cout << curFileName_ <<
"[" << curLineNumber_ <<
"]: ";
451 std::cout <<
"Adding " << key <<
" = " << value << std::endl;
453 std::cout <<
"Ignored " << key <<
" = " << value <<
", using " << val.value << std::endl;
455 std::cout <<
"Replacing " << key <<
" = " << paramValue <<
" by " << value << std::endl;
458 return force ? value : val.value;
462 inline std::string ParameterContainer::stripComment (
const std::string &
line )
465 std::size_t end =
line.find_first_of (
"%#$" );
467 while( (end != std::string::npos) && (
line[end] ==
'$') )
470 end =
line.find_first_of (
"%#$", end+2 );
472 end = std::string::npos;
475 return ParameterContainerData::trim(
line.substr( 0, end ) );
479 inline bool ParameterContainer::insert (
const std::string &s, std::queue< std::string > &includes )
481 const std::size_t
size = s.size();
483 std::size_t key_start = 0;
484 for( ; key_start <
size; ++key_start )
486 if( (s[ key_start ] !=
' ') && (s[ key_start ] !=
'\t') )
490 std::size_t key_end = key_start;
491 for( ; key_end <
size; ++key_end )
493 const char &c = s[ key_end ];
494 if( (c ==
' ') || (c ==
'\t') || (c ==
':') )
498 std::size_t value_start = key_end;
499 for( ; value_start <
size ; ++value_start )
501 if( s[ value_start ] ==
':' )
506 for( ; value_start <
size; ++value_start )
508 if( (s[ value_start ] !=
' ') && (s[ value_start ] !=
'\t') )
512 std::size_t value_end = value_start;
513 for( std::size_t i = 0; i <
size; ++i )
515 if( (s[ i ] !=
' ') && (s[ i ] !=
'\t') )
519 if( value_start >=
size )
522 std::string key = s.substr( key_start, key_end - key_start );
523 std::string value = s.substr( value_start, value_end - value_start );
525 if( key ==
"paramfile" )
526 includes.push( commonInputPath() +
"/" + value );
527 else if( key ==
"deprecated" )
528 parameter_.deprecated.insert( value );
530 insert( key, value );
535 inline void ParameterContainer::processFile (
const std::string &filename )
538 std::cout <<
"Parameter: Processing '" << filename <<
"'..." << std::endl;
540 std::ifstream file( filename );
541 if( !file.is_open() )
543 std::cerr <<
"Warning: Unable to read parameter file '" << filename <<
"'" << std::endl;
547 curFileName_ = filename;
549 std::queue< std::string > includes;
554 std::getline( file,
line );
558 insert(
line, includes );
562 processIncludes( includes );
566 inline void ParameterContainer::processIncludes( std::queue< std::string > &includes )
568 while( !includes.empty() )
571 val.value = includes.front();
573 parameter_.resolveShadows(
"paramfile", val );
574 processFile( val.value );
579 inline void ParameterContainer::append (
int &argc,
char **argv )
581 std::queue< std::string > includes;
582 curFileName_ =
"program arguments";
584 for(
int i = 1 ; i < argc; ++i )
587 if( !insert( std::string( argv[ i ] ), includes ) )
590 std::copy( argv + (i+1), argv + argc, argv + i );
595 processIncludes( includes );
599 inline void ParameterContainer::appendDGF (
const std::string &filename )
602 std::cout <<
"Parameter: Processing DGF '" << filename <<
"'..." << std::endl;
604 std::ifstream file( filename );
605 if( !file.is_open() )
607 std::cerr <<
"Warning: Unable to read DGF file '" << filename <<
"'" << std::endl;
614 DGFBlock block( file );
615 if( !block.isactive() )
618 curFileName_ = filename;
620 std::queue< std::string > includes;
622 while( block.advance() )
625 const std::string
line = stripComment( block.getLine() );
627 insert(
line, includes );
630 processIncludes( includes );
634 inline void ParameterContainer::write ( std::ostream &out,
bool writeAll )
const
636 std::map< std::string, std::map<std::string, std::string> > writeMap;
637 for(
const auto ¶m : parameter_.map )
639 const Value &val = param.second;
640 if( writeAll || !val.hasDefault || (val.used && (val.value != val.defaultValue)) )
641 writeMap[ val.fileName ][ (val.used ?
"":
"# " ) + param.first ] = val.value;
644 for(
const auto &source : writeMap )
646 out <<
"# from " << source.first << std::endl;
647 for(
const auto ¶m : source.second )
648 out << param.first <<
": " << param.second << std::endl;
652 inline auto ParameterContainer::write ()
const
654 std::map< std::string, std::set<std::pair<std::string, std::string>> > writeMap;
655 for(
const auto ¶m : parameter_.map )
657 const Value &val = param.second;
658 writeMap[ val.fileName ].insert( {param.first,val.value} );
std::string toString(Precision p)
map precision to VTK type name
Definition: common.hh:280
#define DUNE_THROW(E, m)
Definition: exceptions.hh:218
constexpr GeometryType line
GeometryType representing a line.
Definition: type.hh:498
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75