Commits

Michael Kuhlen committed 9433149

Adding libconfig parameter control stuff to control/. This compiles, but there's no functionality yet.

  • Participants
  • Parent commits 5bdb648

Comments (0)

Files changed (25)

src/enzo/Makefile

 #-----------------------------------------------------------------------
 
 .PHONY: autogen
-autogen: io/auto_show_config.C io/auto_show_flags.C io/auto_show_version.C io/auto_show_compile_options.C
+autogen: io/auto_show_config.C io/auto_show_flags.C io/auto_show_version.C io/auto_show_compile_options.C control/auto_defaults_string.h
 
 # Force update of auto_show_config.C
 
 io/auto_show_compile_options.C:
 	-@python $(UTILS_DIR)/create_config_info.py
 
+# Force update of auto_defaults_string.h
+
+.PHONY: control/auto_defaults_string.h
+control/auto_defaults_string.h:
+	-@awk 'BEGIN {print "char defaults_string[] = "}; {gsub(/"/,"\\\""); print "  \""$$0"\\n\""}; END {print "  \"\";"}' < control/defaults.cfg > control/auto_defaults_string.h
+
 #-----------------------------------------------------------------------
 # Generate dependency file
 #-----------------------------------------------------------------------
           $(BUILD_DIR)/*.h \
           $(GEN_DIR)/*.C $(GEN_DIR)/*.h \
           io/auto_show*.C hydro_rk/*.o *.oo hydro_rk/*.oo \
-          uuid/*.oo DEPEND TAGS \
-          libconfig/*.o 
+          uuid/*.oo DEPEND TAGS
 	-@touch DEPEND
 
 #-----------------------------------------------------------------------

src/enzo/build/config/Make.config.objects

         TemperatureFieldToolsForComptonHeating.o \
 	WritePhotonSources.o
 
+#-----------------------------------------------------------------------
+# Objects for hydro_rk
+#-----------------------------------------------------------------------
+
 OBJS_HYDRO_RK = \
 	hydro_rk/ModifiedBesselFunctions.o \
 	hydro_rk/AGNDiskInitialize.o \
 	hydro_rk/Riemann_HLLD_MHD.o \
 	hydro_rk/Riemann_LLF_MHD.o
 
+#-----------------------------------------------------------------------
 # Objects for the CUDA GPU-computing support
+#-----------------------------------------------------------------------
+
 OBJS_ECUDA_ALL = \
 	hydro_rk/CUDA_Rec_PLM.o \
 	hydro_rk/HydroSweep_CUDA.o \

src/enzo/control/Make.module.objects

 	InterpretCommandLine.o \
 	SetDefaultGlobalValues.o \
 	SetLevelTimeStep.o \
+        ParameterControl.o \
+        ParameterLibconfigBackend.o \
 
+
+# ENZO BUILD SYSTEM DIRECTORY MODULE
+#
+#   control/libconfig
+#
+
+vpath %.C   control/libconfig/
+vpath %.c   control/libconfig/
+
+ENZO_OBJS +=\
+        libconfig.o \
+        libconfigcpp.o \
+        scanner.o \
+        scanctx.o \
+        strbuf.o \
+        grammar.o \

src/enzo/control/ParameterBackends.h

+#ifndef PARAMETERBACKENDMGR_H
+#define PARAMETERBACKENDMGR_H
+
+#include <string>
+#include <vector>
+#include <map>
+
+#define MAX_PARAMETERS 1024
+#define MAX_PARAM_LENGTH 1024
+
+// interpreter abstract base class
+class interpreter
+{
+public:
+	explicit interpreter( std::string fname )
+	{ }
+	
+	virtual ~interpreter()
+	{ }
+	
+	virtual int query( std::string key, std::string& ret ) = 0;
+	virtual int query_list( std::string key, std::vector< std::string >& ret ) = 0;
+	
+	virtual size_t size( std::string key ) = 0;
+	
+	virtual bool dump( char fname[], char header_string[]=NULL ) = 0;
+	
+	virtual bool remove( std::string key ) = 0;
+
+	virtual bool update( std::string input_string, bool from_file=false, bool overwrite=false ) = 0;
+
+	virtual bool set( std::string key, int value ) = 0;
+	virtual bool set( std::string key, long long value ) = 0;
+	virtual bool set( std::string key, double value ) = 0;
+	virtual bool set( std::string key, bool value ) = 0;
+	virtual bool set( std::string key, char value[] ) = 0;
+	
+	virtual bool set_list( std::string key, size_t n, const int* value ) = 0;
+	virtual bool set_list( std::string key, size_t n, const long long* value ) = 0;
+	virtual bool set_list( std::string key, size_t n, const double* value ) = 0;
+	virtual bool set_list( std::string key, size_t n, const bool* value ) = 0;
+	virtual bool set_list( std::string key, size_t n, char* value[] ) = 0;
+	
+
+};
+
+// abstract factory pattern
+struct interpreter_creator
+{
+  virtual interpreter* create( std::string fname, std::string defaults ) const = 0;
+	virtual ~interpreter_creator() { }
+};
+
+std::map< std::string, interpreter_creator*>& get_interpreter();
+
+template< class Derived >
+struct interpreter_creator_concrete : public interpreter_creator
+{
+	interpreter_creator_concrete( const std::string& interpreter_name )
+	{
+		get_interpreter()[ interpreter_name ] = this;
+	}
+	
+	interpreter * create( std::string fname, std::string defaults ) const
+	{
+	  return new Derived( fname, defaults );
+	}
+	
+};
+
+#include <stdexcept>
+
+//... helper stuff
+//! runtime error that is thrown if type conversion fails
+class ErrInvalidConversion : public std::runtime_error{
+public:
+	ErrInvalidConversion( std::string errmsg )
+	: std::runtime_error( errmsg )
+	{}
+};
+
+#endif

src/enzo/control/ParameterControl.C

+#include "ParameterControl.h"
+
+#include <iostream>
+
+template<>
+void Configuration::GetScalar<char*>( char*& str, const char* key, ... ) const
+{
+	va_list argptr;
+	va_start(argptr, key);
+	va_end(argptr);
+	vsprintf(argbuf,key,argptr);
+
+	std::string strval;
+	int status = 0;
+	status = the_interpreter->query(std::string(argbuf),strval);	
+	if( status != 1 ) {
+	  fprintf(stderr, "Could not find parameter <%s>.\n",argbuf);
+	  throw std::runtime_error("parameter not found!");
+	  
+	}
+	
+	strcpy( str, strval.c_str() );
+}
+
+
+
+template<>
+void Configuration::GetArray<char*>( char** val, const char* key, ... ) const
+{
+	va_list argptr;
+	va_start(argptr, key);
+	va_end(argptr);
+	vsprintf(argbuf,key,argptr);
+	
+	std::vector<std::string> s;
+	int status = 0;
+	the_interpreter->query_list(std::string(argbuf),s);
+	if( status != 1 ) {
+	  
+	  fprintf(stderr, "Could not find parameter <%s>.\n",argbuf);
+	  throw std::runtime_error("parameter not found!");
+	}
+	
+
+	for( size_t i=0; i<s.size(); ++i )
+	  {
+		strcpy(*val,s[i].c_str());
+		++val;
+	  }
+}
+
+
+
+std::map< std::string, interpreter_creator*>& get_interpreter()
+{
+	static std::map< std::string, interpreter_creator* > interpreter_map;
+	return interpreter_map;
+}
+
+

src/enzo/control/ParameterControl.h

+#ifndef PARAMETER_CONTROL_H
+#define PARAMETER_CONTROL_H
+
+#include <map>
+#include <cstring>
+#include <stdexcept>
+#include <vector>
+#include <sstream>
+#include <typeinfo>
+#include <cstdarg>
+#include <cstdio>
+
+#include <iostream>
+
+#include "ParameterBackends.h"
+
+/*********************************************************************/
+// SOME HELPER FUNCTIONS
+
+//! converts between different variable types
+/*!
+ *  The main purpose of this function is to parse and convert
+ *  a string argument into numbers, booleans, etc...
+ * @param ival the input value (typically a std::string)
+ * @param oval the interpreted/converted value
+ */
+template <class in_value, class out_value>
+inline void convert( const in_value & ival, out_value & oval) 
+{
+	std::stringstream ss;
+	ss << ival; //.. insert value into stream
+	ss >> oval; //.. retrieve value from stream
+	
+	if (! ss.eof()) {
+		//.. conversion error
+		//std::cerr << "Error: conversion of \'" << ival << "\' failed." << std::endl;
+		throw std::runtime_error(std::string("invalid conversion to ")+typeid(out_value).name()+'.');
+	}
+}
+
+
+template<>
+inline void convert<std::string,std::string>( const std::string & ival, std::string & oval)
+{
+	oval = ival;
+}
+
+
+
+//... actual configuration class
+
+class Configuration
+{
+        interpreter_creator *ic;
+        interpreter* the_interpreter;
+
+	char *argbuf;
+	
+public:
+	
+	Configuration( void )
+	{
+		ic = NULL;
+		the_interpreter = NULL;
+
+		argbuf = new char[1024];
+	}
+	
+	void Initialize( std::string interpreter_name, std::string input_file, const char defaults_string[] )
+	{
+		if( the_interpreter != NULL ) delete the_interpreter;
+		
+		ic = get_interpreter()[interpreter_name];
+		the_interpreter = ic->create( input_file, std::string(defaults_string) );
+	}
+
+	void Update( const char input_string[] )
+	{
+	  // update the current configuration
+	  if( ! the_interpreter->update( std::string(input_string) ) )
+	    {
+	      fprintf(stderr, "Could not update parameter.\n");
+	      throw std::runtime_error("Error updating parameters.");
+	    }
+	  
+	}
+
+	void Dump( char fname[], char header_string[]=NULL )
+	{
+		// dump current configuration to a file
+	  if( ! the_interpreter->dump( fname, header_string ) )
+		{
+			fprintf(stderr, "Could not write parameters to file \'%s\'.\n", fname );
+			throw std::runtime_error("Error writing parameters to file.");
+		}
+	}
+
+	~Configuration()
+	{
+		delete the_interpreter;
+		delete[] argbuf;
+	}
+
+	// eventually...
+	//int PutScalar(...)
+	//int PutArray(...)
+	
+	void Remove( const char* key, ... ) const
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);
+		
+		int status = 0;
+		status = the_interpreter->remove(std::string(argbuf));
+		
+		if( status != 1 ) {
+			fprintf(stderr, "Could not remove <%s> from parameter file.\n",argbuf);
+			throw std::runtime_error("Could not remove a parameter.");
+		}	
+	}
+	
+
+	template< typename T >
+	void GetScalar( T& val, const char* key, ... ) const
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);		
+
+		std::string strval;
+		int status = 0;
+		status = the_interpreter->query(std::string(argbuf),strval);
+		if( status != 1 ) {
+		  
+		  fprintf(stderr, "Could not find parameter <%s>.\n",argbuf);
+		  throw std::runtime_error("parameter not found!");
+		}
+
+		convert<std::string,T>(strval,val);
+	}
+	
+	template< typename T >
+	void SetScalar( const T& val, const char* key, ... )
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);		
+		
+		std::string strval;
+		int status = 0;
+		status = the_interpreter->set(std::string(argbuf),val);
+		if( status != 1 ) {
+			fprintf(stderr, "Could not set <%s> in parameter file.\n",argbuf);
+			throw std::runtime_error("Could not assign parameter!");	
+		}
+	}
+	
+	
+	template< class T >
+	void GetArray( T* val, const char* key, ... ) const
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);
+		
+		std::vector<std::string> s;
+		int status = 0;
+		status = the_interpreter->query_list(std::string(argbuf),s);
+		if( status != 1 ) {
+		  
+		  fprintf(stderr, "Could not find parameter <%s>.\n",argbuf);
+		}
+		
+		for( size_t i=0; i<s.size(); ++i )
+		  {
+		    convert<std::string,T>(s[i],*val);
+		    ++val;
+		  }
+	}
+	
+	template< typename T >
+	void SetArray( T* val, size_t nelem, const char* key, ... ) const
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);
+		
+		int status = 0;
+		status = the_interpreter->set_list( std::string(argbuf), nelem, val);
+		if( status != 1 ) {
+			fprintf(stderr, "Could not set <%s> in parameter file.\n",argbuf);
+			throw std::runtime_error("Could not assign parameter!");	
+		}
+	}
+		
+	size_t Size( const char* key, ... ) const
+	{
+		va_list argptr;
+		va_start(argptr, key);
+		va_end(argptr);
+		vsprintf(argbuf,key,argptr);
+		
+		return the_interpreter->size(std::string(argbuf));
+		
+	}
+	
+};
+
+
+
+template<>
+void Configuration::GetScalar<char*>( char*& str, const char* key, ... ) const;
+
+template<>
+void Configuration::GetArray<char*>( char** val, const char* key, ... ) const;
+
+/*********************************************************************/
+/*********************************************************************/
+
+
+/*********************************************************************/
+/*********************************************************************/
+/*********************************************************************/
+
+
+#endif

src/enzo/control/ParameterLibconfigBackend.C

+// libconfig style parameter file wrapper
+
+#include <iostream>
+#include <string>
+#include <stdexcept>
+#include <vector>
+#include <sstream>
+#include <iomanip>
+#include <stdexcept>
+
+#include "string.h"
+
+#include "ParameterBackends.h"
+
+#include "libconfig/libconfig.h"
+//using namespace libconfig;
+
+// set this for verbose comments to stdout.
+int verbose_paramconfig = 0;
+
+const char* var_types[9] = { "NONE", "GROUP", "INT", "INT64", "FLOAT", "STRING", "BOOL", "ARRAY", "LIST" };
+
+class enzo_libconfig_backend : public interpreter
+{
+protected:
+  std::string fname_;
+  config_t cfg_;
+  
+  char strbuf_[2048];
+  
+  
+protected:
+  
+  // splits input string 'str' into substrings 'results' delimited by 'delim'
+  size_t string_split( std::string str, const std::string delim, std::vector<std::string>& results ) {
+    size_t i0 = 0;
+    while( (i0 = str.find_first_of(delim)) != str.npos ) {
+      if( i0 > 0l )
+	results.push_back( str.substr(0,i0) );
+      str = str.substr(i0+1);
+    }
+    
+    if( str.length() > 0l )
+      results.push_back(str);
+    
+    return results.size();
+  }
+  
+  // Checks that the types between two setting match.
+  int check_types(config_setting_t *s_old, config_setting_t *s_new, char *path) {
+    short old_type = s_old->type;
+    short new_type = s_new->type;
+    
+    // A type mismatch throws an error, unless it's one of these two
+    // cases:
+    //
+    // (a) old_type == float, new_type == int64
+    // (b) old_type == bool, new_type == int64
+    
+    if(old_type != new_type) {
+
+      if( (old_type == CONFIG_TYPE_FLOAT) && 
+	  (new_type == CONFIG_TYPE_INT64) ) {
+
+	s_new->type = old_type;
+	(s_new->value).fval = (double) (s_new->value).llval;
+      } else if( (old_type == CONFIG_TYPE_BOOL) &&
+		 (new_type == CONFIG_TYPE_INT64) ) {
+
+	s_new->type = old_type;
+      } else {
+	std::string error_message;
+	
+	error_message = "Type mismatch for parameter \"" + std::string(path) + "\": old type = " + std::string(var_types[old_type]) + ", new type = " + std::string(var_types[new_type]) + ".";
+	
+	throw std::runtime_error(error_message);
+      }
+    }
+
+    return 1;
+  }
+
+
+  // returns the setting pointer to the element, creating all groups along the way
+  config_setting_t *create_branch_if_necessary( std::string key, int setting_type ) {
+    std::vector<std::string> split_key;
+    config_setting_t *sptr = config_root_setting( &cfg_ );
+    config_setting_t *next = NULL;
+    
+    string_split( key, ".", split_key );
+    
+    for( size_t i=0; i<split_key.size()-1; ++i ) {
+      next = config_setting_get_member( sptr, split_key[i].c_str() );
+      if( next == NULL )
+	next = config_setting_add( sptr, split_key[i].c_str(), CONFIG_TYPE_GROUP );
+      sptr = next;
+    }
+    
+    next = config_setting_get_member( sptr, split_key.back().c_str() );
+    if( next == NULL )
+      next = config_setting_add( sptr, split_key.back().c_str(), setting_type );
+    
+    return next;
+  }
+  
+  int update_parameters(config_setting_t *setting, char *path, bool overwrite=false) {
+    char this_path[MAX_PARAM_LENGTH+1];
+    this_path[0] = 0;
+    
+    if(setting->name) {
+      if(path[0]==0) {
+	
+	//make sure new path length does not exceed MAX_PARAM_LENGTH
+	if(strlen(setting->name) > MAX_PARAM_LENGTH)
+	  throw std::runtime_error("Path length exceeds MAX_PARAM_LENGTH!\n");
+	
+	sprintf(this_path,"%s",setting->name);
+      }
+      else {
+	
+	//make sure new path length does not exceed MAX_PARAM_LENGTH
+	if(strlen(path) + strlen(setting->name) > MAX_PARAM_LENGTH)
+	  throw std::runtime_error("Path length exceeds MAX_PARAM_LENGTH!\n");
+	
+	sprintf(this_path,"%s.%s",path,setting->name);
+      }
+    }
+    
+    short *type = &(setting->type);
+    config_value_t *value = &(setting->value);
+    config_list_t *list = value->list;
+      
+
+  // ***** If this setting is a group, then recurse further down. *****
+
+    if((*type) == CONFIG_TYPE_GROUP) {
+      if(verbose_paramconfig)
+	printf("update_parameters: %s is a group.\n",this_path);      
+      
+      if(list) {
+	int len = list->length;	
+	config_setting_t **s;
+	for(s = list->elements; len--; s++)
+	  update_parameters(*s, this_path, overwrite);  // recursion
+      }
+      
+      return 1;
+    }
+    
+
+  // ***** If we get here then we're a leaf, i.e. a parameter. ********
+
+    // Force integers to be 64bit.
+    if( (*type) == CONFIG_TYPE_INT ) {
+      (*type) = CONFIG_TYPE_INT64;
+      value->llval = (long long) (value->ival);
+    }
+
+    // Check to see if this parameter already exists.
+    config_setting_t *old_setting = config_lookup(&cfg_, this_path);
+
+    if( (old_setting) && (! overwrite) ) {
+      if(verbose_paramconfig)
+	printf("Parameter \"%s\" already exists -- skipping it.\n",this_path);
+      return 1;
+    }
+
+    if(old_setting) {
+      if(verbose_paramconfig)
+	printf("Parameter \"%s\" already exists -- updating value.\n",this_path);
+      check_types(old_setting, setting, this_path);
+    } else {
+      if(verbose_paramconfig)
+	printf("Adding new parameter \"%s\".\n",this_path);    
+    }
+        
+    // Create a std::string version of the full path name.
+    std::string setting_name = std::string( this_path );
+
+
+    // Update the setting, or create it if necessary.
+    switch( (*type) ) {
+    case CONFIG_TYPE_INT:
+      // should never get here, since we force 64bit ints above...
+      throw std::runtime_error("32bit int detected! This should not have happened...");
+      break;
+    case CONFIG_TYPE_INT64:
+      old_setting = create_branch_if_necessary( setting_name, CONFIG_TYPE_INT64 );
+      config_setting_set_int64( old_setting, value->llval );
+      break;
+    case CONFIG_TYPE_FLOAT:
+      old_setting = create_branch_if_necessary( setting_name, CONFIG_TYPE_FLOAT );
+      config_setting_set_float( old_setting, value->fval );
+      break;
+    case CONFIG_TYPE_STRING:
+      old_setting = create_branch_if_necessary( setting_name, CONFIG_TYPE_STRING );
+      config_setting_set_string( old_setting, value->sval );
+      break;
+    case CONFIG_TYPE_BOOL:
+      old_setting = create_branch_if_necessary( setting_name, CONFIG_TYPE_BOOL );
+      config_setting_set_bool( old_setting, (int) value->llval );
+      break;
+    case CONFIG_TYPE_ARRAY:
+      old_setting = create_branch_if_necessary( setting_name, CONFIG_TYPE_ARRAY );
+      
+      // Remove all existing array elements from the old setting.
+      //
+      // No. We cannot do that, since we need to preserve the full set
+      // of default values for arrays like MinimumOverDensityForRefinement.
+
+      // while( config_setting_remove_elem(old_setting, 0) );
+
+      
+      // If there is more than zero elements...
+      if(list) {
+	int Nelem = list->length;		
+
+	config_setting_t **s;
+	s = list->elements;
+
+	short *this_type;	
+	config_value_t *this_value;
+	for(int i = 0; i < Nelem; i++, s++) {
+
+	  this_value = &((*s)->value);
+
+	  // Force integers to be 64bit. (This needs to happen inside
+	  // this loop in order to typecast the value to 'long long'.)
+	  this_type = &((*s)->type);
+	  if( (*this_type) == CONFIG_TYPE_INT) {
+	    (*this_type) = CONFIG_TYPE_INT64;
+	    this_value->llval = (long long) this_value->ival;
+	  }
+
+	  config_setting_t *element;
+	  element = config_setting_get_elem(old_setting, i);
+
+	  if(element)
+	    check_types(element, (*s), this_path);
+
+	  switch( (*this_type) ) {
+	  case CONFIG_TYPE_INT:
+	    // should never get here, since we force 64bit ints above...
+	    throw std::runtime_error("32bit int detected! This should not have happened...");
+	    break;
+	  case CONFIG_TYPE_INT64:
+	    if(!element)
+	      element = config_setting_add(old_setting, NULL, CONFIG_TYPE_INT64);
+	    config_setting_set_int64( element, this_value->llval );
+	    break;
+	  case CONFIG_TYPE_FLOAT:
+	    if(!element)
+	      element = config_setting_add(old_setting, NULL, CONFIG_TYPE_FLOAT );
+	    config_setting_set_float( element, this_value->fval );
+	    break;
+	  case CONFIG_TYPE_STRING:
+	    if(!element)
+	      element = config_setting_add(old_setting, NULL, CONFIG_TYPE_STRING );
+	    config_setting_set_string( element, this_value->sval );
+	    break;
+	  case CONFIG_TYPE_BOOL:
+	    if(!element)
+	      element = config_setting_add(old_setting, NULL, CONFIG_TYPE_BOOL );
+	    config_setting_set_bool( element, (int) this_value->llval );
+	    break;
+	  default:
+	    std::string error_message;
+	    error_message = "Unknown type for parameter \"" + std::string(this_path) + "\": " + std::string(var_types[(*this_type)]) + ".";
+	    throw std::runtime_error(error_message);
+	  }
+
+	} // loop over all (new) array elements.
+      }
+      
+      break;
+    default:
+      std::string error_message;
+      error_message = "Unknown type for parameter \"" + std::string(this_path) + "\": " + std::string(var_types[(*type)]) + ".";
+      throw std::runtime_error(error_message);
+    }
+    
+    
+    return 1;
+  }
+  
+  
+public:
+  
+  explicit enzo_libconfig_backend( std::string fname, std::string defaults )
+    : interpreter(fname), fname_(fname) {
+    if(verbose_paramconfig)
+      printf("Initializing parameter config (libconfig backend).\n");
+
+    config_init(&cfg_);
+    
+    // We first "update" the newly created config object with the
+    // defaults string. This is done first in order to set some arrays
+    // (like CellFlaggingMethod, etc.) which require more elements
+    // than the user typically specifies.
+    update(defaults);
+    
+    // useful for debugging:
+    //    dump("dump_before.cfg");
+
+    // Now we update (from_file=true, overwrite=true) with the
+    // user-specified parameters.
+    update(fname_, true, true);    
+
+    // useful for debugging:
+    //    dump("dump.cfg");
+  }
+  
+  
+  ~enzo_libconfig_backend()
+  { 
+    config_destroy(&cfg_);
+  }
+  
+  
+  // This updates the existing config object with new values from
+  // <input_string>, which must be in libconfig format.
+  //
+  // Unless overwrite=true, this will simply skip parameters that have
+  // already been defined. This is so UpdateDefaults() doesn't wipe
+  // out the user's parameter choices.
+  // 
+  // When from_file==true, then <input_string> is treated as a
+  // filename, from which to read the new values.
+  //
+  bool update( std::string input_string, bool from_file=false, bool overwrite=false )
+  {	
+    
+    // First we initialize a new (temporary) config
+    // object.
+    config_t tmp_cfg_;
+    config_init(&tmp_cfg_);
+    
+    // Now we read in the new parameters into the temporary config.
+    if( from_file ) {
+
+      if(verbose_paramconfig)
+	printf("Updating parameters from file <%s>.\n", input_string.c_str());
+
+      if(! config_read_file(&tmp_cfg_, input_string.c_str())) {
+	fprintf(stderr, "%s:%d - %s\n", config_error_file(&tmp_cfg_), config_error_line(&tmp_cfg_), config_error_text(&tmp_cfg_));
+	throw std::runtime_error("parse error");
+      }
+    } else {
+
+      if(verbose_paramconfig)
+	printf("Updating parameters from string:\n\"%s\n\".\n", input_string.c_str());
+
+      if(! config_read_string(&tmp_cfg_, input_string.c_str())) {
+	fprintf(stderr, "string:%d - %s\n", config_error_line(&tmp_cfg_), config_error_text(&tmp_cfg_));
+	throw std::runtime_error("parse error");
+      }
+    }
+    
+    // Next we update the parameters in the original config object
+    // with the new ones from the temporary one.
+    update_parameters(tmp_cfg_.root, NULL, overwrite);
+        
+    // Destroy temporary config object.
+    config_destroy(&tmp_cfg_);
+    
+    return true;
+  }	
+  
+  bool dump( char fname[], char header_string[]=NULL )
+  {
+    if(! config_write_file( &cfg_, fname ) )
+      return false;
+    
+    // prepend a header string, if specified.
+    if(header_string) {
+      FILE *fp;
+
+      // find number of characters
+      char c;
+      int Nchar = 0;
+      fp = fopen(fname, "rt");      
+      while((c = fgetc(fp)) != EOF) Nchar++;
+      fclose(fp);
+
+      // read the entire file into a buffer
+      char *buffer = new char[Nchar];
+      fp = fopen(fname, "rt");      
+      for(int i=0;i<Nchar;i++)
+	buffer[i] = fgetc(fp);
+      fclose(fp);
+      
+      // write out the header and then the buffer
+      fp = fopen(fname, "wt");      
+      fprintf(fp,"%s\n",header_string);
+      for(int i=0;i<Nchar;i++)
+	fputc(buffer[i],fp);
+      fclose(fp);
+      
+      delete [] buffer;
+    }
+
+    return true;
+  }
+  
+  bool remove( std::string key )
+  {
+    config_setting_t *setting = config_lookup(&cfg_, key.c_str() );
+    if( setting == NULL )
+      return true;
+    
+    if( config_setting_remove( config_root_setting(&cfg_), key.c_str() ) == CONFIG_TRUE )
+      return true;
+    
+    return false;
+  }
+  
+  bool set( std::string key, int value )
+  {
+
+    // We force 64bit integers!
+    long long lvalue = (long long) value;
+    config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_INT64 );
+    return config_setting_set_int64( setting, lvalue )==CONFIG_TRUE;
+    
+    // config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_INT );
+    // return config_setting_set_int( setting, value )==CONFIG_TRUE;
+  }
+  
+  bool set( std::string key, long long value )
+  {
+    config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_INT64 );
+    return config_setting_set_int64( setting, value )==CONFIG_TRUE;
+  }
+  
+  bool set( std::string key, bool value )
+  {
+    config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_BOOL );
+    return config_setting_set_bool( setting, (int)value )==CONFIG_TRUE;
+  }
+  
+  bool set( std::string key, double value )
+  {
+    config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_FLOAT );
+    return config_setting_set_float( setting, value )==CONFIG_TRUE;
+  }
+  
+  bool set( std::string key, char value[] )
+  {
+
+    config_setting_t *setting = create_branch_if_necessary( key, CONFIG_TYPE_STRING );
+    return config_setting_set_string( setting, value )==CONFIG_TRUE;
+  }
+  
+  bool set_list( std::string key, size_t n, const int* values )
+  {
+    bool ret = true;
+    
+    config_setting_t *array = create_branch_if_necessary( key, CONFIG_TYPE_ARRAY );
+    config_setting_t *element = NULL;
+    
+    for( size_t i=0l; i<n; ++i ) {
+      element = config_setting_get_elem(array, i);
+
+      // We force 64bit integers!
+      long long lvalue = (long long) values[i];
+      if(!element)
+	element = config_setting_add(array, NULL, CONFIG_TYPE_INT64);
+      ret &= config_setting_set_int64(element, lvalue)==CONFIG_TRUE;
+
+      // element = config_setting_add(array, NULL, CONFIG_TYPE_INT);
+      // ret &= config_setting_set_int(element, values[i])==CONFIG_TRUE;
+    }
+    
+    return ret;
+  }
+  
+  bool set_list( std::string key, size_t n, const long long* values )
+  {
+    bool ret = true;
+    
+    config_setting_t *array = create_branch_if_necessary( key, CONFIG_TYPE_ARRAY );
+    config_setting_t *element = NULL;
+    
+    for( size_t i=0l; i<n; ++i ) {
+      element = config_setting_get_elem(array, i);
+
+      if(!element)
+	element = config_setting_add(array, NULL, CONFIG_TYPE_INT64);
+      ret &= config_setting_set_int64(element, values[i])==CONFIG_TRUE;
+    }
+    
+    return ret;
+  }
+  
+  bool set_list( std::string key, size_t n, const bool* values )
+  {
+    bool ret = true;
+    
+    config_setting_t *array = create_branch_if_necessary( key, CONFIG_TYPE_ARRAY );
+    config_setting_t *element = NULL;
+    
+    for( size_t i=0l; i<n; ++i ) {
+      element = config_setting_get_elem(array, i);
+
+      if(!element)
+	element = config_setting_add(array, NULL, CONFIG_TYPE_BOOL);
+      ret &= config_setting_set_int64(element, (int)values[i])==CONFIG_TRUE;
+    }
+    
+    return ret;
+  }
+  
+  bool set_list( std::string key, size_t n, const double* values )
+  {
+    bool ret = true;
+    
+    config_setting_t *array = create_branch_if_necessary( key, CONFIG_TYPE_ARRAY );
+    config_setting_t *element = NULL;
+    
+    for( size_t i=0l; i<n; ++i ) {
+      element = config_setting_get_elem(array, i);
+
+      if(!element)
+	element = config_setting_add(array, NULL, CONFIG_TYPE_FLOAT);
+      ret &= config_setting_set_float(element, values[i])==CONFIG_TRUE;
+    }
+    
+    return ret;
+  }
+  
+  bool set_list( std::string key, size_t n, char* values[] )
+  {
+    bool ret = true;
+    
+    config_setting_t *array = create_branch_if_necessary( key, CONFIG_TYPE_ARRAY );
+    config_setting_t *element = NULL;
+    
+    for( size_t i=0l; i<n; ++i ) {
+      element = config_setting_get_elem(array, i);
+
+      if(!element)
+	element = config_setting_add(array, NULL, CONFIG_TYPE_STRING);
+      ret &= config_setting_set_string(element, values[i])==CONFIG_TRUE;
+    }
+    
+    return ret;
+  }
+  
+  int query( std::string key, std::string &ret )
+  {
+    if(verbose_paramconfig)
+      printf("accessing scalar parameter \"%s\".\n", key.c_str());
+    
+    int intval; double doubleval; char* stringval;
+    long long longval;
+    std::stringstream returnval;
+    
+    config_setting_t *setting = config_lookup(&cfg_, key.c_str() );
+    
+    if( setting == NULL ) {	
+      fprintf(stderr, "No '%s' setting in configuration file.\n",key.c_str());
+      //		  throw std::runtime_error("element not found");
+      return 0;
+    }
+    
+    switch( config_setting_type(setting) ) {
+    case CONFIG_TYPE_INT: 
+      // should never get here, since we force 64bit ints...
+      throw std::runtime_error("32bit int detected! This should not have happened...");
+
+      // intval = config_setting_get_int(setting); 
+      // returnval << intval; 
+      // ret =  returnval.str();
+      break;
+    case CONFIG_TYPE_INT64: 
+      longval = config_setting_get_int64(setting); 
+      returnval << longval; 
+      ret =  returnval.str();
+      break;
+    case CONFIG_TYPE_FLOAT: 
+      doubleval = config_setting_get_float(setting); 
+      returnval << std::setw(20) << std::setprecision(19) << doubleval; 
+      ret =  returnval.str();
+      break;
+    case CONFIG_TYPE_STRING: 
+      ret = config_setting_get_string(setting); 
+      break;
+    case CONFIG_TYPE_BOOL:
+      if( config_setting_get_bool(setting) )
+	ret = "1";
+      else
+	ret = "0";
+      break;
+    default:
+      std::cerr << "unknown type" << config_setting_get_format(setting) << "\n";
+      return 0;
+      
+    }
+    return 1;		
+  }
+  
+  int query_list( std::string key, std::vector< std::string >& ret )
+  {
+    if(verbose_paramconfig)
+      printf("accessing array parameter \"%s\".\n", key.c_str());
+    config_setting_t *setting;
+    setting = config_lookup(&cfg_, key.c_str());
+    
+    if(setting != NULL) {
+      int count = config_setting_length(setting);
+      for( int i=0; i<count; ++i ) {
+	int intval; double doubleval; char* stringval;
+	long long longval;
+	std::stringstream returnval;
+	
+	switch( config_setting_type( config_setting_get_elem(setting,i) ) ) {
+	case CONFIG_TYPE_INT: 
+	  // should never get here, since we force 64bit ints...
+	  throw std::runtime_error("32bit int detected! This should not have happened...");
+
+	  // intval = config_setting_get_int_elem(setting,i); 
+	  // returnval << intval; 
+	  // ret.push_back(returnval.str());
+	  break;
+	case CONFIG_TYPE_INT64: 
+	  longval = config_setting_get_int64_elem(setting,i); 
+	  returnval << longval; 
+	  ret.push_back(returnval.str());
+	  break;
+	case CONFIG_TYPE_FLOAT: 
+	  doubleval = config_setting_get_float_elem(setting,i); 
+	  returnval << std::setw(20) << std::setprecision(19) << doubleval;
+	  ret.push_back(returnval.str());
+	  break;
+	case CONFIG_TYPE_STRING: 
+	  ret.push_back( config_setting_get_string_elem(setting,i) ); 
+	  break;
+	case CONFIG_TYPE_BOOL:
+	  if( config_setting_get_bool_elem(setting,i) )
+	    ret.push_back("1");
+	  else
+	    ret.push_back("0");
+	  break;
+	default:
+	  std::cerr << "unknown type\n";
+	  return 0;
+	}
+      }
+    } else {	
+      fprintf(stderr, "No '%s' setting in configuration file.\n",key.c_str());
+      //		  throw std::runtime_error("element not found");
+      return 0;
+    }
+    return 1;
+  }
+  
+  size_t size( std::string key ) {
+    
+    config_setting_t *setting;
+    setting = config_lookup(&cfg_, key.c_str());
+    int len = 0;
+    if(setting != NULL) {
+      len = config_setting_length(setting);
+    } else {
+      fprintf(stderr, "No '%s' setting in configuration file.\n",key.c_str());
+      //		  throw std::runtime_error("element not found");
+      return 0;
+    }
+        
+    
+    if(verbose_paramconfig)
+      printf("Parameter \"%s\" has %d elements.\n", key.c_str(), len);
+    return len;
+  }
+};
+
+
+namespace {
+  interpreter_creator_concrete< enzo_libconfig_backend > c00("enzo2_libconfig");
+}

src/enzo/control/SimpleParameterParser.h

+#ifndef SIMPLECONFIGPARSER_HH
+#define SIMPLECONFIGPARSER_HH
+
+#include <fstream>
+#include <string>
+#include <iomanip>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+
+/*!
+ * @class config_file
+ * @brief provides read/write access to configuration options
+ *
+ * This class provides access to the configuration file. The 
+ * configuration is stored in hash-pairs and can be queried and
+ * validated by the responsible class/routine
+ */
+class config_file {
+	
+	//! current line number
+	unsigned m_iLine;
+	
+	//! hash table for key/value pairs, stored as strings
+	std::map<std::string, std::string> m_Items;
+	
+public:
+	
+	//! removes all white space from string source
+	/*!
+	 * @param source the string to be trimmed
+	 * @param delims a string of delimiting characters
+	 * @return trimmed string
+	 */
+	std::string trim(std::string const& source, char const* delims = " \t\r\n") const{
+		std::string result(source);
+		//... skip initial whitespace ...
+		std::string::size_type index = result.find_last_not_of(delims);
+		if(index != std::string::npos)
+			result.erase(++index);
+		//... find beginning of trailing whitespace ...
+		index = result.find_first_not_of(delims);
+		//... remove trailing whitespace ...
+		if(index != std::string::npos)
+			result.erase(0, index);
+		else
+			result.erase();
+		return result;
+	}
+	
+	
+	
+	//! constructor of class config_file
+	/*! @param FileName the path/name of the configuration file to be parsed
+	 */
+	config_file( std::string const& FileName )
+	: m_iLine(0), m_Items()	
+	{
+		std::ifstream file(FileName.c_str());
+		
+		if( !file.is_open() )
+			throw std::runtime_error(std::string("Error: Could not open config file \'")+FileName+std::string("\'"));
+		
+		std::string line;
+		std::string name;
+		std::string value;
+		std::string inSection;
+		int posEqual;
+		m_iLine=0;
+		//.. walk through all lines ..
+		while (std::getline(file,line)) {
+			++m_iLine;
+			//.. encounterd EOL ?
+			if (! line.length()) continue;
+			
+			//.. encountered comment ?
+			unsigned long idx;
+			if( (idx=line.find_first_of("#;%")) != std::string::npos )
+				line.erase(idx);
+			
+			if( (idx=line.find_first_of("/")) != std::string::npos )
+				if( line[idx+1] == '/' )
+					line.erase(idx);
+			
+			//.. encountered section tag ?
+			if (line[0] == '[') {
+				inSection=trim(line.substr(1,line.find(']')-1));
+				continue;
+			}
+			
+			//.. seek end of entry name ..
+			posEqual=line.find('=');
+			name  = trim(line.substr(0,posEqual));
+			value = trim(line.substr(posEqual+1));
+			
+			if( (size_t)posEqual==std::string::npos && (name.size()!=0||value.size()!=0) )
+			{
+				printf("Ignoring non-assignment in %s:%d",FileName.c_str(),m_iLine);
+				continue;
+			}
+			
+			if(name.length()==0&&value.size()!=0)
+			{  
+				printf("Ignoring assignment missing entry name in %s:%d",FileName.c_str(),m_iLine);
+				continue;
+				
+			}
+			
+			if(value.length()==0&&name.size()!=0)
+			{	  
+				printf("Empty entry will be ignored in %s:%d",FileName.c_str(),m_iLine);
+				continue;
+			}
+			
+			if( value.length()==0&&name.size()==0)
+				continue;
+			
+			//.. add key/value pair to hash table ..
+			if( m_Items.find(inSection+'/'+name) != m_Items.end() )
+				printf("Redeclaration overwrites previous value in %s:%d",FileName.c_str(),m_iLine);
+			
+			m_Items[inSection+'/'+name] = value;
+			
+		}
+	}
+	
+	//! inserts a key/value pair in the hash map
+	/*! @param key the key value, usually "section/key"
+	 *  @param value the value of the key, also a string
+	 */
+	void insertValue( std::string const& key, std::string const& value )
+	{
+		m_Items[key] = value;
+	}
+	
+	//! inserts a key/value pair in the hash map
+	/*! @param section section name. values are stored under "section/key"
+	 *  @param key the key value usually "section/key"
+	 *  @param value the value of the key, also a string
+	 */
+	void insertValue( std::string const& section, std::string const& key, std::string const& value )
+	{
+		m_Items[section+'/'+key] = value;
+	}
+	
+	//! checks if a key is part of the hash map
+	/*! @param section the section name of the key
+	 *  @param key the key name to be checked
+	 *  @return true if the key is present, false otherwise
+	 */
+	bool containsKey( std::string const& section, std::string const& key )
+	{
+		std::map<std::string,std::string>::const_iterator i = m_Items.find(section+'/'+key);
+		if ( i == m_Items.end() ) 
+			return false;
+		return true;
+	}
+	
+	//! checks if a key is part of the hash map
+	/*! @param key the key name to be checked
+	 *  @return true if the key is present, false otherwise
+	 */
+	bool containsKey( std::string const& key )
+	{
+		std::map<std::string,std::string>::const_iterator i = m_Items.find(key);
+		if ( i == m_Items.end() ) 
+			return false;
+		return true;
+	}
+	
+	
+	//! return value of a key
+	/*! returns the value of a given key, throws a ErrItemNotFound
+	 *  exception if the key is not available in the hash map.
+	 *  @param key the key name
+	 *  @return the value of the key
+	 *  @sa ErrItemNotFound
+	 */
+	template<class T> T getValue( std::string const& key ) const{
+		return getValue<T>( "", key );
+	}
+	
+	//! return value of a key
+	/*! returns the value of a given key, throws a ErrItemNotFound
+	 *  exception if the key is not available in the hash map.
+	 *  @param section the section name for the key
+	 *  @param key the key name
+	 *  @return the value of the key
+	 *  @sa ErrItemNotFound
+	 */
+	template<class T> T getValue( std::string const& section, std::string const& key ) const
+	{
+		T r;
+		std::map<std::string,std::string>::const_iterator i = m_Items.find(section + '/' + key);
+		if ( i == m_Items.end() ) 
+			throw ErrItemNotFound('\'' + section + '/' + key + std::string("\' not found."));
+		
+		convert(i->second,r);
+		return r;
+	}
+	
+	//! exception safe version of getValue
+	/*! returns the value of a given key, returns a default value rather
+	 *  than a ErrItemNotFound exception if the key is not found.
+	 *  @param section the section name for the key
+	 *  @param key the key name
+	 *  @param default_value the value that is returned if the key is not found
+	 *  @return the key value (if key found) otherwise default_value
+	 */
+	template<class T> T getValueSafe( std::string const& section, std::string const& key, T default_value ) const
+	{
+		T r;
+		try{
+			r = getValue<T>( section, key );
+		} catch( ErrItemNotFound ) {
+			r = default_value;
+		}
+		return r;
+	}
+	
+	
+	//! exception safe version of getValue
+	/*! returns the value of a given key, returns a default value rather
+	 *  than a ErrItemNotFound exception if the key is not found.
+	 *  @param key the key name
+	 *  @param default_value the value that is returned if the key is not found
+	 *  @return the key value (if key found) otherwise default_value
+	 */
+	template<class T> T getValueSafe( std::string const& key, T default_value ) const
+	{
+		return getValueSafe( "", key, default_value );
+	}
+	
+	
+	//! dumps all key-value pairs to a std::ostream
+	void dump( std::ostream& out )
+	{
+		std::map<std::string,std::string>::const_iterator i = m_Items.begin();
+		while( i!=m_Items.end() )
+		{
+			if( i->second.length() > 0 )
+				out << std::setw(24) << std::left << i->first << "  =  " << i->second  << std::endl;
+			++i;
+		}
+	}
+	
+	void log_dump( void )
+	{
+		printf("List of all configuration options:\n");
+		std::map<std::string,std::string>::const_iterator i = m_Items.begin();
+		while( i!=m_Items.end() )
+		{
+			if( i->second.length() > 0 )
+				printf("  %24s = %s\n",(i->first).c_str(),(i->second).c_str());//out << std::setw(24) << std::left << i->first << "  =  " << i->second  << std::endl;
+			++i;
+		}
+	}
+	
+	//! converts between different variable types
+	/*!
+	 *  The main purpose of this function is to parse and convert
+	 *  a string argument into numbers, booleans, etc...
+	 * @param ival the input value (typically a std::string)
+	 * @param oval the interpreted/converted value
+	 */
+	template <class in_value, class out_value>
+	inline void convert( const in_value & ival, out_value & oval) const
+	{
+		std::stringstream ss;
+		ss << ival; //.. insert value into stream
+		ss >> oval; //.. retrieve value from stream
+		
+		if (! ss.eof()) {
+			//.. conversion error
+			std::cerr << "Error: conversion of \'" << ival << "\' failed." << std::endl;
+			throw ErrInvalidConversion(std::string("invalid conversion to ")+typeid(out_value).name()+'.');
+		}
+	}
+	
+	
+	
+	template< typename T, class output_inserter >
+	inline void evaluate_list( std::string input, output_inserter it )
+	{
+		std::istringstream istream( input );
+		do{
+			std::string split_str;
+			istream >> split_str;
+			T val;
+			if( split_str.size() == 0 ) continue;
+			convert<std::string,T>( split_str, val );
+			*it = val;
+			++it;
+		}while(istream);
+	}
+	
+	
+	
+	
+	//--- EXCEPTIONS ---
+	
+	//! runtime error that is thrown if key is not found in getValue
+	class ErrItemNotFound : public std::runtime_error{
+	public:
+		ErrItemNotFound( std::string itemname )
+		: std::runtime_error( itemname.c_str() )
+		{}
+	};
+	
+	
+	
+	//! runtime error that is thrown if identifier is not found in keys
+	class ErrIllegalIdentifier : public std::runtime_error{
+	public:
+		ErrIllegalIdentifier( std::string errmsg )
+		: std::runtime_error( errmsg )
+		{}
+	};
+	
+};
+
+template<>
+inline void config_file::convert<std::string,std::string>( const std::string & ival, std::string & oval) const
+{
+	oval = ival;
+}
+
+
+//... Function: getValue( strSection, strEntry ) ...
+//... Descript: specialization of getValue for type boolean to interpret strings ...
+//...           like "true" and "false" etc.
+//...           converts the string to type bool, returns type bool ...
+template<> 
+inline bool config_file::getValue<bool>( std::string const& strSection, std::string const& strEntry ) const{
+	std::string r1 = getValue<std::string>( strSection, strEntry );
+    if( r1=="true" || r1=="yes" || r1=="on" || r1=="1" )
+		return true;
+    if( r1=="false" || r1=="no" || r1=="off" || r1=="0" )
+		return false;
+    throw ErrIllegalIdentifier(std::string("Illegal identifier \'")+r1+std::string("\' in \'")+strEntry+std::string("\'."));
+    //return false;
+}
+
+template<>
+inline bool config_file::getValueSafe<bool>( std::string const& strSection, std::string const& strEntry, bool defaultValue ) const{
+	std::string r1;
+	try{
+		r1 = getValue<std::string>( strSection, strEntry );
+		if( r1=="true" || r1=="yes" || r1=="on" || r1=="1" )
+			return true;
+		if( r1=="false" || r1=="no" || r1=="off" || r1=="0" )
+			return false;
+	} catch( ErrItemNotFound ) {
+		return defaultValue;
+	}
+	return defaultValue;
+}
+
+#endif

src/enzo/control/auto_defaults_string.h

+char defaults_string[] = 
+  "### ENZO DEFAULT PARAMETER VALUES ###\n"
+  "\n"
+  "Internal:\n"
+  "{\n"
+  "	Fields = [\"Density\", \"X-velocity\", \"Y-velocity\", \"Z-velocity\", \"TotalEnergy\", \"GasEnergy\"];\n"
+  "\n"
+  "	Density:\n"
+  "	{\n"
+  "		Name = \"Density\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};	\n"
+  "	X-velocity:\n"
+  "	{\n"
+  "		Name = \"x-velocity\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};\n"
+  "	Y-velocity:\n"
+  "	{\n"
+  "		Name = \"y-velocity\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};\n"
+  "	Z-velocity:\n"
+  "	{\n"
+  "		Name = \"z-velocity\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};\n"
+  "	TotalEnergy:\n"
+  "	{\n"
+  "		Name = \"TotalEnergy\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};\n"
+  "	GasEnergy:\n"
+  "	{\n"
+  "		Name = \"GasEnergy\";\n"
+  "		cgsConversionFactor = \"\";\n"
+  "	};\n"
+  "\n"
+  "#	Units:\n"
+  "#	{\n"
+  "#		Mass = 1.0;\n"
+  "#		Density = 1.0;\n"
+  "#		Length = 1.0;\n"
+  "#		Time = 1.0;\n"
+  "#		Temperature = 1.0;\n"
+  "#	};\n"
+  "\n"
+  "	Provenance:\n"
+  "	{\n"
+  "		MetaDataIdentifier      = \"\";\n"
+  "		SimulationUUID          = \"\";\n"
+  "#		DatasetUUID             = \"\";\n"
+  "		RestartDatasetUUID      = \"\";\n"
+  "		InitialConditionsUUID   = \"\";\n"
+  "		VersionNumber           = \"2.0\";\n"
+  "	};\n"
+  "\n"
+  "	OutputLabeling:\n"
+  "	{\n"
+  "		TimeLastRestartDump = 0.0;\n"
+  "		TimeLastDataDump    = -99999.0;\n"
+  "		TimeLastHistoryDump = -99999.0;\n"
+  "		TimeLastTracerParticleDump = -99999.0;\n"
+  "		TimeLastInterpolatedDataDump    = -99999.0;\n"
+  "		MovieTimestepCounter = 0;\n"
+  "		CycleLastRestartDump = 0;\n"
+  "		CycleLastDataDump    = -99999;\n"
+  "		CycleLastHistoryDump = -99999;\n"
+  "		SubcycleLastDataDump    = -99999;\n"
+  "		RestartDumpNumber   = 0;\n"
+  "		DataDumpNumber      = 0;\n"
+  "		HistoryDumpNumber   = 0;\n"
+  "		TracerParticleDumpNumber = 0;\n"
+  "		CheckpointRestart   = False;\n"
+  "	};\n"
+  "\n"
+  "	InitialCycleNumber  = 0;\n"
+  "	SubcycleNumber      = 0;\n"
+  "	InitialTime         = 0.0;\n"
+  "	Initialdt           = 0.01;\n"
+  "	InitialCPUTime      = 0.0;\n"
+  "	NumberOfParticles      = 0;\n"
+  "	Debug1                          = False;\n"
+  "	Debug2                          = False;\n"
+  "	CosmologyCurrentRedshift   = -99999.0;\n"
+  "	BoundaryConditionName      = \"\";\n"
+  "};\n"
+  "\n"
+  "\n"
+  "SimulationControl: # (subgroup refinement for later on)\n"
+  "{\n"
+  "	StopTime            = -99999.0;\n"
+  "	StopCycle           = 100000;\n"
+  "	StopSteps           = 10000;\n"
+  "	StopCPUTime         = 2592000.0;  # 30 days\n"
+  "	ResubmitOn          = False;\n"
+  "	ResubmitCommand     = \"\";\n"
+  "	MaximumTopGridTimeStep = 1e20;\n"
+  "	TracerParticleOn           = False;\n"
+  "	StopFirstTimeAtLevel    = 0;\n"
+  "	UseCUDA                        = False;\n"
+  "	huge_number                    = 1.000000e20;\n"
+  "	tiny_number                    = 1.000000e-20;\n"
+  "\n"
+  "	Domain:\n"
+  "	{\n"
+  "		TopGridRank         = -99999;\n"
+  "		TopGridDimensions   = [-99999, -99999, -99999];\n"
+  "		LeftFaceBoundaryCondition  = [0, 0, 0];\n"
+  "		RightFaceBoundaryCondition = [0, 0, 0];\n"
+  "		RefineRegionLeftEdge   = [0.0, 0.0, 0.0];\n"
+  "		RefineRegionRightEdge  = [1.0, 1.0, 1.0];\n"
+  "		DomainLeftEdge         = [0.0, 0.0, 0.0];\n"
+  "		DomainRightEdge        = [1.0, 1.0, 1.0];\n"
+  "		RefineRegionAutoAdjust = False;\n"
+  "		MustRefineRegionLeftEdge = [0.0, 0.0, 0.0]; \n"
+  "		MustRefineRegionRightEdge  = [1.0, 1.0, 1.0]; \n"
+  "	};\n"
+  "	\n"
+  "	AMR:\n"
+  "	{\n"
+  "		RefineBy                       = 2;\n"
+  "		MaximumRefinementLevel         = 2;\n"
+  "		MaximumGravityRefinementLevel  = -99999;\n"
+  "		MaximumParticleRefinementLevel = -1;\n"
+  "		NumberOfBufferZones            = 1;\n"
+  "		StaticHierarchy                = True;\n"
+  "		CellFlaggingMethod             = [-99999, -99999, -99999, -99999, -99999, -99999, -99999, -99999, -99999];\n"
+  "		RefineByJeansLengthSafetyFactor  = 4.0;\n"
+  "		JeansRefinementColdTemperature  = -1.0;\n"
+  "		RefineByResistiveLengthSafetyFactor  = 2.000000;\n"
+  "		MustRefineParticlesRefineToLevel = False;\n"
+  "		MustRefineParticlesRefineToLevelAutoAdjust = False;\n"
+  "		MustRefineParticlesMinimumMass = 0.0;\n"
+  "		MustRefineRegionMinRefinementLevel  = -1;\n"
+  "		MetallicityRefinementMinLevel       = -1;\n"
+  "		MetallicityRefinementMinMetallicity = 1e-05;\n"
+  "		MetallicityRefinementMinDensity     = -99999.0;\n"
+  "		RefineRegionTimeType   = -1;\n"
+  "		SlopeFlaggingFields = [-99999, -99999, -99999, -99999, -99999, -99999, -99999, -99999, -99999];\n"
+  "		MinimumSlopeForRefinement = [0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3, 0.3];\n"
+  "		MinimumOverDensityForRefinement = [1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5, 1.5];\n"
+  "		MinimumMassForRefinement = [-99999.0, -99999.0, -99999.0, -99999.0, -99999.0, -99999.0, -99999.0, -99999.0, -99999.0];\n"
+  "		MinimumMassForRefinementLevelExponent = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0];\n"
+  "		MinimumShearForRefinement             = 1.0;\n"
+  "		MinimumPressureJumpForRefinement      = 0.33;\n"
+  "		MinimumEnergyRatioForRefinement       = 0.1;\n"
+  "		ShockwaveRefinementMinMach            = 1.3;\n"
+  "		ShockwaveRefinementMinVelocity        = 1.0e7;\n"
+  "		ShockwaveRefinementMaxLevel           = 0;\n"
+  "		RefineByJeansLengthUnits              = False;\n"
+  "	\n"
+  "		StaticRefineRegion:\n"
+  "		{\n"
+  "			Regions=[];\n"
+  "		};\n"
+  "\n"
+  "		RefineRegionFile = \"\";\n"
+  "	\n"
+  "	\n"
+  "	}; # end amr\n"
+  "\n"
+  "	Optimization:\n"
+  "	{\n"
+  "\n"
+  "		LoadBalancing          = 1;\n"
+  "		ResetLoadBalancing     = False;\n"
+  "		LoadBalancingCycleSkip = 10;\n"
+  "		LoadBalancingMinLevel  = 0;\n"
+  "		LoadBalancingMaxLevel  = 50;\n"
+  "		RadiativeTransferLoadBalance    = False;\n"
+  "		ParallelRootGridIO              = False;\n"
+  "		ParallelParticleIO              = False;\n"
+  "		Unigrid                         = False;\n"
+  "		UnigridTranspose                = False;\n"
+  "		MinimumEfficiency              = 0.2;\n"
+  "		SubgridSizeAutoAdjust          = True;\n"
+  "		OptimalSubgridsPerProcessor    = 16;\n"
+  "		MinimumSubgridEdge             = 6;\n"
+  "		MaximumSubgridSize             = 32768;\n"
+  "		NumberOfRootGridTilesPerDimensionPerProcessor = 1;\n"
+  "		MoveParticlesBetweenSiblings     = True;\n"
+  "		ParticleSplitterIterations       = False;\n"
+  "		ParticleSplitterChildrenParticleSeparation     = 1.0;\n"
+  "		MemoryLimit                     = 4000000000;\n"
+  "		FastSiblingLocatorEntireDomain      = True;\n"
+  "	};\n"
+  "\n"
+  "	Timeaction:\n"
+  "	{\n"
+  "		Actions = [];\n"
+  "	};\n"
+  "\n"
+  "}; # end SimulationControl\n"
+  "\n"
+  "\n"
+  "\n"
+  "OutputControl:\n"
+  "{\n"
+  "\n"
+  "	dtInterpolatedDataDump       = 0.0;\n"
+  "	FileDirectedOutput           = True;\n"
+  "	WriteBinaryHierarchy         = False;\n"
+  "	GlobalDir                    = \"\";\n"
+  "	LocalDir                     = \"\";\n"
+  "	ParticleTypeInFile           = True;\n"
+  "	OutputParticleTypeGrouping   = False;\n"
+  "	ExtractFieldsOnly            = True;\n"
+  "	CubeDumpEnabled              = False;\n"
+  "\n"
+  "\n"
+  "	DataDump:\n"
+  "	{\n"
+  "		Name = \"data\";\n"
+  "		Dir  = \"DD\";\n"
+  "		dt   = 0.0;\n"
+  "	};\n"
+  "\n"
+  "	RestartDump:\n"
+  "	{\n"
+  "		Name = \"restart\";\n"
+  "		Dir  = \"RS\";\n"
+  "		dt   = -99999.0;\n"
+  "	};\n"
+  "\n"
+  "	MovieDump:\n"
+  "	{\n"
+  "		Name                  = \"MoviePack\";\n"
+  "		LeftEdge              = [0.0, 0.0, 0.0];\n"
+  "		RightEdge             = [1.0, 1.0, 1.0];\n"
+  "		SkipTimestep          = -99999;\n"
+  "		Volumes3D             = False;\n"
+  "		VertexCentered        = False;\n"
+  "		ParticleOn            = False;\n"
+  "		DataField             = [-99999, -99999, -99999, -99999, -99999, -99999];\n"
+  "		DumpNumber            = 0;\n"
+  "	};\n"
+  "\n"
+  "	CycleDump:\n"
+  "	{\n"
+  "		SkipRestartDump = 0;\n"
+  "		SkipDataDump    = 0;\n"
+  "		SkipHistoryDump = 0;\n"
+  "	        SkipGlobalDataDump = 0;\n"
+  "		SubcycleSkipDataDump    = 0;\n"
+  "	};\n"
+  "\n"
+  "	RedshiftDump:\n"
+  "	{\n"
+  "		Name        = \"RedshiftOutput\";\n"
+  "		Dir         = \"RD\";\n"
+  "		OutputRedshifts = [];\n"
+  "		OutputRedshiftNames = [];\n"
+  "	};\n"
+  "\n"
+  "	HistoryDump:\n"
+  "	{\n"
+  "		Name     = \"history\";\n"
+  "		Dir      = \"HD\";\n"
+  "		dt       = 0.0;\n"
+  "	};\n"
+  "\n"
+  "	TracerParticleDump:\n"
+  "	{\n"
+  "		Name     = \"TracerOutput\";\n"
+  "		Dir      = \"TD\";\n"
+  "		dt       = 0.0;\n"
+  "	};\n"
+  "\n"
+  "	OutputTriggers:\n"
+  "	{\n"
+  "		OutputFirstTimeAtLevel = 0;\n"
+  "		StartDensityOutputs    = -99999;\n"
+  "		OutputOnDensity        = False;\n"
+  "		CurrentDensityOutput   = -99999;\n"
+  "		IncrementDensityOutput = -99999.0;\n"
+  "	};\n"
+  "\n"
+  "	SupplementalFields:\n"
+  "	{\n"
+  "		WritePotential                 = False;\n"
+  "		OutputCoolingTime              = False;\n"
+  "		OutputTemperature              = False;\n"
+  "		OutputSmoothedDarkMatter       = False;\n"
+  "		SmoothedDarkMatterNeighbors    = 32;\n"
+  "		OutputGriddedStarParticle      = False;\n"
+  "		BAnyl                          = False;\n"
+  "		VelAnyl                        = False;\n"
+  "	};\n"
+  "\n"
+  "}; # end OutputControlParameters\n"
+  "\n"
+  "\n"
+  "\n"
+  "\n"
+  "\n"
+  "Physics:\n"
+  "{\n"
+  "\n"
+  "	TopGridGravityBoundary     = 0;\n"
+  "	ParticleBoundaryType       = 3;\n"
+  "	GridVelocity               = [0.0 ,0.0, 0.0]; #(remove)\n"
+  "	AccretionKernel            = 0;\n"
+  "	UsePhysicalUnit            = False;\n"
+  "	UseFloor                   = False;\n"
+  "	SmallRho                   = 1.0e-30;\n"
+  "	SmallP                     = 1.0e-35;\n"
+  "	SmallT                     = 1.0e-10;\n"
+  "	Coordinate                 = 0;   \n"
+  "	PoissonApproximationThreshold = 0.001;\n"
+  "	PoissonBoundaryType        = 0;\n"
+  "\n"
+  "	AngularVelocity              = 0.001;\n"
+  "	VelocityGradient             = 1.0;\n"
+  "	ShearingVelocityDirection    = -1;\n"
+  "	ShearingBoundaryDirection    = -1;\n"
+  "	ShearingBoxProblemType       = 0;\n"
+  "	UseMHD                       = 0;\n"
+  "	\n"
+  "	Hydro:\n"
+  "	{\n"
+  "		#split between ppm and zeus?\n"
+  "	\n"
+  "		CourantSafetyNumber    = 0.6;\n"
+  "		HydroMethod            = 0;   # PPM Direct Euler\n"
+  "		Gamma                  = 1.6666667;\n"
+  "\n"
+  "		PPMFlatteningParameter = False;\n"
+  "		PPMDiffusionParameter  = False;\n"
+  "		PPMSteepeningParameter = False;\n"
+  "\n"
+  "		EOSType                    = 0;\n"
+  "		EOSSoundSpeed              = 2.65e4;\n"
+  "		EOSCriticalDensity         = 1e-13;\n"
+  "		EOSGamma                   = 1.6666667;\n"
+  "		Mu                         = 0.6;\n"
+  "\n"
+  "		PressureFree                   = False;\n"
+  "\n"
+  "		UseMinimumPressureSupport        = False;\n"
+  "		MinimumPressureSupportParameter  = 100.0;\n"
+  "\n"
+  "		FluxCorrection                 = True;\n"
+  "		InterpolationMethod            = 1;  # SecondOrderA\n"
+  "		ConservativeInterpolation      = True;\n"
+  "\n"
+  "		DualEnergyFormalism         = False;\n"
+  "		DualEnergyFormalismEta1     = 0.001;\n"
+  "		DualEnergyFormalismEta2     = 0.1;\n"
+  "\n"
+  "		ZEUSLinearArtificialViscosity    = 0.0;\n"
+  "		ZEUSQuadraticArtificialViscosity = 2.0;\n"
+  "\n"
+  "		ParticleCourantSafetyNumber = 0.5;\n"
+  "		RootGridCourantSafetyNumber = 1.0;\n"
+  "\n"
+  "		UseViscosity               = False;\n"
+  "		ViscosityCoefficient       = 0.0;\n"
+  "		UseAmbipolarDiffusion      = False;\n"
+  "		UseResistivity             = False;\n"
+  "\n"
+  "		UseHydro                   = True;\n"
+  "		Theta_Limiter              = 1.5;\n"
+  "		RiemannSolver              = -99999;\n"
+  "		RiemannSolverFallback      = False;\n"
+  "		IsothermalSoundSpeed       = 1.0;\n"
+  "\n"
+  "		ConservativeReconstruction = True;\n"
+  "		PositiveReconstruction     = False;\n"
+  "		ReconstructionMethod       = -99999;\n"
+  "		RKOrder                    = 2;\n"
+  "	}; # end hydro\n"
+  "\n"
+  "	OtherParticles:\n"
+  "	{\n"
+  "		StarParticleCreation                  = 0;\n"
+  "		StarMetalYield                        = 0.02;\n"
+  "		StarMassEjectionFraction              = 0.25;\n"
+  "		StarEnergyToThermalFeedback           = 1.0e-05;\n"
+  "		StarEnergyToStellarUV                 = 3.0e-06;\n"
+  "		StarEnergyToQuasarUV                  = 5.0e-06;\n"
+  "		StellarWindFeedback                   = 0;\n"
+  "		StellarWindTurnOnMass                 = 0.1;  #(please document)\n"
+  "		MSStellarWindTurnOnMass               = 10.0; #(please document)\n"
+  "		StarParticleFeedback                  = 0;\n"
+  "		NumberOfParticleAttributes            = -99999;\n"
+  "		AddParticleAttributes                 = False;\n"
+  "		S2ParticleSize                        = 3.0;\n"
+  "\n"
+  "		StarFeedbackDistRadius                = 0;\n"
+  "		StarFeedbackDistCellStep	      = 0;\n"
+  "\n"
+  "		BigStar:\n"
+  "		{\n"
+  "			Formation                      = False;\n"
+  "			FormationDone		       = False;\n"
+  "			Separation                     = 0.25;\n"
+  "		};\n"
+  "\n"
+  "		StarMaker:\n"
+  "		{\n"
+  "			# Question: do any of the other star methods use these parameters?\n"
+  "			OverDensityThreshold         = 100.0;\n"
+  "			SHDensityThreshold           = 7.0e-26;\n"
+  "			MassEfficiency               = 1.0;\n"
+  "			MinimumMass                  = 1.0e9;\n"
+  "			MinimumDynamicalTime         = 1.0e6;\n"
+  "		};\n"
+  "\n"
+  "		PopIIIStarParticle:\n"
+  "		{\n"
+  "\n"
+  "			StarMass                        = 100.0;\n"
+  "			InitialMassFunction             = False;\n"
+  "			InitialMassFunctionSeed         = -99999;\n"
+  "			InitialMassFunctionCalls        = 0;\n"
+  "			LowerMassCutoff                 = 1.0;\n"
+  "			UpperMassCutoff                 = 300.0;\n"
+  "			MassRange                       = [1.0, 300.0]; \n"
+  "			InitialMassFunctionSlope        = -1.3;\n"
+  "			HeliumIonization                = False;\n"
+  "			BlackHoles                      = False;\n"
+  "			BHLuminosityEfficiency          = 0.1;\n"
+  "			OverDensityThreshold            = 1.0e6;\n"
+  "			H2CriticalFraction              = 5.0e-4;\n"
+  "			MetalCriticalFraction           = 1.0e-4;\n"
+  "			SupernovaRadius                 = 1.0;\n"
+  "			SupernovaUseColour              = False;\n"
+  "			SupernovaMustRefine             = False;\n"
+  "			SupernovaMustRefineResolution   = 32;\n"
+  "			ColorDensityThreshold           = 1.0e6;\n"
+  "			ColorMass                       = 1.0e6;\n"
+  "		};\n"
+  "\n"
+  "		MBHParticle:\n"
+  "		{	\n"
+  "			Accretion                          = False;\n"
+  "			AccretionRadius                    = 50.0;\n"
+  "			AccretingMassRatio                 = 1.0;\n"
+  "			AccretionFixedTemperature          = 3.0e5;\n"
+  "			AccretionFixedRate                 = 1.0e-3;\n"
+  "			TurnOffStarFormation               = False;\n"
+  "			CombineRadius                      = 50.0;\n"
+  "			MinDynamicalTime                   = 1.0e7;\n"
+  "			MinimumMass                        = 1.0e3;\n"
+  "			Feedback                           = False;\n"
+  "			FeedbackRadiativeEfficiency        = 0.1;\n"
+  "			FeedbackEnergyCoupling             = 0.05;\n"
+  "			FeedbackMassEjectionFraction       = 0.1;\n"
+  "			FeedbackMetalYield                 = 0.02;\n"
+  "			FeedbackThermalRadius              = 50.0;\n"
+  "			FeedbackJetsThresholdMass          = 10.0;\n"
+  "		};			\n"