1
2
3
4
5 """Module for class defining QTCM fields.
6
7 A field is a model parameters or variables, and includes diagnotic
8 and prognostic variables, run parameters, coefficients, etc.
9 """
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 import os, sys
43 if (__name__ == "__main__") or \
44 ("pydoc" in os.path.basename(sys.argv[0])):
45 import user
46 del os, sys
47
48
49
50
51 import package_version as _package_version
52 __version__ = _package_version.version
53 __author__ = _package_version.author
54 __date__ = _package_version.date
55 __credits__ = _package_version.credits
56
57
58
59
60 import num_settings as num
61 from num_settings import N
62
63
64
65
66 from defaults import qtcm_fields as qtcm_defaults
67
68
69
70
71
72
74 """Class for QTCM fields.
75
76 QTCM fields are model parameters or variables, and includes
77 diagnotic and prognostic variables, run parameters, coefficients,
78 etc. They can be scalars (numeric or string) or arrays. The
79 values of these QTCM parameter objects can be changed in the
80 model by a call at the Python level, though the types of their
81 compiled model counterparts cannot be changed (without recompiling
82 the compiled model, of course).
83
84 The default values of QTCM fields that are defined in the
85 defaults module specify the type of the variables, as well as
86 the rank. This information is used by the Qtcm class to properly
87 interface with the compiled model. Thus, fields that are not
88 specified in the defaults module will not properly interface
89 with the compiled model. However, some fields only need to be
90 defined at the Python level; those fields do not have to be
91 listed in defaults.
92
93 Class Instance Attributes:
94 * id: A string naming the field (e.g., 'Qc', 'mrestart'). This
95 string should contain no whitespace.
96 * value: The value of the field. Can be of any type, though
97 typically is either a string or numeric scalar or a numeric
98 array.
99 * units: A string giving the units of the field.
100 * long_name: A string giving a description of the field.
101
102 Class Instance Methods:
103 * rank: Returns the rank of value.
104 * typecode: Returns the typecode of value.
105 """
107 """Initialize Field object.
108
109 The Field object is instantiated either with one or two
110 positional input parameters, and up to two optional keyword
111 input parameters.
112
113 Positional Input Parameters:
114 * One argument: The argument is a string that specifies
115 the name of the field. The name must match a key in
116 defaults.qtcm_fields. The value of the Field instance
117 is set to the default value given in defaults.qtcm_fields.
118
119 * Two arguments: The first argument is a string specifying
120 the name of the field (as in the one argument case). The
121 second argument is the value that the Field instance is
122 set to. If the second argument is a Field object, the
123 value of that Field object is extracted as the value for
124 creating the current Field object.
125
126 Keyword Input Parameters:
127 * units: String specifying the units of the field.
128
129 * long_name: String specifying the long name of the field.
130
131 Examples:
132 >>> a = Field('dt')
133 >>> print a.id
134 dt
135 >>> print a.value
136 1200.0
137
138 >>> a = Field('dt', 1200.)
139 >>> print a.id
140 dt
141 >>> print a.value
142 1200.0
143 >>> print a.units
144 s
145 >>> print a.long_name
146 time step
147
148 >>> a = Field('dt', Field('dt'), units='h')
149 >>> print a.id
150 dt
151 >>> print a.value
152 1200.0
153 >>> print a.units
154 h
155
156 >>> a = Field(23)
157 Traceback (most recent call last):
158 ...
159 TypeError: Field id must be string
160 """
161 if type(args[0]) != type('a'):
162 raise TypeError, self.__class__.__name__ + ' id must be string'
163
164 if len(args) == 1:
165 self.id = args[0]
166 self.value = qtcm_defaults[self.id]['value']
167 elif len(args) == 2:
168 self.id = args[0]
169 if type(args[1]) == type(self):
170 if args[1].id != self.id:
171 raise ValueError, 'id mismatch'
172 self.value = args[1].value
173 else:
174 self.value = args[1]
175 else:
176 raise ValueError, '1-2 required arguments for ' \
177 + self.__class__.__name__
178
179 if kwds.has_key('units'):
180 self.units = kwds['units']
181 else:
182 self.units = qtcm_defaults[self.id]['units']
183
184 if kwds.has_key('long_name'):
185 self.long_name = kwds['long_name']
186 else:
187 self.long_name = qtcm_defaults[self.id]['long_name']
188
189
191 """Return the rank of self.value.
192
193 If self.value does not exist, returns None.
194 """
195 if hasattr(self, 'value'):
196 return N.rank(self.value)
197 else:
198 return None
199
200
202 """Return the typecode of self.value.
203
204 The typecode is determined by first converting self.value
205 into an array, and then returning the dtype.char (in numpy).
206 This is defined in the module num_settings, and is a function
207 of what type of array package you're using. As a result,
208 you shouldn't assume this method is very precise (e.g.,
209 don't use it to distinguish between single and double
210 precision float), but rather, use it to distinguish between
211 different categories of types (e.g., float vs. int). If
212 self.value does not exist, returns None.
213 """
214 if hasattr(self, 'value'):
215 return num.typecode(self.value)
216 else:
217 return None
218
219
220
221
222
223
224
225
226 if __name__ == "__main__":
227 """Test the module.
228
229 Note: To help ensure that module testing of this file works, the
230 parent directory to the current directory is added to sys.path.
231 """
232 import doctest, sys, os
233 sys.path.append(os.pardir)
234 doctest.testmod(sys.modules[__name__])
235
236
237
238
239
240