|
| 1 | +""" |
| 2 | +Description to come |
| 3 | +""" |
| 4 | +import numpy as np |
| 5 | +import pandas as pd |
| 6 | +import os |
| 7 | + |
| 8 | +class Data(object): |
| 9 | + """ |
| 10 | + PRMS data object to read, write and modify time |
| 11 | + series input to PRMS that are located in the PRMS data file |
| 12 | + """ |
| 13 | + ## data file constant attributes |
| 14 | + date_header = ['year', |
| 15 | + 'month', |
| 16 | + 'day', |
| 17 | + 'hh', |
| 18 | + 'mm', |
| 19 | + 'sec'] |
| 20 | + |
| 21 | + valid_input_variables = ('gate_ht', |
| 22 | + 'humidity', |
| 23 | + 'lake_elev', |
| 24 | + 'pan_evap', |
| 25 | + 'precip', |
| 26 | + 'rain_day', |
| 27 | + 'runoff', |
| 28 | + 'snowdepth', |
| 29 | + 'solrad', |
| 30 | + 'tmax', |
| 31 | + 'tmin', |
| 32 | + 'wind_speed') |
| 33 | + |
| 34 | + def __init__(self, base_file): |
| 35 | + self.base_file = base_file |
| 36 | + self.metadata = self.__load_metadata() |
| 37 | + self.data_frame = self.__load_data() |
| 38 | + |
| 39 | + def __load_metadata(self): |
| 40 | + """ |
| 41 | + """ |
| 42 | + ## valid input time series that can be put into a data file |
| 43 | + |
| 44 | + #### starting list of names for header in dataframe |
| 45 | + input_data_names = [] |
| 46 | + ## append to header list the variables present in the file |
| 47 | + with open(self.base_file, 'r') as inf: |
| 48 | + for idx,l in enumerate(inf): |
| 49 | + if idx == 0: ## first line always string identifier of the file- may use later |
| 50 | + data_head = l.rstrip() |
| 51 | + elif l.startswith('/'): ## comment lines |
| 52 | + continue |
| 53 | + if l.startswith(Data.valid_input_variables): ## header lines with name and number of input variables |
| 54 | + h = l.split() ## split line into list, first element name and second number of columns |
| 55 | + if int(h[1]) > 1: ## more than one input time series of a particular variable |
| 56 | + for el in range(int(h[1])): |
| 57 | + tmp = '{var_name} {var_ind}'.format(var_name = h[0], var_ind = el+1) |
| 58 | + input_data_names.append(tmp) |
| 59 | + elif int(h[1]) == 1: |
| 60 | + input_data_names.append(h[0]) |
| 61 | + if l.startswith('#'): ## end of header info and begin time series input data |
| 62 | + data_startline = idx+1 ## 0 indexed line of first data entry |
| 63 | + break |
| 64 | + |
| 65 | + return dict([('data_startline',data_startline), ('data_variables',input_data_names)]) |
| 66 | + |
| 67 | + def __load_data(self): |
| 68 | + missing_value = -999 ## missing data representation |
| 69 | + df = pd.read_csv(self.base_file, header = -1, skiprows = self.metadata['data_startline'], |
| 70 | + delim_whitespace = True, na_values = [missing_value]) ## read file |
| 71 | + df.columns = Data.date_header + self.metadata['data_variables'] |
| 72 | + date = pd.Series(pd.to_datetime(df.year * 10000 + df.month * 100 + df.day, format = '%Y%m%d'), index = df.index) |
| 73 | + df.index = pd.to_datetime(date) |
| 74 | + df.drop(Data.date_header, axis = 1, inplace = True) ## unneeded columns |
| 75 | + df.columns.name = 'input variables' ; df.index.name = 'date' |
| 76 | + return df |
| 77 | + |
| 78 | + def adjust(self, func, vars_to_adjust): |
| 79 | + for v in vars_to_adjust: |
| 80 | + self.data_frame[v] = self.data_frame[v].apply(func) |
| 81 | + |
| 82 | + def write(self, out_path): |
| 83 | + ## reconstruct original datafile format |
| 84 | + self.data_frame['year'] = self.data_frame.index.year |
| 85 | + self.data_frame['month'] = self.data_frame.index.month |
| 86 | + self.data_frame['day'] = self.data_frame.index.day |
| 87 | + self.data_frame['hh'] = self.data_frame['mm'] = self.data_frame['sec'] = 0 |
| 88 | + self.data_frame = self.data_frame[Data.date_header + self.metadata['data_variables']] |
| 89 | + with open(out_path,'w') as outf: |
| 90 | + with open(self.base_file) as data: |
| 91 | + for idx, line in enumerate(data): |
| 92 | + if idx == self.metadata['data_startline']: |
| 93 | + self.data_frame.to_csv(outf, sep=' ', header=None, index=False, na_rep=-999) |
| 94 | + break |
| 95 | + outf.write(line) # write line by line the header lines from original |
| 96 | + |
0 commit comments