hspf 2.0.2__tar.gz → 2.1.0__tar.gz

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.
Files changed (42) hide show
  1. {hspf-2.0.2 → hspf-2.1.0}/PKG-INFO +1 -1
  2. {hspf-2.0.2 → hspf-2.1.0}/pyproject.toml +1 -1
  3. hspf-2.1.0/src/hspf/bin/WinHSPFLt/WinHspfLt.exe +0 -0
  4. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/hbn.py +10 -35
  5. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/hspfModel.py +32 -12
  6. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/parser/graph.py +153 -332
  7. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/parser/parsers.py +29 -3
  8. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/reports.py +1 -0
  9. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/uci.py +93 -9
  10. hspf-2.1.0/tests/__init__.py +0 -0
  11. hspf-2.1.0/tests/data/Clearwater.tpl +19727 -0
  12. hspf-2.1.0/tests/data/Clearwater.uci +16857 -0
  13. hspf-2.1.0/tests/test_graph.py +86 -0
  14. hspf-2.1.0/tests/test_uci.py +11 -0
  15. {hspf-2.0.2 → hspf-2.1.0}/.gitattributes +0 -0
  16. {hspf-2.0.2 → hspf-2.1.0}/.gitignore +0 -0
  17. {hspf-2.0.2 → hspf-2.1.0}/MANIFEST.in +0 -0
  18. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/__init__.py +0 -0
  19. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/ParseTable.csv +0 -0
  20. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/IMPLND/IQUAL.txt +0 -0
  21. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/IMPLND/IWATER.txt +0 -0
  22. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/IMPLND/IWTGAS.txt +0 -0
  23. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/IMPLND/SOLIDS.txt +0 -0
  24. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/MSTLAY.txt +0 -0
  25. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/PQUAL.txt +0 -0
  26. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/PSTEMP.txt +0 -0
  27. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/PWATER.txt +0 -0
  28. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/PWATGAS.txt +0 -0
  29. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/SEDMNT.txt +0 -0
  30. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/PERLND/SNOW.txt +0 -0
  31. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/CONS.txt +0 -0
  32. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/GQUAL.txt +0 -0
  33. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/HTRCH.txt +0 -0
  34. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/HYDR.txt +0 -0
  35. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/NUTRX.txt +0 -0
  36. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/OXRX.txt +0 -0
  37. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/PLANK.txt +0 -0
  38. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/data/Timeseries Catalog/RCHRES/SEDTRN.txt +0 -0
  39. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/helpers.py +0 -0
  40. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/parser/__init__.py +0 -0
  41. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/wdm.py +0 -0
  42. {hspf-2.0.2 → hspf-2.1.0}/src/hspf/wdmReader.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hspf
3
- Version: 2.0.2
3
+ Version: 2.1.0
4
4
  Summary: Python package for downloading and running HSPF models
5
5
  Project-URL: Homepage, https://github.com/mfratkin1/pyHSPF
6
6
  Author-email: Mulu Fratkin <michael.fratkin@state.mn.us>
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
  [project]
6
6
  name = "hspf"
7
7
  urls = { "Homepage" = "https://github.com/mfratkin1/pyHSPF" } # ? Add this!
8
- version = "2.0.2"
8
+ version = "2.1.0"
9
9
  dependencies = [
10
10
  "pandas",
11
11
  "requests",
@@ -176,6 +176,12 @@ class hbnInterface:
176
176
  def get_multiple_timeseries(self,t_opn,t_code,t_con,opnids = None,activity = None,axis = 1):
177
177
  return pd.concat([hbn.get_multiple_timeseries(t_opn,t_code,t_con,opnids,activity) for hbn in self.hbns],axis = 1)
178
178
 
179
+ def get_perlnd_constituent(self,constituent,perlnd_ids = None,time_step = 5):
180
+ return get_simulated_perlnd_constituent(self,constituent,time_step)
181
+
182
+ def get_implnd_constituent(self,constituent,implnd_ids = None,time_step = 5):
183
+ return get_simulated_implnd_constituent(self,constituent,time_step)
184
+
179
185
  def get_reach_constituent(self,constituent,reach_ids,time_step,unit = None):
180
186
  if constituent == 'Q':
181
187
  df = get_simulated_flow(self,time_step,reach_ids,unit = unit)
@@ -209,48 +215,17 @@ class hbnInterface:
209
215
 
210
216
  return df
211
217
 
212
-
218
+
213
219
  def get_rchres_data(self,constituent,reach_ids,units = 'mg/l',t_code = 'daily'):
214
220
  '''
215
221
  Convience function for accessing the hbn time series associated with our current
216
222
  calibration method. Assumes you are summing across all dataframes.
217
-
218
- Parameters
219
- ----------
220
- hbn : TYPE
221
- DESCRIPTION.
222
- nutrient_id : TYPE
223
- DESCRIPTION.
224
- reach_ids : TYPE
225
- DESCRIPTION.
226
- flux : TYPE, optional
227
- DESCRIPTION. The default is None.
228
-
229
- Returns
230
- -------
231
- df : TYPE
232
- DESCRIPTION.
233
-
234
- '''
235
-
236
-
223
+ '''
237
224
 
238
- t_cons = helpers.get_tcons(constituent,'RCHRES',units)
239
-
240
-
241
-
242
- df = pd.concat([self.get_multiple_timeseries(t_opn = 'RCHRES',
243
- t_code =t_code,
244
- t_con = t_con,
245
- opnids = reach_ids)
246
- for t_con in t_cons],axis = 1).sum(1).to_frame()
247
-
248
- if (constituent == 'Q') & (units == 'cfs'):
249
- df = df/CF2CFS[t_code]*43560 #Acrfeet/invl to cubic feet/s
250
-
225
+ df = pd.concat([self.get_reach_constituent(constituent,[reach_id],t_code,units) for reach_id in reach_ids], axis = 1)
226
+ df.columns = reach_ids
251
227
  df.attrs['unit'] = units
252
228
  df.attrs['constituent'] = constituent
253
- df.attrs['reach_ids'] = reach_ids
254
229
  return df
255
230
 
256
231
 
@@ -30,7 +30,7 @@ class hspfModel():
30
30
 
31
31
  # Imposed structures of an hspf model:
32
32
  # 1. all model files are located in the same directory as the uci file.
33
- def __init__(self,uci_file:str):
33
+ def __init__(self,uci_file:str,run_model:bool = False):
34
34
  #wdm_files:list = None,
35
35
  #hbn_files:str = None):
36
36
  # Inputs
@@ -39,7 +39,7 @@ class hspfModel():
39
39
  self.wdm_paths = []
40
40
  self.uci_file = Path(uci_file).resolve()
41
41
  # Validate and load binary data
42
- self.validate_uci()
42
+ self.validate_uci(run_model = run_model)
43
43
 
44
44
 
45
45
  self.hbns = hbn.hbnInterface(self.hbn_paths)
@@ -51,8 +51,28 @@ class hspfModel():
51
51
  # Compositions
52
52
  self.reports = Reports(self.uci,self.hbns,self.wdms)
53
53
 
54
+
55
+ def validate_wdms(self):
56
+ # Ensure wdm files exist and the folders for the other file types exist relative
57
+ # to the uci path
58
+
59
+ for index, row in self.uci.table('FILES',drop_comments = False).iterrows():
60
+ file_path = self.uci_file.parent.joinpath(Path(row['FILENAME']))
61
+ if file_path.suffix.lower() == '.wdm':
62
+ assert file_path.exists(),'File Specified in the UCI does not exist:' + file_path.as_posix()
63
+ self.wdm_paths.append(file_path)
54
64
 
55
- def validate_uci(self):
65
+ def validate_pltgens(self):
66
+ raise NotImplementedError()
67
+
68
+ def validate_folders(self):
69
+ for index, row in self.uci.table('FILES',drop_comments = False).iterrows():
70
+ file_path = self.uci_file.parent.joinpath(Path(row['FILENAME']))
71
+ assert file_path.parent.exists(),'File folder Specified in the UCI does not exist: ' + file_path.as_posix()
72
+
73
+
74
+
75
+ def validate_uci(self,run_model:bool = False):
56
76
  # Ensure wdm files exist and the folders for the other file types exist relative
57
77
  # to the uci path
58
78
 
@@ -63,15 +83,15 @@ class hspfModel():
63
83
  self.wdm_paths.append(file_path)
64
84
  elif file_path.suffix.lower() == '.hbn':
65
85
  assert file_path.parent.exists(),'File folder Specified in the UCI does not exist: ' + file_path.as_posix()
66
- #self.hbns[file_path.name.split('.')[0]] = None
67
- if file_path.exists():
68
- #self.hbns[file_path.name.split('.')[0]] = hbn.hbnClass(file_path)
69
- self.hbn_paths.append(file_path)
70
- else:
71
- self.run_model()
86
+ self.hbn_paths.append(file_path)
72
87
  else:
73
88
  assert file_path.parent.exists(),'File folder Specified in the UCI does not exist: ' + file_path.as_posix()
74
89
 
90
+ if (all(file_path.exists() for file_path in self.hbn_paths)) & (run_model == False):
91
+ pass
92
+ else:
93
+ self.run_model()
94
+
75
95
  def run_model(self,new_uci_file = None):
76
96
 
77
97
  if new_uci_file is None:
@@ -80,14 +100,14 @@ class hspfModel():
80
100
  # new_uci_file = self.model_path.joinpath(uci_name)
81
101
  # self.uci.write(new_uci_file)
82
102
  subprocess.run([self.winHSPF,self.uci_file.as_posix()]) #, stdout=subprocess.PIPE, creationflags=0x08000000)
83
- self.load_uci(new_uci_file)
103
+ self.load_uci(new_uci_file,run_model = False)
84
104
 
85
105
  def load_hbn(self,hbn_name):
86
106
  self.hbns[hbn_name] = hbn.hbnClass(self.uci_file.parent.joinpath(hbn_name).as_posix())
87
107
 
88
- def load_uci(self,uci_file):
108
+ def load_uci(self,uci_file,run_model:bool = False):
89
109
  self.uci = UCI(uci_file)
90
- self.validate_uci()
110
+ self.validate_uci(run_model = run_model)
91
111
 
92
112
  def convert_wdms(self):
93
113
  for wdm_file in self.wdm_paths: