示例#1
0
def dump_sg_results(sg_results,
                    variables,
                    config_data,
                    user_core_models={},
                    save=False):
    '''
    Adds sg_results for each core_model to the csv file indexed under core_model['ia']
    where the system_type of each core_model is specified in config_data.
    
    If the core_model is not in the database, you must provide your own core_model 
    in user_core_models and index it under its system_type.
    '''
    new_rows = {}
    for key in sg_results:
        system_type = config_data[key].get('system_type')
        core_model = user_core_models.get(system_type)

        if not core_model:
            core_model = mh.quick_search(system_type)

        fixed_parameters = list(config_data[key]['parameter_values'].keys())

        new_row = update_core_model(sg_result=sg_results[key],
                                    model_variables=variables[key],
                                    core_model=core_model,
                                    save=save,
                                    fixed_parameters=fixed_parameters,
                                    **config_data[key])

        new_rows[key] = new_row

    return new_rows
示例#2
0
def export_sg_results(sg_results,
                      variables,
                      config_data,
                      user_core_models={},
                      filename='sg_results.yaml'):
    '''
    Exports the results as a human-readable .yaml file
    '''
    yaml_dict = {}

    for key in sg_results:
        system_type = config_data[key].get('system_type')
        core_model = user_core_models.get(system_type)

        if not core_model:
            core_model = mh.quick_search(system_type)

        fixed_parameters = list(config_data[key]['parameter_values'].keys())

        nested_dict = make_new_nested_dict(sg_result=sg_results[key],
                                           model_variables=variables[key],
                                           core_model=core_model,
                                           fixed_parameters=fixed_parameters,
                                           **config_data[key])
        nested_dict = {**{'system_type': system_type}, **nested_dict}
        yaml_dict[key] = nested_dict

    outfile = filename if filename[-5:] == '.yaml' else filename + '.yaml'

    try:
        with open(outfile, 'w') as file:
            ya.dump(yaml_dict, file, sort_keys=False)
    except FileNotFoundError:  #user wants to use relative path
        cwd = Path(os.getcwd())
        rel_path = Path(outfile)
        folder = rel_path.parent
        stem = rel_path.stem
        ext = rel_path.suffix
        outfile = stem + ext if ext == '.yaml' else stem + ext + '.yaml'

        os.mkdir(folder)

        full_path = cwd / folder / outfile

        with open(full_path, 'w') as file:
            ya.dump(yaml_dict, file, sort_keys=False)

    except Exception as e:
        raise e

    return yaml_dict
示例#3
0
def get_sampler_args_bh(filename, user_core_models={}):
    '''Shortcut for setting up differential evolution for one model
    
    :meta: private
    '''

    config_data    = from_config(filename, 'bh') if type(filename) == str else filename
    core_models    = [mh.quick_search(config_data[key]['system_type']) for key in config_data]
    models, params = compile_models(core_models, config_data)
    
    guess            = {}
    bounds           = {}
    priors           = {}
    fixed_parameters = []
    step_size        = {}
    scipy_args       = {}
    for key in config_data:
        models[key]['init']                    = config_data[key]['init']
        models[key]['tspan']                   = config_data[key]['tspan']
        models[key]['int_args']['solver_args'] = config_data[key]['solver_args']
        
        temp      = {param + '_' + str(key): float(config_data[key]['guess'][param]) for param in config_data[key]['guess']}
        guess     = {**guess, **temp}
        
        temp      = {param + '_' + str(key): config_data[key]['parameter_bounds'][param] for param in config_data[key]['parameter_bounds']}
        bounds    = {**bounds, **temp} 
        
        temp      = {param + '_' + str(key): config_data[key]['priors'][param] for param in config_data[key]['priors']}
        priors    = {**priors, **temp}
        
        temp      = {param + '_' + str(key): config_data[key]['step_size'][param] for param in config_data[key]['step_size']}
        step_size = {**step_size, **temp}
        
        fixed_parameters   += [param + '_' + str(key) for param in config_data[key]['fixed_parameters']]
        fixed_parameters   += [i     + '_' + str(key) for i     in core_models[key-1]['inputs']]
        
        scipy_args = config_data[key]['bh_args'] if 'bh_args' in config_data[key] else scipy_args
        
    sampler_args = {'data'               : {},
                    'guess'              : guess,
                    'models'             : models, 
                    'fixed_parameters'               : fixed_parameters,
                    'priors'             : priors,
                    'bounds'             : bounds,
                    'step_size'          : step_size,
                    'scipy_args'         : scipy_args,
                    'step_size_is_ratio' : False
                    }
        
    return sampler_args, config_data
示例#4
0
def backend_add_to_database(settings, database, dialog=False):
    '''Supporting function for add_to_database. Do not run.
    
    :meta private:
    '''

    #Check core model exists
    core_model = mh.quick_search(settings['system_type'])

    #Prevent duplicates between MBase and UBase
    system_type_ensemble_name = (settings['system_type'],
                                 settings['settings_name'])

    if database == mh.MBase and system_type_ensemble_name in list_settings(
            database=mh.UBase):
        raise Exception(
            str(system_type_ensemble_name) +
            ' cannot be added to MBase as it is already in UBase.')

    if database == mh.UBase and system_type_ensemble_name in list_settings(
            database=mh.MBase):
        raise Exception(
            str(system_type_ensemble_name) +
            ' cannot be added to UBase as it is already in MBase.')

    params_dict = settings['parameters'].to_dict('list')
    params_dict = {
        key: params_dict[key]
        for key in settings['parameters'].to_dict('list')
    }

    row = {
        'system_type': settings['system_type'],
        'settings_name': settings['settings_name'],
        'units': str(settings['units']),
        'parameters': str(params_dict),
    }

    for key1 in ['init', 'priors', 'parameter_bounds']:
        row[key1] = str(
            {key2: list(settings[key1][key2])
             for key2 in settings[key1]})

    row['tspan'] = str([list(span) for span in settings['tspan']])
    row['fixed_parameters'] = str(settings['fixed_parameters'])
    row['solver_args'] = str(settings['solver_args'])

    mh.add_row('settings', row, database)
    print('Added settings ' + row['settings_name'])
    return row['system_type'], row['settings_name']
示例#5
0
def setup_helper(filename, reader, user_core_models={}):
    '''
    The first return value is the config_data which will be generated based on
    three possible scenarios:
    
        1. filename is a dictionary 
           The filename is already config_data. No processing needed.
           
        2. filename is a string
           filename is name of the settings file to be opened and parsed by reader. 
           
        3. filename is neither of the above
           filename is an iterable containing names of settings file. It will be
           iteratively parsed by reader and subsequently reindexed to give config_data.
    
    The second return value is a list of core_model data structures associated with 
    config_data. The list is arranged in the order given by config_data and the 
    core_models are retrieved based on two possible scenarios:
        
        1. The system_type in config_data[model_num]['system_type'] is in core_models
           The core_model indexed under core_models[system_type] will be used.
           
        2. The system_type in config_data[model_num]['system_type'] is not in core_models
           The function searches the BMSS database for the appropriate core_model
           using quick_search
    
    :meta: private
    '''
    if type(filename) == str:
        config_data = reader(filename)
    elif type(filename) == dict:  #Assume user has already imported the data
        config_data = filename
    else:  #Assume data is spread across multiple files
        config_data = [value for f in filename for value in reader(f).values()]
        config_data = dict(enumerate(config_data, start=1))

    core_models = [
        user_core_models[config_data[key]['system_type']]
        if config_data[key]['system_type'] in user_core_models else
        mh.quick_search(config_data[key]['system_type']) for key in config_data
    ]
    core_models = [
        mh.copy_core_model(core_model) for core_model in core_models
    ]

    return config_data, core_models
示例#6
0
def make_settings_template(system_types_settings_names, filename='', user_core_models={}):
    '''Writes settings to a config file. If you are using a core_model that is 
    not in the database, you must provide the core_model using the core_models 
    argument where the key is the system_type.Returns the code as a string.
    
    :param system_types_settings_names: Pairs of tuples containing (system_type, settings_name)
    :type system_types_settings_names: list or tuple
    :param filename: The name of the file to write to
    :type filename: str, optional
    :param user_core_model: A dictionary of core_models indexed by their system_type.
        core_models already in the database do not need to be specified here.
    :type user_core_model: dict, optional
    '''
    result = ''
    
    system_types_settings_names1 = [system_types_settings_names] if type(system_types_settings_names) == str else system_types_settings_names
    
    for pair in system_types_settings_names1:
        try:
            system_type, settings_name = pair
        except:
            system_type, settings_name = pair, '__default__'

        core_model     = user_core_models[system_type] if system_type in user_core_models else mh.quick_search(system_type)
        parameters     = core_model['parameters']
        inputs         = core_model['inputs']
        states         = core_model['states']
        section_header = '[' + core_model['system_type'] + ']'
        
        settings = {'system_type'     : system_type, 
                    'settings_name'   : settings_name,
                    'parameters'      : {},
                    'units'           : {},
                    'init'            : {},  
                    'priors'          : {}, 
                    'parameter_bounds': {},
                    'tspan'            : [],
                    'fixed_parameters' : [],
                    'solver_args'      : {'rtol'   : 1.49012e-8,
                                          'atol'   : 1.49012e-8,
                                          'tcrit'  : [],
                                          'h0'     : 0.0,
                                          'hmax'   : 0.0,
                                          'hmin'   : 0.0,
                                          'mxstep' : 0
                                          },
                    }
        
        if settings_name:
            settings = sh.quick_search(system_type, settings_name, skip_constructor=True)
        
        longest            = len(max(parameters,               key=len))    
        longest_           = len(max(inputs,                   key=len))  if inputs else None
        init_values        = dict_template('init',             states,     longest,  settings['init'],       default = 0)
        param_values       = dict_template('parameter_values', parameters, longest,  settings['parameters'], default = 1)
        input_conditions   = dict_template('input_conditions', inputs,     longest_, dict(zip(inputs, [0]*len(inputs)))) if inputs else ''
        fixed_parameters   = list_template('fixed_parameters', settings['fixed_parameters'])
        measured_states    = list_template('measured_states', states)
        
        model_id         = '#id = ' + str(core_model['id'])
        model_equations  = '#equations = \n' + '\n'.join(['#\t' + line for line in core_model['equations'] ])
        section_header   = '\n'.join([section_header, model_id, model_equations])
        
        result += '\n\n'.join([section_header, param_values, init_values, fixed_parameters, measured_states, input_conditions])
        
    if filename:
        with open(filename, 'w') as file:
            file.write(result)
    return result
示例#7
0
def make_settings_template(system_types_settings_names, filename=''):
    '''Writes settings to a config file. Returns the code as a string.
    
    :param system_types_settings_names: Pairs of tuples containing (system_type, settings_name)
    :type system_types_settings_names: list or tuple
    :param filename: The name of the file to write to
    :type filename: str, optional
    '''
    result = ''
    
    system_types_settings_names1 = [system_types_settings_names] if type(system_types_settings_names) == str else system_types_settings_names
    
    for pair in system_types_settings_names1:
        try:
            system_type, settings_name = pair
        except:
            system_type, settings_name = pair, '__default__'
        
        if type(system_type) == str:
            core_model     = mh.quick_search(system_type)
        else:
            core_model  = system_type
            system_type = core_model['system_type']
            
        parameters     = core_model['parameters'] + core_model['inputs']
        states         = core_model['states']
        section_header = '[]\nsystem_type = ' + core_model['system_type']
        
        if settings_name:
            settings = quick_search(system_type, settings_name, skip_constructor=True)

        else:            
            settings = {'system_type'      : system_type, 
                        'settings_name'    : settings_name,
                        'parameters'       : {},
                        'units'            : {},
                        'init'             : {},  
                        'priors'           : {}, 
                        'parameter_bounds' : {},
                        'tspan'            : [],
                        'fixed_parameters' : [],
                        'solver_args'      : {'rtol'   : 1.49012e-8,
                                              'atol'   : 1.49012e-8,
                                              'tcrit'  : [],
                                              'h0'     : 0.0,
                                              'hmax'   : 0.0,
                                              'hmin'   : 0.0,
                                              'mxstep' : 0
                                              },
                        }
        
        settings['init'] = DataFrame.from_dict(settings['init'], orient='index', columns=states).to_dict('list')
        longest          = len(max(parameters,               key=len))
        longest_         = len(max(settings['solver_args'],  key=len))  
        solver_args      = settings['solver_args'].keys()
        init_values      = dict_template('init',             states,     longest, settings['init'])
        param_values     = dict_template('parameter_values', parameters, longest, settings['parameters'])
        prior_values     = dict_template('priors',           parameters, longest, settings['priors'])
        bounds_values    = dict_template('parameter_bounds', parameters, longest, settings['parameter_bounds'])
        units_values     = dict_template('units',            parameters, longest, settings['units'], default='')
        tspan            = list_template('tspan',            [list(segment) for segment in settings['tspan']])
        fixed_parameters = list_template('fixed_parameters', settings['fixed_parameters'])
        solver_args      = dict_template('solver_args',      solver_args, longest_, settings['solver_args'])
        model_id         = '#id = ' + str(core_model['id'])
        model_equations  = '#equations = \n' + '\n'.join(['#\t' + line for line in core_model['equations'] ])
        section_header   = '\n'.join([section_header, model_id, model_equations])
        
        result += '\n\n'.join([section_header, init_values, param_values, prior_values, bounds_values, units_values, tspan, fixed_parameters, solver_args])
        
    if filename:
        with open(filename, 'w') as file:
            file.write(result)
    return result
示例#8
0
def make_settings(system_type,    settings_name,       units,    
                  parameters,     init=None,           tspan=None,           
                  priors={},      parameter_bounds={}, fixed_parameters=[], 
                  solver_args={}, init_orient='scenario', 
                  user_core_model=None, 
                  **ignored):
    '''Checks and standardizes formatting of data types. Ignores irrelavant keyword arguments.
    Returns a settings data structure which is a dict.
    
    :param system_type: A string of keywords serving as a unique identifier for 
        the core_model separated by commas, will be formatted so there is one space
        after each comma, keywords should be in CamelCase
    :type system_type: str
    :param settings_name: A string, forms a unique identifier when paired with system_type
    :type settings_name: str
    :param units: A dict where the keys are parameter names and the values are the units in strings
    :type units: dict
    :param parameters: A pandas DataFrame of parameter values OR a dictionary, 
        column names/keys must match the parameter names of the corresponding core_model  
    :type parameters: pandas DataFrame or dict
    :param init: A dictionary where the keys correspond to a state in the core_model and 
        the values are the initial values for numerical integration OR where the keys
        correspond to different scenarios 
    :type init: dict
    :param tspan: A list of segments for piecewise numerical integration where each segments
        is a list of time points, defaults to values generated using numpy.linspace
    :type tspan: list, optional
    :param priors: A dictionary of Gaussian priors for parameter estimation where each key 
        is a parameter name and each value a tuple in the form (mean, standard_deviation)
    :type priors: dict, optional
    :param parameter_bounds: A dictionary of parameter bounds for parameter estimation 
        where each key is a parameter name and each value a tuple in the form (lower, upper)
    :type parameter_bounds: dict, optional
    :param fixed_parameters: A list of parameter names that will be fixed during parameter estimation.
    :type fixed_parameters: list, optional 
    :param solver_args: Additional keyword arguments for scipy.integrate.odeint, defaults to None
    :type solver_args: dict, optional
    :param init_orient: 'scenario' if the keys in init are scenario numbers, 'state' 
        if the keys are the state names, defaults to 'scenario'
    :type init_orient: str
    :param user_core_model: A core_model data structure for cross-checking. If None, 
        this function will search the database for the core_model.
    :type user_core_model: dict
    '''
    
    system_type1 = system_type if type(system_type) == str else ', '.join(system_type)
    if user_core_model:
        core_model   = user_core_model
        if core_model['system_type'] != system_type1:
            raise Exception('system_type does not match that of user_core_model.')
        print('Making settings using user_core_model')
    else:
        core_model = mh.quick_search(system_type1)
        
    param_values = sc.check_and_assign_param_values(core_model, parameters)
    init1        = sc.check_and_assign_init(core_model['states'], init, init_orient)
    tspan1       = sc.check_and_assign_tspan(tspan)
    priors1      = sc.check_and_assign_priors(param_values, priors)
    bounds1      = sc.check_and_assign_parameter_bounds(param_values, parameter_bounds)
    solver_args1 = sc.check_and_assign_solver_args(solver_args)

    if fixed_parameters:
        fixable_parameters = core_model['parameters'] + core_model['inputs']
        if not all([p in fixable_parameters for p in fixed_parameters]):
            raise Exception('Error in fixed parameters. Unexpected parameters found.')
    
    
    settings_name1 = '__default__' if settings_name == '_' else settings_name
    
    result       = {'system_type'      : core_model['system_type'],
                    'settings_name'    : settings_name1,
                    'units'            : units,
                    'parameters'       : param_values,
                    'init'             : init1,
                    'priors'           : priors1,
                    'parameter_bounds' : bounds1,
                    'tspan'            : tspan1,
                    'fixed_parameters' : fixed_parameters,
                    'solver_args'      : solver_args1,
                    }
    return result
示例#9
0
def from_config(filename, user_core_models={}):
    '''Returns a settings data structure.
    
    :param filename: Name of file to read.
    :type filename: str
    :param user_core_models: A dictionary of core_models required for calling make_settings,
        to be ignored if the core_model is already in the database.
    :type user_core_models: dict, optional
    '''
    
    config              = configparser.RawConfigParser()
    config.optionxform  = lambda option: option
    all_settings        = []
    with open(filename, 'r') as file:
        config.read_file(file)
    
    for section in config.sections():
        if section in ['id', 'system_type', 'states', 'parameters', 'inputs', 'equations', 'ia']:
            continue
        if 'system_type' not in config[section]:
            continue
        
        system_type   = config[section]['system_type']
        params        = config[section]['parameter_values']
        units         = config[section]['units']
        init          = config[section].get('init', {})
        priors        = config[section].get('priors', {})
        bounds        = config[section].get('parameter_bounds', {})
        tspan         = config[section].get('tspan', '[[0, 600, 31]]')
        fixed_parameters = config[section].get('fixed_parameters', '[]')
        settings_name = str(section)
        
        core_model    = mh.quick_search(system_type)
        system_type   = core_model['system_type']
        states        = core_model['states']
        if not settings_name:
            raise Exception('Ensemble name not valid!')
        settings_name = '__default__' if settings_name == '_' else settings_name
        
        if init:
            if '=' in init:
                init = string_to_dict(init)
                try: 
                    init        = DataFrame(init)
                    init.index += 1
                    init        = init.T.to_dict('list')
                except:
                    init  = {1: list(init.values())}

                for key in init:
                    if len(init[key]) != len(states):
                        raise Exception('Length of init must match number of states. system_type given: ' + str(system_type))
            else:
                init = eval(init)
                if len(init) != len(states):
                    raise Exception('Length of init must match number of states. system_type given: ' + str(system_type))
                init = {1: init}

        params           = string_to_dict(params)
        units            = string_to_dict(units)
        priors           = string_to_dict(priors) if priors else {}
        bounds           = string_to_dict(bounds) if bounds else {}
        fixed_parameters = string_to_list_string(fixed_parameters)
        tspan            = eval_tspan_string(tspan)
        
        settings = {'system_type'      : system_type, 
                    'settings_name'    : settings_name,
                    'parameters'       : params,
                    'units'            : units,
                    'init'             : init,  
                    'priors'           : priors, 
                    'parameter_bounds' : bounds,
                    'tspan'            : tspan,
                    'fixed_parameters' : fixed_parameters
                    }
        
        user_core_model = user_core_models.get(settings['system_type'], {})
        all_settings.append(make_settings(**settings, user_core_model=user_core_model))
        
    return all_settings
示例#10
0
def search_database(system_type='', settings_name='', database=None, skip_constructor=False, active_only=True):
    '''Searches database for settings data structure based on system_type and settings
    name. Returns a list of settings dictionaries.
    
    :param system_type: A string that will be matched against entries in the database
    :type system_type: str
    :param settings_name: A string corresponding to any key in the core_model, will 
        be used for matching
    :type settings_name: str
    :param database: Can be either MBase or UBase, if None, this function will search
        both databases, defaults to None
    :type database: SQL Connection, optional
    :param skip_constructor: For backend use, defaults to False
    :type skip_constructor: bool, optional
    :param active_only: A boolean for backend use, if True, this limits the search 
        to rows where the value of active is True, defaults to True
    :type active_only: bool, optional
    '''
    #Can only add a settings for active models
    core_model = mh.quick_search(system_type, active_only=True)
    result     = []
    
    if settings_name and system_type:
        comm = 'SELECT * FROM settings WHERE system_type LIKE "%' + system_type + '%" AND settings_name LIKE "%' + settings_name
    elif settings_name:
        comm = 'SELECT * FROM settings WHERE settings_name LIKE "%' + settings_name
    else:
        comm = 'SELECT * FROM settings WHERE system_type LIKE "%' + system_type  
    
    if active_only:
        comm += '%" AND active = 1;'
    else:
        comm += '%";'
        
    databases = [database] if database else [mh.MBase, mh.UBase]
    
    for database in databases:
        with database as db:
            cursor       = db.execute(comm)
            all_settings = cursor.fetchall()    
         
        columns = database.execute('PRAGMA table_info(settings);')
        columns = columns.fetchall()
        columns = [column[1] for column in columns if column[1]!='active']
        all_settings  = [dict(zip(columns, s[:-1])) for s in all_settings]
        
        for s in all_settings:
            s['units']            = eval(s['units'])
            s['parameters']       = eval(s['parameters'])
            s['init']             = eval(s['init'])
            s['priors']           = eval(s['priors'])
            s['parameter_bounds'] = eval(s['parameter_bounds'])
            s['tspan']            = eval(s['tspan'])
            s['fixed_parameters'] = eval(s['fixed_parameters'])
            s['solver_args']      = eval(s['solver_args'])
        
        if skip_constructor:
            result += all_settings
        else:
            result += [make_settings(**s) for s in all_settings]

    return result