pyPRMS 0.9.7__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.
- pyPRMS/Exceptions_custom.py +31 -0
- pyPRMS/__init__.py +52 -0
- pyPRMS/cbh/Cbh.py +431 -0
- pyPRMS/cbh/CbhAscii.py +458 -0
- pyPRMS/cbh/CbhNetcdf.py +199 -0
- pyPRMS/cbh/__init__.py +3 -0
- pyPRMS/constants.py +131 -0
- pyPRMS/control/Control.py +362 -0
- pyPRMS/control/ControlFile.py +161 -0
- pyPRMS/control/ControlVariable.py +208 -0
- pyPRMS/control/__init__.py +3 -0
- pyPRMS/dimensions/Dimension.py +154 -0
- pyPRMS/dimensions/Dimensions.py +256 -0
- pyPRMS/dimensions/__init__.py +2 -0
- pyPRMS/input/DataFile.py +354 -0
- pyPRMS/input/InputVariable.py +61 -0
- pyPRMS/input/__init__.py +0 -0
- pyPRMS/metadata/__init__.py +1 -0
- pyPRMS/metadata/metadata.py +430 -0
- pyPRMS/parameters/ParamDb.py +73 -0
- pyPRMS/parameters/Parameter.py +624 -0
- pyPRMS/parameters/ParameterFile.py +190 -0
- pyPRMS/parameters/ParameterNetCDF.py +74 -0
- pyPRMS/parameters/ParameterSet.py +96 -0
- pyPRMS/parameters/Parameters.py +1506 -0
- pyPRMS/parameters/__init__.py +5 -0
- pyPRMS/plot_helpers.py +305 -0
- pyPRMS/prms_helpers.py +235 -0
- pyPRMS/py.typed +0 -0
- pyPRMS/summary/OutputCSV.py +64 -0
- pyPRMS/summary/OutputVariable.py +163 -0
- pyPRMS/summary/OutputVariables.py +227 -0
- pyPRMS/summary/__init__.py +2 -0
- pyPRMS/utilities/__init__.py +0 -0
- pyPRMS/utilities/convert_cbh.py +107 -0
- pyPRMS/utilities/convert_model_output.py +91 -0
- pyPRMS/utilities/convert_params.py +60 -0
- pyPRMS/version.py +13 -0
- pyPRMS/xml/cbh.xml +163 -0
- pyPRMS/xml/control.xml +1447 -0
- pyPRMS/xml/dimensions.xml +311 -0
- pyPRMS/xml/modules.xml +251 -0
- pyPRMS/xml/parameters.xml +6932 -0
- pyPRMS/xml/time_series_input.xml +198 -0
- pyPRMS/xml/variables.xml +8173 -0
- pyprms-0.9.7.dist-info/LICENSE.md +21 -0
- pyprms-0.9.7.dist-info/METADATA +67 -0
- pyprms-0.9.7.dist-info/RECORD +51 -0
- pyprms-0.9.7.dist-info/WHEEL +5 -0
- pyprms-0.9.7.dist-info/entry_points.txt +3 -0
- pyprms-0.9.7.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import io
|
|
2
|
+
import pkgutil
|
|
3
|
+
import xml.etree.ElementTree as xmlET # type: ignore
|
|
4
|
+
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from packaging.version import Version
|
|
7
|
+
from typing import Dict, Optional, Union
|
|
8
|
+
|
|
9
|
+
from pyPRMS.prms_helpers import set_date
|
|
10
|
+
from pyPRMS.constants import MetaDataType, NEW_PTYPE_TO_DTYPE, PRMS_VERSION
|
|
11
|
+
|
|
12
|
+
from rich.console import Console
|
|
13
|
+
from rich import pretty
|
|
14
|
+
|
|
15
|
+
pretty.install()
|
|
16
|
+
con = Console(record=False, force_jupyter=False)
|
|
17
|
+
|
|
18
|
+
# For each metadata type, define the outer element name for each variable in the XML file
|
|
19
|
+
outside_elem = {'control': 'control_param',
|
|
20
|
+
'parameters': 'parameter',
|
|
21
|
+
'dimensions': 'dimension',
|
|
22
|
+
'variables': 'variable',
|
|
23
|
+
'cbh': 'variable'}
|
|
24
|
+
|
|
25
|
+
NEW_DTYPE = {1: 'int32', 2: 'float32', 3: 'float64', 4: 'string'}
|
|
26
|
+
NEW_PARAM_DTYPE = {'I': 'int32', 'F': 'float32', 'D': 'float64', 'S': 'string'}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MetaData(object):
|
|
30
|
+
"""Class to handle variable and parameter metadata"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, version: Union[str, Version] = PRMS_VERSION,
|
|
33
|
+
verbose: bool = False):
|
|
34
|
+
# meta_type - one of control, dimension, parameter, output
|
|
35
|
+
# version - PRMS major version to use for filtering
|
|
36
|
+
|
|
37
|
+
fcn_map = {'control': self.__control_to_dict,
|
|
38
|
+
'dimensions': self.__dimensions_to_dict,
|
|
39
|
+
'parameters': self.__parameters_to_dict,
|
|
40
|
+
'variables': self.__variables_to_dict,
|
|
41
|
+
'cbh': self.__cbh_to_dict}
|
|
42
|
+
|
|
43
|
+
self.__meta_dict: MetaDataType = {}
|
|
44
|
+
|
|
45
|
+
if isinstance(version, str):
|
|
46
|
+
version = Version(version)
|
|
47
|
+
|
|
48
|
+
self.__version: Version = version
|
|
49
|
+
self.__verbose = verbose
|
|
50
|
+
|
|
51
|
+
# Add information about the metadata
|
|
52
|
+
self.__meta_dict['info'] = {'version': str(self.__version)}
|
|
53
|
+
|
|
54
|
+
if self.__verbose:
|
|
55
|
+
con.print(f'[green]INFO[/]: Metadata for PRMS version {self.__version}')
|
|
56
|
+
|
|
57
|
+
# meta_type: one of - control, dimensions, parameters, variables
|
|
58
|
+
for mt, mf in fcn_map.items():
|
|
59
|
+
xml_fh = io.StringIO(pkgutil.get_data('pyPRMS', f'xml/{mt}.xml').decode('utf-8'))
|
|
60
|
+
xml_tree = xmlET.parse(xml_fh)
|
|
61
|
+
xml_root = xml_tree.getroot()
|
|
62
|
+
|
|
63
|
+
if self.__verbose:
|
|
64
|
+
con.print(f'[bold green]{mt}[/bold green]')
|
|
65
|
+
self.__meta_dict[mt] = mf(xml_root, mt, self.__version)
|
|
66
|
+
|
|
67
|
+
@property
|
|
68
|
+
def version(self) -> Version:
|
|
69
|
+
"""Return the PRMS version used for metadata selection
|
|
70
|
+
|
|
71
|
+
:returns: PRMS version
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
return self.__version
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def metadata(self) -> MetaDataType:
|
|
78
|
+
return self.__meta_dict
|
|
79
|
+
|
|
80
|
+
def __control_to_dict(self, xml_root: xmlET.Element,
|
|
81
|
+
meta_type: str,
|
|
82
|
+
req_version: Version) -> Dict:
|
|
83
|
+
"""Convert control variables metadata to dictionary
|
|
84
|
+
|
|
85
|
+
:param xml_root: XML root element
|
|
86
|
+
:param meta_type: Type of metadata
|
|
87
|
+
:param req_version: Required minimum version for filtering
|
|
88
|
+
"""
|
|
89
|
+
|
|
90
|
+
meta_dict: Dict = {}
|
|
91
|
+
|
|
92
|
+
for elem in xml_root.findall(outside_elem[meta_type]):
|
|
93
|
+
name = elem.attrib.get('name')
|
|
94
|
+
|
|
95
|
+
meta_dict[name] = {}
|
|
96
|
+
try:
|
|
97
|
+
var_version = Version(elem.attrib.get('version'))
|
|
98
|
+
|
|
99
|
+
if var_version > req_version:
|
|
100
|
+
if self.__verbose: # pragma: no cover
|
|
101
|
+
print(f'{name} rejected by version {str(var_version)}, req: {str(req_version)}')
|
|
102
|
+
|
|
103
|
+
del meta_dict[name]
|
|
104
|
+
continue
|
|
105
|
+
meta_dict[name]['version'] = str(var_version)
|
|
106
|
+
except TypeError:
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
depr_version = Version(elem.attrib.get('deprecated'))
|
|
111
|
+
|
|
112
|
+
if depr_version <= req_version:
|
|
113
|
+
if self.__verbose: # pragma: no cover
|
|
114
|
+
print(f'{name} rejected by deprecation version {str(depr_version)}, req: {str(req_version)}')
|
|
115
|
+
|
|
116
|
+
del meta_dict[name]
|
|
117
|
+
continue
|
|
118
|
+
meta_dict[name]['deprecated'] = depr_version
|
|
119
|
+
except TypeError:
|
|
120
|
+
pass
|
|
121
|
+
|
|
122
|
+
if name in ['start_time', 'end_time']:
|
|
123
|
+
meta_dict[name]['datatype'] = 'datetime'
|
|
124
|
+
else:
|
|
125
|
+
datatype = int(elem.find('type').text)
|
|
126
|
+
meta_dict[name]['datatype'] = NEW_DTYPE[datatype]
|
|
127
|
+
|
|
128
|
+
elems = {'description': 'desc',
|
|
129
|
+
'numvals': 'numvals',
|
|
130
|
+
'default': 'default', }
|
|
131
|
+
|
|
132
|
+
for ek, ev in elems.items():
|
|
133
|
+
try:
|
|
134
|
+
if ev == 'numvals':
|
|
135
|
+
tmp = elem.find(ev).text
|
|
136
|
+
|
|
137
|
+
if tmp in ['1', '6']:
|
|
138
|
+
meta_dict[name]['context'] = 'scalar'
|
|
139
|
+
else:
|
|
140
|
+
meta_dict[name]['context'] = 'array'
|
|
141
|
+
# meta_dict[name][ek] = int(elem.find(ev).text)
|
|
142
|
+
elif ev == 'default':
|
|
143
|
+
cdtype = NEW_PTYPE_TO_DTYPE[meta_dict[name]['datatype']]
|
|
144
|
+
|
|
145
|
+
if meta_dict[name]['datatype'] == 'datetime':
|
|
146
|
+
meta_dict[name][ek] = cdtype(set_date(elem.find(ev).text))
|
|
147
|
+
else:
|
|
148
|
+
meta_dict[name][ek] = cdtype(elem.find(ev).text)
|
|
149
|
+
else:
|
|
150
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
151
|
+
except ValueError:
|
|
152
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
153
|
+
except AttributeError:
|
|
154
|
+
pass
|
|
155
|
+
|
|
156
|
+
# meta_dict[name]['description'] = elem.find('desc').text
|
|
157
|
+
# meta_dict[name]['numvals'] = elem.find('numvals').text
|
|
158
|
+
|
|
159
|
+
if elem.find('force_default') is not None:
|
|
160
|
+
meta_dict[name]['force_default'] = elem.find('force_default').text == '1'
|
|
161
|
+
|
|
162
|
+
# Possible valid values for variable
|
|
163
|
+
# outvals = {}
|
|
164
|
+
for cvals in elem.findall('./values'):
|
|
165
|
+
meta_dict[name]['valid_value_type'] = cvals.attrib.get('type')
|
|
166
|
+
|
|
167
|
+
meta_dict[name]['valid_values'] = {}
|
|
168
|
+
for cv in cvals.findall('./value'):
|
|
169
|
+
meta_dict[name]['valid_values'][cv.attrib.get('name')] = cv.text
|
|
170
|
+
|
|
171
|
+
return meta_dict
|
|
172
|
+
|
|
173
|
+
def __parameters_to_dict(self, xml_root: xmlET.Element,
|
|
174
|
+
meta_type: str,
|
|
175
|
+
req_version: Version) -> Dict:
|
|
176
|
+
"""Convert parameter metadata to dictionary"""
|
|
177
|
+
|
|
178
|
+
meta_dict: Dict = {}
|
|
179
|
+
|
|
180
|
+
for elem in xml_root.findall(outside_elem[meta_type]):
|
|
181
|
+
name = elem.attrib.get('name')
|
|
182
|
+
|
|
183
|
+
meta_dict[name] = defaultdict(list)
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
var_version = Version(elem.attrib.get('version'))
|
|
187
|
+
|
|
188
|
+
if var_version > req_version:
|
|
189
|
+
if self.__verbose: # pragma: no cover
|
|
190
|
+
print(f'{name} rejected by version {str(var_version)}, req: {str(req_version)}')
|
|
191
|
+
|
|
192
|
+
del meta_dict[name]
|
|
193
|
+
continue
|
|
194
|
+
meta_dict[name]['version'] = str(var_version)
|
|
195
|
+
except TypeError:
|
|
196
|
+
pass
|
|
197
|
+
|
|
198
|
+
try:
|
|
199
|
+
depr_version = Version(elem.attrib.get('deprecated'))
|
|
200
|
+
|
|
201
|
+
if depr_version <= req_version:
|
|
202
|
+
if self.__verbose: # pragma: no cover
|
|
203
|
+
print(f'{name} rejected by deprecation version {str(depr_version)}, req: {str(req_version)}')
|
|
204
|
+
|
|
205
|
+
del meta_dict[name]
|
|
206
|
+
continue
|
|
207
|
+
meta_dict[name]['deprecated'] = depr_version
|
|
208
|
+
except TypeError:
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
# var_version = version_info(elem.attrib.get('version'))
|
|
212
|
+
# depr_version = version_info(elem.attrib.get('deprecated'))
|
|
213
|
+
#
|
|
214
|
+
# if var_version.major is not None and var_version.major > version.major:
|
|
215
|
+
# if self.__verbose: # pragma: no cover
|
|
216
|
+
# print(f'{name} rejected by version')
|
|
217
|
+
# continue
|
|
218
|
+
# if depr_version.major is not None and depr_version.major <= version.major:
|
|
219
|
+
# if self.__verbose: # pragma: no cover
|
|
220
|
+
# print(f'{name} rejected by deprecation version')
|
|
221
|
+
# continue
|
|
222
|
+
#
|
|
223
|
+
# meta_dict[name] = defaultdict(list)
|
|
224
|
+
#
|
|
225
|
+
# var_version = elem.attrib.get('version')
|
|
226
|
+
# if var_version is not None:
|
|
227
|
+
# meta_dict[name]['version'] = var_version
|
|
228
|
+
# # meta_dict[name]['version'] = elem.attrib.get('version')
|
|
229
|
+
#
|
|
230
|
+
# depr_version = elem.attrib.get('deprecated')
|
|
231
|
+
# if depr_version is not None:
|
|
232
|
+
# meta_dict[name]['deprecated'] = depr_version
|
|
233
|
+
|
|
234
|
+
datatype = elem.find('type').text
|
|
235
|
+
meta_dict[name]['datatype'] = NEW_PARAM_DTYPE[datatype]
|
|
236
|
+
|
|
237
|
+
elems = {'description': 'desc',
|
|
238
|
+
'help': 'help',
|
|
239
|
+
'units': 'units',
|
|
240
|
+
'default': 'default',
|
|
241
|
+
'minimum': 'minimum',
|
|
242
|
+
'maximum': 'maximum', }
|
|
243
|
+
|
|
244
|
+
for ek, ev in elems.items():
|
|
245
|
+
if ek in ['default', 'minimum', 'maximum']:
|
|
246
|
+
# Try to convert to the parameter datatype
|
|
247
|
+
# Bounded parameters will fail
|
|
248
|
+
cdtype = NEW_PTYPE_TO_DTYPE[meta_dict[name]['datatype']]
|
|
249
|
+
|
|
250
|
+
try:
|
|
251
|
+
meta_dict[name][ek] = cdtype(elem.find(ev).text)
|
|
252
|
+
except ValueError:
|
|
253
|
+
# Leave the value as a string
|
|
254
|
+
if elem.find(ev).text == 'bounded':
|
|
255
|
+
meta_dict[name][ek] = meta_dict[name]['default']
|
|
256
|
+
else:
|
|
257
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
258
|
+
except AttributeError:
|
|
259
|
+
# Occurs when element does not exist; just default to string
|
|
260
|
+
meta_dict[name][ek] = ''
|
|
261
|
+
else:
|
|
262
|
+
try:
|
|
263
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
264
|
+
except AttributeError:
|
|
265
|
+
pass
|
|
266
|
+
|
|
267
|
+
for cdim in elem.findall('./dimensions/dimension'):
|
|
268
|
+
meta_dict[name]['dimensions'].append(cdim.attrib.get('name'))
|
|
269
|
+
|
|
270
|
+
for cmod in elem.findall('./modules/module'):
|
|
271
|
+
meta_dict[name]['modules'].append(cmod.text)
|
|
272
|
+
|
|
273
|
+
for creq in elem.findall('./requires/*'):
|
|
274
|
+
meta_dict[name][f'requires_{creq.tag}'].append(creq.text)
|
|
275
|
+
|
|
276
|
+
return meta_dict
|
|
277
|
+
|
|
278
|
+
def __dimensions_to_dict(self, xml_root: xmlET.Element,
|
|
279
|
+
meta_type: str,
|
|
280
|
+
req_version: Version) -> Dict:
|
|
281
|
+
"""Convert control variables metadata to dictionary"""
|
|
282
|
+
|
|
283
|
+
meta_dict: Dict = {}
|
|
284
|
+
|
|
285
|
+
for elem in xml_root.findall(outside_elem[meta_type]):
|
|
286
|
+
name = elem.attrib.get('name')
|
|
287
|
+
|
|
288
|
+
meta_dict[name] = {}
|
|
289
|
+
|
|
290
|
+
elems = {'description': {'orig_name': 'desc',
|
|
291
|
+
'datatype': str},
|
|
292
|
+
'size': {'orig_name': 'size',
|
|
293
|
+
'datatype': int},
|
|
294
|
+
'default': {'orig_name': 'default',
|
|
295
|
+
'datatype': int},
|
|
296
|
+
'is_fixed': {'orig_name': 'is_fixed',
|
|
297
|
+
'datatype': bool}}
|
|
298
|
+
|
|
299
|
+
for ek, ev in elems.items():
|
|
300
|
+
try:
|
|
301
|
+
meta_dict[name][ek] = ev['datatype'](elem.find(ev['orig_name']).text)
|
|
302
|
+
except AttributeError:
|
|
303
|
+
if ek == 'is_fixed':
|
|
304
|
+
meta_dict[name][ek] = False
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
for creq in elem.findall('./requires/*'):
|
|
308
|
+
meta_dict[name].setdefault(f'requires_{creq.tag}', list()).append(creq.text)
|
|
309
|
+
|
|
310
|
+
return meta_dict
|
|
311
|
+
|
|
312
|
+
def __variables_to_dict(self, xml_root: xmlET.Element,
|
|
313
|
+
meta_type: str,
|
|
314
|
+
req_version: Version) -> Dict:
|
|
315
|
+
"""Convert output variables metadata to dictionary"""
|
|
316
|
+
|
|
317
|
+
meta_dict: Dict = {}
|
|
318
|
+
|
|
319
|
+
for elem in xml_root.findall(outside_elem[meta_type]):
|
|
320
|
+
name = elem.attrib.get('name')
|
|
321
|
+
# var_version = version_info(elem.attrib.get('version'))
|
|
322
|
+
# depr_version = version_info(elem.attrib.get('deprecated'))
|
|
323
|
+
#
|
|
324
|
+
# if var_version.major is not None and var_version.major > version:
|
|
325
|
+
# if self.__verbose:
|
|
326
|
+
# print(f'{name} rejected by version')
|
|
327
|
+
# continue
|
|
328
|
+
# if depr_version.major is not None and depr_version.major <= version:
|
|
329
|
+
# if self.__verbose:
|
|
330
|
+
# print(f'{name} rejected by deprecation version')
|
|
331
|
+
# continue
|
|
332
|
+
|
|
333
|
+
meta_dict[name] = defaultdict(list)
|
|
334
|
+
|
|
335
|
+
# var_version = elem.attrib.get('version')
|
|
336
|
+
# if var_version is not None:
|
|
337
|
+
# meta_dict[name]['version'] = var_version
|
|
338
|
+
# # meta_dict[name]['version'] = elem.attrib.get('version')
|
|
339
|
+
#
|
|
340
|
+
# depr_version = elem.attrib.get('deprecated')
|
|
341
|
+
# if depr_version is not None:
|
|
342
|
+
# meta_dict[name]['deprecated'] = depr_version
|
|
343
|
+
|
|
344
|
+
datatype = elem.find('type').text
|
|
345
|
+
meta_dict[name]['datatype'] = NEW_PARAM_DTYPE[datatype]
|
|
346
|
+
|
|
347
|
+
elems = {'description': 'desc',
|
|
348
|
+
'units': 'units', }
|
|
349
|
+
|
|
350
|
+
for ek, ev in elems.items():
|
|
351
|
+
try:
|
|
352
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
353
|
+
except AttributeError:
|
|
354
|
+
pass
|
|
355
|
+
|
|
356
|
+
for cdim in elem.findall('./dimensions/dimension'):
|
|
357
|
+
meta_dict[name]['dimensions'].append(cdim.attrib.get('name'))
|
|
358
|
+
|
|
359
|
+
for cmod in elem.findall('./modules/module'):
|
|
360
|
+
meta_dict[name]['modules'].append(cmod.text)
|
|
361
|
+
|
|
362
|
+
# for creq in elem.findall('./requires/*'):
|
|
363
|
+
# meta_dict[name][f'requires_{creq.tag}'].append(creq.text)
|
|
364
|
+
|
|
365
|
+
return meta_dict
|
|
366
|
+
|
|
367
|
+
def __cbh_to_dict(self, xml_root: xmlET.Element,
|
|
368
|
+
meta_type: str,
|
|
369
|
+
req_version: Version) -> Dict:
|
|
370
|
+
"""Convert cbh variables metadata to dictionary"""
|
|
371
|
+
|
|
372
|
+
meta_dict: Dict = {}
|
|
373
|
+
|
|
374
|
+
for elem in xml_root.findall(outside_elem[meta_type]):
|
|
375
|
+
name = elem.attrib.get('name')
|
|
376
|
+
|
|
377
|
+
meta_dict[name] = defaultdict(list)
|
|
378
|
+
|
|
379
|
+
try:
|
|
380
|
+
var_version = Version(elem.attrib.get('version'))
|
|
381
|
+
|
|
382
|
+
if var_version > req_version:
|
|
383
|
+
if self.__verbose: # pragma: no cover
|
|
384
|
+
print(f'{name} rejected by version {str(var_version)}, req: {str(req_version)}')
|
|
385
|
+
|
|
386
|
+
del meta_dict[name]
|
|
387
|
+
continue
|
|
388
|
+
meta_dict[name]['version'] = str(var_version)
|
|
389
|
+
except TypeError:
|
|
390
|
+
pass
|
|
391
|
+
|
|
392
|
+
try:
|
|
393
|
+
depr_version = Version(elem.attrib.get('deprecated'))
|
|
394
|
+
|
|
395
|
+
if depr_version <= req_version:
|
|
396
|
+
if self.__verbose: # pragma: no cover
|
|
397
|
+
print(f'{name} rejected by deprecation version {str(depr_version)}, req: {str(req_version)}')
|
|
398
|
+
|
|
399
|
+
del meta_dict[name]
|
|
400
|
+
continue
|
|
401
|
+
meta_dict[name]['deprecated'] = depr_version
|
|
402
|
+
except TypeError:
|
|
403
|
+
pass
|
|
404
|
+
|
|
405
|
+
datatype = elem.find('type').text
|
|
406
|
+
meta_dict[name]['datatype'] = NEW_PARAM_DTYPE[datatype]
|
|
407
|
+
|
|
408
|
+
elems = {'description': 'desc',
|
|
409
|
+
'help': 'help',
|
|
410
|
+
'units': 'units',
|
|
411
|
+
'default': 'default',
|
|
412
|
+
'minimum': 'minimum',
|
|
413
|
+
'maximum': 'maximum', }
|
|
414
|
+
|
|
415
|
+
for ek, ev in elems.items():
|
|
416
|
+
try:
|
|
417
|
+
meta_dict[name][ek] = elem.find(ev).text
|
|
418
|
+
except AttributeError:
|
|
419
|
+
pass
|
|
420
|
+
|
|
421
|
+
for cdim in elem.findall('./dimensions/dimension'):
|
|
422
|
+
meta_dict[name]['dimensions'].append(cdim.attrib.get('name'))
|
|
423
|
+
|
|
424
|
+
for cmod in elem.findall('./modules/module'):
|
|
425
|
+
meta_dict[name]['modules'].append(cmod.text)
|
|
426
|
+
|
|
427
|
+
for creq in elem.findall('./requires/*'):
|
|
428
|
+
meta_dict[name][f'requires_{creq.tag}'].append(creq.text)
|
|
429
|
+
|
|
430
|
+
return meta_dict
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
|
|
2
|
+
import os
|
|
3
|
+
import pandas as pd # type: ignore
|
|
4
|
+
from typing import cast, Optional
|
|
5
|
+
|
|
6
|
+
from ..prms_helpers import read_xml
|
|
7
|
+
from .Parameters import Parameters
|
|
8
|
+
from ..constants import NEW_PTYPE_TO_DTYPE, PARAMETERS_XML, DIMENSIONS_XML
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ParamDb(Parameters):
|
|
12
|
+
def __init__(self, paramdb_dir: str,
|
|
13
|
+
metadata,
|
|
14
|
+
verbose: Optional[bool] = False):
|
|
15
|
+
"""Initialize ParamDb object.
|
|
16
|
+
|
|
17
|
+
This object handles the monolithic parameter database.
|
|
18
|
+
|
|
19
|
+
:param paramdb_dir: Path to the ParamDb directory
|
|
20
|
+
:param verbose: Output additional debug information
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
super(ParamDb, self).__init__(metadata=metadata, verbose=verbose)
|
|
24
|
+
self.__paramdb_dir = paramdb_dir
|
|
25
|
+
self.__verbose = verbose
|
|
26
|
+
|
|
27
|
+
# Read the parameters from the parameter database
|
|
28
|
+
self._read()
|
|
29
|
+
|
|
30
|
+
def _read(self):
|
|
31
|
+
"""Read a parameter database.
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
# Get the parameters available from the parameter database
|
|
35
|
+
# Returns a dictionary of parameters and associated units and types
|
|
36
|
+
|
|
37
|
+
# Get the parameters available from the parameter database
|
|
38
|
+
# Returns a dictionary of parameters and associated units and types
|
|
39
|
+
global_params_file = f'{self.__paramdb_dir}/{PARAMETERS_XML}'
|
|
40
|
+
global_dimens_file = f'{self.__paramdb_dir}/{DIMENSIONS_XML}'
|
|
41
|
+
|
|
42
|
+
# Read in the parameters.xml and dimensions.xml file
|
|
43
|
+
params_root = read_xml(global_params_file)
|
|
44
|
+
dimens_root = read_xml(global_dimens_file)
|
|
45
|
+
|
|
46
|
+
# Populate the global dimensions from the xml file
|
|
47
|
+
for xml_dim in dimens_root.findall('dimension'):
|
|
48
|
+
self.dimensions.add(name=cast(str, xml_dim.attrib.get('name')), size=cast(int, xml_dim.find('size').text))
|
|
49
|
+
|
|
50
|
+
# Populate parameterSet with all available parameter names
|
|
51
|
+
for param in params_root.findall('parameter'):
|
|
52
|
+
xml_param_name = cast(str, param.attrib.get('name'))
|
|
53
|
+
curr_file = f'{self.__paramdb_dir}/{xml_param_name}.csv'
|
|
54
|
+
|
|
55
|
+
if self.exists(xml_param_name):
|
|
56
|
+
# Sometimes the global parameter xml file has duplicates of parameters
|
|
57
|
+
print(f'WARNING: {xml_param_name} is duplicated in {PARAMETERS_XML}; skipping')
|
|
58
|
+
continue
|
|
59
|
+
|
|
60
|
+
if os.path.exists(curr_file):
|
|
61
|
+
self.add(xml_param_name)
|
|
62
|
+
|
|
63
|
+
cdtype = NEW_PTYPE_TO_DTYPE[self.get(xml_param_name).meta['datatype']]
|
|
64
|
+
tmp_data = pd.read_csv(curr_file,
|
|
65
|
+
skiprows=0,
|
|
66
|
+
usecols=[1],
|
|
67
|
+
dtype={1: cdtype}).squeeze('columns').to_numpy()
|
|
68
|
+
|
|
69
|
+
self.get(xml_param_name).data = tmp_data
|
|
70
|
+
else:
|
|
71
|
+
print(f'WARNING: {xml_param_name}, ParamDb file does not exist; skipping')
|
|
72
|
+
|
|
73
|
+
self.adjust_bounded_parameters()
|