Skip to content

Commit d88e994

Browse files
authored
Merge pull request #111 from arbennett/feature/update_summa
Feature/update summa
2 parents b4dece7 + 105869a commit d88e994

15 files changed

+156
-149
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# pysumma
2+
13
pysumma is a Python wrapper for manipulating, running, managing, and analyzing
24
of SUMMA (Structure for Unifying Multiple Modeling Alternatives)
35
* [SUMMA web site at UCAR ](https://www.rap.ucar.edu/projects/summa)
@@ -6,6 +8,7 @@ pysumma provides methods for:
68
- Running SUMMA
79
- Modifying SUMMA input files
810
- Automatically parallelizing distributed and sensitivity analysis type experiments
11+
- Calibration via OSTRICH
912
- Visualizing output
1013

1114
# Installation

docs/configuration.rst

Lines changed: 31 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -44,52 +44,38 @@ Then, you can see what is in it simply by printing it out:
4444

4545
print(fm)
4646

47-
> 'SUMMA_FILE_MANAGER_V1.0' ! filemanager_version
48-
> '/home/user/summa_setup_template/settings/' ! settings_path
49-
> '/home/user/summa_setup_template/forcing/' ! input_path
50-
> '/home/user/summa_setup_template/output/' ! output_path
51-
> 'decisions.txt' ! decisions_path
52-
> '[notUsed]' ! meta_time
53-
> '[notUsed]' ! meta_attr
54-
> '[notUsed]' ! meta_type
55-
> '[notUsed]' ! meta_force
56-
> '[notUsed]' ! meta_localparam
57-
> 'output_control.txt' ! output_control
58-
> '[notUsed]' ! meta_localindex
59-
> '[notUsed]' ! meta_basinparam
60-
> '[notUsed]' ! meta_basinmvar
61-
> 'local_attributes.nc' ! local_attributes
62-
> 'local_param_info.txt' ! local_param_info
63-
> 'basin_param_info.txt' ! basin_param_info
64-
> 'forcing_file_list.txt' ! forcing_file_list
65-
> 'initial_conditions.nc' ! model_init_cond
66-
> 'parameter_trial.nc' ! parameter_trial
67-
> 'test' ! output_prefix
47+
> controlVersion 'SUMMA_FILE_MANAGER_V3.0.0'
48+
> simStartTime '2002-10-01 00:00'
49+
> simEndTime '2003-05-31 00:00'
50+
> tmZoneInfo 'localTime'
51+
> settingsPath '/pool0/data/andrbenn/dana_3_test/.pysumma/_test/settings/'
52+
> forcingPath './forcings/'
53+
> outputPath './output/'
54+
> decisionsFile 'decisions.txt'
55+
> outputControlFile 'output_control.txt'
56+
> globalHruParamFile '../params/local_param_info.txt'
57+
> globalGruParamFile '../params/basin_param_info.txt'
58+
> attributeFile '../params/local_attributes.nc'
59+
> trialParamFile '../params/parameter_trial.nc'
60+
> forcingListFile '../forcings/forcing_file_list.txt'
61+
> initConditionFile '../params/initial_conditions.nc'
62+
> outFilePrefix 'template_output'
63+
> vegTableFile 'VEGPARM.TBL'
64+
> soilTableFile 'SOILPARM.TBL'
65+
> generalTableFile 'GENPARM.TBL'
66+
> noahmpTableFile 'MPTABLE.TBL'
6867

6968
To see how to access each of these specific options you can use the ``list_options`` method.
70-
71-
::
72-
73-
print(fm.list_options)
74-
75-
> ['filemanager_version', 'settings_path', 'input_path',
76-
> 'output_path', 'decisions_path', 'meta_time',
77-
> 'meta_attr', 'meta_type', 'meta_force', 'meta_localparam',
78-
> 'output_control', 'meta_localindex', 'meta_basinparam',
79-
> 'meta_basinmvar', 'local_attributes', 'local_param_info',
80-
> 'basin_param_info', 'forcing_file_list', 'model_init_cond',
81-
> 'parameter_trial', 'output_prefix']
82-
8369
Then, each of these keys can be accessed directly similarly to how is done with python dictionaries.
8470
This can be used to inspect the values of each option as well as modify their values.
8571

8672
::
8773

88-
print(fm['output_prefix'])
74+
print(fm['outputPrefix'])
8975

9076
> 'test' ! output_prefix
9177

92-
fm['output_prefix'] = 'tutorial'
78+
fm['outputPrefix'] = 'tutorial'
9379

9480
print(fm['output_prefix'])
9581

@@ -114,14 +100,13 @@ Once instantiated you can inspect the available decisions and the options availa
114100

115101
print(dec.list_options())
116102

117-
> ['simulStart', 'simulFinsh', 'tmZoneInfo', 'soilCatTbl',
118-
> 'vegeParTbl', 'soilStress', 'stomResist', 'num_method',
103+
> ['soilCatTbl', 'vegeParTbl', 'soilStress', 'stomResist',
119104
> 'fDerivMeth', 'LAI_method', 'f_Richards', 'groundwatr',
120105
> 'hc_profile', 'bcUpprTdyn', 'bcLowrTdyn', 'bcUpprSoiH',
121106
> 'bcLowrSoiH', 'veg_traits', 'canopyEmis', 'snowIncept',
122107
> 'windPrfile', 'astability', 'canopySrad', 'alb_method',
123108
> 'compaction', 'snowLayers', 'thCondSnow', 'thCondSoil',
124-
> 'spatial_gw', 'subRouting']
109+
> 'spatial_gw', 'subRouting', 'num_method']
125110

126111
print(dec['snowLayers'])
127112

@@ -136,12 +121,12 @@ Once instantiated you can inspect the available decisions and the options availa
136121
Forcing file list
137122
-----------------
138123
The forcing file list contains a listing of each of the forcing files available for use as SUMMA input.
139-
To instantiate the `ForceFileList` you will have to specify the path that is set as the ``input_path`` in your ``FileManager``. Below we show using the ``FileManager`` (``fm``) to do so.
140-
Once instantiated you can also use the `ForceFileList` object to inspect the forcing files themselves.
124+
To instantiate the `ForcingList` you will have to specify the path that is set as the ``input_path`` in your ``FileManager``. Below we show using the ``FileManager`` (``fm``) to do so.
125+
Once instantiated you can also use the `ForcingList` object to inspect the forcing files themselves.
141126

142127
::
143128

144-
ff = ps.ForceFileList('.', 'forcingFileList.1hr.txt', fm['input_path'])
129+
ff = ps.ForcingList('.', 'forcingFileList.1hr.txt', fm['input_path'])
145130
print(ff)
146131

147132
>> 'forcing_file.nc'
@@ -204,9 +189,9 @@ The format of the output control file mirrors the way that it is described in th
204189
>> sum
205190

206191

207-
Local parameter info
192+
GlobalParams
208193
--------------------
209-
The local parameter info file contains a listing of global parameters. Spatially dependent parameters are specified
194+
The GlobalParams object listing of global parameters. Spatially dependent parameters are specified
210195
in the parameter trial NetCDF file. Values which are specified in the local parameter info file will be overwritten
211196
by those specified in the parameter trial file.
212197
As with the output control file, there are many parameters which can be specified, so we omit them for brevity.
@@ -215,7 +200,7 @@ this out currently is by looking at the SUMMA source code directly.
215200

216201
::
217202

218-
lpi = ps.LocalParamInfo('.', 'local_param_info.txt')
203+
lpi = ps.GlobalParams('.', 'global_param_info.txt')
219204
print(lpi.list_options())
220205

221206
>> ['upperBoundHead', 'lowerBoundHead', 'upperBoundTheta', 'lowerBoundTheta',
@@ -230,7 +215,7 @@ NetCDF based files
230215
==================
231216
The following input files are NetCDF-based and therefore, should be interacted with via ``xarray`` when using pysumma:
232217

233-
- Parameter trial
218+
- Parameter trial (Spatially distributed parameters)
234219
- Basin parameters
235220
- Local attributes
236221
- Initial conditions

environment.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ dependencies:
1919
- geopandas
2020
- jupyter
2121
- pip
22+
- summa=3.0.0
2223
- pip:
2324
- hs_restclient

pysumma/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from .file_manager import FileManager
55
from .decisions import Decisions
66
from .output_control import OutputControl
7-
from .local_param_info import LocalParamInfo
8-
from .force_file_list import ForceFileList
7+
from .global_params import GlobalParams
8+
from .force_file_list import ForcingList
99
from . import utils
1010
from .calibration import Ostrich, OstrichParam

pysumma/decisions.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ def __init__(self, name, value):
2222
self.set_value(value)
2323

2424
def set_value(self, new_value):
25-
datestring = r"[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}"
26-
if (self.name in ['simulStart', 'simulFinsh'] and
27-
re.match(datestring, new_value) is not None):
28-
self.value = new_value
29-
elif new_value in self.available_options:
25+
if new_value in self.available_options:
3026
self.value = new_value
3127
else:
3228
raise ValueError(os.linesep.join([

pysumma/file_manager.py

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
from .option import BaseOption, OptionContainer
88
from .decisions import Decisions
99
from .output_control import OutputControl
10-
from .local_param_info import LocalParamInfo
11-
from .force_file_list import ForceFileList
10+
from .global_params import GlobalParams
11+
from .force_file_list import ForcingList
1212

1313
# Option names for the file manager, this is just a list,
1414
# as the order of these values matters. They may also not be
@@ -31,7 +31,7 @@ def set_value(self, new_value):
3131
self.value = new_value
3232

3333
def __str__(self):
34-
return "'{}' ! {}".format(self.value, self.name)
34+
return "{} '{}'".format(self.name.ljust(36), self.value)
3535

3636

3737
class FileManager(OptionContainer):
@@ -42,96 +42,104 @@ class FileManager(OptionContainer):
4242

4343
def __init__(self, path, name):
4444
super().__init__(FileManagerOption, path, name)
45+
assert self.get_value('controlVersion') == 'SUMMA_FILE_MANAGER_V3.0.0'
4546

4647
def set_option(self, key, value):
4748
o = self.get_option(key)
4849
o.set_value(value)
4950

5051
def get_constructor_args(self, line):
51-
return (OPTION_NAMES[self.opt_count],
52-
line.split('!')[0].replace("'", "").strip())
52+
name, *value = line.split('!')[0].strip().split()
53+
if isinstance(value, list):
54+
value = " ".join(value).replace("'", "")
55+
return (name.strip(), value.strip().replace("'", "").strip())
5356

5457
@property
5558
def decisions(self):
56-
p1 = self.get_value('settings_path')
57-
p2 = self.get_value('decisions_path')
59+
p1 = self.get_value('settingsPath')
60+
p2 = self.get_value('decisionsFile')
5861
self._decisions = Decisions(p1, p2)
5962
return self._decisions
6063

6164
@property
6265
def output_control(self):
63-
p1 = self.get_value('settings_path')
64-
p2 = self.get_value('output_control')
66+
p1 = self.get_value('settingsPath')
67+
p2 = self.get_value('outputControlFile')
6568
self._output_control = OutputControl(p1, p2)
6669
return self._output_control
6770

6871
@property
69-
def local_param_info(self):
70-
p1 = self.get_value('settings_path')
71-
p2 = self.get_value('local_param_info')
72-
self._local_param_info = LocalParamInfo(p1, p2)
73-
return self._local_param_info
72+
def global_hru_params(self):
73+
p1 = self.get_value('settingsPath')
74+
p2 = self.get_value('globalHruParamFile')
75+
self._hru_params = GlobalParams(p1, p2)
76+
return self._hru_params
7477

7578
@property
76-
def basin_param_info(self):
77-
p1 = self.get_value('settings_path')
78-
p2 = self.get_value('basin_param_info')
79-
self._basin_param_info = LocalParamInfo(p1, p2)
80-
return self._basin_param_info
79+
def global_gru_params(self):
80+
p1 = self.get_value('settingsPath')
81+
p2 = self.get_value('globalGruParamFile')
82+
self._gru_params = GlobalParams(p1, p2)
83+
return self._gru_params
8184

8285
@property
8386
def force_file_list(self):
84-
p1 = self.get_value('settings_path')
85-
p2 = self.get_value('forcing_file_list')
86-
p3 = self.get_value('input_path')
87-
self._force_file_list = ForceFileList(p1, p2, p3)
87+
p1 = self.get_value('settingsPath')
88+
p2 = self.get_value('forcingListFile')
89+
p3 = self.get_value('forcingPath')
90+
self._force_file_list = ForcingList(p1, p2, p3)
8891
return self._force_file_list
8992

9093
@property
9194
def local_attributes(self):
92-
p1 = self.get_value('settings_path')
93-
p2 = self.get_value('local_attributes')
95+
p1 = self.get_value('settingsPath')
96+
p2 = self.get_value('attributeFile')
9497
self._local_attrs = xr.open_dataset(p1 + p2)
9598
return self._local_attrs
9699

97100
@property
98-
def parameter_trial(self):
99-
p1 = self.get_value('settings_path')
100-
p2 = self.get_value('parameter_trial')
101-
self._param_trial = xr.open_dataset(p1 + p2)
102-
return self._param_trial
101+
def trial_params(self):
102+
p1 = self.get_value('settingsPath')
103+
p2 = self.get_value('trialParamFile')
104+
self._trial_params = xr.open_dataset(p1 + p2)
105+
return self._trial_params
103106

104107
@property
105108
def initial_conditions(self):
106-
p1 = self.get_value('settings_path')
107-
p2 = self.get_value('model_init_cond')
109+
p1 = self.get_value('settingsPath')
110+
p2 = self.get_value('initConditionFile')
108111
self._init_cond = xr.open_dataset(p1 + p2)
109112
return self._init_cond
110113

111114
@property
112115
def genparm(self):
113-
p1, p2 = self.get_value('settings_path'), 'GENPARM.TBL'
116+
p1 = self.get_value('settingsPath')
117+
p2 = self.get_value('generalTableFile')
118+
print(p1, p2)
114119
with open(p1 + p2, 'r') as f:
115120
self._genparm = f.readlines()
116121
return self._genparm
117122

118123
@property
119124
def mptable(self):
120-
p1, p2 = self.get_value('settings_path'), 'MPTABLE.TBL'
125+
p1 = self.get_value('settingsPath')
126+
p2 = self.get_value('noahmpTableFile')
121127
with open(p1 + p2, 'r') as f:
122128
self._mptable = f.readlines()
123129
return self._mptable
124130

125131
@property
126132
def soilparm(self):
127-
p1, p2 = self.get_value('settings_path'), 'SOILPARM.TBL'
133+
p1 = self.get_value('settingsPath')
134+
p2 = self.get_value('soilTableFile')
128135
with open(p1 + p2, 'r') as f:
129136
self._soilparm = f.readlines()
130137
return self._soilparm
131138

132139
@property
133140
def vegparm(self):
134-
p1, p2 = self.get_value('settings_path'), 'VEGPARM.TBL'
141+
p1 = self.get_value('settingsPath')
142+
p2 = self.get_value('vegTableFile')
135143
with open(p1 + p2, 'r') as f:
136144
self._vegparm = f.readlines()
137145
return self._vegparm

pysumma/force_file_list.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from .option import OptionContainer
66

77

8-
class ForceFileListOption(BaseOption):
8+
class ForcingOption(BaseOption):
99

1010
def __init__(self, name):
1111
super().__init__(name)
@@ -26,13 +26,13 @@ def __str__(self):
2626
return "'{}'".format(self.name.split('/')[-1])
2727

2828

29-
class ForceFileList(OptionContainer):
29+
class ForcingList(OptionContainer):
3030

3131
prefix: str = ''
3232

3333
def __init__(self, dirpath, filepath, force_file_prefix_path):
3434
self.prefix = str(force_file_prefix_path)
35-
super().__init__(ForceFileListOption, dirpath, filepath)
35+
super().__init__(ForcingOption, dirpath, filepath)
3636

3737
def set_option(self, key, value):
3838
o = self.get_option(key)

0 commit comments

Comments
 (0)