pyhcal 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyhcal/__init__.py +7 -0
- pyhcal/calibrators.py +642 -0
- pyhcal/data/HUC_Names.csv +84 -0
- pyhcal/data/WISKI_EQUIS_XREF.csv +25789 -0
- pyhcal/data/stations_EQUIS.gpkg +0 -0
- pyhcal/data/stations_wiski.gpkg +0 -0
- pyhcal/figures.py +1024 -0
- pyhcal/metrics.py +485 -0
- pyhcal/modl_db.py +97 -0
- pyhcal/repository.py +98 -0
- pyhcal/setup_utils.py +573 -0
- pyhcal-1.0.0.dist-info/METADATA +15 -0
- pyhcal-1.0.0.dist-info/RECORD +14 -0
- pyhcal-1.0.0.dist-info/WHEEL +4 -0
pyhcal/setup_utils.py
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""
|
|
3
|
+
Created on Wed Jun 15 15:21:35 2022
|
|
4
|
+
|
|
5
|
+
@author: mfratki
|
|
6
|
+
"""
|
|
7
|
+
from mpcaHydro.data_manager import dataManager
|
|
8
|
+
from pyhspf.wdmReader import readWDM
|
|
9
|
+
from pyhspf.uci import UCI
|
|
10
|
+
from pyhcal.repository import Repository
|
|
11
|
+
|
|
12
|
+
import numpy as np
|
|
13
|
+
import pandas as pd
|
|
14
|
+
from pathlib import Path
|
|
15
|
+
import subprocess
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def create_calibration_project(model_name,project_location,download_station_data = True,run_model = True,convert_wdms = True):
|
|
19
|
+
project = Builder(model_name)
|
|
20
|
+
project.copy(project_location,model_name)
|
|
21
|
+
project.load_uci()
|
|
22
|
+
project.format_uci()
|
|
23
|
+
project.uci.build_targets().to_csv(project.project_path.joinpath('targets.csv'))
|
|
24
|
+
if convert_wdms: project.convert_wdms()
|
|
25
|
+
if download_station_data: project.download_station_data()
|
|
26
|
+
if run_model: project.run_model()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Builder():
|
|
33
|
+
|
|
34
|
+
def __init__(self,model_name):
|
|
35
|
+
self.repository = Repository(model_name)
|
|
36
|
+
self.project_path = None
|
|
37
|
+
self.project_name = None
|
|
38
|
+
self.new_uci = None
|
|
39
|
+
self.uci = None
|
|
40
|
+
self.dm = None
|
|
41
|
+
|
|
42
|
+
def valid_models():
|
|
43
|
+
return Repository.valid_models()
|
|
44
|
+
|
|
45
|
+
def set_project_path(self,project_path):
|
|
46
|
+
self.project_path = Path(project_path)
|
|
47
|
+
self.project_name = Path(project_path).name
|
|
48
|
+
#self.new_uci = self.project_path.joinpath('model','_'.join([self.project_name,'0.uci']))
|
|
49
|
+
#self.uci = UCI(self.project_path.joinpath('model','.'.join([self.project_name,'uci'])))
|
|
50
|
+
|
|
51
|
+
def copy(self,project_location,project_name):
|
|
52
|
+
self.project_path = Path(project_location).joinpath(project_name)
|
|
53
|
+
self.project_name = project_name
|
|
54
|
+
self.repository.copy(self.project_path)
|
|
55
|
+
self.dm = dataManager(self.project_path.joinpath('data'))
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def load_uci(self):
|
|
59
|
+
self.new_uci = self.project_path.joinpath('model','_'.join([self.project_name,'0.uci']))
|
|
60
|
+
self.uci = UCI(self.project_path.joinpath('model','.'.join([self.project_name,'uci'])))
|
|
61
|
+
|
|
62
|
+
def process(self):
|
|
63
|
+
self.load_uci()
|
|
64
|
+
self.format_uci()
|
|
65
|
+
self.download_station_data()
|
|
66
|
+
self.uci.build_targets().to_csv(self.project_path.joinpath('targets.csv'))
|
|
67
|
+
|
|
68
|
+
# if not self.project_path.joinpath('model',self.project_name + '_0-0.hbn').exists():
|
|
69
|
+
# self.run_model()
|
|
70
|
+
|
|
71
|
+
#TODO move to UCI class
|
|
72
|
+
|
|
73
|
+
def format_uci(self,calibration_reaches = None):
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
setup_files(self.uci,self.project_name,run = 0)
|
|
77
|
+
setup_geninfo(self.uci)
|
|
78
|
+
|
|
79
|
+
if calibration_reaches is None:
|
|
80
|
+
calibration_reaches = self.repository.modl_db.loc[self.repository.modl_db['wplmn_flag'] == 1]['opnids'].str.split(',').to_list()
|
|
81
|
+
calibration_reaches = [abs(int(j)) for i in calibration_reaches for j in i]
|
|
82
|
+
#calibration_reaches = self.uci.network.station_order(calibration_reaches)[-1][0]
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
self.uci.initialize(name = self.project_name + '_0')
|
|
86
|
+
# for reaches in self._MODL_DB['opnids'].str.split('+').to_list():
|
|
87
|
+
# [calibration_reaches.append(int(reach)) for reach in reaches if ~pd.isna(reach)]
|
|
88
|
+
|
|
89
|
+
setup_binaryinfo(self.uci,reach_ids = calibration_reaches)
|
|
90
|
+
setup_qualid(self.uci)
|
|
91
|
+
self.uci.write(self.new_uci)
|
|
92
|
+
|
|
93
|
+
# Download observation data
|
|
94
|
+
# Sources/Databases WISKI and EQUIS (DELTA databases?)
|
|
95
|
+
#TODO: use a single WISKI etl script for csg and wplmn data
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def download_station_data(self):#:,station_id,source_id):
|
|
99
|
+
stations = self.repository.modl_db.drop_duplicates(subset = ['source','station_id'])
|
|
100
|
+
if not stations.empty:
|
|
101
|
+
for index, row in stations.iterrows():
|
|
102
|
+
assert(row['source'].lower() in ['wiski','equis','swd'])
|
|
103
|
+
station_id = row['station_id']
|
|
104
|
+
self.dm.download_station_data(station_id,row['source'].lower())
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def convert_wdms(self):
|
|
108
|
+
copy_path = Path(self.project_path.joinpath('model'))
|
|
109
|
+
wdm_files = [copy_path.joinpath(wdm_file.name) for wdm_file in self.repository.wdm_files]
|
|
110
|
+
for wdm_file in wdm_files:
|
|
111
|
+
readWDM(wdm_file,
|
|
112
|
+
copy_path.joinpath(wdm_file.name.replace('.wdm','.hdf5').replace('.WDM','hdf5')))
|
|
113
|
+
|
|
114
|
+
def run_model(self):
|
|
115
|
+
# Run the uci file
|
|
116
|
+
winHSPF = str(Path(__file__).resolve().parent.parent) + '\\bin\\WinHSPFLt\\WinHspfLt.exe'
|
|
117
|
+
subprocess.run([winHSPF,self.new_uci]) #, stdout=subprocess.PIPE, creationflags=0x08000000)
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
### functions for setting up the UCI file properly
|
|
123
|
+
def setup(uci,name,run = 0,reach_ids = None,n = 1,time_step = 3):
|
|
124
|
+
uci = setup_files(uci,name,run,n)
|
|
125
|
+
uci = setup_geninfo(uci)
|
|
126
|
+
uci = setup_binaryinfo(uci,reach_ids = reach_ids)
|
|
127
|
+
uci = setup_qualid(uci)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
#def setup_files(uci,name,run = 0,n=5): # Add as method to a Files class?
|
|
131
|
+
# # Update paths in Files block
|
|
132
|
+
|
|
133
|
+
def setup_files(uci,name,run,n = 5):
|
|
134
|
+
table = uci.table('FILES',drop_comments = False)
|
|
135
|
+
for index, row in table.iterrows():
|
|
136
|
+
filename = Path(row['FILENAME'])
|
|
137
|
+
if filename.suffix in ['.wdm','.ech','.out']:
|
|
138
|
+
table.loc[index,'FILENAME'] = filename.name
|
|
139
|
+
if filename.suffix in ['.hbn']:
|
|
140
|
+
table.loc[index,'FILENAME'] = filename.name
|
|
141
|
+
if filename.suffix in ['.plt']:
|
|
142
|
+
table.drop(index,inplace = True)
|
|
143
|
+
|
|
144
|
+
# Get new binary number and create new BINO rows
|
|
145
|
+
bino_nums = []
|
|
146
|
+
invalid = table['UNIT'].values
|
|
147
|
+
for num in range(15,100):
|
|
148
|
+
if num not in invalid:
|
|
149
|
+
bino_nums.append(num)
|
|
150
|
+
if len(bino_nums) == n:
|
|
151
|
+
break
|
|
152
|
+
binary_names = ['_'.join([name,str(run)])+ '-' + str(num) + '.hbn' for num in range(len( bino_nums))]
|
|
153
|
+
rows = [['BINO',bino_num,binary_name,''] for bino_num,binary_name in zip(bino_nums,binary_names)]
|
|
154
|
+
rows = pd.DataFrame(rows, columns = table.columns).astype({'FTYPE':'string','UNIT':'Int64','FILENAME':'string','comments':'string'} )
|
|
155
|
+
# Drop old BINO rows and insert new BINO rows
|
|
156
|
+
table = table.loc[table['FTYPE'] != 'BINO'].reset_index(drop=True)
|
|
157
|
+
rows = pd.DataFrame(rows, columns = table.columns).astype(table.dtypes) #{'FTYPE':'string','UNIT':'Int64','FILENAME':'string','comments':'string'} )
|
|
158
|
+
table = pd.concat([table,rows])
|
|
159
|
+
table.reset_index(drop=True,inplace=True)
|
|
160
|
+
|
|
161
|
+
# Update table in the uci
|
|
162
|
+
uci.replace_table(table,'FILES')
|
|
163
|
+
|
|
164
|
+
return uci
|
|
165
|
+
|
|
166
|
+
def setup_geninfo(uci):
|
|
167
|
+
# Initialize Gen-Info
|
|
168
|
+
bino_nums = uci.table('FILES').set_index('FTYPE').loc['BINO','UNIT'].tolist()
|
|
169
|
+
if isinstance(bino_nums,int): #Pands is poorly designed. Why would tolist not return a goddamn list...?
|
|
170
|
+
bino_nums = [bino_nums]
|
|
171
|
+
|
|
172
|
+
#opnids = uci.table(operation,'GEN-INFO').index
|
|
173
|
+
for operation in ['RCHRES','PERLND','IMPLND']:
|
|
174
|
+
opnids = np.array_split(uci.table(operation,'GEN-INFO').index.to_list(),len(bino_nums))
|
|
175
|
+
|
|
176
|
+
for opnid,bino_num in zip(opnids,bino_nums):
|
|
177
|
+
if operation == 'RCHRES': #TODO convert BUNITE to BUNIT1 to get rid of this if statement
|
|
178
|
+
uci.update_table(bino_num,'RCHRES','GEN-INFO',0,opnids = opnid,columns = 'BUNITE',operator = 'set')
|
|
179
|
+
else:
|
|
180
|
+
uci.update_table(bino_num,operation,'GEN-INFO',0,opnids = opnid,columns = 'BUNIT1',operator = 'set')
|
|
181
|
+
return uci
|
|
182
|
+
|
|
183
|
+
def setup_binaryinfo(uci,default_output = 4,reach_ids = None):
|
|
184
|
+
# Initialize Binary-Info
|
|
185
|
+
uci.update_table(default_output,'PERLND','BINARY-INFO',0,
|
|
186
|
+
columns = ['AIRTPR', 'SNOWPR', 'PWATPR', 'SEDPR', 'PSTPR', 'PWGPR', 'PQALPR','MSTLPR', 'PESTPR', 'NITRPR', 'PHOSPR', 'TRACPR'],
|
|
187
|
+
operator = 'set')
|
|
188
|
+
uci.update_table(default_output,'IMPLND','BINARY-INFO',0,
|
|
189
|
+
columns = ['ATMPPR', 'SNOWPR', 'IWATPR', 'SLDPR', 'IWGPR', 'IQALPR'],
|
|
190
|
+
operator = 'set')
|
|
191
|
+
uci.update_table(default_output,'RCHRES','BINARY-INFO',0,
|
|
192
|
+
columns = ['HYDRPR', 'ADCAPR', 'CONSPR', 'HEATPR', 'SEDPR', 'GQLPR', 'OXRXPR', 'NUTRPR', 'PLNKPR', 'PHCBPR'],
|
|
193
|
+
operator = 'set')
|
|
194
|
+
|
|
195
|
+
uci.update_table(default_output,'PERLND','BINARY-INFO',0,columns = ['SNOWPR','SEDPR','PWATPR','PQALPR'],operator = 'set')
|
|
196
|
+
uci.update_table(default_output,'IMPLND','BINARY-INFO',0,columns = ['SNOWPR','IWATPR','SLDPR','IQALPR'],operator = 'set')
|
|
197
|
+
uci.update_table(default_output,'RCHRES','BINARY-INFO',0,columns = ['HYDRPR','SEDPR','HEATPR','OXRXPR','NUTRPR','PLNKPR'],operator = 'set')
|
|
198
|
+
if reach_ids is not None:
|
|
199
|
+
uci.update_table(3,'RCHRES','BINARY-INFO',0,columns = ['SEDPR','OXRXPR','NUTRPR','PLNKPR'],opnids = reach_ids,operator = 'set')
|
|
200
|
+
uci.update_table(2,'RCHRES','BINARY-INFO',0,columns = ['HEATPR','HYDRPR'],opnids = reach_ids,operator = 'set')
|
|
201
|
+
return uci
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def setup_qualid(uci):
|
|
205
|
+
#### Standardize QUAL-ID Names
|
|
206
|
+
# Perlands
|
|
207
|
+
uci.update_table('NH3+NH4','PERLND','QUAL-PROPS',0,columns = 'QUALID',operator = 'set')
|
|
208
|
+
uci.update_table('NO3','PERLND','QUAL-PROPS',1,columns = 'QUALID',operator = 'set')
|
|
209
|
+
uci.update_table('ORTHO P','PERLND','QUAL-PROPS',2,columns = 'QUALID',operator = 'set')
|
|
210
|
+
uci.update_table('BOD','PERLND','QUAL-PROPS',3,columns = 'QUALID',operator = 'set')
|
|
211
|
+
|
|
212
|
+
# Implands
|
|
213
|
+
uci.update_table('NH3+NH4','IMPLND','QUAL-PROPS',0,columns = 'QUALID',operator = 'set')
|
|
214
|
+
uci.update_table('NO3','IMPLND','QUAL-PROPS',1,columns = 'QUALID',operator = 'set')
|
|
215
|
+
uci.update_table('ORTHO P','IMPLND','QUAL-PROPS',2,columns = 'QUALID',operator = 'set')
|
|
216
|
+
uci.update_table('BOD','IMPLND','QUAL-PROPS',3,columns = 'QUALID',operator = 'set')
|
|
217
|
+
return uci
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
# def build_targets(uci,reach_ids,wplmn_map,wplmn_path,wplmn = None):
|
|
222
|
+
# targets = uci.lc_info()
|
|
223
|
+
# uci_names = targets['uci_name'].values
|
|
224
|
+
# if wplmn is None:
|
|
225
|
+
# wplmn = get_yields(reach_ids,uci,wplmn_path)
|
|
226
|
+
|
|
227
|
+
# npsl_names = [wplmn_map[name] for name in targets['uci_name']]
|
|
228
|
+
# targets['npsl_name'] = npsl_names #targets['npsl_name'] = npsl_names
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
# npsl_rates = pd.concat([uci.npsl_targets.loc[name].mean() for name in npsl_names],axis = 1).transpose()
|
|
233
|
+
# npsl_rates['uci_name'] = uci_names
|
|
234
|
+
# npsl_rates = npsl_rates.melt(id_vars = 'uci_name',var_name = 'parameter', value_name = 'npsl_yield')
|
|
235
|
+
|
|
236
|
+
# targets = npsl_rates.merge(targets,on = 'uci_name')
|
|
237
|
+
# targets = targets.set_index(['uci_name','parameter'])
|
|
238
|
+
|
|
239
|
+
# # normalize by dominant landcover of the model
|
|
240
|
+
# dom_lc_name = targets.index.get_level_values(0)[np.argmax(targets['area'])]
|
|
241
|
+
# targets['npsl_yield_ratio'] = np.nan
|
|
242
|
+
# for parameter in ['TSS','TKN','N','OP','BOD']:
|
|
243
|
+
# values = targets.loc[:,parameter,:]['npsl_yield']/targets.loc[dom_lc_name,parameter]['npsl_yield']
|
|
244
|
+
# targets.loc[values.index,'npsl_yield_ratio'] = values
|
|
245
|
+
|
|
246
|
+
# # landcover area ratio compared to total area of watershed
|
|
247
|
+
# targets['lc_area_ratio']= targets['area']/np.sum(targets.loc[:,'TSS',:]['area'])
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# targets['wplmn_yield'] = np.nan
|
|
251
|
+
# for parameter in ['TSS','TKN','N','OP','BOD']:
|
|
252
|
+
# targets.loc[targets.loc[:,parameter,:].index,'wplmn_yield'] = wplmn[parameter]
|
|
253
|
+
|
|
254
|
+
# # interative solution to determine target landcover loading rates
|
|
255
|
+
# targets['lc_yield'] = np.nan
|
|
256
|
+
# threshold = .05
|
|
257
|
+
# for parameter in ['TSS','TKN','N','OP','BOD']:
|
|
258
|
+
# print(parameter)
|
|
259
|
+
# diff = 1
|
|
260
|
+
# scaling_factor = 1
|
|
261
|
+
# new_factor = 1
|
|
262
|
+
# while diff > threshold:
|
|
263
|
+
# scaling_factor = new_factor
|
|
264
|
+
# lc_yield = (targets['lc_area_ratio']*targets['npsl_yield_ratio']*scaling_factor).loc[:,parameter,:]
|
|
265
|
+
# new_factor = wplmn[parameter]/np.sum(lc_yield)*scaling_factor
|
|
266
|
+
# diff = np.abs((np.nansum(lc_yield)-wplmn[parameter])/wplmn[parameter])
|
|
267
|
+
# print(scaling_factor)
|
|
268
|
+
# values = targets.loc[targets.loc[:,parameter,:].index,'npsl_yield_ratio']*scaling_factor
|
|
269
|
+
# targets.loc[values.index,'lc_yield'] = values.values
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
# targets = uci.lc_info().set_index('uci_name').join(targets.unstack()['lc_yield'])
|
|
273
|
+
# targets['dom_lc'] = np.nan
|
|
274
|
+
# targets.loc[targets.index[np.argmax(targets['area'])],'dom_lc'] = 1
|
|
275
|
+
# return targets
|
|
276
|
+
|
|
277
|
+
# def get_yields(reach_ids,uci,wplmn_path):
|
|
278
|
+
# loadNetwork = dm.loadNetwork(wplmn_path,reach_ids)
|
|
279
|
+
|
|
280
|
+
# schematic = uci.table('SCHEMATIC')
|
|
281
|
+
# schematic = schematic.astype({'TVOLNO': int, "SVOLNO": int, 'AFACTR':float})
|
|
282
|
+
# schematic = schematic[(schematic['SVOL'] == 'PERLND')| (schematic['SVOL'] == 'IMPLND')]
|
|
283
|
+
# schematic = schematic[schematic['TVOL'] == 'RCHRES']
|
|
284
|
+
# reaches = np.concatenate([nu.get_opnids(uci,reach_id)[0] for reach_id in reach_ids])
|
|
285
|
+
# area = np.sum([schematic['AFACTR'][schematic['TVOLNO'] == reach].sum() for reach in reaches])
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# # wplmn2 = {'TSS': 18.01,
|
|
289
|
+
# # 'TP': 0.23,
|
|
290
|
+
# # 'OP':0.082,
|
|
291
|
+
# # 'TKN':1.921,
|
|
292
|
+
# # 'N':2.304}
|
|
293
|
+
# # wplmn2['BOD'] = 50*(wplmn['TP'] - wplmn['OP'])
|
|
294
|
+
# # wplmn2['TKN'] = wplmn['TKN'] - wplmn['BOD']*.144
|
|
295
|
+
|
|
296
|
+
# wplmn = {'TSS': 0,
|
|
297
|
+
# 'TP': 0,
|
|
298
|
+
# 'OP':0,
|
|
299
|
+
# 'TKN':0,
|
|
300
|
+
# 'N':0}
|
|
301
|
+
|
|
302
|
+
# for key in wplmn.keys():
|
|
303
|
+
# if key == 'TSS':
|
|
304
|
+
# wplmn[key] = np.mean(loadNetwork.get_timeseries(key,'Load').groupby('year').sum()['Ts Value']/area*2000)
|
|
305
|
+
# else:
|
|
306
|
+
# wplmn[key] = np.mean(loadNetwork.get_timeseries(key,'Load').groupby('year').sum()['Ts Value']/area)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
# wplmn['BOD'] = 50*(wplmn['TP'] - wplmn['OP'])
|
|
310
|
+
# wplmn['TKN'] = wplmn['TKN'] - wplmn['BOD']*.144
|
|
311
|
+
# return wplmn
|
|
312
|
+
|
|
313
|
+
# def lc_info(uci):
|
|
314
|
+
# uci.get_metzones2()
|
|
315
|
+
# geninfo = uci.table('PERLND','GEN-INFO')
|
|
316
|
+
# targets = uci.opnid_dict['PERLND'].loc[:,['LSID','landcover']] #.drop_duplicates(subset = 'landcover').loc[:,['LSID','landcover']].reset_index(drop = True)
|
|
317
|
+
# targets.columns = ['LSID','lc_number']
|
|
318
|
+
# schematic = uci.table('SCHEMATIC')
|
|
319
|
+
# schematic = schematic.astype({'TVOLNO': int, "SVOLNO": int, 'AFACTR':float})
|
|
320
|
+
# schematic = schematic[(schematic['SVOL'] == 'PERLND')]
|
|
321
|
+
# schematic = schematic[(schematic['TVOL'] == 'PERLND') | (schematic['TVOL'] == 'IMPLND') | (schematic['TVOL'] == 'RCHRES')]
|
|
322
|
+
# areas = []
|
|
323
|
+
# for lc_number in targets['lc_number'].unique():
|
|
324
|
+
# areas.append(np.sum([schematic['AFACTR'][schematic['SVOLNO'] == perland].sum() for perland in targets.index[targets['lc_number'] == lc_number]]))
|
|
325
|
+
# areas = np.array(areas)
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
# lc_number = targets['lc_number'].drop_duplicates()
|
|
329
|
+
# uci_names = geninfo.loc[targets['lc_number'].drop_duplicates().index]['LSID']
|
|
330
|
+
# targets = pd.DataFrame([uci_names.values,lc_number.values,areas]).transpose()
|
|
331
|
+
# targets.columns = ['uci_name','lc_number','area']
|
|
332
|
+
# targets['npsl_name'] = ''
|
|
333
|
+
|
|
334
|
+
# targets[['TSS','N','TKN','OP','BOD']] = ''
|
|
335
|
+
|
|
336
|
+
# targets['dom_lc'] = ''
|
|
337
|
+
# targets.loc[targets['area'].astype('float').argmax(),'dom_lc'] = 1
|
|
338
|
+
# return targets
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
#WPLMN = pd.read_csv()
|
|
345
|
+
# HUC_DIRECTORY = pd.read_csv('C:/Users/mfratki/Documents/Github/hspf_tools/calibrator/HUC_Names.csv',dtype = {'USGS HUC-8':'string',
|
|
346
|
+
# 'USGS HUC-6':'string',
|
|
347
|
+
# 'USGS HUC-4':'string',
|
|
348
|
+
# 'USGS HUC-2':'string'})
|
|
349
|
+
#MODL_DB = pd.read_csv('C:/Users/mfratki/Documents/Github/hspf_tools/calibrator/WPLMN.csv',dtype = {'stn_HUC12':'string'})
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
# REPO = Path('X:\Databases2\Water_Quality\Watershed_Modeling\MPCA_HSPF_Model_Repository') #could point to the github website if it becomes public
|
|
353
|
+
# huc8_id = '10170204'
|
|
354
|
+
# huc6_name = HUC_DIRECTORY.loc[HUC_DIRECTORY['USGS HUC-6'] == huc8_id[:6],'Repository_HUC6 Name'].iloc[0]
|
|
355
|
+
# model_name = HUC_DIRECTORY.loc[HUC_DIRECTORY['USGS HUC-8'] == huc8_id[:8],'Repository_HUC8 Name'].iloc[0]
|
|
356
|
+
# repo_folder = [item for item in REPO.joinpath('_'.join([huc6_name,huc8_id[:6]])).iterdir() if item.name.startswith(model_name)]
|
|
357
|
+
# repo_folder = repo_folder[0]
|
|
358
|
+
|
|
359
|
+
# stations = gpd.read_file('C:/Users/mfratki/Documents/Projects/MODL Database/stations_WISKI2.gpkg')
|
|
360
|
+
# stations.dropna(subset='stn_HUC12',inplace=True)
|
|
361
|
+
# stations['opnids'] = stations['opnids'].str.replace('-','+')
|
|
362
|
+
# HUC_DIRECTORY = pd.read_csv('C:/Users/mfratki/Documents/Github/hspf_tools/calibrator/HUC_Names.csv',dtype = {'USGS HUC-8':'string',
|
|
363
|
+
# 'USGS HUC-6':'string',
|
|
364
|
+
# 'USGS HUC-4':'string',
|
|
365
|
+
# 'USGS HUC-2':'string'})
|
|
366
|
+
# test = pd.merge(wiski, HUC_DIRECTORY, left_on= 'HUC8',
|
|
367
|
+
# right_on= 'USGS HUC-8',
|
|
368
|
+
# how = 'left')
|
|
369
|
+
# class Builder():
|
|
370
|
+
# # HUC_DIRECTORY = pd.read_csv('C:/Users/mfratki/Documents/Github/hspf_tools/calibrator/HUC_Names.csv',dtype = {'USGS HUC-8':'string',
|
|
371
|
+
# # 'USGS HUC-6':'string',
|
|
372
|
+
# # 'USGS HUC-4':'string',
|
|
373
|
+
# # 'USGS HUC-2':'string'})
|
|
374
|
+
# # MODL_DB = pd.read_csv('C:/Users/mfratki/Documents/Github/hspf_tools/calibrator/WPLMN.csv',dtype = {'stn_HUC12':'string',
|
|
375
|
+
# # 'USGS HUC-8':'string',
|
|
376
|
+
# # 'USGS HUC-6':'string',
|
|
377
|
+
# # 'USGS HUC-4':'string',
|
|
378
|
+
# # 'USGS HUC-2':'string'}
|
|
379
|
+
|
|
380
|
+
# # MODL_DB = pd.read_csv(Path(__file__).parent/'stations_WISKI.csv',dtype = {'stn_HUC12':'string',
|
|
381
|
+
# # 'USGS HUC-8':'string',
|
|
382
|
+
# # 'USGS HUC-6':'string',
|
|
383
|
+
# # 'USGS HUC-2':'string',
|
|
384
|
+
# # 'USGS HUC-4':'string'})
|
|
385
|
+
# # MODL_DB = pd.read_csv('C:/Users/mfratki/Documents/Projects/MODL Database/stations_WISKI.csv', dtype = {'stn_HUC12':'string',
|
|
386
|
+
# # 'USGS HUC-8':'string',
|
|
387
|
+
# # 'USGS HUC-6':'string',
|
|
388
|
+
# # 'USGS HUC-4':'string',
|
|
389
|
+
# # 'USGS HUC-2':'string'})
|
|
390
|
+
|
|
391
|
+
# MODL_DB = gpd.read_file('C:/Users/mfratki/Documents/Projects/MODL Database/gis/stations_csg.gpkg').dropna(subset='opnids')
|
|
392
|
+
# #MODL_DB = gpd.read_file('C:/Users/mfratki/Documents/Projects/MODL Database/stations_WISKI2.gpkg') #.dropna(subset='opnids')
|
|
393
|
+
# #MODL_DB['opnids'] = MODL_DB['opnids'].str.replace('-','+')
|
|
394
|
+
# MODL_DB = MODL_DB.dropna(subset='opnids')
|
|
395
|
+
# MODL_DB = MODL_DB.loc[~(MODL_DB['opnids'] == -1)]
|
|
396
|
+
# REPO = Path('X:\Databases2\Water_Quality\Watershed_Modeling\MPCA_HSPF_Model_Repository') #could point to the github website if it becomes public
|
|
397
|
+
|
|
398
|
+
# @classmethod
|
|
399
|
+
# def valid_models(self):
|
|
400
|
+
# return list(self.MODL_DB['Repository_HUC8 Name'].dropna()) #replace('NO MODEL',pd.NA).dropna())
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
# def __init__(self,model_name):# = None, huc8_id = None)
|
|
404
|
+
# if model_name not in self.valid_models():
|
|
405
|
+
# print('Please provide a valid model name (see .valid_models)')
|
|
406
|
+
# return
|
|
407
|
+
|
|
408
|
+
# self.model_name = model_name
|
|
409
|
+
# #self._HUC_DIRECTORY = self.HUC_DIRECTORY.loc[self.HUC_DIRECTORY['Repository_HUC8 Name'] == self.model_name]
|
|
410
|
+
# #self.huc6_name = self._HUC_DIRECTORY['Repository_HUC6 Name'].iloc[0]
|
|
411
|
+
# #self.huc8_id = self._HUC_DIRECTORY['USGS HUC-8'].iloc[0] #HUC_DIRECTORY.loc[HUC_DIRECTORY['USGS HUC-6'] == huc8_id[:6],'Repository_HUC6 Name'].iloc[0]
|
|
412
|
+
|
|
413
|
+
# self._MODL_DB = self.MODL_DB.loc[self.MODL_DB['Repository_HUC8 Name'] == self.model_name]
|
|
414
|
+
# self.huc6_name = self._MODL_DB['Repository_HUC6 Name'].iloc[0]
|
|
415
|
+
# self.huc6_id = self._MODL_DB['USGS HUC-6'].iloc[0]
|
|
416
|
+
# self.huc8_ids = self._MODL_DB['USGS HUC-8'].unique()
|
|
417
|
+
# self.repo_folder = [item for item in self.REPO.joinpath('_'.join([self.huc6_name,self.huc6_id])).iterdir() if item.name.startswith(self.model_name)][0]
|
|
418
|
+
# self.uci_file = self.repo_folder.joinpath('HSPF','.'.join([self.model_name,'uci']))
|
|
419
|
+
# self.wdm_files = [item for item in self.repo_folder.joinpath('HSPF').iterdir() if item.name.endswith('.wdm')]
|
|
420
|
+
|
|
421
|
+
# def copy(self,project_location):
|
|
422
|
+
|
|
423
|
+
|
|
424
|
+
# build_folders(self.model_name,project_location)
|
|
425
|
+
# self.project_path = Path(project_location).joinpath(self.model_name)
|
|
426
|
+
# self.new_uci = self.project_path.joinpath('model','_'.join([self.model_name,'0.uci']))
|
|
427
|
+
# shutil.copyfile(self.uci_file, self.project_path.joinpath('model','.'.join([self.model_name,'uci'])))
|
|
428
|
+
# self.uci = UCI(self.project_path.joinpath('model','.'.join([self.model_name,'uci'])))
|
|
429
|
+
# for wdm_file in self.wdm_files:
|
|
430
|
+
# shutil.copyfile(wdm_file,self.project_path.joinpath('model',Path(wdm_file).name))
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
# self.format_uci()
|
|
434
|
+
# self.download_wplmn()
|
|
435
|
+
# self.download_csg()
|
|
436
|
+
# self.build_lc_targets()
|
|
437
|
+
# if not self.project_path.joinpath('model',self.model_name + '_0-0.hbn').exists():
|
|
438
|
+
# self.run_model()
|
|
439
|
+
# self._MODL_DB.to_csv(self.project_path.joinpath('_'.join([self.model_name,'MODL_DB.csv'])))
|
|
440
|
+
|
|
441
|
+
# def format_uci(self):
|
|
442
|
+
|
|
443
|
+
# setup_files(self.uci,self.model_name,run = 0)
|
|
444
|
+
# setup_geninfo(self.uci)
|
|
445
|
+
|
|
446
|
+
# calibration_reaches = self._MODL_DB['opnids'].astype('int').to_list()
|
|
447
|
+
# # for reaches in self._MODL_DB['opnids'].str.split('+').to_list():
|
|
448
|
+
# # [calibration_reaches.append(int(reach)) for reach in reaches if ~pd.isna(reach)]
|
|
449
|
+
|
|
450
|
+
# setup_binaryinfo(self.uci,reach_ids = calibration_reaches)
|
|
451
|
+
# setup_qualid(self.uci)
|
|
452
|
+
# self.uci.write(self.new_uci)
|
|
453
|
+
|
|
454
|
+
# # Download observation data
|
|
455
|
+
# # Sources/Databases WISKI and EQUIS (DELTA databases?)
|
|
456
|
+
# #TODO: use a single WISKI etl script for csg and wplmn data
|
|
457
|
+
# def download_csg(self):
|
|
458
|
+
# if self.project_path.joinpath('csg.csv').exists():
|
|
459
|
+
# print('CSG data already downloaded')
|
|
460
|
+
# station_nos = (self._MODL_DB.loc[self._MODL_DB['WPLMN'] == 0,'station_no'].unique())
|
|
461
|
+
# if len(station_nos) == 0:
|
|
462
|
+
# print('No CSG stations linked to Watershed yet')
|
|
463
|
+
# return
|
|
464
|
+
# data = pd.concat([etlCSG.download(station_no).pipe(etlCSG.transform) for station_no in station_nos])
|
|
465
|
+
# #reach_map = dict(self._MODL_DB.loc[self._MODL_DB['station_no'].isin(station_nos),['station_no','opnids']].values)
|
|
466
|
+
# #data['reach_id'] = data['station_no'].map(reach_map)
|
|
467
|
+
# etlCSG.load(data,self.project_path.joinpath('csg.csv'))
|
|
468
|
+
|
|
469
|
+
# def download_wplmn(self):
|
|
470
|
+
# if self.project_path.joinpath('wplmn.csv').exists():
|
|
471
|
+
# print('WPLMN data already downloaded')
|
|
472
|
+
# station_nos = list(self._MODL_DB.loc[self._MODL_DB['WPLMN'] == 1,'station_no'].unique())
|
|
473
|
+
# data = pd.concat([etlWPLMN.download(station_no).pipe(etlWPLMN.transform) for station_no in station_nos])
|
|
474
|
+
# #reach_map = dict(self._MODL_DB.loc[self._MODL_DB['station_no'].isin(station_nos),['station_no','opnids']].values)
|
|
475
|
+
# #data['reach_id'] = data['Station number'].map(reach_map)
|
|
476
|
+
# etlCSG.load(data,self.project_path.joinpath('wplmn.csv'))
|
|
477
|
+
|
|
478
|
+
# def download_swd(self):
|
|
479
|
+
# if self.project_path.joinpath('swd.csv').exists():
|
|
480
|
+
# print('SWD data already downloaded')
|
|
481
|
+
# station_nos = list(self._MODL_DB.loc[self._MODL_DB['source'] == 'swd','station_no'].unique())
|
|
482
|
+
# data = pd.concat([etlSWD.download(station_no).pipe(etlSWD.transform) for station_no in station_nos])
|
|
483
|
+
# etlSWD.load(data,self.project_path.joinpath('swd.csv'))
|
|
484
|
+
|
|
485
|
+
# # Create landcover targets spreadsheet
|
|
486
|
+
# def build_lc_targets(self):
|
|
487
|
+
# lc_info(self.uci).to_csv(self.project_path.joinpath('targets.csv'))
|
|
488
|
+
|
|
489
|
+
# def run_model(self):
|
|
490
|
+
# # Run the uci file
|
|
491
|
+
# winHSPF = str(Path(__file__).resolve().parent.parent) + '\\bin\\WinHSPFLt\\WinHspfLt.exe'
|
|
492
|
+
# subprocess.run([winHSPF,self.new_uci]) #, stdout=subprocess.PIPE, creationflags=0x08000000)
|
|
493
|
+
|
|
494
|
+
|
|
495
|
+
# # if (model_name is None) & (huc8_id is None):
|
|
496
|
+
# # print('Please provide Either a HUC8 ID or a valid model name. To see valid model names see .valid_models')
|
|
497
|
+
# # return
|
|
498
|
+
# #if model_name is None:
|
|
499
|
+
# # else:
|
|
500
|
+
# # self._HUC_DIRECTORY = self.HUC_DIRECTORY.loc[self.HUC_DIRECTORY['Repository_HUC8 Name',:]
|
|
501
|
+
# # self.huc6_name = self._HUC_DIRECTORY.loc[0,'Repository_HUC6 Name']
|
|
502
|
+
# # self.model_name = self._HUC_DIRECTORY.loc[0,'Repository_HUC8 Name']
|
|
503
|
+
# # self.repo_folder =
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
# load original uci
|
|
510
|
+
|
|
511
|
+
# def setup_files(uci,project_name): # Add as method to a Files class?
|
|
512
|
+
# # Update paths in Files block
|
|
513
|
+
# table = uci.table('FILES',drop_comments = False)
|
|
514
|
+
# for index, row in table.iterrows():
|
|
515
|
+
# name = Path(row['FILENAME'])
|
|
516
|
+
# if name.suffix in ['ech','out','wdm']:
|
|
517
|
+
# table.loc[index,'FILENAME'] = name
|
|
518
|
+
# if name.suffix in ['hbn']:
|
|
519
|
+
# table.loc[index,'FILENAME'] = name
|
|
520
|
+
# if name.suffix in ['plt']:
|
|
521
|
+
# table.drop(index)
|
|
522
|
+
|
|
523
|
+
# table = table.set_index(table.columns[0])
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
# # Rename hbn in Files block
|
|
527
|
+
# #TODO: dynamic size management of hbn files
|
|
528
|
+
# new_bino = table.loc['BINO'][~table.loc['BINO'].index.duplicated()]
|
|
529
|
+
# table = table.drop('BINO',axis=0)
|
|
530
|
+
# table = table.append(new_bino)
|
|
531
|
+
# table.loc['BINO','FILENAME'] = project_name + '_0.hbn'
|
|
532
|
+
# table = table.reset_index()
|
|
533
|
+
# uci.replace_table(table,'FILES')
|
|
534
|
+
# return uci
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
# def setup_geninfo(uci):
|
|
538
|
+
# # Initialize Gen-Info
|
|
539
|
+
# bino_num = uci.table('FILES').set_index('FTYPE').loc['BINO','UNIT']
|
|
540
|
+
# uci.update_table(bino_num,'PERLND','GEN-INFO',0,columns = 'BUNIT1',operator = 'set')
|
|
541
|
+
# uci.update_table(bino_num,'RCHRES','GEN-INFO',0,columns = 'BUNITE',operator = 'set')
|
|
542
|
+
# uci.update_table(bino_num,'IMPLND','GEN-INFO',0,columns = 'BUNIT1',operator = 'set')
|
|
543
|
+
# return uci
|
|
544
|
+
|
|
545
|
+
# def setup_binaryinfo(uci,reach_ids = None):
|
|
546
|
+
# # Initialize Binary-Info
|
|
547
|
+
# uci.update_table(4,'PERLND','BINARY-INFO',0,columns = ['SNOWPR','SEDPR','PWATPR','PQALPR'],operator = 'set')
|
|
548
|
+
# uci.update_table(4,'IMPLND','BINARY-INFO',0,columns = ['SNOWPR','IWATPR','SLDPR','IQALPR'],operator = 'set')
|
|
549
|
+
# uci.update_table(4,'RCHRES','BINARY-INFO',0,columns = ['HYDRPR','SEDPR','HEATPR','OXRXPR','NUTRPR','PLNKPR'],operator = 'set')
|
|
550
|
+
# if reach_ids is not None:
|
|
551
|
+
# uci.update_table(3,'RCHRES','BINARY-INFO',0,columns = ['HYDRPR','SEDPR','HEATPR','OXRXPR','NUTRPR','PLNKPR'],opnids = reach_ids,operator = 'set')
|
|
552
|
+
# return uci
|
|
553
|
+
|
|
554
|
+
# def setup_qualid(uci):
|
|
555
|
+
# #### Standardize QUAL-ID Names
|
|
556
|
+
# # Perlands
|
|
557
|
+
# uci.update_table('NH3+NH4','PERLND','QUAL-PROPS',0,columns = 'QUALID',operator = 'set')
|
|
558
|
+
# uci.update_table('NO3','PERLND','QUAL-PROPS',1,columns = 'QUALID',operator = 'set')
|
|
559
|
+
# uci.update_table('ORTHO P','PERLND','QUAL-PROPS',2,columns = 'QUALID',operator = 'set')
|
|
560
|
+
# uci.update_table('BOD','PERLND','QUAL-PROPS',3,columns = 'QUALID',operator = 'set')
|
|
561
|
+
|
|
562
|
+
# # Implands
|
|
563
|
+
# uci.update_table('NH3+NH4','IMPLND','QUAL-PROPS',0,columns = 'QUALID',operator = 'set')
|
|
564
|
+
# uci.update_table('NO3','IMPLND','QUAL-PROPS',1,columns = 'QUALID',operator = 'set')
|
|
565
|
+
# uci.update_table('ORTHO P','IMPLND','QUAL-PROPS',2,columns = 'QUALID',operator = 'set')
|
|
566
|
+
# uci.update_table('BOD','IMPLND','QUAL-PROPS',3,columns = 'QUALID',operator = 'set')
|
|
567
|
+
# return uci
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: pyhcal
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Python package for calibrating MPCA HSPF models
|
|
5
|
+
Project-URL: Homepage, https://github.com/mfratkin1/pyhcal
|
|
6
|
+
Author-email: Mulu Fratkin <michael.fratkin@state.mn.us>
|
|
7
|
+
Maintainer-email: Mulu Fratkin <michael.fratkin@state.mn.us>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: HSPF,Hydrology
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Programming Language :: Python
|
|
12
|
+
Requires-Python: >=3.8
|
|
13
|
+
Requires-Dist: geopandas
|
|
14
|
+
Requires-Dist: hspf
|
|
15
|
+
Requires-Dist: mpcahydro
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
pyhcal/__init__.py,sha256=4TEpGD-PfEY8yK-od8DpEMA4_iQ-q9y0PBvROXSPdB0,94
|
|
2
|
+
pyhcal/calibrators.py,sha256=DuJHBpleICf6f9CbMQBB1CQuiGNVOIHY4U9olOHEObE,29964
|
|
3
|
+
pyhcal/figures.py,sha256=Iu7LaN_i2IuDA_nfxj-a8AkG-FTLZVicJ3-efIs5OiE,45534
|
|
4
|
+
pyhcal/metrics.py,sha256=GUGHd-op-g1Foj8wnS_JVURSms4ifcC0a5h8ketQ29I,17911
|
|
5
|
+
pyhcal/modl_db.py,sha256=0NoWNNxfbF1fy43geOO4EJt-Uev6Og4Hw-KNn9xvAys,3163
|
|
6
|
+
pyhcal/repository.py,sha256=4mbWqTHnVWpfSt8Rs8PBMLePrjPVakOMRuZse0LGY54,4456
|
|
7
|
+
pyhcal/setup_utils.py,sha256=KWWygZc9KLOGonzwMEOWNl5G2Zhq62Esuy7AKGdpIxA,29865
|
|
8
|
+
pyhcal/data/HUC_Names.csv,sha256=UGmd3Q5E8DyFWggXzaXWpsRze7sFyrlpYqaYpMWAiGM,18946
|
|
9
|
+
pyhcal/data/WISKI_EQUIS_XREF.csv,sha256=bPYq-f4-Qc6jsvUgl81lwXBeFamfDe5TjohqUV1XJlg,1244704
|
|
10
|
+
pyhcal/data/stations_EQUIS.gpkg,sha256=KyWMRbNoSSMDB1IweoLhyFeKu1P-YoYpQbXna6VYp8I,3284992
|
|
11
|
+
pyhcal/data/stations_wiski.gpkg,sha256=HlH5EwUo9qEEoxtbEpL0cJZHEW57XEUA-ROy4sN7eE4,892928
|
|
12
|
+
pyhcal-1.0.0.dist-info/METADATA,sha256=MiHmRB0kKf207o1IijXt7VHuY8-0zdPXv8AyBeSmVjQ,513
|
|
13
|
+
pyhcal-1.0.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
14
|
+
pyhcal-1.0.0.dist-info/RECORD,,
|