def _get_value(val_in, settings_dict, tracers_dict, dict_prefix=''): """ Translate val_in (which may be a variable name) to an integer value """ logger = logging.getLogger(__name__) # If val_in is an integer, then it is the dimension size and should be returned if isinstance(val_in, int): return val_in # If val_in is a string, then it is a variable name that should be in # settings_dict already if isinstance(val_in, type(u'')): # If val_in = _tracer_list, that's a special case where we want # to find a list of tracers according to current settings if val_in == '_tracer_list': return len(tracers_dict.keys()) # Otherwise, val_in must refer to a variable that could be # in the dictionary with or without the prefix try: val_out = settings_dict[dict_prefix + val_in] except: try: val_out = settings_dict[val_in] except: logger.error('Unknown variable name in _get_value: %s' % val_in) MARBL_tools.abort(1) return val_out # Otherwise this is not a well-defined variable request logger.error('_get_value() requires integer or string argument') MARBL_tools.abort(1)
def _get_array_info(array_size_in, settings_dict, tracers_dict, dict_prefix=''): """ Return a list of the proper indexing for array elements, e.g. ['(1)', '(2)'] for 1D array or ['(1,1)', '(2,1)'] for 2D array If array_size_in is not an integer, check to see if it is in settings_dict """ logger = logging.getLogger(__name__) # List to be returned: str_index = [] # How many dimensions? if isinstance(array_size_in, list): # Error checking: # This script only support 2D arrays for now # (and assumes array_size_in is not a list for 1D arrays) if len(array_size_in) > 2: logger.error("_get_array_info() only supports 1D and 2D arrays") MARBL_tools.abort(1) for i in range(0, _get_value(array_size_in[0], settings_dict, tracers_dict, dict_prefix)): for j in range(0, _get_value(array_size_in[1], settings_dict, tracers_dict, dict_prefix)): str_index.append("(%d,%d)" % (i+1,j+1)) return str_index # How many elements? May be an integer or an entry in self.settings_dict for i in range(0, _get_value(array_size_in, settings_dict, tracers_dict, dict_prefix)): str_index.append("(%d)" % (i+1)) return str_index
def __init__(self, default_settings_file, saved_state_vars_source="settings_file", grid=None, input_file=None): """ Class constructor: set up a dictionary of config keywords for when multiple default values are provided, read the JSON file, and then populate self.settings_dict and self.tracers_dict. """ logger = logging.getLogger(__name__) # 1. List of configuration keywords to match in JSON if default_default is a dictionary self._config_keyword = [] if grid != None: self._config_keyword.append('GRID == "%s"' % grid) self._config_keyword.append('SAVED_STATE_VARS_SOURCE == "%s"' % saved_state_vars_source) # 2. Read settings JSON file import json with open(default_settings_file) as settings_file: self._settings = json.load(settings_file) # 3 Make sure JSON file adheres to MARBL settings file schema if not MARBL_tools.settings_dictionary_is_consistent(self._settings): logger.error("%s is not a valid MARBL settings file" % default_settings_file) MARBL_tools.abort(1) # 4. Read settings input file self._input_dict = _parse_input_file(input_file) # 5. Use an ordered dictionary for keeping variable, value pairs # Also, tracer information is in its own dictionary (initialized to None) from collections import OrderedDict self.settings_dict = OrderedDict() self.tracers_dict = None for cat_name in self.get_category_names(): for var_name in self.get_variable_names(cat_name): self._process_variable_value(cat_name, var_name) # 5b. Need tracer count after determining PFT_derived_types, which means # determining which tracers are active if cat_name == "PFT_derived_types": self.tracers_dict = self._get_tracers() # 6. Abort if not all values from input file were processed # (That implies at least one variable from input file was not recognized) if (self._input_dict): message = "Did not fully parse input file:" for varname in self._input_dict.keys(): message = message + "\n * Variable %s not found in JSON file" % varname message = message + "\n (this was a case-insensitive lookup)" logger.error(message) MARBL_tools.abort(1)
def _parse_input_file(input_file): """ 1. Read an input file; ignore blank lines and non-quoted Fortran comments. 2. Turn lines of the form variable = value Into input_dict['variable'] = value 3. Return input_dict """ input_dict = dict() logger = logging.getLogger(__name__) try: f = open(input_file, "r") for line in f: # Ignore comments in input file! line_loc = _string_to_substring(line, '!')[0] # ignore empty lines if len(line_loc.lstrip()) == 0: continue line_list = line_loc.strip().split('=') # keys in input_dict are all lowercase to allow case-insensitive match var_name = line_list[0].strip().lower() value = line_list[1].strip() val_array = _string_to_substring(value, ',') if len(val_array) > 1: # Treat comma-delimited value as an array for n, value in enumerate(val_array): suffix = "(%d)" % (n + 1) input_dict[var_name + suffix] = value.strip() else: # Single value input_dict[var_name] = value f.close() except TypeError: # If inputfile == None then the open will result in TypeError pass except: logger.error("input_file '%s' was not found" % input_file) MARBL_tools.abort(1) return input_dict
def get_category_names(self): """ Returns category names as determined by the '_order' key in JSON file """ # Consistency checks: # 1. All keys listed in self._settings["_order"] should also be in self._settings.keys() for key in self._settings["_order"]: if key not in self._settings.keys(): msg = "ERROR: can not find '" + key + "' in JSON file" MARBL_tools.abort(msg) # 2. All keys listed in self._settings.keys() should also be in self._settings["_order"] # (except _order itself) for key in self._settings.keys(): if key not in ["_order", "_tracer_list" ] and key not in self._settings["_order"]: msg = "ERROR: '" + key + "' is not listed in '_order' and won't be processed" MARBL_tools.abort(msg) # 3. No duplicates in _order unique_keys = [] for key in self._settings["_order"]: if key in unique_keys: msg = "ERROR: '" + key + "' appears in '_order' multiple times" MARBL_tools.abort(msg) unique_keys.append(key) return self._settings["_order"]