HWRF  trunk@4391
regrib.py
1 """!Describes regribbing operations using an algebraic structure.
2 
3 This module provides an object-oriented interface to the low-level
4 GRIB manipulation routines in produtil.gribop. It also sits on top of
5 the produtil.datastore module, providing a means to grab GRIB files
6 from Task and Product objects, processing them upon availability."""
7 
8 import os,stat,errno,os.path,copy,threading, collections, logging
10 
11 from hwrf.exceptions import RegribError,GRIBInputError,Subsetless,\
12  InvalidRegribResult,RegribProductError,NoProductError, \
13  ProductAmbiguityError,RegribManyError, \
14  RegribKeyError,RegribGridError,GridlessError,GridMismatchError,\
15  NoIndexError
16 
17 from produtil.run import exe,alias,run,runstr,runsync
18 from produtil.datastore import UpstreamFile,FileProduct
19 
20 ##@var __all__
21 # List of symbols to export by "from hwrf.regrib import *"
22 __all__=['GRIBOp','GRIB2Op','GRIB1Op','GRIBGrid','GRIBSubsetter',
23  'GRIB1Merge','Regrib','GRIB1','GRIB2','GRIB1File',
24  'GRIB2File','UpstreamGRIB1','GRIB2Product','quarterDegree']
25 
26 ##@var GRIB1
27 # Constant used to represent a request to convert GRIB files to GRIB version 1.
28 GRIB1=1
29 
30 ##@var GRIB2
31 # Constant used to represent a request to convert GRIB files to GRIB version 2.
32 GRIB2=2
33 
34 ########################################################################
35 
36 class RegribBase(object):
37  """!This is the abstract base class of Regrib and RegribMany and
38  should not be instantiated directly. It exists only to reduce
39  code duplication."""
40  def __init__(self,logger=None,prodargs=None,prodkwargs=None,_base=None,
41  cnvgrib_g12=None,cnvgrib_g21=None,wgrib=None,copygb=None):
42  """!Creates a RegribBase.
43 
44  @param _base Do not use. The _base should be another
45  RegribBase to copy. If this is specified, all other
46  arguments are ignored, and the _base is copied. This is
47  the implementation of self.copy()
48 
49  @param logger the logging.Logger that should be used when regribbing
50  @param prodargs a list of additional arguments to send to "products"
51  iterators.
52  @param prodkwargs a dict of additional keyword arguments to send to
53  "products" iterators.
54 
55  @param cnvgrib_g12 The "cnvgrib -p32 -g12" program (a
56  produtil.prog.ImmutableRunner) to convert from GRIB1 to GRIB2.
57  (Other compression types besides -p32 are okay.)
58  @param cnvgrib_g21 The "cnvgrib -g21" program (a
59  produtil.prog.ImmutableRunner) to convert from GRIB2 to GRIB1
60  @param wgrib the wgrib program, with no arguments,
61  a produtil.prog.ImmutableRunner
62  @param copygb the copygb program, with no arguments,
63  a produtil.prog.ImmutableRunner"""
64  super(RegribBase,self).__init__()
65  if _base is not None:
66  self._copygb=_base.copygb
67  self._wgrib=_base.wgrib
68  self._cnvgrib_g12=_base.cnvgrib_g12
69  self._cnvgrib_g21=_base.cnvgrib_g21
70  self._logger=_base.logger
71  self._prodargs=list(_base._prodargs)
72  self._prodkwargs=dict(_base._prodkwargs)
73  self._sync_frequently=bool(_base._sync_frequently)
74  else:
75  assert(copygb is not None)
76  if copygb is None: copygb=alias(exe('copygb'))
77  if wgrib is None: wgrib=alias(exe('wgrib'))
78  if cnvgrib_g12 is None: cnvgrib_g12=alias(exe('cnvgrib')['-g12','-p32'])
79  if cnvgrib_g21 is None: cnvgrib_g21=alias(exe('cnvgrib')['-g21'])
80 
81  self._copygb=copygb
82  self._cnvgrib_g12=cnvgrib_g12
83  self._cnvgrib_g21=cnvgrib_g21
84  self._wgrib=wgrib
85  self._sync_frequently=False
86 
87  if prodargs is None:
88  self._prodargs=[]
89  else:
90  self._prodargs=list(prodargs)
91  if prodkwargs is None:
92  self._prodkwargs={}
93  else:
94  self._prodkwargs=dict(prodkwargs)
95  self._logger=logger
96 
97  def getcopygb(self):
98  """!Returns the copygb ImmutableRunner"""
99  return self._copygb
100  def getcnvgrib_g12(self):
101  """!Returns the cnvgrib -p32 -g12 command, which should be an
102  ImmutableRunner"""
103  return self._cnvgrib_g12
104  def getcnvgrib_g21(self):
105  """!Returns the cnvgrib -g21 command, which should be an
106  ImmutableRunner."""
107  return self._cnvgrib_g21
108  def getwgrib(self):
109  """!Returns the wgrib command, which should be an
110  ImmutableRunner."""
111  return self._wgrib
112  def getlog(self):
113  """!Returns the logger.Logging object to use for logging
114  messages, or None if no logger was provided to the
115  constructor."""
116  return self._logger
117  def setlog(self,val):
118  """!Sets the logger.Logging object to use for logging
119  messages.
120  @param val the new logger"""
121  self._logger=val
122  return self._logger
123  def getprodargs(self):
124  """!Returns the array of arguments to send to the products
125  iterators."""
126  return self._prodargs
127  def getprodkwargs(self):
128  """!Returns a dict of keyword arguments to send to the products
129  iterators."""
130  return self._prodkwargs
131 
132  def setsync_frequently(self,flag):
133  """!Sets the sync_frequently flag.
134  @param flag if True, the sync program is called frequently"""
135  self._sync_frequently=bool(flag)
137  """!Returns the value of the sync_frequently flag.
138  @returns True if sync is to be called frequently, and False
139  otherwise"""
140  return self._sync_frequently
141 
142  ##@property sync_frequently
143  # Boolean flag: should we call sync frequently?
144  sync_frequently=property(getsync_frequently,setsync_frequently,None,
145  """Boolean flag: should we call sync frequently?""")
146 
147  ##@property logger
148  # A logging.Logger for log messages.
149  logger=property(getlog,setlog,None,
150  """Either None or the logging.Logger object for this Regrib.""")
151 
152  ##@var prodargs
153  # A list of additional positional arguments to send to Task.products.
154  prodargs=property(getprodargs,None,None,
155  """A list of additional positional arguments to send to Task.products.""")
156 
157  ##@var prodkwargs
158  # A dict of additional keyword arguments to send to Task.products.
159  prodkwargs=property(getprodkwargs,None,None,
160  """A dict of additional keyword arguments to send to Task.products.""")
161 
162  ##@var wgrib
163  # A produtil.prog.ImmutableRunner for running wgrib, or None if unavailable.
164  wgrib=property(getwgrib,None,None,
165  """Returns None or a wgrib object suitable for produtil.run.run""")
166 
167  ##@var copygb
168  # A produtil.prog.ImmutableRunner for running copygb, or None if unavailable.
169  copygb=property(getcopygb,None,None,
170  """Returns None or a copygb object suitable for produtil.run.run""")
171 
172  ##@var cnvgrib_g21
173  # A produtil.prog.ImmutableRunner for running cnvgrib to convert
174  # from GRIB2 to GRIB1, or None if unavailable.
175  cnvgrib_g21=property(getcnvgrib_g21,None,None,
176  """Returns None or a cnvgrib -g21 object suitable for produtil.run.run""")
177 
178  ##@var cnvgrib_g12
179  # A produtil.prog.ImmutableRunner for running cnvgrib to convert
180  # from GRIB1 to GRIB2, or None if unavailable.
181  cnvgrib_g12=property(getcnvgrib_g12,None,None,
182  """Returns None or a cnvgrib -g12 object suitable for produtil.run.run""")
183 
184 ########################################################################
185 
187  """!This is a helper class intended to be used internally by
188  RegribMany. It performs a small number of GRIB manipulations
189  intended to produce the result of a single GRIB expression."""
190  def __init__(self,result,op,workprefix=None,**kwargs):
191  """!Creates a Regrib object whose result has the given name (in
192  "result") and produces the output of the specified operation
193  "op", prepending the given prefix "workprefix" to temporary
194  and output filenames.
195  @param result the name of this operation result, for
196  referencing it again in a RegribMany object after the
197  operation is complete.
198  @param op the operation to perform
199  @param workprefix
200  @param kwargs Additional keyword arguments are sent to
201  RegribBase.__init__()"""
202  super(Regrib,self).__init__(**kwargs)
203  (self._result,self._op,self._step,self._workprefix)=(result,op,0,None)
204  self.set_workprefix(workprefix)
205 
206  def set_workprefix(self,workprefix=None):
207  """!Sets the work directory and filename prefix to the given
208  value, or sets it to a reasonable default if workprefix is
209  None or missing. The work prefix is not necessarily a
210  directory: it can include additional text to prepend to the
211  filename.
212 
213  @param workprefix The new work directory and filename
214  prefix."""
215  if workprefix is None:
216  self._workprefix=os.path.join('./',os.path.basename(result)+'.step')
217  else:
218  self._workprefix=workprefix
219  def reset(self,result,op,workprefix=None):
220  """!Discards all temporary data, and re-initializes this object
221  for the specified result name, operator and workprefix. This
222  is used by RegribMany to re-use a single Regrib object over
223  and over.
224 
225  @param result the new result object to return, if queried
226  @param op the new operation to return if queried
227  @param workprefix the new work directory and filename prefix"""
228  self.set_workprefix(workprefix)
229  self._result=result
230  self._op=op
231  self._step=0
232  def getop(self):
233  """!Returns the GRIBBase object that performs this Regrib's work."""
234  return self._op
235 
236  ##@var op
237  # The GRIBBase object that performs this Regrib's work
238  op=property(getop,None,None,
239  """Returns the GRIBBase object that performs this Regrib's work""")
240  def is_ready(self,**kwargs):
241  """!Returns True if this Regrib object's operator is "ready"
242  (according to is_ready) and False otherwise.
243 
244  @param kwargs Additional keyword arguments passed to GRIBBase.is_ready(), called on self.op.
245  @returns The result of GRIBBase.is_ready(), called on self.op"""
246  return self.op.is_ready(self,**kwargs)
247  def input_valid(self,**kwargs):
248  """!Returns True if the specified kwargs are valid for this
249  Regrib object's operator and False otherwise.
250 
251  @param kwargs Additional keyword arguments passed to GRIBBase.input_valid() called on self.op
252  @returns the result of GRIBBase.is_ready(), called on self.op"""
253  return self.op.input_valid(self,**kwargs)
254  def make(self,**kwargs):
255  """!Runs this Regrib object's operator's make function with the
256  given keyword arguments, returning the results.
257 
258  @param kwargs Additional keyword arguments passed to GRIBBase.make() called on self.op
259  @returns the result of GRIBBase.is_ready(), called on self.op"""
260  result=self.op.make(self,**kwargs)
261  assert(result is not None)
262  if not (isinstance(result,GRIBBase) or isinstance(result,GRIBGrid)):
263  logging.critical(
264  'Invalid result for type=%s repr=%s which came from running '
265  'self.op.make(**kwargs) on an op=%s and kwargs=%s'%
266  (type(result).__name__,repr(result),repr(self.op),
267  repr(kwargs)))
268  return result
269  def indextemp(self,grib):
270  """!Generates a temporary filename to use for the specified
271  GRIB1/2 file's index file.
272 
273  @param grib the grib filename
274  @returns the suggested filename for the wgrib -s output"""
275  if not isinstance(grib,basestring):
276  raise TypeError('Regrib.indextemp requires a string argument, not %s'
277  %(type(grib).__name__))
278  if(grib.startswith(self._workprefix)):
279  return grib+'.wgrib_s'
280  else:
281  self._step+=1
282  out="%s%02d.%s"%(self._workprefix,self._step,
283  os.path.basename(grib))
284  return out
285  def gribtemp(self,what=None):
286  """!Returns a tuple (grib,index) containing a suggested GRIB1/2
287  filename and index filename.
288 
289  @param what The optional argument "what" must contain no shell
290  metacharacters and is incorporated into the file name."""
291  self._step+=1
292  if what is None:
293  what='tmp'
294  out="%s%02d.%s"%(self._workprefix,self._step,str(what))
295  return (out,out+'.wgrib_s')
296  def tempfile(self,what=None):
297  """!Creates a name of a temporary file.
298 
299  @param what The "what" argument is a terse explanation of the
300  purpose of the file (such as "merge" or "to-grib2") to include
301  in the filename.
302  @returns The suggested filename."""
303  self._step+=1
304  if what is None:
305  what='tmp'
306  out="%s%02d.%s"%(self._workprefix,self._step,str(what))
307  return out
308 
309 ########################################################################
310 
312  """!Runs regrib operations on many input times, sending output to
313  an hwrf.gribtask.GRIBTask.
314 
315  This class keeps track of a set of named regribbing operations
316  and target grids. Each operation may connect to another by name,
317  allowing the output of one operation to be the input to one or
318  more other operations. The RegribMany.make can then produce the
319  output of an operation, on the condition that its inputs from
320  earlier operations are ready.
321 
322  The RegribMany is not intended to be used alone. Instead, the
323  GRIBTask class in hwrf.gribtask should be used to execute
324  RegribMany tasks. You can run multiple GRIBTasks at the same
325  time, on the same RegribMany outputs, and the GRIBTasks will
326  automatically work together via file locking and a database to
327  produce the outputs in parallel, as fast as possible.
328 
329  Here is a simple example of the use of a RegribMany object:
330 
331  @code
332  # This code assumes a PostManyWRF object is available as "mypost",
333  # and HWRFConfig as "conf", and two WRFDomain are available as
334  # "d01" and "d02". We also assume the post has already been run.
335 
336  r = RegribMany()
337  getd01 = igrb1(mypost,domain=d01)
338  getd02 = igrb1(mypost,domain=d02)
339  r.add('cgrid',clatlon(getd02,res=[0.05,0.05],size=[30.,30.],
340  scan=136,n=[600,600]))
341  r.add('cGRIB1',getd01*r.grid('cgrid')+getd02*r.grid('cgrid'))
342  r.add('cGRIB2',r.GRIB('cGRIB1') * GRIB2)
343  r.to_intercom('output_f{fahr:03d}.grib2','cGRIB2')
344  gribber = GribTask(conf.datastore,conf,'mygrib',r,conf.cycle,
345  126*3600, 6*3600)
346  gribber.run()
347  @endcode
348 
349  Now lets step through that and explain what it does.
350 
351  @code
352  r = RegribMany() - creates a RegribMany.
353  @endcode
354 
355  First, we create the RegribMany object. We're actually doing this
356  in a sloppy way: it will search the $PATH for cnvgrib, wgrib, and
357  other programs. It is better to specify the exact location. That
358  can be done by passing arguments to the RegribMany constructor.
359  See the RegribBase instructor for a list.
360 
361  @code
362  getd01 = igrb1(mypost,domain=d01)
363  getd02 = igrb1(mypost,domain=d02)
364  @endcode
365 
366  This creates a pair of GRIB1Selectors, operations recognized by
367  RegribMany. A GRIB1Selector takes a Task, in this case mypost,
368  and calls its "products" function to get a Product as input to the
369  next step in a regribbing operation. The domain=d01 is passed
370  into products, as is the time=X for each time X the RegribMany
371  processes.
372 
373  @code
374  r.add('cgrid',clatlon(getd02,res=[0.05,0.05],size=[30.,30.],
375  scan=136,n=[600,600]))
376  @endcode
377 
378  This instructs the RegribMany to add an operation to its
379  dictionary. The operation is called "cgrid", and consists of a
380  GRIBGridCompute created by the clatlon function, defined later in
381  this module. The clatlon takes our getd02, and creates a 30x30
382  degree, 600x600 gridpoint, 0.05 degree grid, centered on that
383  domain at each time. If domain d02 moves, this clatlon output
384  will be a moving domain.
385 
386 
387  @code
388  r.add('cGRIB1',getd01*r.grid('cgrid')+getd02*r.grid('cgrid'))
389  @endcode
390 
391  This adds another operation to the RegribMany's dictionary, this
392  time a grib output operation called cGRIB1. The r.grid('cgrid')
393  looks up the cgrid operation we just inserted, connecting that to
394  the cGRIB1. Recall that getd01 and getd02 are also operations,
395  and produce a GRIB1 file. When we multiply that by a grid, it
396  creates a new operation that will use copygb to output a new GRIB1
397  file on that grid. Hence, we have created two temporary files:
398 
399  @code
400  getd01*r.grid('cgrid') = domain 1's post output on the cgrid
401  getd02*r.grid('cgrid') = domain 2's post output on the cgrid
402  @endcode
403 
404  When we add those two together, it pastes the second one on top of
405  the first via a copygb merge operation. That result is then
406  stored as cGRIB1.
407 
408  @code
409  r.add('cGRIB2',r.GRIB('cGRIB1') * GRIB2)
410  @endcode
411 
412  This adds a third operation to the RegribMany, called cGRIB2. The
413  r.GRIB('cGRIB1') looks up the operation that creates cGRIB1,
414  connecting that to the new cGRIB2. When we multiply by the
415  special constant GRIB2, it creates a new operation to convert that
416  file to GRIB2.
417 
418  @code
419  r.to_com('output_0p05_degree_f{fahr:03d}.grib2','cGRIB2')
420  @endcode
421 
422  This sets the delivery location for the cGRIB2 outputs. It will
423  create files with names like:
424 
425  @code
426  output_0p05_degree_048.grib2 # 48hr output file
427  @endcode
428 
429  Without that command, the output will go to automatically-generated
430  locations somewhere in intercom, which is likely not what you want.
431 
432  @code
433  gribber = GRIBTask(conf.datastore,conf,'mygrib',r,conf.cycle,
434  126*3600, 6*3600)
435  @endcode
436 
437  This creates a GRIBTask that will execute the regribber we just made.
438 
439  The GRIBTask is configured to be able to run our RegribMany for
440  all forecast times starting at the analysis time (conf.cycle) and
441  running to 126 hours afterwards (126*3600), every six hours
442  (6*3600). The GRIBTask will set the time= keyword argument to
443  mypost.products, allowing each RegribMany operation to run on the
444  correct input time.
445 
446  @code
447  gribber.run()
448  @endcode
449 
450  This tells the gribber to run to completion, generating our output
451  files."""
452  def __init__(self,_copy=None,workprefix=None,**kwargs):
453  """!Creats a new RegribMany.
454 
455  @param workprefix The workprefix, if specified,
456  sets the location in which to run. The _copy is used by the
457  self.copy() for copying.
458 
459  @param _copy,kwargs All other arguments are passed to the
460  superclass RegribBase.__init__ constructor ."""
461  assert('time' not in kwargs)
462  self._name_deliver=collections.defaultdict(list)
463  if _copy is not None:
464  RegribBase.__init__(self,_base=_copy)
465  self._workprefix=_copy._workprefix
466  self._gens=dict(_copy._gens)
467  self._order=list(_copy._order)
468  self._kwargs=dict(_copy._kwargs)
469  self._delivery=copy.copy(_copy._delivery)
470  for f in self._delivery:
471  self._name_deliver[f[2]]=f
472  else:
473  assert( not ( not 'copygb' in kwargs or kwargs['copygb'] is None ) )
474  RegribBase.__init__(self,**kwargs)
475  if workprefix is None:
476  workprefix='./'
477  self._workprefix=workprefix
478  self._delivery=list()
479  self._gens=dict()
480  self._kwargs=dict()
481  self._order=list()
482  self._data=None
483  self._lock=threading.RLock()
484  def __enter__(self):
485  """!Has no effect. This is for forward compatibility to a
486  later thread-safe implementation.
487  @note This used to be implemented but it turns out that
488  Python locks are VERY slow, so the locking had to be
489  removed. Multiple simultaneous regrib operrations are now
490  done through multiple processes"""
491  pass # self._lock.acquire()
492  def __exit__(self,etype,evalue,traceback):
493  """!Has no effect. This is for forward compatibility to a
494  later thread-safe implementation.
495  @param etype,evalue,traceback Exception information.
496  @note This used to be implemented but it turns out that
497  Python locks are VERY slow, so the locking had to be
498  removed. Multiple simultaneous regrib operations are now
499  done through multiple processes."""
500  pass # self._lock.release()
501  def has_name(self,name):
502  """!Returns True if an operation by the given name exists.
503  @param name the operation name to query"""
504  with self:
505  return name in self._gens
506  def reset(self):
507  """!Erases all cached results."""
508  with self:
509  self._data=None
510  def copy(self):
511  """!Returns a copy of self with no cached results."""
512  with self:
513  return RegribMany(_copy=self)
514  def GRIB(self,name):
515  """!Returns a GRIB1Fetcher object that will grab the GRIB1 data
516  with the given name.
517  @param name the operation name to query"""
518  self._gens[name]
519  return GRIB1Fetcher(name)
520  def nonGRIBOps(self):
521  """!Iterates over all non-GRIBOp operations yielding tuples
522  containing the name and operation."""
523  for k,v in self._gens.iteritems():
524  if not isinstance(v,GRIBOp):
525  yield k,v
526  def GRIBOps(self):
527  """!Iterates over all GRIBOp operations yielding tuples
528  containing the name and operation."""
529  for k,v in self._gens.iteritems():
530  if isinstance(v,GRIBOp):
531  yield k,v
532  def is_grid(self,name):
533  """!Returns True if the name corresponds to a grid
534  @param name the operation name to query"""
535  return isinstance(self._gens.get(name,None),GRIBGridBase)
536  def grid(self,name):
537  """!Returns a GRIBGridFetcher object that will grab the grid
538  structure with the given name.
539  @param name the operation name to query"""
540  self._gens[name]
541  return GRIBGridFetcher(name)
542  def subset(self,name):
543  """!Returns a GRIBSubsetterFetcher object that will grab the
544  GRIB subsetter with the given name.
545  @param name the operation name to query"""
546  self._gens[name]
547  return GRIBSubsetterFetcher(name)
548  def add(self,name,arg,**kwargs):
549  """!Adds the given generator "arg" under the specified name (in
550  "name") to this object.
551  @param name the operation name to query
552  @param arg A object of a subclass of GRIBBase
553  @param kwargs Stored for later passing to function calls to arg"""
554  with self:
555  assert name not in self._gens
556  self._gens[name]=arg
557  self._order.append(name)
558  self._kwargs[name]=dict(kwargs)
559  def to_com(self,location,name,category=None,prodname=None,keep=True):
560  """!Requests delivery to the com directory in file "location"
561  of operation "name".
562 
563  @param category,prodname The category and prodname are used to
564  create the FileProduct object.
565  @param keep Sent to the final deliver_file operation. It
566  should be left as True.
567  @param name the operation's name
568  @param location the destination, which will be sent through
569  hwrf.config.HWRFConfig.conftimestrinterp() by the
570  hwrf.gribtask.GRIBTask"""
571  assert(isinstance(location,basestring))
572  assert(isinstance(name,basestring))
573  assert(category is None or isinstance(category,basestring))
574  assert(prodname is None or isinstance(prodname,basestring))
575  assert(isinstance(keep,bool))
576  with self:
577  if not name in self._gens:
578  raise RegribKeyError('%s: no such key'%(name,))
579  deldat=['com',name,location,category,prodname,keep]
580  self._delivery.append(deldat)
581  self._name_deliver[name].append(deldat)
582  def to_intercom(self,location,name,category=None,prodname=None,keep=True):
583  """!Requests delivery to the intercom directory in file
584  "location" of operation "name".
585  @param category,prodname The category and prodname are used to
586  create the FileProduct object.
587  @param keep Sent to the final deliver_file operation. It
588  should be left as True.
589  @param name the operation's name
590  @param location the destination, which will be sent through
591  hwrf.config.HWRFConfig.conftimestrinterp() by the
592  hwrf.gribtask.GRIBTask"""
593  assert(isinstance(location,basestring))
594  assert(isinstance(name,basestring))
595  assert(category is None or isinstance(category,basestring))
596  assert(prodname is None or isinstance(prodname,basestring))
597  assert(isinstance(keep,bool))
598  with self:
599  if not name in self._gens:
600  raise RegribKeyError('%s: no such key'%(name,))
601  deldat=['intercom',name,location,category,prodname,keep]
602  self._delivery.append(deldat)
603  self._name_deliver[name].append(deldat)
604  def deliveries(self,name=None):
605  """!Iterates over all deliveries yielding a six element tuple
606 
607  @param name The name of the operation of interest.
608  The tuple contents:
609  1. "com" or "intercom"
610  2. operation name
611  3. location within target directory
612  4. requested category or None
613  5. requested prodname or None
614  6. keep flag from the to_com or to_intercom"""
615  for (where,iname,loc,cat,prod,keep) in self._delivery:
616  if name is None or name==iname:
617  yield where,iname,loc,cat,prod,keep
618  def has_deliveries(self):
619  """!Returns True if there are any requested deliveries and
620  False otherwise.
621 
622  @returns True if to_com() or to_intercom() were called for a known name."""
623  with self:
624  return len(self._delivery)>0
625  def has_data(self,name,**kwargs):
626  """!Returns True if there is a cached result for the specified
627  operation.
628 
629  @param kwargs The keyword arguments are passed on to the
630  get_data routine for the caching object (usually an
631  hwrf.gribtask.GRIBTask).
632  @param name The operation name."""
633  if self._data is None:
634  return self.is_ready(name,**kwargs)
635  args=dict(self._kwargs[name])
636  args.update(kwargs)
637  args['regribmany']=self
638  with self:
639  with self._data:
640  return self._data.get_data(name,**args) is not None
641  def is_ready(self,name,**kwargs):
642  """!Determines if the specified operation is ready.
643 
644  @param name Obtains the operation by the specified name.
645  @param kwargs The is_ready funciton is called on the named
646  operation's generator, passing the given keyword arguments to
647  it."""
648  with self:
649  op=self._gens[name]
650  if 'regribmany' in kwargs:
651  return op.is_ready(**kwargs)
652  else:
653  args=dict(kwargs)
654  args['regribmany']=self
655  return op.is_ready(**args)
656  def input_valid(self,name,**kwargs):
657  """!Determines if it is possible to run the specified operation
658  with the given keyword arguments.
659 
660  @param name Obtains the operation by the specified name.
661  @param kwargs The input_valid function is called on the
662  generator for the named operation, passing these keyword
663  arguments."""
664  with self:
665  op=self._gens[name]
666  if 'regribmany' in kwargs:
667  return op.input_valid(**kwargs)
668  else:
669  args=dict(kwargs)
670  args['regribmany']=self
671  return op.input_valid(**args)
672  def make(self,name,**kwargs):
673  """!Executes the operation previously stored in
674  self.add(), passing it the given keyword arguments,
675  returning the result. If a cache is available (usually a
676  GRIBTask), stores the result in that cache.
677 
678  @param name the name of the operation of interest
679  @param kwargs Passed to the make function in the generator
680  for the named operation"""
681  args=dict(self._kwargs[name])
682  args.update(kwargs)
683  args['regribmany']=self
684  with self:
685  if self._data is not None:
686  with self._data:
687  got=self._data.get_data(name,**args)
688  if got is not None: return got
689  op=self._gens[name]
690  r=Regrib(name,op,workprefix=os.path.join(
691  self._workprefix,name+'.step'),_base=self)
692  result=r.make(**args)
693  if not (isinstance(result,GRIBBase) or isinstance(op,GRIBGrid)):
694  raise InvalidRegribResult(
695  'Invalid result for %s: type=%s repr=%s which came from '
696  'running r.make(**args) on an r=%s and args=%s'%
697  (str(name),type(result).__name__,repr(result),repr(r),
698  repr(args)))
699  with self:
700  if self._data is not None:
701  self._data.set_data(name,result,**args)
702  return result
703  def names(self):
704  """!Iterates over the names provided to self.add(name,...) in
705  the order they were added."""
706  for name in self._order:
707  yield name
708 
709 ########################################################################
710 
711 # These functions are a mediation layer that sit between the
712 # produtil.regrib low-level functions and the objects in this module.
713 # Their primary job is to get filenames and other information from a
714 # Regrib and various GRIBOp objects and send them to the
715 # produtil.gribop functions. All return either a GRIB1File or a
716 # GRIB2File except "checkgrib" which is a bool function that checks to
717 # see if a GRIB1/2 file can plausibly contain data, without opening
718 # the file..
719 
720 ##@var GRIB_FILE_MIN_SIZE
721 #Eight bytes: the minimum required size of a non-empty GRIB1 or
722 #GRIB2 file. This size is chosen because it is not possible for a file
723 #to be smaller than this and still meet the GRIB standard.
724 #Realistically, the file should be much larger.
725 GRIB_FILE_MIN_SIZE=8
726 """Eight bytes: the minimum required size of a non-empty GRIB1 or
727 GRIB2 file. This size is chosen because it is not possible for a file
728 to be smaller than this and still meet the GRIB standard.
729 Realistically, the file should be much larger."""
730 
731 def checkgrib(regrib,filename):
732  """!Internal function for validating GRIB files.
733 
734  This is a low-level implementation function. It should not be
735  called directly. This checks a file to make sure it exists, is a
736  regular file (or symlink to a regular file) and is large enough to
737  plausibly contain some GRIB1 or GRIB2 data. Returns True for such
738  plausible files and False otherwise. Does not open the file, and
739  performs only a single stat. Uses errno ENOENT (no such file or
740  directory) and ELOOP (too many symbolic links) to detect
741  non-existence. Other exceptions will be passed to the caller.
742  @param regrib a regrib for logging information
743  @param filename the name of the file of interest"""
744  if filename is None:
745  if regrib.logger is not None:
746  regrib.logger.warning(
747  'checkgrib: filename=None. Probable code error.')
748  return False
749  try:
750  s=os.stat(filename)
751  sizeok=s.st_size>GRIB_FILE_MIN_SIZE
752  if not sizeok:
753  if regrib.logger is not None:
754  regrib.logger.warning('%s: size=%d < 8 bytes'
755  %(str(filename),s.st_size))
756  return False
757  typeok=stat.S_ISREG(s.st_mode)
758  if not typeok:
759  if regrib.logger is not None:
760  regrib.logger.warning('%s: not a regular file'
761  %(str(filename),s.st_size))
762  return False
763  except EnvironmentError as e:
764  if e.errno == errno.ENOENT:
765  if regrib.logger is not None:
766  regrib.logger.warning('%s: input GRIB1/2 file does not exist: %s'%(str(filename),os.strerror(e.errno)))
767  return False
768  elif e.errno == errno.ELOOP:
769  if regrib.logger is not None:
770  regrib.logger.warning('%s: input GRIB1/2 file path results in too many symlinks (likely a symbolic link loop): %s'%(str(filename),os.strerror(e.errno)))
771  return False
772  # We get here on genuine errors
773  raise
774  return True
775 
776 def action_grib1to2(op,regrib,infile,*args,**kwargs):
777  """!Converts GRIB1 file to GRIB2
778 
779  This is a low-level implementation function. It should not be
780  called directly. This function is sent as a parameter to GRIB1Op
781  to produce a GRIB2 version of a GRIB1 file. It uses
782  regrib.cnvgrib_g12 to perform the conversion.
783 
784  @param op The GRIBBase operation running this funciton.
785  @param regrib a Regrib for data information
786  @param infile The input filename.
787  @param args,kwargs Ignored
788  @returns a new GRIB2File for the output file"""
789  (outfile,outindex)=regrib.gribtemp('grb2')
790  cmd=regrib.cnvgrib_g12[infile.grib1file,outfile]
791  if regrib.logger is not None:
792  regrib.logger.info(repr(cmd))
793  if regrib.sync_frequently:
794  runsync()
795  ex=run(cmd)
796  if ex!=0:
797  raise RegribError('ERROR: regrib.cnvgrib_g12 command failed with '
798  'exit status %d'%(ex,))
799  return GRIB2File(outfile,None,None)
800 
801 def action_grib2to1(op,regrib,infile,*args,**kwargs):
802  """!Converts GRIB2 files to GRIB1
803 
804  This is a low-level implementation function. It should not be
805  called directly. This function is sent as a parameter to GRIB2Op
806  to produce a GRIB1 version of a GRIB2 file. It uses
807  regrib.cnvgrib_g21 to do the conversion.
808 
809  @param op The GRIBBase operation running this funciton.
810  @param regrib a Regrib for data information
811  @param infile The input filename.
812  @param args,kwargs Ignored
813  @returns a new GRIB1File for the output file
814  @warning This is not used by any HWRF configuration and
815  has not been tested in a while."""
816  (outfile,outindex)=regrib.gribtemp('grb1')
817  cmd=regrib.cnvgrib_g21[infile.grib2file,outfile]
818  if regrib.logger is not None:
819  regrib.logger.info(repr(cmd))
820  if regrib.sync_frequently:
821  runsync()
822  ex=run(cmd)
823  if ex!=0:
824  raise RegribError('ERROR: regrib.cnvgrib_g21 command failed with '
825  'exit status %d'%(ex,))
826  return GRIB1File(outfile,None,None)
827 
828 def action_grib1regridmerge(op,regrib,grid,in1,in2,**kwargs):
829  """!Performs regridding and merges two files in a single operation.
830 
831  This is a low-level implementation function. It should not be
832  called directly. This function is sent as a parameter to GRIB1Op
833  to do a copygb regrid AND merge in a single operation (one call to
834  the copygb program). The grid argument is the target grid, and
835  the in1 and in2 arguments are the input GRIB1 files.
836 
837  @param op The GRIBBase operation running this funciton.
838  @param regrib a Regrib for data information
839  @param in1,in2 The input filenames.
840  @param grid The GRIBGrid that provides grid information.
841  @param kwargs Ignored
842  @returns a GRIB1File for the output file, which may be in1 or in2, or a new GRIB1File"""
843  grid=grid.grib1grid
844  if grid is None:
845  raise GridlessError('No GRIB1 grid in input grid object'
846  ' (grid.grib1grid is None).')
847 
848  file1=in1.grib1file
849  file2=in2.grib1file
850 
851  ok1=checkgrib(regrib,file1)
852  ok2=checkgrib(regrib,file2)
853 
854  if ok1 and ok2:
855  (outfile,outindex)=regrib.gribtemp('merge.grb1')
856  cmd=regrib.copygb['-xg'+grid,'-M',file1,file2,outfile]
857  if regrib.logger is not None:
858  regrib.logger.info(repr(cmd))
859  if regrib.sync_frequently:
860  runsync()
861  ex=run(cmd)
862  if ex!=0:
863  message='%s + %s: GRIB1 merge failed: exit status %d'%(
864  file1,file2,ex)
865  if regrib.logger is not None:
866  regrib.logger.error(message)
867  raise RegribError(message)
868  return GRIB1File(outfile,None,grid)
869  elif ok1:
870  run(exe('ls')['-l'])
871  run(exe('pwd'))
872  raise GRIBInputError(file2,': failed sanity checks')
873  return in1
874  elif ok2:
875  run(exe('ls')['-l'])
876  run(exe('pwd'))
877  raise GRIBInputError(file1,': failed sanity checks')
878  return in2
879  else:
880  raise GRIBInputError(
881  '%s, %s: both inputs to GRIB1 regribmerge are empty or '
882  'missing.'%(file1,file2))
883 
884 def action_grbindex(op,regrib,ingrib,task=None,**kwargs):
885  """!Runs the grbindex program on a GRIB1 file.
886 
887  This is a low-level implementation function. It should not be
888  called directly. This function adds a grbindex output to the
889  specified input file's product, unless one is already available.
890  Unlike most action_* functions, this one does not create a new
891  GRIBFile or GRIBProduct, instead it modifies the existing one to
892  add the location of the grbindex output.
893 
894  @param op The GRIBBase operation running this funciton.
895  @param regrib a Regrib for data information
896  @param ingrib The input GRIBBase that represents the input file.
897  @param task An hwrf.hwrftask.HWRFTask to provide the path to
898  grbindex
899  @param kwargs Ignored
900  @returns ingrib"""
901  assert(task is not None)
902  assert(ingrib is not None)
903 
904  infile=ingrib.grib1file
905  inindex=ingrib.grib1grbindex
906  logger=regrib.logger
907 
908  if inindex is None:
909  if logger is not None:
910  logger.info('%s: make the grbindex'%(infile,))
911  inindex=infile+'.grbindex'
912  grbindex=alias(exe(task.getexe('grbindex')))
913  if regrib.sync_frequently:
914  runsync()
915  produtil.run.checkrun(grbindex[infile,inindex],logger=logger)
916  ingrib.grib1grbindex=inindex
917  elif logger is not None:
918  logger.info('%s: already has grbindex %s'%(infile,inindex))
919  return ingrib
920 
921 def action_grib1merge(op,regrib,in1,in2,**kwargs):
922  """!Merges two GRIB1 files that must already have the same grid.
923 
924  This is a low-level implementation function. It should not be
925  called directly. This function is sent as a parameter to GRIB1Op
926  to do a copygb merge (-xM) of two GRIB1 files to produce a single
927  GRIB1 file. It requires that at least one of the files have a
928  known grid, and if both have a known grid then their grids must
929  mach.
930  @param op The GRIBBase operation running this funciton.
931  @param regrib a Regrib for data information
932  @param in1,in2 The input GRIBGrid objects that provide filenames
933  @param kwargs Ignored
934  @returns The resulting GRIB1File, which may be in1, in2 or a new
935  GRIB1File
936  @bug This function calls pwd and ls -l if things go wrong. It
937  needs to use produtil.listing instead."""
938  grid1=in1.grib1grid
939  grid2=in2.grib1grid
940  if grid1 is None and grid2 is None:
941  raise GridlessError(
942  '%s: unable to guess the grid for this GRIB merge'
943  %(outfile,))
944  elif grid1 is None:
945  grid=grid2
946  elif grid2 is None:
947  grid=grid1
948  elif grid1!=grid2:
949  raise GridMismatchError(
950  'input grids to not match in GRIB merge: (%s) != (%s)'
951  %(grid1,grid2))
952  else:
953  grid=grid1
954 
955  file1=in1.grib1file
956  file2=in2.grib1file
957 
958  ok1=checkgrib(regrib,file1)
959  ok2=checkgrib(regrib,file2)
960 
961  if ok1 and ok2:
962  (outfile,outindex)=regrib.gribtemp('merge.grb1')
963  cmd=regrib.copygb['-g'+grid,'-xM',file1,file2,outfile]
964  if regrib.logger is not None:
965  regrib.logger.info(repr(cmd))
966  if regrib.sync_frequently:
967  runsync()
968  ex=run(cmd)
969  if ex!=0:
970  message='%s + %s: GRIB1 merge failed: exit status %d'%(
971  file1,file2,ex)
972  if regrib.logger is not None:
973  regrib.logger.error(message)
974  raise RegribError(message)
975  return GRIB1File(outfile,None,grid)
976  elif ok1:
977  run(exe('ls')['-l'])
978  run(exe('pwd'))
979  raise GRIBInputError(file2,': not ok (empty or missing)') # FIXME: REMOVE
980  return in1
981  elif ok2:
982  run(exe('ls')['-l'])
983  run(exe('pwd'))
984  raise GRIBInputError(file1,': not ok (empty or missing)') # FIXME: REMOVE
985  return in2
986  else:
987  raise GRIBInputError('%s, %s: both inputs to GRIB1 merge are empty or missing.'%(file1,file2))
988 
989 def action_grib1regrid(op,regrib,infile,ingrid,*args,**kwargs):
990  """!Regrids a GRIB1 file.
991 
992  This is a low-level implementation function. It should not be
993  called directly. This is sent as a parameter to GRIB1Op to
994  convert a GRIB1 file from one grid to another. The output has a
995  known grid, so it can be sent into an action_grib1merge.
996  @param op The GRIBBase operation running this funciton.
997  @param regrib a Regrib for data information
998  @param infile The input filename.
999  @param ingrid Input GRIB1Grid that specifies the target grid.
1000  @param args,kwargs Ignored
1001  @returns a new GRIB1File for the output file"""
1002  (outfile,outindex) = regrib.gribtemp('to_'+ingrid.gridname)
1003  grid=ingrid.grib1grid
1004  if grid is None:
1005  raise GridlessError(
1006  'Tried to regrid a GRIB1 file, but the GRIBGrid did not have '
1007  'GRIB1 grid information.')
1008  cmd=regrib.copygb['-g'+ingrid.grib1grid,'-x',infile.grib1file,outfile]
1009  if regrib.logger is not None:
1010  regrib.logger.info(repr(cmd))
1011  if regrib.sync_frequently:
1012  runsync()
1013  ex=run(cmd)
1014  if ex!=0:
1015  raise RegribError('ERROR: copygb regrid command failed with '
1016  'exit status %d'%(ex,))
1017  checkgrib(regrib,outfile)
1018  return GRIB1File(outfile,None,ingrid.grib1grid)
1019 
1020 def action_grib1subset(op,regrib,infile,subsetter,*args,**kwargs):
1021  """!Subsets a GRIB1 file.
1022 
1023  This is a low-level implementation function. It should not be
1024  called directly. It subsets a GRIB1 file infile using the given
1025  subsetter. The subsetter should have a list of strings accessible
1026  via subsetter.grib1sub. It should also have a name accessible
1027  through subsetter.subsetname. The wgrib -s output of infile is
1028  scanned. Any line in wgrib -s's output that contains the entirety
1029  of any line in the subsetter.grib1sub is retained. The subsetting
1030  is done via wgrib -i -grib (infile) -o (outfile).
1031 
1032  @param op The GRIBBase operation running this funciton.
1033  @param regrib a Regrib for data information
1034  @param infile The input filename.
1035  @param subsetter A GRIBSubsetter that chooses the fields to keep.
1036  @param args,kwargs Ignored
1037  @returns a new GRIB1File for the output file"""
1038  (outfile,outindex)=regrib.gribtemp('sub_'+subsetter.subsetname)
1039  if subsetter.grib1sub is None:
1040  raise SubsetlessError('%s: cannot create: no GRIB1 subsetter '
1041  'for subset %s'%(outfile,subname))
1042 
1043  index=infile.wgrib_s(regrib)
1044  subindex=[line for line in subsetter.grib1sub(index)]
1045  cmd=regrib.wgrib['-i','-grib',infile.grib1file,'-o',outfile] \
1046  << '\n'.join(subindex)
1047  if regrib.logger is not None:
1048  regrib.logger.info(repr(cmd))
1049  if regrib.sync_frequently:
1050  runsync()
1051  ex=run(cmd,logger=regrib.logger)
1052  if ex!=0:
1053  raise RegribError('ERROR: wgrib subset command failed with '
1054  'exit status %d'%(ex,))
1055  return GRIB1File(outfile,None,infile.grib1grid,
1056  infile.nscenter,infile.ewcenter)
1057 
1058 def action_clatlon(op,regrib,name,center,nsres,ewres,nssize,ewsize,
1059  nscount,ewcount,scan,**kwargs):
1060  """!Generates a latitude-longitude grid centered on a GRIB file or
1061  specified point.
1062 
1063  This is an internal implementation function that should not be
1064  called directly. It queries the center object's nscenter and
1065  ewcenter properties to get the objects location. It then adds a
1066  border around that, creating a GRIB1 grid 255 grid specification
1067  centered on the @c center object.
1068  @param op The GRIBBase operation running this funciton.
1069  @param center The GRIBBase operation on which to center the grid
1070  @param regrib a Regrib for data information
1071  @param name the name of the resulting grid, for storage in
1072  a RegribMany
1073  @param nsres,ewres GRIB1 grid 255 resolution information
1074  @param nssize,ewsize GRIB1 grid 255 size information, but in degrees.
1075  It will be converted to millidegrees for passing to underlying
1076  GRIB manipulation programs.
1077  @param nscount,ewcount Number of gridpoints in each direction,
1078  for the GRIB1 grid 255 information.
1079  @param scan GRIB1 grid 255 scanning mode byte
1080  @param kwargs Ignored
1081  @returns a new GRIBGrid for the new grid"""
1082  assert (regrib.logger is not None)
1083  regrib.logger.info('IN CLATLON')
1084  nscen=float(center.nscenter)
1085  ewcen=float(center.ewcenter)
1086  if regrib.logger is not None:
1087  regrib.logger.info(
1088  'CLATLON: nsres=%s ewres=%s nssize=%s ewsize=%s nscount=%s '
1089  'ewcount=%s nscen=%f ewcen=%f'%
1090  (repr(nsres),repr(ewres),repr(nssize),repr(ewsize),
1091  repr(nscount),repr(ewcount),nscen,ewcen))
1092  iewres = int(ewres*1000)
1093  insres = int(nsres*1000)
1094  iscan = int(scan)
1095  inscount = int(nscount)
1096  iewcount = int(ewcount)
1097  inlat = int(nscen*1000+1000*nssize/2)
1098  islat = int(nscen*1000-1000*nssize/2)
1099  ielon = int(ewcen*1000+1000*ewsize/2)
1100  iwlon = int(ewcen*1000-1000*ewsize/2)
1101  if 0!=(int(scan)&128):
1102  if regrib.logger is not None:
1103  regrib.logger.info('CLATLON scan=%d, swap EW'%(int(scan),))
1104  (ielon,iwlon)=(iwlon,ielon)
1105  if 0!=(int(scan)&64):
1106  if regrib.logger is not None:
1107  regrib.logger.info('CLATLON scan=%d, swap NS'%(int(scan),))
1108  (inlat,islat)=(islat,inlat)
1109  if 0!=(int(scan)&32):
1110  if regrib.logger is not None:
1111  regrib.logger.info('CLATLON scan=%d, swap NS-EW sizes'
1112  %(int(scan),))
1113  (ewcount,nscount)=(nscount,ewcount)
1114  assert(insres>0)
1115  assert(iewres>0)
1116  s = '255 0 %d %d %d %d %d %d %d %d %d 0' % \
1117  ( inscount, iewcount, inlat, ielon, iscan, islat,
1118  iwlon, insres, iewres )
1119  return GRIBGrid(name,s,None)
1120 
1121 ########################################################################
1122 
1123 class GRIBBase(object):
1124  """!Base class for the regridding object tree.
1125 
1126  This is the abstract base class for all GRIB files, operators,
1127  subsetters and grids. Everything that is representable as an
1128  Regrib operation is a subclass of GRIBBase. This class should
1129  never be instantiated directly."""
1130  def is_ready(self,*args,**kwargs):
1131  """!Returns True if this object and its subobjects are all
1132  ready for a call to make, and False otherwise.
1133  @param args,kwargs Ignored, but used by subclasses."""
1134  return True
1135  def input_valid(self,**kwargs):
1136  """!Returns True if the specified kwargs are valid and False
1137  otherwise.
1138  @param kwargs Ignored, but used by subclasses"""
1139  return True
1140  def make(self,regrib,**kwargs):
1141  """!Runs the action this object should perform and returns
1142  another GRIBBase object.
1143  @param regrib a Regrib for data information
1144  @param kwargs Ignored, but used by subclasses."""
1145  return self
1146 
1148  """!This abstract base class represents something that is able to
1149  produce a GRIBGrid object when make() is called."""
1150 
1151 class GRIBGrid(GRIBGridBase):
1152  """!This class represents a GRIB1 or GRIB2 grid specification."""
1153  def __init__(self,gridname,grib1grid=None,grib2grid=None):
1154  """!Creates a GRIBGrid with a given name, a copygb -g style
1155  GRIB1 grid specification and a GRIB2 grid specification that
1156  is currently unused.
1157  @param gridname The gridname is mandatory and will be used to
1158  generate temporary filenames.
1159  @param grib1grid The GRIB1 grid information, a string
1160  @param grib2grid The GRIB2 grid information (unsupported)"""
1161  super(GRIBGrid,self).__init__()
1162  self._gridname=gridname
1163  self._grib1grid=grib1grid
1164  self._grib2grid=grib2grid
1165  def is_ready(self,*args,**kwargs):
1166  """!Returns True. The grid information is always ready.
1167  @param args,kwargs Ignored, but used by subclasses."""
1168  return True
1169  def input_valid(self,**kwargs):
1170  """!Returns True. The grid information is always available,
1171  regardless of the kwargs.
1172  @param kwargs Ignored, but used by subclasses."""
1173  return True
1174  def make(self,*args,**kwargs):
1175  """!Returns self. This grid is the output grid of this grid.
1176  @param args,kwargs Ignored, but used by subclasses."""
1177  return self
1178  def getgridname(self):
1179  """!Returns the name of this grid, as provided to the
1180  constructor."""
1181  return self._gridname
1182  def getgrib1grid(self):
1183  """!Returns the GRIB1 (wgrib) style grid information, as sent
1184  to the constructor's grib1grid argument."""
1185  return self._grib1grid
1186  def getgrib2grid(self):
1187  """!This is a placeholder to return the GRIB2-style grid
1188  information. At present, it returns whatever was sent to the
1189  constructor's grib2grid argument"""
1190  return self._grib2grid
1191 
1192  ##@property gridname
1193  # The name of this grid, a read-only property
1194  gridname=property(getgridname,None,None,
1195  """The name of this grid. This is used to generate output filenames when regridding.""")
1196 
1197  ##@property grib1grid
1198  # The GRIB1 grid string, a read-only property
1199  grib1grid=property(getgrib1grid,None,None,
1200  """A string to send to copygb's -g parameter for interpolating to this grid.""")
1201 
1202  ##@property grib2grid
1203  # The GRIB2 grid information, currently unused.
1204  grib2grid=property(getgrib2grid,None,None,
1205  """GRIB2 regridding information, currently unused.""")
1206 
1207 ##@var quarterDegree
1208 # A special GRIBGrid representing grid 193, which is a quarter degree
1209 # regular lat-lon grid the NCEP GFS model uses as output.
1210 quarterDegree=GRIBGrid('Quarter_Degree_Grid_193','193',None)
1211 
1213  """!This class represents a GRIBGrid that is stored in a RegribMany
1214  object. It is able to check for readiness via RegribMany.is_ready
1215  and produce a result via RegribMany.make."""
1216  def __init__(self,name):
1217  """!GRIBGridFetcher constructor
1218  @param name The name of the grid that is fetched. This is used
1219  to generate temporary filenames and is used in RegribMany for
1220  the generator name."""
1221  self._name=name
1222  def is_ready(self,*args,**kwargs):
1223  """!Calls kwargs['regribmany'].has_data to see if the specified
1224  operation has produced its grid.
1225  @param args,kwargs Passed to source.has_data. The meaning
1226  is implementation-specific, but generally the kwargs are
1227  used for string replacement in an hwrf.config.HWRFConfig"""
1228  source=kwargs['regribmany']
1229  assert(source)
1230  return source.has_data(self._name,*args,**kwargs)
1231  def input_valid(self,**kwargs):
1232  """!Calls kwargs['regribmany'].input_valid to see if the
1233  specified kwargs make a valid input to the operation.
1234  @param kwargs Passed to source.input_valid. The meaning
1235  is implementation-specific, but generally the kwargs are
1236  used for string replacement in an hwrf.config.HWRFConfig"""
1237  source=kwargs['regribmany']
1238  assert(source)
1239  return source.input_valid(self._name,**kwargs)
1240  def make(self,*args,**kwargs):
1241  """!Calls kwargs['regribmany'].make to produce the grid.
1242  @param args,kwargs Passed to source.make. The meaning
1243  is implementation-specific, but generally the kwargs are
1244  used for string replacement in an hwrf.config.HWRFConfig"""
1245  source=kwargs['regribmany']
1246  assert(source)
1247  return source.make(self._name,**kwargs)
1248 
1250  """!This class represents a GRIBGrid that must be computed from
1251  some other input, usually a GRIB file. This is used to create
1252  storm-centered or E-grid GRIB-centered grids for the HWRF."""
1253  def __init__(self,name,action,*args):
1254  """!Creates a new GRIBGridCompute with the given name and
1255  action. The action is a function or callable object that
1256  takes this object, the regrib, the name and the contents of
1257  args. Also, any keyword arguments given to self.make are
1258  passed on as well.
1259  @param name The name of the computed grid.
1260  @param action The function that computes the grid.
1261  @param args Additional positional arguments are sent to the function."""
1262  self._name=name
1263  self._action=action
1264  self._args=list(args)
1265  def is_ready(self,*args,**kwargs):
1266  """!Returns the logical "or" of is_ready(*args,**kwargs) called
1267  on all subobjects. Subobjects that are not instances of
1268  GRIBBase are assumed to be ready.
1269  @param args,kwargs Passed to arg.is_ready, for all args sent to
1270  the constructor that are subclasses of GRIBBase"""
1271  for arg in self._args:
1272  if isinstance(arg,GRIBBase) and not arg.is_ready(*args,**kwargs):
1273  return False
1274  return True
1275  def input_valid(self,*args,**kwargs):
1276  """!Returns the logical "or" of input_valid(**kwargs) called on
1277  all subobjects. Subobjects that are not instances of GRIBBase
1278  are assumed to be ready.
1279  @param args,kwargs Passed to arg.input_valid, for all args sent to
1280  the constructor that are subclasses of GRIBBase"""
1281  for arg in self._args:
1282  if isinstance(arg,GRIBBase) and not arg.input_valid(**kwargs):
1283  return False
1284  return True
1285  def make(self,regrib,**kwargs):
1286  """!Runs the action specified in the constructor, providing as
1287  arguments regrib, and the result of running make on all of the
1288  other arguments sent to the constructor.
1289  @param regrib The Regrib object for data storage.
1290  @param kwargs Passed to arg.make, for all args sent to
1291  the constructor that are subclasses of GRIBBase"""
1292  args=[]
1293  for arg in self._args:
1294  if isinstance(arg,GRIBBase):
1295  args.append(arg.make(regrib,**kwargs))
1296  else:
1297  args.append(arg)
1298  return self._action(self,regrib,self._name,*args,**kwargs)
1299 
1301  """!Represents a specific location on the earth as a latitude,
1302  longitude pair. This is meant to be used with action_clatlon to
1303  generate fixed lat-lon grids."""
1304  def __init__(self,lat,lon):
1305  """!FixedLocation constructor
1306  @param lat,lon The fixed location in degrees North and East."""
1307  self.__lat=float(lat)
1308  self.__lon=float(lon)
1309  def getlat(self):
1310  """!Returns the point's latitude"""
1311  return self.__lat
1312  def getlon(self):
1313  """!Returns the point's longitude."""
1314  return self.__lon
1315  def setlat(self,val):
1316  """!Sets the point's latitude
1317  @param val The new latitude in degrees North."""
1318  self.__lat=val
1319  def setlon(self,val):
1320  """!Sets the point's longitude.
1321  @param val The new longitude in degrees East"""
1322  self.__lon=val
1323 
1324  ##@property nscenter
1325  # The latitude in degrees North.
1326  nscenter=property(getlat,setlat,None,
1327  """The latitude of this fixed location.""")
1328 
1329  ##@property ewcenter
1330  # The longitude in degrees East.
1331  ewcenter=property(getlon,setlon,None,
1332  """The longitude of this fixed location.""")
1333 
1334 def clatlon(center,res,size,n,scan=136,name=None):
1335  """!Create a GRIBGridCompute that makes a lat-lon grid.
1336 
1337  Returns a GRIBGridCompute that will produce a lat-lon grid
1338  centered on the given object. The provided object must have
1339  nscenter and ewcenter properties that produce real lats and lons
1340  that are positive North and positive East. The res parameter is a
1341  two element array containing the resolution in degrees.
1342 
1343  @param name the new grid's name
1344  @param center An object on which to center. Must have nscenter and ewcenter
1345  properties.
1346  @param res The GRIB1 grid 255 resolution information in a two-element array.
1347  @param size The size parameter is a two-element array containing the
1348  extent in degrees.
1349  @param n The n parameter contains the number of gridpoints.
1350  @param scan The "scan" parameter is the scanning mode parameter: 128
1351  means E-W are reversed, 64 means N-S are reversed, and 32 means
1352  the data is transposed.
1353 
1354  @note All three, res, size and n, are two element arrays with the
1355  N-S value first and the E-W value second. These are turned into
1356  a GRIB1 grid 255 specification."""
1357  assert(len(n)==2 and n[0]>0 and n[1]>0)
1358  assert(len(size)==2 and size[0]>0 and size[1]>0)
1359  assert(scan>=0 and scan<=255)
1360  assert(len(res)==2 and res[0]>0 and res[1]>0)
1361  if name is None:
1362  name='clatlon%dx%dp'%(int(n[0]),int(n[1]))
1363  return GRIBGridCompute(name,action_clatlon,center,res[0],res[1],size[0],
1364  size[1],n[0],n[1],scan)
1365 
1367  """!A GRIBBase that subsets GRIB files, keeping only certain parameters."""
1368  def __init__(self,subsetname,grib1sub=None,grib2sub=None):
1369  """!GRIBSubsetter constructor.
1370 
1371  Creates a GRIBSubsetter with a given name, a callable
1372  object grib1sub that will be sent to
1373  produtil.gribop.grib1subset, and an unused grib2sub that will
1374  be used for GRIB2 subsetting one day.
1375  @param grib1sub Callable object that iterates over
1376  wgrib -s output and yields only fields that should be kept,
1377  potentially in a new order.
1378  @param grib2sub Unsupported: GRIB2 subsetter.
1379  @param subsetname The subsetname is mandatory and will be used to
1380  generate temporary filenames."""
1381  super(GRIBSubsetter,self).__init__()
1382  self._subsetname=subsetname
1383  self._grib1sub=grib1sub
1384  self._grib2sub=grib2sub
1385  def is_ready(self,*args,**kwargs):
1386  """!Returns True. The subsetter is its own product, so it is
1387  always "ready."
1388  @param args,kwargs Ignored, but used by subclasses. """
1389  return True
1390  def input_valid(self,**kwargs):
1391  """!Returns True. The subsetter's product (itself) does not
1392  vary with the kwargs, so any input is valid.
1393  @param kwargs Ignored, but used by subclasses."""
1394  return True
1395  def make(self,*args,**kwargs):
1396  """!Returns self. The subsetter is its own product.
1397  @param args,kwargs Ignored, but used by subclasses."""
1398  return self
1399  def getsubsetname(self):
1400  """!Returns a name of this subset for use in filenames."""
1401  return self._subsetname
1402  def getgrib1sub(self):
1403  """!Returns an iterator that takes as its only argument an
1404  array of lines of wgrib -s output."""
1405  return self._grib1sub
1406  def getgrib2sub(self):
1407  """!This is a placeholder for future GRIB2 subsetting
1408  support."""
1409  return self._grib2sub
1410 
1411  ##@var subsetname
1412  # Read-only property: the name of the subset.
1413  subsetname=property(getsubsetname,None,None,
1414  """The name of this GRIB1/2 subset. This is used to generate
1415  output filenames.""")
1416 
1417  ##@var grib1sub
1418  # Read-only property: a callable object that chooses the fields to
1419  # keep and their order.
1420  grib1sub=property(getgrib1sub,None,None,
1421  """A callable object to send to produtil.gribop.grib1subset's
1422  subsetter argument.""")
1423 
1424  ##@var grib2sub
1425  # Unused: the grib2 subsetter.
1426  grib2sub=property(getgrib2sub,None,None,
1427  """GRIB2 subsetting information, currently unused.""")
1428 
1430  """!This class grabs a GRIBSubsetter from a RegribMany object."""
1431  def __init__(self,name):
1432  """!GRIBSubsetterFetcher constructor
1433  @param name the name of the subset"""
1434  self._name=name
1435  def input_valid(self,**kwargs):
1436  """!Calls kwargs['regribmany'].input_valid to see if the kwargs
1437  make a valid input.
1438  @param kwargs Contains a regribmany key mapping to a RegribMany object"""
1439  source=kwargs['regribmany']
1440  assert(source)
1441  return source.input_valid(self._name,**kwargs)
1442  def is_ready(self,*args,**kwargs):
1443  """!Calls kwargs['regribmany'].has_data to see if the operation
1444  has produced its subsetter yet.
1445  @param kwargs Contains a regribmany key mapping to a RegribMany object.
1446  Is also passed to has_data
1447  @param args Additional positional arguments passed to has_data"""
1448  source=kwargs['regribmany']
1449  assert(source)
1450  return source.has_data(self._name,*args,**kwargs)
1451  def make(self,*args,**kwargs):
1452  """!Calls kwargs['regribmany'].make to produce the subsetter.
1453  @param args,kwargs Passed to source.make. The meaning
1454  is implementation-specific, but generally the kwargs are
1455  used for string replacement in an hwrf.config.HWRFConfig"""
1456  source=kwargs['regribmany']
1457  assert(source)
1458  return source.make(self._name,**kwargs)
1459 
1460 ########################################################################
1461 
1463  """!This is the abstract base class for all GRIB1 and GRIB2 files
1464  and operators. It should never be instantiated directly."""
1465  def __init__(self,action,*args):
1466  """!Creates a GRIBOp that has a number of child GRIBBase
1467  objects, with a specified action to perform in the GRIBOp.make
1468  method. The action should be a callable object that takes as
1469  input a Regrib, the contents of args and any keyword arguments
1470  sent to make.
1471  @param action the function that performs the operation
1472  @param args arguments to the action"""
1473  self._action=action
1474  self._args=list(args)
1475  def getaction(self):
1476  """!Returns the action, a function or callable object."""
1477  return self._action
1478  def args(self):
1479  """!Iterates over all child GRIBBase objects."""
1480  for arg in self._args:
1481  yield arg
1482 
1483  ##@property action
1484  # A read-only property: this objects action function.
1485  action=property(getaction,None,None,
1486  """Returns the callable object that performs this object's work""")
1487  def is_ready(self,*args,**kwargs):
1488  """!Returns the logical "and" of is_ready(*args,**kwargs)
1489  called on all subobjects.
1490  @param args,kwargs Passed to arg.is_ready. The meaning
1491  is implementation-specific, but generally the kwargs are
1492  used for string replacement in an hwrf.config.HWRFConfig"""
1493  for arg in self.args():
1494  if not arg.is_ready(*args,**kwargs):
1495  return False
1496  return True
1497  def input_valid(self,**kwargs):
1498  """!Returns the logical "and" of input_valid(**kwargs) called
1499  on all subobjects.
1500  @param kwargs Passed to source.has_data. The meaning
1501  is implementation-specific, but generally the kwargs are
1502  used for string replacement in an hwrf.config.HWRFConfig"""
1503  for arg in self.args():
1504  if not arg.input_valid(**kwargs):
1505  return False
1506  return True
1507  def make(self,regrib,**kwargs):
1508  """!Runs the action specified in the constructor, providing as
1509  arguments regrib, and the result of running make on all of the
1510  other arguments sent to the constructor.
1511  @param regrib a Regrib for data storage
1512  @param kwargs Passed to the action. The meaning
1513  is implementation-specific, but generally the kwargs are
1514  used for string replacement in an hwrf.config.HWRFConfig"""
1515  args=[]
1516  for arg in self.args():
1517  result=arg.make(regrib,**kwargs)
1518  assert(result is not None)
1519  assert(isinstance(result,GRIBBase))
1520  args.append(result)
1521  return self._action(self,regrib,*args,**kwargs)
1522  def __repr__(self):
1523  """!A string representation of this GRIB operation."""
1524  return '<%s %s %s>'%(type(self).__name__,repr(self._action),
1525  ','.join([repr(x) for x in self.args()]))
1526 
1528  """!This subclass of GRIBOp produces GRIB2 files, and can be
1529  converted to GRIB1 via obj*GRIB1 or obj.to_grib1(). Calls to
1530  obj.to_grib2() or obj*GRIB2 simply return self."""
1531  def __init__(self,action,*args):
1532  """!GRIB2Op constructor
1533  @param action,args Passed to GRIBOp.__init__"""
1534  super(GRIB2Op,self).__init__(action,*args)
1535  def to_grib1(self):
1536  """!Returns a GRIB2Op that converts this operation's output to GRIB1"""
1537  return GRIB2Op(action_grib2to1,self)
1538  def to_grib2(self):
1539  """!Returns self (converting GRIB2 to GRIB2 is a no-op)"""
1540  return self
1541  def __mul__(self,grid):
1542  """!If grid is the special constant GRIB1, this is the same as to_grib1(),
1543  if GRIB2, then returns self. Otherwise, returns NotImplemented to indicate
1544  that GRIB2 regridding is not implemented yet.
1545  @param grid The constant GRIB1, GRIB2, or a GRIBGrid"""
1546  if grid is GRIB1:
1547  return self.to_grib1()
1548  elif grid is GRIB2:
1549  return self
1550  return NotImplemented
1551 
1553  """!This subclass of GRIBOp produces GRIB1 files. It introduces a
1554  number of convenience calls:
1555 
1556  * file1 + file2 + file3 = a copygb merge of the three files
1557  * file1*grid = copygb interpolate file1 to the specified GRIBGrid
1558  * file1*GRIB2 = convert to GRIB2
1559  * file1*GRIB1 = no-op (returns self)
1560  * file1/subsetter = subsets the GRIB1 file using the given GRIBSubsetter
1561 
1562  These can be combined, of course, and follow the usual Python
1563  order of precedence:
1564 
1565  * (file1*grid + file2*grid + file3/subsetter*grid)*GRIB1
1566 
1567  As with the GRIB2Op, there are also to_grib1() and to_grib2()
1568  methods which return self, and a GRIB2 conversion of self,
1569  respectively."""
1570  def __init__(self,action,*args):
1571  """!Creates a new GRIB1Op, passing all arguments to the
1572  superclass constructor.
1573  @param action,args Passed to GRIBOp.__init__"""
1574  super(GRIB1Op,self).__init__(action,*args)
1575  def to_grib1(self):
1576  """!Returns self. The GRIB1Op already produces a GRIB1 file."""
1577  return self
1578  def to_grib2(self):
1579  """!Returns a GRIB2Op that will make a GRIB2 version of this
1580  operation's output."""
1581  return GRIB2Op(action_grib1to2,self)
1582  def regridmerge(self,grid,other):
1583  """!Returns a GRIB1Op that will ask copygb to merge the other
1584  grid on top of this one.
1585  @param grid The target grid (GRIBGrid) for both objects
1586  @param other The other GRIB1 file producer to regrid. """
1587  if not isinstance(grid,GRIBGridBase):
1588  raise TypeError(
1589  'First argument to GRIB1Op.regridmerge must be a '
1590  'GRIBGridBase subclass, not a %s.'
1591  %(type(grid).__name__,))
1592  return GRIB1Op(action_grib1regridmerge,grid,self,other.to_grib1())
1593  def make_grbindex(self):
1594  """!Returns a GRIB1Op that will run grbindex and save the
1595  results, unless that has already been done."""
1596  return GRIB1Op(action_grbindex,self)
1597  def __div__(self,subsetter):
1598  """!Returns a GRIB1Op that will subset this one using the
1599  specified subsetter.
1600  @param subsetter a GRIBSubsetter to do the subsetting."""
1601  if isinstance(subsetter,GRIBSubsetter):
1602  return GRIB1Op(action_grib1subset,self,subsetter)
1603  return NotImplemented
1604  def __mul__(self,grid):
1605  """!If the grid is a GRIBGridBase, returns a GRIB1Op that will
1606  regrid this GRIB1Op's output to that grid. If grid is the
1607  special constant GRIB2, returns self.to_grib2. If it is the
1608  constant GRIB1, returns self.to_grib1. Otherwise, returns
1609  NotImplemented.
1610  @param grid Constants GRIB1, GRIB2, or a GRIBGridBase"""
1611  if isinstance(grid,GRIBGridBase):
1612  return GRIB1Op(action_grib1regrid,self,grid)
1613  elif grid is GRIB1:
1614  return self.to_grib1()
1615  elif grid is GRIB2:
1616  return self.to_grib2()
1617  return NotImplemented
1618  def __add__(self,other):
1619  """!If the argument is a GRIBOp, returns a GRIB1Op that will
1620  paste a GRIB1 version of that operations output onto this
1621  operation's output. For any other argument type, returns
1622  NotImplemented.
1623  @param other a GRIBOp whose output will be interpolated
1624  on top of this one."""
1625  if isinstance(other,GRIBOp):
1626  return GRIB1Op(action_grib1merge,self,other.to_grib1())
1627  return NotImplemented
1628 
1629 ########################################################################
1630 
1632  """!The GRIB1Fetcher is a GRIB1Op subclass that fetches a GRIB1
1633  file from a RegribMany."""
1634  def __init__(self,name):
1635  """!Creates a GRIB1Fetcher for the specified operation name.
1636  @param name the name of this operation for temporary filename
1637  generation"""
1638  self._name=name
1639  def input_valid(self,**kwargs):
1640  """!Calls kwargs['regribmany'].input_valid to determine if the
1641  specified keyword arguments make a valid input to the
1642  operation.
1643  @param kwargs Contains a regribmany key mapping to a RegribMany object.
1644  Is also passed to source.input_valid"""
1645  source=kwargs['regribmany']
1646  assert(source)
1647  return source.input_valid(self._name,**kwargs)
1648  def is_ready(self,*args,**kwargs):
1649  """!Calls kwargs['regribmany'].has_data to see if there is
1650  cached output from the operation.
1651  @param kwargs Contains a regribmany key mapping to a RegribMany object.
1652  Is also passed to source.has_data.
1653  @param args Positional arguments passed to source.has_data"""
1654  source=kwargs['regribmany']
1655  assert(source)
1656  return source.has_data(self._name,*args,**kwargs)
1657  def make(self,*args,**kwargs):
1658  """!Calls kwargs['regribmany'].make to produce the operation's
1659  output.
1660  @param kwargs Contains a regribmany key mapping to a RegribMany object.
1661  Is also passed to source.make.
1662  @param args Additional positional arguments are unused."""
1663  source=kwargs['regribmany']
1664  assert(source)
1665  return source.make(self._name,**kwargs)
1666 
1668  """!This subclass of GRIB1Op represents a GRIB1 file on disk that
1669  is ALREADY PRESENT. Its is_ready function is overridden to assume
1670  the file is always ready, and its "make" method simply returns
1671  self."""
1672  def __init__(self,grib1file,grib1index,grib1grid,
1673  nscenter=None,ewcenter=None,grib1grbindex=None):
1674  """!GRIB1File constructor.
1675  @param grib1file The file path.
1676  @param grib1index Path to the wgrib -s output
1677  @param grib1grid Grid information.
1678  @param nscenter,ewcenter Latitude and longitude of the grid center point,
1679  in degrees North and East
1680  @param grib1grbindex Path to the grbindex output."""
1681  super(GRIB1File,self).__init__(None)
1682  self._grib1file=grib1file
1683  self._grib1index=grib1index
1684  self._grib1grid=grib1grid
1685  self._grib1grbindex=grib1grbindex
1686  if not (ewcenter is None or float(ewcenter) is not None):
1687  raise TypeError('ewcenter must be None, or an int or float, not a %s (ewcenter=%s)'
1688  %(ewcenter.__class__.__name__,repr(ewcenter)))
1689  if not (nscenter is None or float(nscenter) is not None):
1690  raise TypeError('nscenter must be None, or an int or float, not a %s (nscenter=%s)'
1691  %(nscenter.__class__.__name__,repr(nscenter)))
1692  self._ewcenter=ewcenter
1693  self._nscenter=nscenter
1694  self._indexdata=None
1695  def input_valid(self,**kwargs):
1696  """!Returns True. The file is already present, so any kwargs
1697  make a valid input.
1698  @param kwargs Ignored."""
1699  return True
1700  def is_ready(self,*args,**kwargs):
1701  """!Returns True. The operation is ready to run because it has
1702  nothing to do: the file is already present.
1703  @param args,kwargs Ignored."""
1704  return True
1705  def make(self,*args,**kwargs):
1706  """!Returns self. This class represents a GRIB1 file, so it is
1707  its own output.
1708  @param args,kwargs Ignored."""
1709  return self
1710  def getnscenter(self):
1711  """!Returns the domain center latitude."""
1712  return self._nscenter
1713  def getewcenter(self):
1714  """!Returns the domain center longitude."""
1715  return self._ewcenter
1716  def getgrib1file(self):
1717  """!Returns the GRIB1 file's location."""
1718  return self._grib1file
1719  def getgrib1index(self):
1720  """!Returns the location of the file that stores the output of
1721  wgrib -s."""
1722  return self._grib1index
1723  def getgrib1grbindex(self):
1724  """!Returns the location of the file that stores the output of
1725  the grbindex program run on the GRIB1 file."""
1726  return self._grib1grbindex
1727  def setgrib1grbindex(self,here):
1728  """!Sets the location of the file that stores the output of
1729  the grbindex program run on the GRIB1 file."""
1730  self._grib1grbindex=here
1731  def getgrib1grid(self):
1732  """!Returns the GRIB1 grid information as a string."""
1733  return self._grib1grid
1734  def wgrib_s(self,regrib):
1735  """!Returns the output of wgrib -s run on this file, which may
1736  be from cached data.
1737  @param regrib a Regrib for data storage"""
1738  if self._indexdata is not None:
1739  return self._indexdata
1740  indexfile=self.grib1index
1741  if indexfile is None or not os.path.exists(indexfile):
1742  indexfile=regrib.indextemp(self.grib1file)
1743  index=runstr(regrib.wgrib['-s',self.grib1file])
1744  with open(indexfile,'wt') as f:
1745  f.write(index)
1746  else:
1747  with open(indexfile,'rt') as f:
1748  index=f.readall()
1749  self._indexdata=index.splitlines()
1750  return self._indexdata
1751 
1752  ##@property resultfile
1753  # Read-only: the path to the result file, in this case the GRIB1 file.
1754  resultfile=property(getgrib1file,None,None,
1755  'The path to the result file, in this case the GRIB1 file.')
1756 
1757  ##@property grib1file
1758  # Read-only: the path to the GRIB1 file which is assumed to already exist.
1759  grib1file=property(getgrib1file,None,None,
1760  'The path to the GRIB1 file which is assumed to already exist.')
1761 
1762  ##@property grib1index
1763  # Read-only: either None or the wgrib -s index file for the GRIB1 file.
1764  grib1index=property(getgrib1index,None,None,
1765  'Either None or the wgrib -s index file for the GRIB1 file.')
1766 
1767  ##@property grib1grbindex
1768  # Mutable property: either None or the grbindex binary index file for the GRIB1 file.
1769  grib1grbindex=property(getgrib1grbindex,setgrib1grbindex,None,
1770  'Either None or the grbindex binary index file for the GRIB1 file.')
1771 
1772  ##@property grib1grid
1773  # Read-only: either None or the copygb -g argument data for the GRIB1 file's grid.
1774  grib1grid=property(getgrib1grid,None,None,
1775  "Either None or the copygb -g argument data for the GRIB1 file's grid")
1776 
1777  ##@property nscenter
1778  # Read-only: the center latitude of this GRIB1 file in degrees North.
1779  nscenter=property(getnscenter,None,None,
1780  'Returns None or the center latitude of this GRIB1 file.')
1781 
1782  ##@property ewcenter
1783  # Read-only: the center longitude of this GRIB1 file in degrees East
1784  ewcenter=property(getewcenter,None,None,
1785  'Returns None or the center longitude of this GRIB1 file.')
1786 
1788  """!This subclass of GRIB2Op represents a GRIB2 file on disk that
1789  is ALREADY PRESENT. Its is_ready function is overridden to assume
1790  the file is always ready, and its "make" method simply returns
1791  self."""
1792  def __init__(self,grib2file,grib2index,grib2grid):
1793  """!GRIB2File constructor
1794  @param grib2file The grib2 file path.
1795  @param grib2index The grib 2 index file path.
1796  @param grib2grid GRIB2 grid information."""
1797  super(GRIB2File,self).__init__(None)
1798  self._grib2file=grib2file
1799  self._grib2index=grib2index
1800  self._grib2grid=grib2grid
1801  def is_ready(self,*args,**kwargs):
1802  """!Returns True. The operation is ready to run because it has
1803  nothing to do: the file is already present.
1804  @param args,kwargs Ignored."""
1805  return True
1806  def input_valid(self,**kwargs):
1807  """!Returns True. The file is already present, so any kwargs
1808  make a valid input.
1809  @param kwargs Ignored."""
1810  return True
1811  def make(self,*args,**kwargs):
1812  """!Returns self. This class represents a GRIB2 file, so it is
1813  its own output.
1814  @param args,kwargs Ignored."""
1815  return self
1816  def getgrib2file(self):
1817  """!Returns the GRIB2 file's location."""
1818  return self._grib2file
1819  def getgrib2index(self):
1820  """!This is a placeholder for future development. It returns
1821  the grib2index argument from the constructor."""
1822  return self._grib2index
1823  def getgrib2grid(self):
1824  """!This is a placeholder for future development. It returns
1825  the grib2grid argument from the constructor."""
1826  return self._grib2grid
1827 
1828  ##@property resultfile
1829  # The path to the result file, in this case the GRIB2 file.
1830  resultfile=property(getgrib2file,None,None,
1831  'The path to the result file, in this case the GRIB2 file.')
1832 
1833  ##@property grib2file
1834  # The path to the GRIB2 file which is assumed to already exist.
1835  grib2file=property(getgrib2file,None,None,
1836  'The path to the GRIB2 file which is assumed to already exist.')
1837 
1838  ##@property grib2index
1839  # This is a placeholder for future GRIB2 subsetting support
1840  grib2index=property(getgrib2index,None,None,
1841  'This is a placeholder for future GRIB2 subsetting support')
1842 
1843  ##@property grib2grid
1844  # This is a placeholder for future GRIB2 regridding support
1845  grib2grid=property(getgrib2grid,None,None,
1846  "This is a placeholder for future GRIB2 regridding support")
1847 
1849  """!This subclass of GRIB1Op and UpstreamFile represents a GRIB1
1850  file that is produced by an upstream workflow. The is_ready
1851  subroutine calls self.check to check the modification time and
1852  file size. The make subroutine copies the file to a local
1853  location."""
1854  def __init__(self,dstore,*args,**kwargs):
1855  """!UpstreamGRIB1 constructor
1856  @param dstore the produtil.datastore.Datastore for database info
1857  @param args,kwargs All other arguments passed to produtil.datastore.UpstreamFile.__init__"""
1858  UpstreamFile.__init__(self,dstore,*args,**kwargs)
1859  GRIB1Op.__init__(self,None)
1860  def is_ready(self,*args,**kwargs):
1861  """!Runs the check function on the upstream product, and
1862  returns its results. If the frominfo argument is in kwargs,
1863  it is passed as the first positional parameter to check.
1864  @param kwargs The frominfo argument to UpstreamFile.check()
1865  @param args Additional positional arguments are ignored."""
1866  if 'frominfo' in kwargs:
1867  return self.check(kwargs['frominfo'])
1868  else:
1869  return self.check()
1870  def input_valid(self,**kwargs):
1871  """!Returns True.
1872  @param kwargs Keyword arguments are ignored."""
1873  return True
1874  def make(self,regrib,*args,**kwargs):
1875  """!Calls deliver_file to copy the file to a temporary location
1876  decided by regrib.gribtemp. Returns a GRIB1File for that
1877  file.
1878  @param regrib a Regrib for data storage
1879  @param args,kwargs All other arguments are ignored."""
1880  loc=self.location
1881  (filename,index)=regrib.gribtemp('upstream.'+os.path.basename(loc))
1882  produtil.fileop.deliver_file(loc,filename,logger=regrib.logger)
1883  return GRIB1File(filename,None,None)
1884  ##@property resultfile
1885  # The path to the result file, in this case self.location.
1886  resultfile=property(UpstreamFile.getlocation,None,None,
1887  'The path to the result file, in this case self.location.')
1888 
1890  """!This object produces a GRIB1Op from a call to a Task object's
1891  Task.product. This is the class that underlies the implementation
1892  of igrb1."""
1893  def __init__(self,task,**kwargs):
1894  """!Creates a GRIB1Selector for the specified task.
1895 
1896  @param task The task whose products function is called.
1897  @param kwargs All other arguments are sent to task.products."""
1898  self._task=task
1899  self._kwargs=dict(kwargs)
1900  def is_ready(self,**kwargs):
1901  """!Returns True if the task's product is available.
1902  @param kwargs All keyword arguments are sent to select()"""
1903  product=self.select(kwargs)
1904  return product.is_available()
1905  def input_valid(self,**kwargs):
1906  """!Returns True if select() is able to find a product and
1907  False if NoProductError is raised.
1908  @param kwargs Keyword arguments are passed to select()"""
1909  try:
1910  product=self.select(kwargs)
1911  return True
1912  except NoProductError:
1913  return False
1914  def make(self,regrib,**kwargs):
1915  """!Calls self.select(kwargs) to get the product, and calls
1916  make on the result.
1917  @param regrib A Regrib for data storage
1918  @param kwargs Keyword arguments are passed to select()"""
1919  product=self.select(kwargs)
1920  if not isinstance(product,GRIB1Op):
1921  raise GRIBInputError('Selected product is not a GRIB product.')
1922  return product.make(regrib,**kwargs)
1923  def select(self,kwargs):
1924  """!Attempts to attain a Product from the supplied Task.
1925 
1926  @protected
1927  Calls a Task's products function to get the Product of
1928  interest. The kwargs is a dict of keyword arguments to pass
1929  to task.products. Those will override any keyword arguments
1930  that were sent to the constructor. If more than one Product
1931  is yielded, then ProductAmbiguityError is raised. If no
1932  Product is yielded, NoProductError is raised. If the returned
1933  Product is not a GRIBBase, TypeError is raised. Otherwise,
1934  the result is returned.
1935 
1936  @param kwargs a dict to pass to task.products"""
1937  arg=dict(self._kwargs)
1938  arg.update(kwargs)
1939  products=[p for p in self._task.products(**arg)]
1940  if len(products)>1:
1941  raise ProductAmbiguityError('Specified arguments produced more than one product.')
1942  elif len(products)==0:
1943  raise NoProductError('Specified arguments produced no product.')
1944  else:
1945  p=products[0]
1946  if not isinstance(p,GRIBBase):
1947  raise TypeError(
1948  'ERROR: in GRIB1Selector, a Task.products call '
1949  'returned something that was not a GRIBBase object. '
1950  'It returned a %s %s.'%(type(p).__name__,repr(p)))
1951  return p
1952  def __repr__(self):
1953  """!Returns a Pythonic representation of self"""
1954  return '%s(%s)'%(self.__class__.__name__,self._task.__class__.__name__)
1955 
1956 def igrb1(task,**kwargs):
1957  """!This is a convenient alias for the GRIB1Selector constructor.
1958  @param task,kwargs Passed to GRIB1Selector.__init__()"""
1959  return GRIB1Selector(task,**kwargs)
1960 
1961 ########################################################################
1962 
1964  """!This class represents a GRIB2 file that is produced by this
1965  workflow. It is a direct subclass of both GRIB2File and
1966  FileProduct."""
1967  def __init__(self,dstore,*args,**kwargs):
1968  """!Creates a new GRIB2Product.
1969 
1970  @param dstore The dstore is the produtil.datastore.Datastore
1971  for database storage.
1972  @param args,kwargs All other arguments are passed on to
1973  FileProduct's constructor.
1974  @note The GRIB2File constructor is initialized with None for
1975  the file, index and grid."""
1976  assert('location' in kwargs and kwargs['location']!='' )
1977  FileProduct.__init__(self,dstore,*args,**kwargs)
1978  GRIB2File.__init__(self,None,None,None)
1979  self._indexdata=None
1980  assert(self.location is not None and self.location!='')
1981  def input_valid(self,**kwargs):
1982  """!Returns True. Since this object is already its product,
1983  any kwargs make a valid input.
1984  @param kwargs Ignored."""
1985  return True
1986  def is_ready(self,*args,**kwargs):
1987  """!Calls self.check to see if the product is available.
1988 
1989  @param args Additional positional arguments are ignored.
1990  @param kwargs Additional keyword arguments. If frominfo is in
1991  the kwargs, it is passed as the first positional argument to
1992  check."""
1993  if 'frominfo' in kwargs:
1994  return self.check(kwrargs['frominfo'])
1995  else:
1996  return self.check()
1997  def make(self,regrib,*args,**kwargs):
1998  """!Calls deliver_file to copy the file to a new temporary
1999  location from regrib.gribtemp. Returns a GRIB2File for that
2000  temporary file.
2001  @param regrib A Regrib for data storage
2002  @param args,kwargs All other arguments are ignored."""
2003  loc=self.location
2004  (filename,index)=regrib.gribtemp('prod.'+os.path.basename(loc))
2005  produtil.fileop.deliver_file(loc,filename,logger=regrib.logger)
2006  return GRIB2File(filename,None,None)
2007  def setgrib2grid(self,grid):
2008  """!Sets the grib2 grid information.
2009  @param grid GRIB2 grid information."""
2010  if grid is None or grid=='' or grid=='None': return
2011  self['grib2grid']=grid
2012  def getgrib2grid(self):
2013  """!Returns the grib2 grid information."""
2014  return self.get('grib2grid',None)
2015  def delgrib2grid(self):
2016  """!Clears the grib2 grid information."""
2017  del self['grib2grid']
2018 
2019  ##@property grib2grid
2020  # The GRIB2 grid information if known.
2021  grib2grid=property(getgrib2grid,setgrib2grid,delgrib2grid,
2022  """The GRIB2 grid information if known.""")
2023 
2024  def setgrib2index(self,index):
2025  """!Sets the grib2 index information."""
2026  if index is None or index=='' or index=='None': return
2027  self['grib2index']=index
2028  def getgrib2index(self):
2029  """!Gets the grib2 index information, or returns None if unknown."""
2030  return self.get('grib2index',None)
2031  def delgrib2index(self):
2032  """!Cleares the stored information about the index location.
2033  Does NOT delete the index file."""
2034  del self['grib2index']
2035 
2036  ##@property grib2index
2037  # The disk location of the GRIB2 index file.
2038  grib2index=property(getgrib2index,setgrib2index,delgrib2index,
2039  """The disk location of the GRIB2 index file.""")
2040 
2041  def getgrib2file(self):
2042  """!Returns the location of the GRIB2 file from self.location."""
2043  return self.location
2044  def setgrib2file(self,val):
2045  """!Sets the location of the GRIB2 file by setting self.location."""
2046  self.location=val
2047 
2048  ##@property grib2file
2049  # The location of the grib2 file, synonym for self.location.
2050  grib2file=property(getgrib2file,setgrib2file,None,
2051  """Synonym for self.location""")
2052 
2053  ##@property resultfile
2054  # The location of the grib2 file, synonym for self.location.
2055  resultfile=property(getgrib2file,setgrib2file,None,
2056  """Synonym for self.location""")
2057 
2058  def deliver(self,location=None,index=None,grbindex=None,frominfo=None,
2059  keep=True,logger=None):
2060  """!Delivers a GRIB2 file to its destination. May also deliver
2061  other files associated with that GRIB2 file.
2062 
2063  @param location Delivery location.
2064  @param index Index file delivery location
2065  @param grbindex Ignored.
2066  @param frominfo Either a source filename, or a GRIB2Op.
2067  @param keep If True, the source file will be copied instead of moved.
2068  @param logger A logging.Logger for log information."""
2069  if isinstance(frominfo,basestring):
2070  # Delivering from a specified file. Deliver as a FileProduct:
2071  FileProduct.deliver(self,location=location,frominfo=frominfo,
2072  keep=keep)
2073  return
2074  elif not isinstance(frominfo,GRIB2Op):
2075  raise TypeError(
2076  'GRIB2Product.deliver requires a frominfo that is either '
2077  'a string filename or a GRIB2Op.')
2078 
2079  # Get from/to information in a transaction for speed:
2080  with self.dstore.transaction():
2081  loc=location if(location is not None) else self.location
2082  if loc is None:
2084  '%s: no location known when delivering product. '
2085  'Specify a location to deliver().'%(self.did))
2086  (fromindex,toindex)=(None,None)
2087  try:
2088  fromindex=frominfo.grib2index
2089  except AttributeError, KeyError: pass
2090  try:
2091  fromloc=frominfo.grib2file
2092  except AttributeError, KeyError:
2093  fromloc=frominfo.resultfile
2094  toindex=str(index) if (index is not None) else '%s.wgrib_s'%(loc,)
2095 
2096  # Deliver the GRIB2 file and the text and binary index files:
2097  assert(fromloc is not None and fromloc!='')
2098  assert(loc is not None and loc!='')
2099  produtil.fileop.deliver_file(fromloc,loc,keep=keep)
2100 
2101  haveindex=False
2102  if fromindex is not None and toindex is not None and \
2103  produtil.fileop.isnonempty(fromindex):
2104  produtil.fileop.deliver_file(fromindex,toindex,keep=keep)
2105  haveindex=True
2106 
2107  # Store grid, index location, etc. in a transaction for speed
2108  # and also to ensure all records are updated or none are:
2109  with self.dstore.transaction():
2110  self.location=loc
2111  if haveindex: self.grib2index=toindex
2112  try:
2113  self.grib2grid=frominfo.grib2grid
2114  except AttributeError,KeyError: pass
2115  self.available=True
2116  self.call_callbacks(logger=logger)
2117 
2118  def undeliver(self):
2119  """!Deletes the delivered GRIB2 file and discards the index and
2120  grid information."""
2121  loc=self.location
2122  if loc is not None and loc!='':
2124  index=self.grib2index
2125  with self.dstore.transaction():
2126  del self.grib2index
2127  del self.grib2grid
2128  self.available=False
2129 
2130 
2131 ########################################################################
2133  """!This class represents a GRIB1 file produced by this workflow.
2134  It stores grid information, if available, and will also deliver an
2135  index file if one exists. It is a direct subclass of both
2136  FileProduct and GRIB1File."""
2137  def __init__(self,dstore,*args,**kwargs):
2138  """!Creates a new GRIB1Product.
2139 
2140  @param dstore The dstore is the produtil.datastore.Datastore.
2141  @param args Positional arguments, passed to the FileProduct
2142  constructor.
2143  @param kwargs Keyword arguments. The kwargs must specify the
2144  file location as a non-empty string.
2145 
2146  @note The GRIB1File is initialized with the various indexes
2147  and grid missing (None)."""
2148  assert('location' in kwargs and kwargs['location']!='' )
2149  FileProduct.__init__(self,dstore,*args,**kwargs)
2150  GRIB1File.__init__(self,None,None,None)
2151  self._indexdata=None
2152  assert(self.location is not None and self.location!='')
2153  def input_valid(self,**kwargs):
2154  """!Returns True. This object is its own product, so any
2155  kwargs are valid.
2156  @param kwargs Keyword arguments are ignored."""
2157  return True
2158  def is_ready(self,*args,**kwargs):
2159  """!Runs self.check and returns the result.
2160  @param args Positional arguments are ignored.
2161  @param kwargs Keyword arguments. If frominfo is in kwargs, it
2162  is sent as the first positional argument to check."""
2163  if 'frominfo' in kwargs:
2164  return self.check(kwargs['frominfo'])
2165  else:
2166  return self.check()
2167  def make(self,regrib,*args,**kwargs):
2168  """!Gets a temporary filename from gribtemp, and copies the
2169  GRIB1 file there. Returns a new GRIB1File object for that
2170  file.
2171  @param regrib A Regrib for data storage
2172  @param args,kwargs All other arguments are ignored."""
2173  loc=self.location
2174  (filename,index)=regrib.gribtemp('prod.'+os.path.basename(loc))
2175  produtil.fileop.deliver_file(loc,filename,logger=regrib.logger)
2176  return GRIB1File(filename,None,None)
2177 
2178  def setgrib1grid(self,grid):
2179  """!Sets the GRIB1 grid information; modifies the grib1grid
2180  metadata in the datastore.
2181  @param grid the new grid information"""
2182  self['grib1grid']=grid
2183  def getgrib1grid(self):
2184  """!Returns the GRIB1 grid information from the grib1grid
2185  metadata in the datastore."""
2186  return self.get('grib1grid',None)
2187  def delgrib1grid(self):
2188  """!Discards GRIB1 grid information by removing the grib1grid
2189  metadata from the datastore."""
2190  del self['grib1grid']
2191 
2192  ##@property grib1grid
2193  # The GRIB1 grid (GDS) information if known.
2194  grib1grid=property(getgrib1grid,setgrib1grid,delgrib1grid,
2195  """The GRIB1 grid (GDS) information if known.""")
2196 
2197  def setgrib1grbindex(self,index):
2198  """!Sets the output location of grbindex to the given location,
2199  and sets the grib1grbindex metadata value.
2200  @param index Location of the grbindex output."""
2201  self['grib1grbindex']=index
2202  def getgrib1grbindex(self):
2203  """!Returns the output location of grbindex from the
2204  grib1grbindex metadata value."""
2205  return self.get('grib1grbindex',None)
2206  def delgrib1grbindex(self):
2207  """!Cleares the stored information about the grbindex binary
2208  index file location for this GRIB1 product by deleting the
2209  grib1grbindex metadata value. Does NOT delete the grbindex
2210  file."""
2211  del self['grib1grbindex']
2212 
2213  ##@property grib1grbindex
2214  # The disk location of the GRIB1 grbindex binary index file.
2215  grib1grbindex=property(getgrib1grbindex,setgrib1grbindex,delgrib1grbindex,
2216  """The disk location of the GRIB1 grbindex binary index file.""")
2217 
2218  def setgrib1index(self,index):
2219  """!Sets the output location of wgrib -s and sets the
2220  grib1index metadata value.
2221  @param index Location of the wgrib -s output."""
2222  self['grib1index']=index
2223  def getgrib1index(self):
2224  """!Returns the output location of wgrib -s from the grib1index
2225  metadata value."""
2226  return self.get('grib1index',None)
2227  def delgrib1index(self):
2228  """!Cleares the stored information about the index location.
2229  Does NOT delete the index file."""
2230  del self['grib1index']
2231 
2232  ##@property grib1index
2233  # Location of the wgrib -s output.
2234  grib1index=property(getgrib1index,setgrib1index,delgrib1index,
2235  """The disk location of the GRIB1 index file, from wgrib -s.""")
2236 
2237  def getgrib1file(self):
2238  """!Returns the GRIB1 file location from self.location."""
2239  return self.location
2240  def setgrib1file(self,val):
2241  """!Sets the GRIB1 file location. Same as setting self.location.
2242  @param val New file location."""
2243  self.location=val
2244 
2245  ##@property grib1file
2246  # GRIB1 file location, synonym for self.location
2247  grib1file=property(getgrib1file,setgrib1file,None,
2248  """Synonym for self.location""")
2249 
2250  ##@property resultfile
2251  # GRIB1 file location, synonym for self.location
2252  resultfile=property(getgrib1file,setgrib1file,None,
2253  """Synonym for self.location""")
2254 
2255  def deliver(self,location=None,index=None,grbindex=None,
2256  frominfo=None,keep=True,logger=None):
2257  """!Delivers the GRIB1 data, and possibly the various index
2258  files as well.
2259 
2260  If frominfo is supplied, then that file is
2261  delivered, and no other action is performed. Otherwise, the
2262  file is delivered from self.location to the supplied location,
2263  the grib1index is delivered to the same location with an added
2264  ".wgrib_s" extension and the grib1grbindex is delivered with a
2265  ".grbindex" extension.
2266 
2267  @param location GRIB file delivery location
2268  @param index Delivery wgrib -s output location
2269  @param grbindex Where to deliver the output of grbindex
2270  @param frominfo Source information; see above.
2271  @param keep If False, source files can be moved instead of copied.
2272  @param logger a logging.Logger for log messages."""
2273  if isinstance(frominfo,basestring):
2274  # Delivering from a specified file. Deliver as a FileProduct:
2275  FileProduct.deliver(
2276  self,location=location,frominfo=frominfo,keep=keep)
2277  return
2278  elif not isinstance(frominfo,GRIB1Op):
2279  raise TypeError('GRIB1Product.deliver requires a frominfo '
2280  'that is either a string filename or a GRIB1Op.')
2281 
2282  # Get from/to information in a transaction for speed:
2283  with self.dstore.transaction():
2284  loc=location if(location is not None) else self.location
2285  if loc is None:
2287  '%s: no location known when delivering '
2288  'product. Specify a location to deliver().'
2289  %(self.did))
2290  (fromindex,toindex)=(None,None)
2291  try:
2292  fromindex=frominfo.grib1index
2293  except AttributeError, KeyError: pass
2294  try:
2295  fromloc=frominfo.grib1file
2296  except AttributeError, KeyError:
2297  fromloc=frominfo.resultfile
2298  try:
2299  fromgrbindex=frominfo.grib1grbindex
2300  except AttributeError, KeyError:
2301  if fromloc.find('hwrftrk')>=0:
2302  raise NoIndexError('hwrf track input has no grib1grbindex')
2303  if fromgrbindex is None and fromloc.find('hwrftrk')>=0:
2304  raise NoIndexError('hwrf track input has a grib1grbindex=None')
2305  toindex=str(index) if (index is not None) else '%s.wgrib_s'%(loc,)
2306  togrbindex=str(grbindex) if (grbindex is not None) \
2307  else '%s.grbindex'%(loc,)
2308 
2309  # Deliver the GRIB1 file and the text and binary index files:
2310  assert(fromloc is not None and fromloc!='')
2311  assert(loc is not None and loc!='')
2312  produtil.fileop.deliver_file(fromloc,loc,keep=keep,logger=logger)
2313 
2314  haveindex=False
2315  if fromindex is not None and toindex is not None and \
2316  produtil.fileop.isnonempty(fromindex):
2318  fromindex,toindex,keep=keep,logger=logger)
2319  haveindex=True
2320 
2321  havegrbindex=False
2322  if fromgrbindex is not None and togrbindex is not None and \
2323  produtil.fileop.isnonempty(fromgrbindex):
2325  fromgrbindex,togrbindex,keep=keep,logger=logger)
2326  havegrbindex=True
2327 
2328  if fromloc.find('hwrftrk')>=0:
2329  # print 'fromgrbindex = %s'%(repr(fromgrbindex),)
2330  # print 'togrbindex = %s'%(repr(togrbindex),)
2331  # if fromgrbindex is not None:
2332  # print 'isnonempty = %s'%(repr(produtil.fileop.isnonempty(fromgrbindex),))
2333  assert(havegrbindex)
2334 
2335  # Store grid, index location, etc. in a transaction for speed
2336  # and also to ensure all records are updated or none are:
2337  with self.dstore.transaction():
2338  self.location=loc
2339  if haveindex: self.grib1index=toindex
2340  if havegrbindex: self.grib1grbindex=togrbindex
2341  try:
2342  self.grib1grid=frominfo.grib1grid
2343  except AttributeError,KeyError: pass
2344  self.available=True
2345  self.call_callbacks(logger=logger)
2346 
2347  def undeliver(self):
2348  """!Undoes the effect of deliver(), removing the destination
2349  index files and GRIB file."""
2350  loc=self.location
2351  if loc is not None and loc!='':
2353  index=self.grib1index
2354  if index: produtil.fileop.remove_file(index)
2355  grbindex=self.grib1grbindex
2356  if grbindex: produtil.fileop.remove_file(index)
2357  with self.dstore.transaction():
2358  del self.grib1grbindex
2359  del self.grib1index
2360  del self.grib1grid
2361  self.available=False
def getgrib1grid(self)
Returns the GRIB1 (wgrib) style grid information, as sent to the constructor's grib1grid argument...
Definition: regrib.py:1182
def make(self, regrib, kwargs)
Runs the action specified in the constructor, providing as arguments regrib, and the result of runnin...
Definition: regrib.py:1285
def deliver_file
This moves or copies the file "infile" to "outfile" in a unit operation; outfile will never be seen i...
Definition: fileop.py:359
def delgrib1index(self)
Cleares the stored information about the index location.
Definition: regrib.py:2227
def make(self, args, kwargs)
Calls kwargs['regribmany'].make to produce the operation's output.
Definition: regrib.py:1657
def getgrib1sub(self)
Returns an iterator that takes as its only argument an array of lines of wgrib -s output...
Definition: regrib.py:1402
def set_workprefix
Sets the work directory and filename prefix to the given value, or sets it to a reasonable default if...
Definition: regrib.py:206
def make(self, regrib, args, kwargs)
Calls deliver_file to copy the file to a temporary location decided by regrib.gribtemp.
Definition: regrib.py:1874
def setlog(self, val)
Sets the logger.Logging object to use for logging messages.
Definition: regrib.py:117
def getprodargs(self)
Returns the array of arguments to send to the products iterators.
Definition: regrib.py:123
def action_grib1regrid(op, regrib, infile, ingrid, args, kwargs)
Regrids a GRIB1 file.
Definition: regrib.py:989
This class represents a GRIB2 file that is produced by this workflow.
Definition: regrib.py:1963
Runs regrib operations on many input times, sending output to an hwrf.gribtask.GRIBTask.
Definition: regrib.py:311
def getgrib2grid(self)
This is a placeholder for future development.
Definition: regrib.py:1823
def __init__
GRIBSubsetter constructor.
Definition: regrib.py:1368
def getgrib1grid(self)
Returns the GRIB1 grid information as a string.
Definition: regrib.py:1731
def setlon(self, val)
Sets the point's longitude.
Definition: regrib.py:1319
Superclass of errors used by Regrib.
Definition: exceptions.py:248
def __init__(self, name)
GRIBSubsetterFetcher constructor.
Definition: regrib.py:1431
def GRIBOps(self)
Iterates over all GRIBOp operations yielding tuples containing the name and operation.
Definition: regrib.py:526
def __init__(self, action, args)
Creates a new GRIB1Op, passing all arguments to the superclass constructor.
Definition: regrib.py:1570
def input_valid(self, kwargs)
Returns the logical "and" of input_valid(**kwargs) called on all subobjects.
Definition: regrib.py:1497
def getprodkwargs(self)
Returns a dict of keyword arguments to send to the products iterators.
Definition: regrib.py:127
def getlog(self)
Returns the logger.Logging object to use for logging messages, or None if no logger was provided to t...
Definition: regrib.py:112
def delgrib1grbindex(self)
Cleares the stored information about the grbindex binary index file location for this GRIB1 product b...
Definition: regrib.py:2206
This is the abstract base class for all GRIB1 and GRIB2 files and operators.
Definition: regrib.py:1462
def getgrib1grbindex(self)
Returns the output location of grbindex from the grib1grbindex metadata value.
Definition: regrib.py:2202
def getgrib2index(self)
This is a placeholder for future development.
Definition: regrib.py:1819
def input_valid(self, name, kwargs)
Determines if it is possible to run the specified operation with the given keyword arguments...
Definition: regrib.py:656
def undeliver(self)
Deletes the delivered GRIB2 file and discards the index and grid information.
Definition: regrib.py:2118
Raised when delivering data, but no location is provided.
Definition: datastore.py:82
A subclass of Product that represents file delivery.
Definition: datastore.py:856
The GRIB1Fetcher is a GRIB1Op subclass that fetches a GRIB1 file from a RegribMany.
Definition: regrib.py:1631
def wgrib_s(self, regrib)
Returns the output of wgrib -s run on this file, which may be from cached data.
Definition: regrib.py:1734
def __init__
GRIB1File constructor.
Definition: regrib.py:1673
def names(self)
Iterates over the names provided to self.add(name,...) in the order they were added.
Definition: regrib.py:703
def remove_file
Deletes the specified file.
Definition: fileop.py:251
def deliver
Delivers a GRIB2 file to its destination.
Definition: regrib.py:2059
Base class for the regridding object tree.
Definition: regrib.py:1123
def getgrib1file(self)
Returns the GRIB1 file location from self.location.
Definition: regrib.py:2237
def has_data(self, name, kwargs)
Returns True if there is a cached result for the specified operation.
Definition: regrib.py:625
def has_name(self, name)
Returns True if an operation by the given name exists.
Definition: regrib.py:501
def getgrib2file(self)
Returns the GRIB2 file's location.
Definition: regrib.py:1816
def input_valid(self, kwargs)
Calls kwargs['regribmany'].input_valid to determine if the specified keyword arguments make a valid i...
Definition: regrib.py:1639
def input_valid(self, kwargs)
Calls kwargs['regribmany'].input_valid to see if the kwargs make a valid input.
Definition: regrib.py:1435
def getcnvgrib_g12(self)
Returns the cnvgrib -p32 -g12 command, which should be an ImmutableRunner.
Definition: regrib.py:100
def gribtemp
Returns a tuple (grib,index) containing a suggested GRIB1/2 filename and index filename.
Definition: regrib.py:285
def action_grib2to1(op, regrib, infile, args, kwargs)
Converts GRIB2 files to GRIB1.
Definition: regrib.py:801
def action_grbindex(op, regrib, ingrib, task=None, kwargs)
Runs the grbindex program on a GRIB1 file.
Definition: regrib.py:884
grib2index
This is a placeholder for future GRIB2 subsetting support.
Definition: regrib.py:1840
def indextemp(self, grib)
Generates a temporary filename to use for the specified GRIB1/2 file's index file.
Definition: regrib.py:269
def is_grid(self, name)
Returns True if the name corresponds to a grid.
Definition: regrib.py:532
This subclass of GRIBOp produces GRIB1 files.
Definition: regrib.py:1552
def make(self, args, kwargs)
Calls kwargs['regribmany'].make to produce the grid.
Definition: regrib.py:1240
This subclass of GRIBOp produces GRIB2 files, and can be converted to GRIB1 via obj*GRIB1 or obj...
Definition: regrib.py:1527
def __init__(self, name, action, args)
Creates a new GRIBGridCompute with the given name and action.
Definition: regrib.py:1253
def to_grib2(self)
Returns a GRIB2Op that will make a GRIB2 version of this operation's output.
Definition: regrib.py:1578
def is_ready(self, args, kwargs)
Returns True.
Definition: regrib.py:1801
def to_grib2(self)
Returns self (converting GRIB2 to GRIB2 is a no-op)
Definition: regrib.py:1538
def undeliver(self)
Undoes the effect of deliver(), removing the destination index files and GRIB file.
Definition: regrib.py:2347
def __init__(self, action, args)
GRIB2Op constructor.
Definition: regrib.py:1531
def action_grib1to2(op, regrib, infile, args, kwargs)
Converts GRIB1 file to GRIB2.
Definition: regrib.py:776
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1806
def input_valid(self, args, kwargs)
Returns the logical "or" of input_valid(**kwargs) called on all subobjects.
Definition: regrib.py:1275
def action_grib1merge(op, regrib, in1, in2, kwargs)
Merges two GRIB1 files that must already have the same grid.
Definition: regrib.py:921
def checkrun(arg, logger=None, kwargs)
This is a simple wrapper round run that raises ExitStatusException if the program exit status is non-...
Definition: run.py:398
def tempfile
Creates a name of a temporary file.
Definition: regrib.py:296
def is_ready(self, args, kwargs)
Runs the check function on the upstream product, and returns its results.
Definition: regrib.py:1860
def make(self, args, kwargs)
Returns self.
Definition: regrib.py:1395
def is_ready(self, args, kwargs)
Calls kwargs['regribmany'].has_data to see if the specified operation has produced its grid...
Definition: regrib.py:1222
def getgrib1file(self)
Returns the GRIB1 file's location.
Definition: regrib.py:1716
def subset(self, name)
Returns a GRIBSubsetterFetcher object that will grab the GRIB subsetter with the given name...
Definition: regrib.py:542
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1981
def is_ready(self, args, kwargs)
Calls self.check to see if the product is available.
Definition: regrib.py:1986
def action_grib1regridmerge(op, regrib, grid, in1, in2, kwargs)
Performs regridding and merges two files in a single operation.
Definition: regrib.py:828
def getwgrib(self)
Returns the wgrib command, which should be an ImmutableRunner.
Definition: regrib.py:108
def setgrib2index(self, index)
Sets the grib2 index information.
Definition: regrib.py:2024
def setgrib2grid(self, grid)
Sets the grib2 grid information.
Definition: regrib.py:2007
def make(self, kwargs)
Runs this Regrib object's operator's make function with the given keyword arguments, returning the results.
Definition: regrib.py:254
def to_com
Requests delivery to the com directory in file "location" of operation "name".
Definition: regrib.py:559
def __init__(self, _copy=None, workprefix=None, kwargs)
Creats a new RegribMany.
Definition: regrib.py:452
A GRIBBase that subsets GRIB files, keeping only certain parameters.
Definition: regrib.py:1366
def is_ready(self, args, kwargs)
Returns True.
Definition: regrib.py:1385
def getlat(self)
Returns the point's latitude.
Definition: regrib.py:1309
def setsync_frequently(self, flag)
Sets the sync_frequently flag.
Definition: regrib.py:132
A shell-like syntax for running serial, MPI and OpenMP programs.
Definition: run.py:1
def setgrib2file(self, val)
Sets the location of the GRIB2 file by setting self.location.
Definition: regrib.py:2044
def reset
Discards all temporary data, and re-initializes this object for the specified result name...
Definition: regrib.py:219
def make(self, regrib, kwargs)
Calls self.select(kwargs) to get the product, and calls make on the result.
Definition: regrib.py:1914
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1870
def getgrib1index(self)
Returns the output location of wgrib -s from the grib1index metadata value.
Definition: regrib.py:2223
def __div__(self, subsetter)
Returns a GRIB1Op that will subset this one using the specified subsetter.
Definition: regrib.py:1597
def make_grbindex(self)
Returns a GRIB1Op that will run grbindex and save the results, unless that has already been done...
Definition: regrib.py:1593
def args(self)
Iterates over all child GRIBBase objects.
Definition: regrib.py:1478
def __enter__(self)
Has no effect.
Definition: regrib.py:484
This subclass of GRIB2Op represents a GRIB2 file on disk that is ALREADY PRESENT. ...
Definition: regrib.py:1787
This is the abstract base class of Regrib and RegribMany and should not be instantiated directly...
Definition: regrib.py:36
def get
Alias for self.meta() Returns the value of the specified metadata key or returns default if it is uns...
Definition: datastore.py:637
def is_ready(self, args, kwargs)
Calls kwargs['regribmany'].has_data to see if there is cached output from the operation.
Definition: regrib.py:1648
def make(self, regrib, args, kwargs)
Gets a temporary filename from gribtemp, and copies the GRIB1 file there.
Definition: regrib.py:2167
This class represents a GRIBGrid that must be computed from some other input, usually a GRIB file...
Definition: regrib.py:1249
This subclass of GRIB1Op and UpstreamFile represents a GRIB1 file that is produced by an upstream wor...
Definition: regrib.py:1848
def isnonempty(filename)
Returns True if the filename refers to an existent file that is non-empty, and False otherwise...
Definition: fileop.py:333
def is_ready(self, args, kwargs)
Runs self.check and returns the result.
Definition: regrib.py:2158
def is_ready(self, args, kwargs)
Returns the logical "or" of is_ready(*args,**kwargs) called on all subobjects.
Definition: regrib.py:1265
def getgrib2file(self)
Returns the location of the GRIB2 file from self.location.
Definition: regrib.py:2041
Stores products and tasks in an sqlite3 database file.
Definition: datastore.py:1
location
Read-write property, an alias for getlocation() and setlocation().
Definition: datastore.py:563
def to_intercom
Requests delivery to the intercom directory in file "location" of operation "name".
Definition: regrib.py:582
def __init__(self, task, kwargs)
Creates a GRIB1Selector for the specified task.
Definition: regrib.py:1893
def make(self, args, kwargs)
Returns self.
Definition: regrib.py:1705
def setgrib1grbindex(self, index)
Sets the output location of grbindex to the given location, and sets the grib1grbindex metadata value...
Definition: regrib.py:2197
def __repr__(self)
A string representation of this GRIB operation.
Definition: regrib.py:1522
def __init__(self, action, args)
Creates a GRIBOp that has a number of child GRIBBase objects, with a specified action to perform in t...
Definition: regrib.py:1465
def is_ready(self, kwargs)
Returns True if this Regrib object's operator is "ready" (according to is_ready) and False otherwise...
Definition: regrib.py:240
This object produces a GRIB1Op from a call to a Task object's Task.product.
Definition: regrib.py:1889
def is_ready(self, args, kwargs)
Returns True.
Definition: regrib.py:1165
This abstract base class represents something that is able to produce a GRIBGrid object when make() i...
Definition: regrib.py:1147
grib1grid
Read-only: either None or the copygb -g argument data for the GRIB1 file's grid.
Definition: regrib.py:1774
def getlon(self)
Returns the point's longitude.
Definition: regrib.py:1312
def getgrib2grid(self)
Returns the grib2 grid information.
Definition: regrib.py:2012
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1390
def setgrib1index(self, index)
Sets the output location of wgrib -s and sets the grib1index metadata value.
Definition: regrib.py:2218
def action_grib1subset(op, regrib, infile, subsetter, args, kwargs)
Subsets a GRIB1 file.
Definition: regrib.py:1020
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1169
def __exit__(self, etype, evalue, traceback)
Has no effect.
Definition: regrib.py:492
def to_grib1(self)
Returns a GRIB2Op that converts this operation's output to GRIB1.
Definition: regrib.py:1535
def make(self, name, kwargs)
Executes the operation previously stored in self.add(), passing it the given keyword arguments...
Definition: regrib.py:672
grib1file
Read-only: the path to the GRIB1 file which is assumed to already exist.
Definition: regrib.py:1759
def getgrib1index(self)
Returns the location of the file that stores the output of wgrib -s.
Definition: regrib.py:1719
def make(self, args, kwargs)
Calls kwargs['regribmany'].make to produce the subsetter.
Definition: regrib.py:1451
def is_ready(self, kwargs)
Returns True if the task's product is available.
Definition: regrib.py:1900
def reset(self)
Erases all cached results.
Definition: regrib.py:506
def input_valid(self, kwargs)
Returns True if select() is able to find a product and False if NoProductError is raised...
Definition: regrib.py:1905
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:1695
def add(self, name, arg, kwargs)
Adds the given generator "arg" under the specified name (in "name") to this object.
Definition: regrib.py:548
def is_ready(self, name, kwargs)
Determines if the specified operation is ready.
Definition: regrib.py:641
Represents a specific location on the earth as a latitude, longitude pair.
Definition: regrib.py:1300
def is_ready(self, args, kwargs)
Returns True.
Definition: regrib.py:1700
def select(self, kwargs)
Attempts to attain a Product from the supplied Task.
Definition: regrib.py:1923
def __init__(self, dstore, args, kwargs)
UpstreamGRIB1 constructor.
Definition: regrib.py:1854
def copy(self)
Returns a copy of self with no cached results.
Definition: regrib.py:510
def getgrib1grbindex(self)
Returns the location of the file that stores the output of the grbindex program run on the GRIB1 file...
Definition: regrib.py:1723
def getsync_frequently(self)
Returns the value of the sync_frequently flag.
Definition: regrib.py:136
This class represents a GRIB1 file produced by this workflow.
Definition: regrib.py:2132
def __init__
Creates a RegribBase.
Definition: regrib.py:41
This subclass of GRIB1Op represents a GRIB1 file on disk that is ALREADY PRESENT. ...
Definition: regrib.py:1667
def getaction(self)
Returns the action, a function or callable object.
Definition: regrib.py:1475
grib1index
Read-only: either None or the wgrib -s index file for the GRIB1 file.
Definition: regrib.py:1764
def make(self, args, kwargs)
Returns self.
Definition: regrib.py:1811
def nonGRIBOps(self)
Iterates over all non-GRIBOp operations yielding tuples containing the name and operation.
Definition: regrib.py:520
def __mul__(self, grid)
If the grid is a GRIBGridBase, returns a GRIB1Op that will regrid this GRIB1Op's output to that grid...
Definition: regrib.py:1604
This class represents a GRIB1 or GRIB2 grid specification.
Definition: regrib.py:1151
grib1grbindex
Mutable property: either None or the grbindex binary index file for the GRIB1 file.
Definition: regrib.py:1769
def __mul__(self, grid)
If grid is the special constant GRIB1, this is the same as to_grib1(), if GRIB2, then returns self...
Definition: regrib.py:1541
def __init__(self, dstore, args, kwargs)
Creates a new GRIB2Product.
Definition: regrib.py:1967
def getgrib2index(self)
Gets the grib2 index information, or returns None if unknown.
Definition: regrib.py:2028
This is a helper class intended to be used internally by RegribMany.
Definition: regrib.py:186
def deliver
Delivers the GRIB1 data, and possibly the various index files as well.
Definition: regrib.py:2256
def __repr__(self)
Returns a Pythonic representation of self.
Definition: regrib.py:1952
did
Read-only property, an alias for getid().
Definition: datastore.py:551
def setgrib1grbindex(self, here)
Sets the location of the file that stores the output of the grbindex program run on the GRIB1 file...
Definition: regrib.py:1727
def __init__
Creates a GRIBGrid with a given name, a copygb -g style GRIB1 grid specification and a GRIB2 grid spe...
Definition: regrib.py:1153
def __init__(self, grib2file, grib2index, grib2grid)
GRIB2File constructor.
Definition: regrib.py:1792
def delgrib2grid(self)
Clears the grib2 grid information.
Definition: regrib.py:2015
def checkgrib(regrib, filename)
Internal function for validating GRIB files.
Definition: regrib.py:731
def __init__(self, lat, lon)
FixedLocation constructor.
Definition: regrib.py:1304
def input_valid(self, kwargs)
Returns True if the specified kwargs are valid and False otherwise.
Definition: regrib.py:1135
def input_valid(self, kwargs)
Returns True if the specified kwargs are valid for this Regrib object's operator and False otherwise...
Definition: regrib.py:247
def input_valid(self, kwargs)
Returns True.
Definition: regrib.py:2153
def getsubsetname(self)
Returns a name of this subset for use in filenames.
Definition: regrib.py:1399
def input_valid(self, kwargs)
Calls kwargs['regribmany'].input_valid to see if the specified kwargs make a valid input to the opera...
Definition: regrib.py:1231
def delgrib1grid(self)
Discards GRIB1 grid information by removing the grib1grid metadata from the datastore.
Definition: regrib.py:2187
def make(self, regrib, kwargs)
Runs the action specified in the constructor, providing as arguments regrib, and the result of runnin...
Definition: regrib.py:1507
def __init__(self, name)
GRIBGridFetcher constructor.
Definition: regrib.py:1216
def __init__(self, dstore, args, kwargs)
Creates a new GRIB1Product.
Definition: regrib.py:2137
def __add__(self, other)
If the argument is a GRIBOp, returns a GRIB1Op that will paste a GRIB1 version of that operations out...
Definition: regrib.py:1618
def setlat(self, val)
Sets the point's latitude.
Definition: regrib.py:1315
Exceptions raised by the hwrf package.
Definition: exceptions.py:1
def __init__(self, name)
Creates a GRIB1Fetcher for the specified operation name.
Definition: regrib.py:1634
def getop(self)
Returns the GRIBBase object that performs this Regrib's work.
Definition: regrib.py:232
def regridmerge(self, grid, other)
Returns a GRIB1Op that will ask copygb to merge the other grid on top of this one.
Definition: regrib.py:1582
def getgrib2sub(self)
This is a placeholder for future GRIB2 subsetting support.
Definition: regrib.py:1406
def deliveries
Iterates over all deliveries yielding a six element tuple.
Definition: regrib.py:604
def getgrib1grid(self)
Returns the GRIB1 grid information from the grib1grid metadata in the datastore.
Definition: regrib.py:2183
def igrb1(task, kwargs)
This is a convenient alias for the GRIB1Selector constructor.
Definition: regrib.py:1956
def call_callbacks
Calls all delivery callback functions.
Definition: datastore.py:759
This class represents a GRIBGrid that is stored in a RegribMany object.
Definition: regrib.py:1212
def getnscenter(self)
Returns the domain center latitude.
Definition: regrib.py:1710
def grid(self, name)
Returns a GRIBGridFetcher object that will grab the grid structure with the given name...
Definition: regrib.py:536
def __init__(self, result, op, workprefix=None, kwargs)
Creates a Regrib object whose result has the given name (in "result") and produces the output of the ...
Definition: regrib.py:190
Raised when a GRIB file is invalid.
Definition: exceptions.py:250
def is_ready(self, args, kwargs)
Returns True if this object and its subobjects are all ready for a call to make, and False otherwise...
Definition: regrib.py:1130
def getcopygb(self)
Returns the copygb ImmutableRunner.
Definition: regrib.py:97
def getgrib2grid(self)
This is a placeholder to return the GRIB2-style grid information.
Definition: regrib.py:1186
def getcnvgrib_g21(self)
Returns the cnvgrib -g21 command, which should be an ImmutableRunner.
Definition: regrib.py:104
def delgrib2index(self)
Cleares the stored information about the index location.
Definition: regrib.py:2031
def make(self, regrib, kwargs)
Runs the action this object should perform and returns another GRIBBase object.
Definition: regrib.py:1140
def action_clatlon(op, regrib, name, center, nsres, ewres, nssize, ewsize, nscount, ewcount, scan, kwargs)
Generates a latitude-longitude grid centered on a GRIB file or specified point.
Definition: regrib.py:1059
This class grabs a GRIBSubsetter from a RegribMany object.
Definition: regrib.py:1429
def to_grib1(self)
Returns self.
Definition: regrib.py:1575
def has_deliveries(self)
Returns True if there are any requested deliveries and False otherwise.
Definition: regrib.py:618
def check(self, kwargs)
Asks the product to check its own availability and update the database.
Definition: datastore.py:786
def setgrib1file(self, val)
Sets the GRIB1 file location.
Definition: regrib.py:2240
def make(self, regrib, args, kwargs)
Calls deliver_file to copy the file to a new temporary location from regrib.gribtemp.
Definition: regrib.py:1997
def make(self, args, kwargs)
Returns self.
Definition: regrib.py:1174
op
The GRIBBase object that performs this Regrib's work.
Definition: regrib.py:238
def setgrib1grid(self, grid)
Sets the GRIB1 grid information; modifies the grib1grid metadata in the datastore.
Definition: regrib.py:2178
def GRIB(self, name)
Returns a GRIB1Fetcher object that will grab the GRIB1 data with the given name.
Definition: regrib.py:514
def is_ready(self, args, kwargs)
Returns the logical "and" of is_ready(*args,**kwargs) called on all subobjects.
Definition: regrib.py:1487
def getewcenter(self)
Returns the domain center longitude.
Definition: regrib.py:1713
def is_ready(self, args, kwargs)
Calls kwargs['regribmany'].has_data to see if the operation has produced its subsetter yet...
Definition: regrib.py:1442
Represents a Product created by an external workflow.
Definition: datastore.py:915
def clatlon
Create a GRIBGridCompute that makes a lat-lon grid.
Definition: regrib.py:1334
grib2grid
This is a placeholder for future GRIB2 regridding support.
Definition: regrib.py:1845
def getgridname(self)
Returns the name of this grid, as provided to the constructor.
Definition: regrib.py:1178