""" Utilities for working with PRMS data or other functionality that aren't appropriate to put elsewhere at this time. """ import numpy as np import pandas as pd def load_statvar(statvar_file): """ Read the statvar file and load into a datetime indexed Pandas dataframe object Arguments: statvar_file (str): statvar file path Returns: (pandas.DataFrame) Pandas DataFrame of PRMS variables date indexed from statvar file """ # make list of statistical output variables for df header column_list = ['index', 'year', 'month', 'day', 'hh', 'mm', 'sec'] # append to header list the variables present in the file with open(statvar_file, 'r') as inf: for idx, l in enumerate(inf): # first line is always number of stat variables if idx == 0: n_statvars = int(l) elif idx <= n_statvars and idx != 0: column_list.append(l.rstrip().replace(' ', '_')) else: break # arguments for read_csv function missing_value = -999 skiprows = n_statvars+1 df = pd.read_csv( statvar_file, delim_whitespace=True, skiprows=skiprows, header=-1, na_values=[missing_value] ) # apply correct header names using metadata retrieved from file df.columns = column_list date = pd.Series( pd.to_datetime(df.year*10000+df.month*100+df.day, format='%Y%m%d'), index=df.index ) # make the df index the datetime for the time series data df.index = pd.to_datetime(date) # drop unneeded columns df.drop(['index', 'year', 'month', 'day', 'hh', 'mm', 'sec'], axis=1, inplace=True) # name dataframe axes (index,columns) df.columns.name = 'statistical_variables' df.index.name = 'date' return df def load_data_file(data_file): """ Read the data file and load into a datetime indexed Pandas dataframe object Arguments: data_file (string): data file path Returns: df (pandas.DataFrame): Pandas dataframe of input time series data from data file with datetime index """ # valid input time series that can be put into a data file valid_input_variables = ('gate_ht', 'humidity', 'lake_elev', 'pan_evap', 'precip', 'rain_day', 'runoff', 'snowdepth', 'solrad', 'tmax', 'tmin', 'wind_speed') # starting list of names for header in dataframe column_list = ['year', 'month', 'day', 'hh', 'mm', 'sec'] # append to header list the variables present in the file with open(data_file, 'r') as inf: for idx, l in enumerate(inf): # first line always string identifier of the file- may use later if idx == 0: data_head = l.rstrip() elif l.startswith('/'): # comment lines continue # header lines with name and number of input variables if l.startswith(valid_input_variables): # split line into list, first element name and # second number of columns h = l.split() # more than one input time series of a particular variable if int(h[1]) > 1: for el in range(int(h[1])): tmp = '{var_name}_{var_ind}'.format(var_name=h[0], var_ind=el+1) column_list.append(tmp) elif int(h[1]) == 1: column_list.append(h[0]) # end of header info and begin time series input data if l.startswith('#'): skip_line = idx+1 break # read data file into pandas dataframe object with correct header names missing_value = -999 # missing data representation df = pd.read_csv(data_file, header=-1, skiprows=skip_line, delim_whitespace=True, na_values=[missing_value]) # apply correct header names using metadata retrieved from file df.columns = column_list # create date column date = pd.Series( pd.to_datetime(df.year*10000+df.month*100+df.day, format='%Y%m%d'), index=df.index ) df.index = pd.to_datetime(date) # make the df index the datetime # drop unneeded columns df.drop(['year', 'month', 'day', 'hh', 'mm', 'sec'], axis=1, inplace=True) df.columns.name = 'input variables' df.index.name = 'date' # name dataframe axes (index,columns) return df def nash_sutcliffe(observed, modeled): """ Calculates the Nash-Sutcliffe Goodness-of-fit Arguments: observed (numpy.ndarray): historic observational data modeled (numpy.ndarray): model output with matching time index """ numerator = sum((observed - modeled)**2) denominator = sum((observed - np.mean(observed))**2) return 1 - (numerator/denominator)