1
2
3
4
5 """Definition of the Qtcm class.
6 """
7
8
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 import os, sys
41 if (__name__ == "__main__") or \
42 ("pydoc" in os.path.basename(sys.argv[0])):
43 import user
44
45
46
47
48 import package_version as _package_version
49 __version__ = _package_version.version
50 __author__ = _package_version.author
51 __date__ = _package_version.date
52 __credits__ = _package_version.credits
53
54
55
56
57 import num_settings as num
58 from num_settings import N
59
60
61
62
63 import copy
64 import defaults
65 from field import Field
66 from plot import plot_ncdf_output
67 import Scientific.IO.NetCDF as S
68 import shutil
69 import tempfile
70
71
72
73
74
75
76
77
78 _test_field = Field('dt')
79
80
81
82
83
84
85
86 _init_prog_dict = defaults.init_prognostic_dict
87 _init_vars_keys = _init_prog_dict.keys() + ['dateofmodel', 'title']
88
89
90
91
92
93
94
96 "Field variable unable to be read from QTCM compiled model."
97
98
99
100
101
102
103
104
105
106
108 """Qtcm model object.
109
110 Public Instance Attributes:
111 * compiled_form: What form the compiled Fortran version of the
112 QTCM model has. This attribute is a string and can have the
113 following values:
114
115 - 'full': The compiled portion of the model encompasses the
116 entire QTCM model. Thus, the only compiled QTCM model
117 modules or subroutines that Python should interact with is
118 __qtcm.driver (which executes the entire model) and
119 __qtcm.setbypy (which enables communication between the
120 compiled model and the Python-level of model fields.
121
122 - 'parts': The compiled portion of the model encompasses
123 parts of the model as separate units all the way down to
124 an atmosphere timestep. Thus, compiled QTCM model
125 module/subroutines include those that are executed within
126 an atmosphere timestep.
127
128 This attribute must be set on instantiation via a keyword
129 input parameter.
130
131 * coupling_day: Current value of atmosphere-ocean coupling
132 day. When compiled_form of type 'parts' is run, is started
133 at 1 and then is updated every coupling day. coupling_day
134 not changed from instantiation value for compiled_form 'full'.
135 Is a Field object with integer scalar value, but is set to
136 None on instantiation (unless its value is overridden through
137 keyword input parameters). Is set to a Field object to enable
138 run lists that specify it to be able to be updated.
139
140 * init_with_instance_state: This keyword only has an effect if
141 compiled_form = 'parts'. Boolean scalar.
142
143 If True, uses, in general, the values of the instance attributes
144 (for prognostic variables and right-hand sides, and start
145 date) are right before the run_session method call as the
146 initial values for the run_session. If False, run_session
147 initialization, in general, follows the rules set by all the
148 standard QTCM model input parameters (e.g., the sign of day0,
149 month0, and year0, the value of the mrestart flag, etc.).
150 See the docstring for the varinit method for details, as well
151 as the manual. Default is True, unless overridden, on
152 instantiation.
153
154 * QTCM fields: This is not the name of an attribute, but a
155 category of attributes. These attributes are QTCM fields
156 whose names correspond to those given in the _qtcm_fields_ids
157 attribute, and whose values are Field objects. Initially set
158 on instantiation.
159
160 Override of default values on instantiation is accomplished
161 by setting the value to a keyword input parameter with the
162 Field object id as the keyword key. The __init__ method takes
163 all keyword input and sets it to instance attributes with the
164 key as the attribute name and attribute values being Field
165 objects. Note that the instantiation keyword parameter does
166 not have to itself be a Field object; if the keyword is set
167 to a plain value, the __init__method will form a Field object
168 around that value and set the Field object to the instance
169 attribute.
170
171 * runlists: Dictionary of lists of methods, routines, and other
172 run lists that can be executed by the run_list method. Altering
173 lists in this dictionary enables one to simply change order
174 or execution or insert/delete methods. Runlist's keys are
175 strings, and are names that describe that the category of
176 routines does. Run list names should not be preceeded by two
177 underscores (though runlist elements may be very private
178 variables), nor should runlist names be the same as any
179 instance attribute. See list of run lists below for details
180 about the lists.
181
182 * sodir: Name of temporary directory containing all the copies
183 of shared object files for this instance of Qtcm. This
184 temporary directory is located in the default temporary
185 directory, whose location is platform dependent, using the
186 rules of the module tempfile. The name of the temporary
187 directory is generated randomly, and should not conflict with
188 any existing temporary directory. String. Set on model
189 instantiation.
190
191
192 Public Instance Methods:
193 * get_qtcm_item: Get field from the compiled QTCM model (same
194 as get_qtcm1_item).
195
196 * get_qtcm1_item: Get field from the compiled QTCM model.
197
198 * make_snapshot: Make copy of current state of run session
199 variables that would be used for a restart.
200
201 * more_first_method_at_atm_oc_step: More of first method
202 executed at the atmosphere-coupling timestep. This gives an
203 easy way to change the model at the atmosphere-coupling
204 timestep, after the update of the interval attribute: Just
205 overload this method.
206
207 * plotm: Plot mean output for model field id. Matplotlib is
208 used.
209
210 * qtcm: Run the qtcm atmosphere over a coupling interval step.
211
212 * run_list: Run runlist of run lists and/or instance methods.
213
214 * run_session: Run model session.
215
216 * set_qtcm_item: Set Python-accessible compiled QTCM model
217 fields (same as set_qtcm1_item).
218
219 * set_qtcm1_item: Set Python-accessible compiled QTCM model
220 fields.
221
222 * sync_set_py_values_to_snapshot: Set Python attributes to
223 snapshot values from a dictionary created by make_snapshot.
224
225 * sync_set_qtcm_items_to_all_py_values: Synchronize so that
226 any Python attribute that corresponds to a compiled model
227 Python-changable variable is set, on both the Python attribute
228 side and the compiled model side, to the value of the Python
229 attribute.
230
231 * sync_set_all_py_values_to_qtcm_items: Set all Python-level
232 attributes to QTCM compiled model values. Synchoronize so
233 that any Python attribute that corresponds to a compiled model
234 Python-changable variable is set to the value of the QTCM
235 compiled variable.
236
237 * varinit: Initialize model variables in a run session.
238
239
240 List of Run Lists:
241 * 'atm_oc_step': Methods to run at an atmosphere-ocean coupling
242 time step. As default, set to methods that set the calendar,
243 run the ocean (make SST for atmo), run the atmosphere, and
244 output all output variables. Set on model instantiation.
245 See method __run_parts for details.
246
247 * 'init_model': Methods to initialize model variables. Not
248 all model variables are initalized in these methods. Note
249 that many of these methods use the values of QTCM parameters
250 as defined as instance attributes (and the defaults of which
251 are set by the _set_all_qtcm_scalar_fields_to_defaults method).
252 As default, set to initialize the atmosphere, ocean, and
253 output files. Set on model instantiation. See method
254 __run_parts for details.
255
256 * 'qtcminit': Duplicates functionality of the Fortran subroutine
257 qtcminit, for compiled_form 'parts'.
258
259
260 Private Instance Attributes (partial list):
261 * _monlen: Integer array of the number of days in each month.
262 Assumes a 365 day year.
263
264 * __qtcm: The compiled Fortran model for this instance. Set on
265 instantiation.
266
267 * _qtcm_fields_ids: Field ids for all default QTCM fields.
268 NB: The model assumes this is a list of all the default fields.
269 Set on instantiation.
270
271 * _runlists_long_names: Descriptions of the standard run lists.
272
273
274 Private Instance Methods (partial list):
275 * _bartropic_mode_at_atm_step: Calculate the atmosphere
276 barotropic mode at atmosphere timestep.
277
278 * _first_method_at_atm_oc_step: First method executed at the
279 atmosphere-coupling timestep.
280
281 * __run_parts: Run parts model starting at the atmosphere-ocean
282 coupling level. This method duplicates the functionality of
283 the driver subroutine in the original compiled QTCM model.
284
285 * _set_qtcm_array_item_in_model: Set Python-accessible QTCM
286 array settings in compiled model.
287
288 * _set_qtcm_scalar_item_in_model: Set Python scalar variable
289 in the compiled QTCM model.
290
291
292 Description of Compiled QTCM Modules Available to Class:
293 * _qtcm_full_365.so: QTCM shared object file for the full
294 model, compiled assuming a year is 365 days. This is essentially
295 the default version of QTCM, with netCDF output used.
296
297 * _qtcm_parts_365.so: QTCM shared object file for the model
298 separated so units within the atmosphere timestep are separate
299 compiled units.
300 """
301
302
303
304
305
306
308 """Initialize Qtcm instance.
309
310 Items in kwds are attributes of the model instance to be
311 set. There are two types of attributes: (1) Field objects,
312 and (2) Non-Field objects. In both cases you can pass in
313 the name and value in the input kwds dictionary. For Field
314 object attributes, the kwds key is the id, and the kwds
315 value can be either the value of the Field object or a Field
316 object itself. For Non-Field objects, the kwds key:value
317 pair directly provides the instance attribute name and
318 value. A more detailed description of this input and other
319 input is provided in the class documentation.
320
321 Examples:
322 model = Qtcm(dt=1200., compiled_form='parts')
323 model = Qtcm(dt=Field('dt'), compiled_form='full')
324 model = Qtcm(dt=Field('dt', 1200), compiled_form='full')
325 inputs = {}
326 inputs['dt'] = 1200.
327 inputs['title'] ='QTCM spinup part 1 test (aquaplanet)'
328 inputs['compiled_form'] = 'parts'
329 model = Qtcm(**inputs)
330
331 NB: Not all compiled QTCM model variables are accessible
332 at the Python level, and vice versa. Only the variables
333 in defaults (whose names are specified by the _qtcm_fields_ids
334 attribute) can be passed between the compiled QTCM model
335 and the Python model instance.
336
337 Additionally, there is only a full-as-possible syncronization
338 between compiled QTCM model fields and Python fields at the
339 beginning and end of the execution of a Python method. If
340 the compiled QTCM model changes a variable as the model is
341 running, the Python field that variable corresponds to will
342 in general not also be changed, since you need to execute
343 get_qtcm_item at the Python level to retrieve it. This
344 only occurs with Python methods (e.g., run_session, varinit).
345 """
346
347
348 self._qtcm_fields_ids = defaults.qtcm_fields_ids
349
350
351
352
353 if kwds.has_key('compiled_form'):
354 setattr( self, 'compiled_form', kwds['compiled_form'] )
355 else:
356 raise ValueError, 'must pass in complied_form on instantiation'
357
358
359
360
361
362 self._set_compiled_qtcm_attr()
363 self._set_all_qtcm_scalar_fields_to_defaults()
364
365
366
367
368
369
370
371
372
373
374 for ikey in kwds.keys():
375 if ikey in self._qtcm_fields_ids:
376 self.set_qtcm_item(ikey, kwds[ikey])
377 else:
378 setattr(self, ikey, kwds[ikey])
379
380
381
382
383
384
385
386
387 if not hasattr(self, 'coupling_day'):
388 self.coupling_day = Field( 'coupling_day', None, units='dy' \
389 , long_name='current coupling day')
390 else:
391 self.coupling_day = Field( 'coupling_day', self.coupling_day \
392 , units='dy' \
393 , long_name='current coupling day')
394
395 if not hasattr(self, 'init_with_instance_state'):
396 self.init_with_instance_state = True
397
398 if not hasattr(self, '_monlen'):
399 self._monlen = N.array([31,28,31,30,31,30,31,31,30,31,30,31])
400
401
402
403
404 self.runlists = {}
405
406
407 self.runlists['init_model'] = \
408 [ 'qtcminit',
409 '__qtcm.wrapcall.woceaninit',
410 '__qtcm.wrapcall.woutpinit' ]
411
412
413 self.runlists['qtcminit'] = \
414 [ '__qtcm.wrapcall.wparinit',
415 '__qtcm.wrapcall.wbndinit',
416 'varinit',
417 {'__qtcm.wrapcall.wtimemanager':[1,]},
418 'atm_physics1' ]
419
420
421 self.runlists['atm_physics1'] = \
422 [ '__qtcm.wrapcall.wmconvct',
423 '__qtcm.wrapcall.wcloud',
424 '__qtcm.wrapcall.wradsw',
425 '__qtcm.wrapcall.wradlw',
426 '__qtcm.wrapcall.wsflux' ]
427
428
429 self.runlists['atm_oc_step'] = \
430 [ '_first_method_at_atm_oc_step',
431 {'__qtcm.wrapcall.wtimemanager':[self.coupling_day,]},
432 {'__qtcm.wrapcall.wocean': [self.interval, self.coupling_day]},
433 'qtcm',
434 '__qtcm.wrapcall.woutpall' ]
435
436
437 self.runlists['atm_step'] = \
438 [ 'atm_physics1',
439 '__qtcm.wrapcall.wsland1',
440 '__qtcm.wrapcall.wadvctuv',
441 '__qtcm.wrapcall.wadvcttq',
442 '__qtcm.wrapcall.wdffus',
443 '__qtcm.wrapcall.wbarcl',
444 '_bartropic_mode_at_atm_step',
445 '__qtcm.wrapcall.wvarmean' ]
446
447
448
449
450 self.runlists['atm_bartr_mode'] = \
451 [ '__qtcm.wrapcall.wsavebartr',
452 '__qtcm.wrapcall.wbartr',
453 '__qtcm.wrapcall.wgradphis']
454
455
456
457
458 self._runlists_long_names = {}
459 self._runlists_long_names['init_model'] = \
460 'initialize the entire model, i.e., the atmosphere and ocean ' + \
461 'components and output'
462
463 self._runlists_long_names['qtcminit'] = \
464 'initialize the atmosphere portion of the entire model'
465
466 self._runlists_long_names['atm_physics1'] = \
467 'calculate atmospheric physics at one instant'
468
469 self._runlists_long_names['atm_oc_step'] = \
470 'calculate the atmosphere and ocean models at a coupling timestep'
471
472 self._runlists_long_names['atm_step'] = \
473 'calculate the entire atmosphere at one atmosphere timestep'
474
475 self._runlists_long_names['atm_bartr_mode'] = \
476 'calculate the atmospheric barotropic mode at the barotropic ' + \
477 'timestep'
478
479
480
481
482
483 if len(self.runlists) != len(self._runlists_long_names):
484 raise ValueError, 'number of run lists incorrect'
485 for ikey in self.runlists.keys():
486 if not self._runlists_long_names.has_key(ikey):
487 raise ValueError, 'description and runlist key mismatch'
488
489
490
491
492
493
495 """Method to execute before garbage collection.
496
497 Delete the sodir temporary directory.
498 """
499 shutil.rmtree(self.sodir)
500
501
502
503
504
505
507 """Get field from the compiled QTCM model.
508
509 Gets the value of the variable key from the compiled QTCM
510 model. (Note that not all compiled QTCM model variables
511 are accessible to Python.) Method does nothing else (such
512 as saving that value as an object attribute).
513
514 For scalar variables, in order to know which Fortran routine
515 to use to access the item, this method needs to know the
516 type of the variable named key. For arrays, it needs to
517 know the rank of the array. It assumes that type is the
518 same as the corresponding Field object default value, and
519 rank is the same as the corresponding Field object default
520 value.
521
522 If the compiled QTCM model variable is unreadable, the
523 custom exception FieldNotReadableFromCompiledModel is thrown.
524
525 Positional Input Parameter:
526 * key: Name of QTCM variable. String. Scalar.
527
528 Output:
529 * Returns the value of the variable named key. Scalar
530 string or numeric value, or numeric array. The value
531 returned is a copy of the values, not a reference to the
532 array in memory.
533 """
534
535
536
537 tmpfield = Field(key)
538 value_type = tmpfield.typecode()
539 value_rank = tmpfield.rank()
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557 if value_type in N.typecodes['Float']:
558 if value_rank == 0:
559 tmp = copy.copy(self.__qtcm.setbypy.getitem_real(key))
560 if not self.__qtcm.setbypy.is_readable:
561 raise FieldNotReadableFromCompiledModel, \
562 'Compiled model variable not readable'
563 else:
564 self.__qtcm.setbypy.getitem_real_array(key)
565 if not self.__qtcm.setbypy.is_readable:
566 raise FieldNotReadableFromCompiledModel, \
567 'Compiled model variable not readable'
568 else:
569 if value_rank == 1:
570 tmp = copy.copy(self.__qtcm.setbypy.real_rank1_array)
571 self.__qtcm.setbypy.real_rank1_array = None
572 elif value_rank == 2:
573 tmp = copy.copy(self.__qtcm.setbypy.real_rank2_array)
574 self.__qtcm.setbypy.real_rank2_array = None
575 elif value_rank == 3:
576 tmp = copy.copy(self.__qtcm.setbypy.real_rank3_array)
577 self.__qtcm.setbypy.real_rank3_array = None
578 else:
579 raise ValueError, 'bad rank value'
580
581 elif value_type in N.typecodes['Integer']:
582 if value_rank == 0:
583 tmp = copy.copy(self.__qtcm.setbypy.getitem_int(key))
584 if not self.__qtcm.setbypy.is_readable:
585 raise FieldNotReadableFromCompiledModel, \
586 'Compiled model variable not readable'
587 else:
588 raise ValueError, 'variable option does not exist'
589
590 elif value_type in num.typecodes['Character']:
591 if value_rank == 0:
592 tmp = self.__qtcm.setbypy.getitem_str(key)
593 if not self.__qtcm.setbypy.is_readable:
594 raise FieldNotReadableFromCompiledModel, \
595 'Compiled model variable not readable'
596 tmp = tmp.strip()
597 else:
598 raise ValueError, 'variable option does not exist'
599
600 else:
601 raise TypeError, 'Value type does not exist'
602
603
604
605
606
607 return tmp
608
609
610
611
612
613
615 """Get field from the compiled QTCM model.
616
617 Identical to get_qtcm_item. See get_qtcm_item description.
618 """
619 return self.get_qtcm_item(*args, **kwds)
620
621
622
623
624
625
627 """Make copy of current state of run session variables.
628
629 The snapshot is a copy of the variables of the current state
630 of the run session that would be used for a restart. The
631 variables are saved in a dictionary, and the dictionary is
632 saved in the attribute snapshot. As most of the variables
633 are Field objects, most of the values in the dictionary are
634 Field objects. Any variables that don't exist are just
635 left out of the dictionary.
636 """
637 self.snapshot = {}
638 for ikey in _init_vars_keys:
639 if hasattr(self, ikey):
640 self.snapshot[ikey] = copy.deepcopy(getattr(self, ikey))
641
642
643
644
645
646
647 - def _plot(self, id, datafn, **kwds):
648 """Plot model field id from the data in netCDF file datafn.
649
650 See docstrings for submodule plot in package qtcm, module
651 function plot_ncdf_output.
652 """
653 plot_ncdf_output(id, datafn, **kwds)
654
655
656
657
658
659
660 - def plotm(self, id, **kwds):
661 """Plot mean output for model field id.
662
663 Plotting is done using Matplotlib, and can accomodate either
664 line plots or contour plots. This method is designed for
665 a quick look at the output, and thus only a few plotting
666 parameters can be adjusted.
667
668 Positional Input Parameter:
669 * id: Name of the id of the field to plot. String.
670
671 Input Keyword Parameters:
672 * lat: Latitude range to plot. List of the min and max
673 value, or a scalar, in degrees. If the keyword is not
674 passed in, the entire range is plotted.
675
676 * lon: Longitude range to plot. List of the min and max
677 value, or a scalar, in degrees. If the keyword is not
678 passed in, the entire range is plotted.
679
680 * time: Time range to plot. List of the min and max value,
681 or a scalar, in days. If the keyword is not passed in,
682 the entire range is plotted.
683
684 * fn: Filename to write figure out to. String. If set to
685 None, plot is output to screen.
686
687 * levels: If a contour plot, the min, max, and interval
688 of the contour levels to be plotted. If set to None,
689 contour levels are calculated automatically.
690
691 * filled: If is True, and the plot is a contour plot, a
692 filled contour plot is drawn along with a horizontal
693 colorbar. If not True, a line contour plot is drawn. If
694 plot is a line plot, this keyword is ignored.
695
696 * title: Title of plot. String.
697
698 * xlabel: Label for the x-axis.
699
700 * ylabel: Label for the y-axis.
701
702 * nlatlon: For lat vs. lon contour plots, this sets the
703 approximate number of meridions and parallels to annotate.
704 Ignored for all other types of plots. Default is 8.
705
706 * tmppreview: If True, and your platform is 'darwin',
707 instead of screen display the method will write the plot
708 to a temp file and display that file using Preview. You
709 must delete the temp file yourself (it's located probably
710 in /tmp, and is created using the tempfile module default
711 settings). The variable is boolean.
712
713 The default of all input keywords is None, unless otherwise
714 noted. Depending on which series of keywords is chosen,
715 the range is chosen accordingly. Title, x-axis and y-axis
716 labels are automatically added, unless overridden by the
717 title, xlabel, and ylabel keywords.
718
719 For a lat vs. lon plot, the contour plot is superimposed
720 onto a cylindrical projection map of the Earth with continents
721 drawn and labeled meridians and parallels. The title also
722 includes the model time, and x- and y-axis labels are not
723 drawn.
724
725 Examples for model an instance of Qtcm:
726 * model.plotm('Qc', lat=1.875): A time vs. longitude contour
727 plot is made for the full range of time and longitude,
728 at the latitude 1.875 deg N, for mean precipitation. The
729 period over which the mean is taken is self.ntout.
730
731 * model.plotm('Evap', lat=1.875, lon=[100,200]): A time
732 vs. longitude contour plot of evaporation is made for the
733 longitude points between 100 and 200 degrees east, at the
734 latitude 1.875 deg N. The period over which the mean is
735 taken is self.ntout.
736
737 * model.plotm('cl1', lat=1.875, lon=[100,200], time=20):
738 A deep cloud amount vs. longitude line plot is made for
739 the longitude points between 100 and 200 degrees east,
740 at the latitude 1.875 deg N, at day 20 of the model run.
741 The period over which the mean is taken is self.ntout.
742 """
743 datafn = os.path.join( self.outdir.value,
744 "qm_" + self.runname.value + ".nc" )
745 self._plot(id, datafn, **kwds)
746
747
748
749
750
751
753 """Run the qtcm atmosphere over a coupling interval step.
754
755 This method duplicates the functionality of the qtcm
756 subroutine in the original compiled QTCM model. It assumes
757 all fields that can be synchronized between the Python and
758 compiled QTCM model levels have been so before the calling
759 of this method. The coupling interval step is given by the
760 interval attribute. It is meant to be called once in a run
761 session, and assumes that the compiled_form is 'parts'.
762 """
763
764
765
766
767
768
769
770 self.run_list(['__qtcm.wrapcall.wgetbnd',])
771 nastep = self.interval.value * (86400./self.dt.value)
772 if N.mod(nastep, self.mt0.value) != 0:
773 raise ValueError, 'Fatal error: mt0*dt not a divisor of 1 day'
774 self.set_qtcm_item('nastep', int(nastep))
775
776
777
778
779 for self.it.value in xrange(1, self.nastep.value+1):
780 self.run_list(['atm_step',])
781
782
783
784
785
786
788 """Run runlist of run lists and/or instance methods.
789
790 Run through list of elements that specify other run lists
791 or instance method names to execute through in runlist
792 order. Methods with private attribute names are automatically
793 mangled as needed to become executable by the method. Note
794 that if an item in runlist is an instance method, it should
795 be the entire name (after "self.") of the callable method,
796 separated by periods as appropriate.
797
798 Input Via Arguments:
799
800 * runlist: List whose elements are 1-element dictionaries
801 or strings. The list can contain a mix of 1-element
802 dictionaries and strings, or just one of those types:
803
804 + If 1-element dictionaries: The key of the dictionary
805 is a string, and is the name of the method to execute.
806 The value of the entry is a list, which gives the
807 positional input parameters, or is None, if there are
808 no input parameters.
809
810 + If strings: Each string is the name of a run list or
811 the name of the method to execute. All methods are
812 assumed to not require any positional input parameters.
813
814 The methods in runlist are called in the order given in
815 runlist. For each element, we first check if the key name
816 corresponds to the key of an entry in self.runlists. If
817 so, run_list is executed using that run list (recursive
818 call). If the key name is not a run list, we check if it
819 is a method of the instance, and if so the method is called.
820 Any other value throws an exception.
821
822 If input parameters for a method are of class Field, we
823 first try to pass the parameters into the method as is
824 (i.e., as Field object(s)). If that fails, we pass its
825 parameters in as the value of the Field object.
826
827 Examples:
828 a = Qtcm(...)
829 a.run_list( ['qtcminit' \
830 , {'sync_set_all_py_values_to_qtcm_items':None} \
831 , '__qtcm.driver' \
832 , {'set_qtcm_item': ['outdir', '/home/jlin']}] )
833 a.run_list( [{'sync_set_all_py_values_to_qtcm_items':None} \
834 , {'__qtcm.driver':None} \
835 , {'set_qtcm_item': ['outdir', '/home/jlin']} )
836 a.run_list(['sync_set_all_py_values_to_qtcm_items',])
837 """
838
839
840 str_type = type('a')
841 dict_type = type({'a':None})
842
843
844
845
846
847
848 if type(runlist) != type([]):
849 raise TypeError, 'runlist must be a list'
850
851
852
853
854 for imethod in runlist:
855
856
857
858
859
860
861
862
863
864 if type(imethod) == str_type:
865 imethodname = imethod
866 if self.runlists.has_key(imethodname):
867 if hasattr(self, imethodname):
868 raise AttributeError, \
869 'run list cannot be same name as instance attrib.'
870 self.run_list(self.runlists[imethodname])
871 else:
872 if imethodname[0:2] == '__':
873 imethodname = '_' + self.__class__.__name__ \
874 + imethodname
875 imethodname_seplist = imethodname.split('.')
876 f = self
877 for subname in imethodname_seplist:
878 f = getattr(f, subname)
879 f()
880
881
882
883
884 elif type(imethod) == dict_type:
885
886
887
888 imethodname = imethod.keys()[0]
889 if imethodname[0:2] == '__':
890 imethodname = '_' + self.__class__.__name__ + imethodname
891 imethodname_seplist = imethodname.split('.')
892
893
894
895
896
897 f = self
898 for subname in imethodname_seplist:
899 f = getattr(f, subname)
900 inputparams = imethod.values()[0]
901
902
903
904
905
906
907
908
909
910
911 if inputparams == None:
912 f()
913 else:
914 try:
915 f(*inputparams)
916 except TypeError:
917 inputparams_vals = []
918 for iparam in inputparams:
919 if type(iparam) == type(_test_field):
920 inputparams_vals.append(iparam.value)
921 try:
922 f(*inputparams_vals)
923 except:
924 print "Unexpected error (A):", sys.exc_info()[0]
925 raise
926 except:
927 print "Unexpected error (B):", sys.exc_info()[0]
928 raise
929
930
931
932
933 else:
934 raise TypeError, 'bad run_list element input type'
935
936
937
938
939
940
942 """Run model session.
943
944 Run the QTCM model in a model session. A model session is
945 defined as a "complete" model run, at the end of which
946 restart files are written and the Python Qtcm instance is
947 synchronized to the Fortran model.
948
949 The following tasks are done by this method, in this order:
950 * The attribute snapshot, if present, is deleted.
951 * The compiled model is synchronized with the Python model
952 instance so that any Python attribute that corresponds to a
953 compiled model Python-changable variable is set to the value
954 of the Python attribute. If the compiled model variable is
955 not accessible, nothing is done, and the Python attribute is
956 left unchanged.
957 * The model is run until lastday. Restart and output files
958 are written accordingly.
959 * The Python-changable model attributes are set to the compiled
960 model's values. If the compiled model variable is not
961 accessible, an exception is raised.
962 * A snapshot of the Python attributes that store the variables
963 that would be used in a restart run is taken and stored as
964 the attribute snapshot.
965
966 Input Via Keywords Arguments:
967
968 * cont: If set to False, the run session is not a continuation
969 of the previous run, but a new run session. If set to
970 True, the run session is a continuation of the previous
971 run, and whatever the field values are in the Python
972 instance are used in the model (if init_with_instance_state
973 is True). If set to an integer greater than zero, the run
974 session is a continuation just like cont=True, but the
975 value set to cont is used for lastday and replaces
976 lastday.value. This keyword has no effect if
977 compiled_form='full'. Default is False. (Note whatever
978 cont is set to in this method call is stored as attribute
979 _cont, in case you really need to access it elsewhere.)
980 """
981
982
983 if kwds.has_key('cont'):
984 cont = kwds['cont']
985 else:
986 cont = False
987 self._cont = cont
988
989 if type(cont) == type(1):
990 self.lastday.value = cont
991 elif type(cont) == type(False):
992 pass
993 else:
994 raise TypeError, 'cont keyword must be integer or boolean'
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031 if hasattr(self, 'snapshot'): del self.snapshot
1032 self.sync_set_qtcm_items_to_all_py_values()
1033
1034
1035
1036
1037 if self.compiled_form == 'full':
1038 self.run_list(['__qtcm.driver',])
1039 elif self.compiled_form == 'parts':
1040 self.run_list(['__run_parts',])
1041 else:
1042 raise ValueError, 'Compiled form not recognized'
1043
1044
1045
1046
1047
1048
1049 self.sync_set_all_py_values_to_qtcm_items()
1050 self.make_snapshot()
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1067 """Set Python-accessible compiled QTCM model fields.
1068
1069 Sets the value in the compiled QTCM model as well as at the
1070 Python level. If no value given, the default value is used.
1071 When the compiled model variable is set, a copy of the
1072 Python value input via the parameter list is passed to the
1073 Fortran model, not a reference.
1074
1075 If this method is called with a single positional input
1076 argument, and that argument is a string, the compiled QTCM
1077 model variable is set to the default value of the Python
1078 counterpart of that same name. If the single positional
1079 argument is a Field variable, the compiled QTCM model
1080 variable is set to that Field variable (the id and value
1081 attributes of the Field variable thus corresponding to the
1082 name and value of the compiled QTCM variable, respectively).
1083
1084 Positional Input Parameters (for 1 argument):
1085 * Name of QTCM variable (scalar string) or a Field variable.
1086
1087 Positional Input Parameters (for 2 arguments):
1088 * key: Name of QTCM variable. String. Scalar.
1089 * value_in: Value of variable or a Field object. Scalar
1090 or numeric array. If you want to set an array to a single
1091 quantity, value can be a scalar. Type of value must be
1092 the same as the type of Field(key), which is the same as
1093 in the compiled QTCM model; the routine doesn't check for
1094 this, however, as the compiled will return a fatal error
1095 if this mismatch happens.
1096
1097 Some compiled QTCM model variables are not ready to be set.
1098 An example is a compiled QTCM model pointer variable prior
1099 to the pointer being associated with a target (this would
1100 result in a bus error). In such cases, this method will
1101 throw a FieldNotReadableFromCompiledModel exception, nothing
1102 will be set in the compiled QTCM model, and the Python
1103 counterpart variable (if it previously existed) would be
1104 left unchanged. Otherwise, both the compiled QTCM model
1105 variable and its Python attribute counterpart are set by
1106 the method to the same value, overwriting any previous
1107 values held by either.
1108 """
1109
1110
1111
1112
1113 if len(args) == 1:
1114 if type(args[0]) == type(_test_field):
1115 key = args[0].id
1116 value_in = args[0].value
1117 else:
1118 key = args[0]
1119 value_in = Field(key).value
1120 elif len(args) == 2:
1121 key = args[0]
1122 value_in = args[1]
1123 if type(value_in) == type(_test_field):
1124 if key != value_in.id:
1125 raise ValueError, 'inconsistent input args.'
1126 value_in = args[1].value
1127 else:
1128 raise ValueError, 'set_qtcm_item uses only 1 or 2 args'
1129
1130
1131
1132
1133
1134
1135 value = copy.copy(value_in)
1136 value_rank = N.rank(value)
1137 if value_rank == 0:
1138 value_dtype = type(value)
1139 else:
1140 value_dtype = num.typecode(value)
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165 field_rank = Field(key).rank()
1166
1167
1168
1169
1170
1171 if field_rank == 0:
1172 try:
1173 tmp = self.get_qtcm_item(key)
1174 self._set_qtcm_scalar_item_in_model(key, value)
1175 setattr( self, key, Field(key, value) )
1176 except FieldNotReadableFromCompiledModel:
1177 raise FieldNotReadableFromCompiledModel, \
1178 'Compiled model variable not writeable'
1179 except:
1180 print "Unexpected error:", sys.exc_info()[0]
1181 raise
1182
1183
1184
1185
1186
1187
1188 else:
1189 try:
1190 ashape = self._set_qtcm_array_item_in_model(key, value)
1191 if value_rank == 0:
1192 valarr = N.empty(ashape, dtype=value_dtype)
1193 valarr.fill(value)
1194 else:
1195 valarr = value
1196 setattr( self, key, Field(key, valarr) )
1197 except FieldNotReadableFromCompiledModel:
1198 raise FieldNotReadableFromCompiledModel, \
1199 'Compiled model variable not writeable'
1200 except:
1201 print "Unexpected error:", sys.exc_info()[0]
1202 raise
1203
1204
1205
1206
1207
1208
1210 """Set Python-accessible compiled QTCM model fields.
1211
1212 Identical to set_qtcm_item. See set_qtcm_item description.
1213 """
1214 return self.set_qtcm_item(*args, **kwds)
1215
1216
1217
1218
1219
1220
1222 """Set Python attributes to snapshot values.
1223
1224 The snapshot is copies of the variables of the current state
1225 of the run session that would be used for a restart. This
1226 method sets the Python attributes corresponding to the
1227 snapshot variables to the snapshot values. It does not set
1228 anything on the compiled QTCM model side.
1229
1230 Keyword Input Parameter:
1231 * snapshot: The snapshot (a dictionary, following the rules
1232 of method make_snapshot) that is the source of the value
1233 for the syncronization. If set to None, the instance
1234 attribute snapshot is used. Default is None.
1235 """
1236 if snapshot == None:
1237 for ikey in self.snapshot.keys():
1238 setattr(self, ikey, self.snapshot[ikey])
1239 else:
1240 for ikey in snapshot.keys():
1241 setattr(self, ikey, snapshot[ikey])
1242
1243
1244
1245
1246
1247
1249 """Set QTCM items in compiled model to all Python-level values.
1250
1251 Synchronize so that any Python attribute that corresponds
1252 to a compiled model Python-changable variable is set, on
1253 both the Python attribute side and the compiled model side,
1254 to the value of the Python attribute. Note this method
1255 only sets attributes that are already defined in the object;
1256 it does not create new attributes. If a compiled QTCM model
1257 variable is not ready to be set (e.g., a pointer variable
1258 is not yet associated, that variable is not set in the
1259 compiled QTCM model, and its Python counterpart is left
1260 unchanged.
1261 """
1262 for ikey in self._qtcm_fields_ids:
1263 if hasattr(self, ikey):
1264 try:
1265 self.set_qtcm_item(getattr(self, ikey))
1266 except FieldNotReadableFromCompiledModel:
1267 pass
1268 except:
1269 print "Unexpected error:", sys.exc_info()[0]
1270 raise
1271
1272
1273
1274
1275
1276
1278 """Set all Python-level attributes to QTCM compiled model values.
1279
1280 Synchoronize so that any Python attribute that corresponds
1281 to a compiled model Python-changable variable is set to the
1282 value of the QTCM compiled variable. Note this method goes
1283 through all items listed in self._qtcm_fields_ids and sets
1284 those values as object attributes.
1285
1286 If a compiled QTCM model variable is not ready to be read
1287 (e.g., a pointer variable is not yet associated, a
1288 FieldNotReadableFromCompiledModel exception is raised,
1289 because for the situations where this method is called
1290 (usually after the model has run for some time), that
1291 situation should not occur.
1292 """
1293 for ikey in self._qtcm_fields_ids:
1294 try:
1295 setattr( self, ikey, Field(ikey, self.get_qtcm_item(ikey)) )
1296 except FieldNotReadableFromCompiledModel:
1297 raise FieldNotReadableFromCompiledModel, \
1298 'Compiled model variable not readable'
1299 except:
1300 print "Unexpected error:", sys.exc_info()[0]
1301 raise
1302
1303
1304
1305
1306
1307
1309 """First method executed at the atmosphere-coupling timestep.
1310
1311 This is a private method. If you wish to add more computations
1312 at the beginning of the atmosphere-ocean coupling timestep,
1313 overload more_first_method_at_atm_oc_step.
1314 """
1315 self.interval.value = self.get_qtcm_item('interval')
1316 self.more_first_method_at_atm_oc_step()
1317
1318
1319
1320
1321
1322
1324 """More of first method executed at the atmo.-coupling timestep.
1325
1326 This gives an easy way to change the model at the
1327 atmosphere-coupling timestep, after the update of the interval
1328 attribute: Just overload this method.
1329 """
1330 pass
1331
1332
1333
1334
1335
1336
1338 """Calculate the atmos. barotropic mode at atmos. timestep.
1339
1340 The calculation is made at self.it timestep for the atmosphere,
1341 which is the time of day in terms of atmospheric timesteps.
1342 It assumes that the compiled_form is 'parts'.
1343 """
1344 if N.mod(self.it.value, self.mt0.value) == 0:
1345 self.run_list(['atm_bartr_mode',])
1346
1347
1348
1349
1350
1351
1353 """Initialize model variables in a run session.
1354
1355 Method duplicates the functionality of the Fortran QTCM1
1356 subroutine varinit, but with changes that will enable us
1357 to handle restarts at the Python-level in a dynamic way.
1358 This method only works with compiled_form set to 'parts'.
1359
1360 If init_with_instance_state is False, this method just
1361 executes the compiled Fortran QTCM model varinit subroutine,
1362 and thus run_session initialization follows the rules set
1363 by all the standard QTCM model input parameters (e.g., the
1364 sign of day0, month0, and year0, the value of the mrestart
1365 flag, etc.). If init_with_instance_state is True, variable
1366 initialization uses the algorithm described below.
1367
1368 First, all prognostic pointer variables are associated.
1369 Next, initialization of prognostic variables and right-hand
1370 sides to default values (which for most of the variables
1371 is 0) occur for the cases where the corresponding Python
1372 attribute is not defined. If the corresponding Python
1373 attribute is defined, the compiled QTCM model variable is
1374 set to the value that the attribute already has (the mrestart
1375 flag, given as the instance attribute mrestart, is ignored).
1376 The exception is day0, month0, and year0, which are overwritten
1377 with values derived from dateofmodel to set the run to start
1378 the day after dateofmodel. If dateofmodel is less than or
1379 equal to 0, day0, month0, and year0 are set to their
1380 respective instance values, if valid (for invalid values,
1381 day0, month0, and year0 are all set to 1).
1382
1383 Note for init_with_instance_state True or False, at the end
1384 of this method, day0, month0, and year0, may all be changed,
1385 and dateofmodel may be inconsistent with will be updated
1386 to match the values of day0, month0, and year0.
1387 """
1388
1389
1390
1391
1392
1393
1394
1395 init_dict = copy.copy(_init_prog_dict)
1396
1397
1398
1399
1400
1401
1402
1403
1404 if not self.init_with_instance_state:
1405 self.run_list(['__qtcm.wrapcall.wvarinit',])
1406
1407 update_list = init_dict.keys() + ['day0', 'month0', 'year0']
1408 for ikey in update_list:
1409 setattr(self, ikey, Field(ikey, self.get_qtcm_item(ikey)) )
1410
1411 self.dateofmodel.value = self.year0.value*10000 \
1412 + self.month0.value*100 \
1413 + self.day0.value
1414 self.set_qtcm_item(self.dateofmodel)
1415
1416
1417
1418
1419 else:
1420
1421
1422 if not self._cont:
1423 self.run_list(['__qtcm.varptrinit',])
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433 tmpstype = self.get_qtcm_item('STYPE')
1434 tmpwd0 = self.get_qtcm_item('WD0')
1435 tmpwd = N.choose(tmpstype.astype(int), tmpwd0) * 0.7
1436 init_dict['WD'] = tmpwd
1437
1438
1439
1440
1441
1442 for ikey in init_dict.keys():
1443 if not hasattr(self, ikey):
1444 self.set_qtcm_item(ikey, init_dict[ikey])
1445 else:
1446 self.set_qtcm_item(getattr(self, ikey))
1447
1448
1449
1450
1451
1452
1453
1454
1455 yearr = self.dateofmodel.value / 10000
1456 monthr = N.mod(self.dateofmodel.value, 10000) / 100
1457 dayr = N.mod(self.dateofmodel.value, 100) + 1
1458
1459 if self._monlen[monthr-1] < dayr:
1460 dayr = 1
1461 monthr = monthr + 1
1462 if monthr > 12:
1463 monthr = 1
1464 yearr = yearr + 1
1465
1466
1467
1468
1469
1470
1471
1472
1473 if self.dateofmodel.value > 0:
1474 self.year0.value = yearr
1475 self.month0.value = monthr
1476 self.day0.value = dayr
1477 else:
1478 if (self.day0.value < 1) or (self.day0.value > 31):
1479 self.day0.value = 1
1480 if (self.month0.value < 1) or (self.month0.value > 12):
1481 self.month0.value = 1
1482 if self.year0.value < 1:
1483 self.year0.value = 1
1484
1485
1486
1487
1488 self.dateofmodel.value = self.year0.value*10000 \
1489 + self.month0.value*100 \
1490 + self.day0.value
1491
1492
1493
1494
1495
1496 update_list = ['day0', 'month0', 'year0', 'dateofmodel']
1497 for ikey in update_list:
1498 self.set_qtcm_item(getattr(self, ikey))
1499
1500
1501
1502
1503
1504
1506 """Run parts model starting at the atmos.-oc. coupling level.
1507
1508 This method duplicates the functionality of the driver
1509 subroutine in the original compiled QTCM model. It assumes
1510 all fields that can be synchronized between the Python and
1511 compiled QTCM model levels have been so before the calling
1512 of this method. It is meant to be called once in a run
1513 session, and assumes that the compiled_form is 'parts'.
1514 """
1515
1516
1517
1518
1519
1520
1521 interval = self.interval.value
1522 lastday = self.lastday.value
1523 if not self._cont:
1524 self.run_list(self.runlists['init_model'])
1525 else:
1526 self.run_list(['varinit',])
1527
1528
1529
1530
1531
1532
1533
1534
1535 startday = 1
1536 endday = lastday+interval
1537
1538 for self.coupling_day.value in xrange(startday, endday, interval):
1539 self.run_list(self.runlists['atm_oc_step'])
1540 print 'Driver: Running for %i days at model date %i ' \
1541 % (self.coupling_day.value, self.get_qtcm_item('dateofmodel'))
1542
1543
1544
1545
1546 self.run_list(['__qtcm.wrapcall.woutrestart',])
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560 if self._cont:
1561 testoutdir = self.get_qtcm_item('outdir')
1562 if self.outdir.value != testoutdir:
1563 raise ValueError, 'bad outdir value for contiguous run'
1564
1565 path = self.outdir.value
1566 suffix = self.runname.value
1567 fn_inst = os.path.join( path, "qi_" + suffix + ".nc" )
1568 fn_mean = os.path.join( path, "qm_" + suffix + ".nc" )
1569
1570 for ifn in [fn_inst, fn_mean]:
1571 fileobj = S.NetCDFFile(ifn, mode='r+')
1572 oldvalue = fileobj.variables['time'].getValue()
1573 varshape = N.shape(oldvalue)
1574 if len(varshape) != 1: raise ValueError, 'bad time shape'
1575 if oldvalue[0] != 0:
1576 if N.squeeze(oldvalue[0]) != 0:
1577 raise ValueError, 'bad time first value'
1578 newvalue = N.arange(varshape[0], dtype=num.typecode(oldvalue))
1579 fileobj.variables['time'].assignValue(newvalue)
1580 fileobj.close()
1581
1582
1583
1584
1585
1586
1588 """Set all scalar QTCM fields to their default values.
1589
1590 Sets the values in the compiled QTCM model as well as at
1591 the Python level to their default values. Scalar values
1592 are defined as those with rank 0.
1593 """
1594 for ikey in self._qtcm_fields_ids:
1595 if N.rank(Field(ikey).value) == 0:
1596 self.set_qtcm_item(ikey)
1597
1598
1599
1600
1601
1602
1604 """Set compiled QTCM attribute in Qtcm instance.
1605
1606 This method makes a copy of the needed compiled shared
1607 object file in a unique hidden subdirectory of the current
1608 working directory, imports that .so file, and sets that
1609 imported shared object library to the compiled QTCM attribute
1610 self.__qtcm.
1611 """
1612
1613
1614
1615
1616
1617 self.sodir = tempfile.mkdtemp(prefix='qtcm_sodir_')
1618
1619
1620
1621
1622
1623 if self.compiled_form == 'full':
1624 soname = '_qtcm_full_365'
1625 elif self.compiled_form == 'parts':
1626 soname = '_qtcm_parts_365'
1627 else:
1628 raise ValueError, 'Compiled form not recognized'
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643 origsofile = \
1644 os.path.join( os.path.split(_package_version.__file__)[0] \
1645 , soname + '.so' )
1646 shutil.copy2(origsofile, self.sodir)
1647 sys.path.insert(0, self.sodir)
1648 self.__qtcm = __import__(soname)
1649 sys.path.remove(self.sodir)
1650 del sys.modules[soname]
1651
1652 if os.path.split(self.__qtcm.__file__)[0] != self.sodir:
1653 raise ValueError, 'Incorrect import of .so library'
1654
1655
1656
1657
1658
1659
1661 """Set Python-accessible QTCM array settings in compiled model.
1662
1663 Sets the value of arrays in the compiled QTCM model only.
1664 Custom exception FieldNotReadableFromCompiledModel is raised
1665 if the compiled QTCM model variable is not readable/writable.
1666
1667 Positional Input Parameters:
1668 * key: Name of QTCM variable. String. Scalar.
1669
1670 * value: Value of variable. Must be numeric scalar or
1671 real numeric array. If a scalar, all values in the array
1672 named key are set to that scalar value. If value cannot
1673 be mapped onto the compiled QTCM model array successfully,
1674 you'll receive a bus error or other unexpected error.
1675
1676 Output:
1677 * Sets value into the compiled QTCM model array variable,
1678 and also returns the shape of the array that was set.
1679 """
1680
1681
1682 default_type = Field(key).typecode()
1683 value_type = num.typecode(value)
1684 field_rank = Field(key).rank()
1685
1686
1687
1688
1689
1690 if (value_type in N.typecodes['Float']) and \
1691 (default_type not in N.typecodes['Float']):
1692 raise TypeError, 'value type different from default for key'
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702 if value_type in N.typecodes['Float']:
1703 if field_rank == 1:
1704 self.__qtcm.setbypy.getitem_real_array(key)
1705 if not self.__qtcm.setbypy.is_readable:
1706 self.__qtcm.setbypy.real_rank1_array = None
1707 raise FieldNotReadableFromCompiledModel, \
1708 'Compiled model variable not readable'
1709 else:
1710 if N.rank(value) == 0:
1711 ashape = N.shape(self.__qtcm.setbypy.real_rank1_array)
1712 tmpa = N.zeros(ashape, float)
1713 tmpa.fill(value)
1714 self.__qtcm.setbypy.real_rank1_array = tmpa
1715 else:
1716 ashape = N.shape(value)
1717 self.__qtcm.setbypy.real_rank1_array = value
1718 self.__qtcm.setbypy.setitem_real_array(key)
1719 self.__qtcm.setbypy.real_rank1_array = None
1720
1721 elif field_rank == 2:
1722 self.__qtcm.setbypy.getitem_real_array(key)
1723 if not self.__qtcm.setbypy.is_readable:
1724 self.__qtcm.setbypy.real_rank2_array = None
1725 raise FieldNotReadableFromCompiledModel, \
1726 'Compiled model variable not readable'
1727 else:
1728 if N.rank(value) == 0:
1729 ashape = N.shape(self.__qtcm.setbypy.real_rank2_array)
1730 tmpa = N.zeros(ashape, float)
1731 tmpa.fill(value)
1732 self.__qtcm.setbypy.real_rank2_array = tmpa
1733 else:
1734 ashape = N.shape(value)
1735 self.__qtcm.setbypy.real_rank2_array = value
1736 self.__qtcm.setbypy.setitem_real_array(key)
1737 self.__qtcm.setbypy.real_rank2_array = None
1738
1739 elif field_rank == 3:
1740 self.__qtcm.setbypy.getitem_real_array(key)
1741 if not self.__qtcm.setbypy.is_readable:
1742 self.__qtcm.setbypy.real_rank3_array = None
1743 raise FieldNotReadableFromCompiledModel, \
1744 'Compiled model variable not readable'
1745 else:
1746 if N.rank(value) == 0:
1747 ashape = N.shape(self.__qtcm.setbypy.real_rank3_array)
1748 tmpa = N.zeros(ashape, float)
1749 tmpa.fill(value)
1750 self.__qtcm.setbypy.real_rank3_array = tmpa
1751 else:
1752 ashape = N.shape(value)
1753 self.__qtcm.setbypy.real_rank3_array = value
1754 self.__qtcm.setbypy.setitem_real_array(key)
1755 self.__qtcm.setbypy.real_rank3_array = None
1756
1757 else:
1758 raise ValueError, 'bad rank value'
1759
1760 elif value_type in N.typecodes['Integer']:
1761 raise TypeError, 'array type not yet supported'
1762
1763 elif value_type in num.typecodes['Character']:
1764 raise TypeError, 'array type not yet supported'
1765
1766 else:
1767 raise TypeError, 'value is of unsupported type'
1768
1769
1770
1771
1772 return ashape
1773
1774
1775
1776
1777
1778
1780 """Set Python scalar variable in the compiled QTCM model.
1781
1782 Sets value of Python scalar variable key in the compiled
1783 QTCM model. Nothing else is done (e.g., nothing is set on
1784 the Python side). Exception FieldNotReadableFromCompiledModel
1785 is raised if the compiled QTCM model variable is not
1786 readable/writable.
1787
1788 Positional Input Parameters:
1789 * key: Name of QTCM variable. String. Scalar.
1790 * value: Value of variable. String or numeric value. Must be
1791 a scalar.
1792 """
1793 default_type = Field(key).typecode()
1794 value_type = num.typecode(value)
1795
1796 if value_type in N.typecodes['Float']:
1797 if default_type not in N.typecodes['Float']:
1798 raise TypeError, 'value type different from default for key'
1799 tmp = copy.copy(self.__qtcm.setbypy.getitem_real(key))
1800 if not self.__qtcm.setbypy.is_readable:
1801 raise FieldNotReadableFromCompiledModel, \
1802 'Compiled model variable not readable'
1803 self.__qtcm.setbypy.setitem_real(key, value)
1804
1805 elif value_type in N.typecodes['Integer']:
1806 if default_type not in N.typecodes['Integer']:
1807 raise TypeError, 'value type different from default for key'
1808 tmp = copy.copy(self.__qtcm.setbypy.getitem_int(key))
1809 if not self.__qtcm.setbypy.is_readable:
1810 raise FieldNotReadableFromCompiledModel, \
1811 'Compiled model variable not readable'
1812 self.__qtcm.setbypy.setitem_int(key, value)
1813
1814 elif value_type in num.typecodes['Character']:
1815 if default_type not in num.typecodes['Character']:
1816 raise TypeError, 'value type different from default for key'
1817 tmp = self.__qtcm.setbypy.getitem_str(key)
1818 if not self.__qtcm.setbypy.is_readable:
1819 raise FieldNotReadableFromCompiledModel, \
1820 'Compiled model variable not readable'
1821 self.__qtcm.setbypy.setitem_str(key, value)
1822
1823 else:
1824 raise TypeError, 'value is of unsupported type'
1825
1826
1827
1828
1829
1830
1831
1832
1833 if __name__ == "__main__":
1834 """Test the module.
1835
1836 Note: To help ensure that module testing of this file works, the
1837 parent directory to the current directory is added to sys.path.
1838 """
1839 import doctest, sys, os
1840 sys.path.append(os.pardir)
1841 doctest.testmod(sys.modules[__name__])
1842
1843
1844
1845
1846
1847