1   
  2   
  3   
  4   
  5   
  6   
  7   
  8   
  9   
 10   
 11   
 12   
 13   
 14   
 15   
 16   
 17  """ 
 18  This module provides a bunch of user-friendly wrappers to the HDF5 
 19  data format, for reading and writing SWIG-bound TimeSeries and 
 20  FrequencySeries objects from LAL. Issues should be raised on redmine: 
 21  https://bugs.ligo.org/redmine/projects/lalsuite 
 22  """ 
 23   
 24   
 25   
 26   
 27   
 28  from __future__ import division 
 29  import numpy 
 30  import h5py 
 31  import lal 
 32   
 33  from pylal import seriesutils 
 34  from pylal import git_version 
 35   
 36   
 37  __author__ = "Duncan M. Macleod <duncan.macleod@ligo.org>" 
 38  __version__ = git_version.id 
 39  __date__ = git_version.date 
 40   
 41   
 42   
 43   
 44   
 45   
 46  _numpy_lal_typemap = {numpy.int16: lal.LAL_I2_TYPE_CODE,\ 
 47                        numpy.int32: lal.LAL_I4_TYPE_CODE,\ 
 48                        numpy.int64: lal.LAL_I8_TYPE_CODE,\ 
 49                        numpy.uint16: lal.LAL_U2_TYPE_CODE,\ 
 50                        numpy.uint32: lal.LAL_U4_TYPE_CODE,\ 
 51                        numpy.uint64: lal.LAL_U8_TYPE_CODE,\ 
 52                        numpy.float32: lal.LAL_S_TYPE_CODE,\ 
 53                        numpy.float64: lal.LAL_D_TYPE_CODE,\ 
 54                        numpy.complex64: lal.LAL_C_TYPE_CODE,\ 
 55                        numpy.complex128: lal.LAL_Z_TYPE_CODE} 
 56  _lal_numpy_typemap = dict((v,k) for k, v in _numpy_lal_typemap.items()) 
 57   
 58   
 59   
 60   
 61   
 62 -def readTimeSeries(h5file, name, group="", start=None, duration=None,\ 
 63                     datatype=None): 
  64      """ 
 65      Read a 1-D array from an HDF5 file into a LAL TimeSeries. 
 66   
 67      Returns SWIG-bound LAL TimeSeries. 
 68   
 69      Arguments: 
 70   
 71          h5file : [ h5py.File | str ] 
 72              open HDF5 file object, or path to HDF5 file on disk. 
 73          name : str 
 74              name of data object in HDF5 file relative in it's group. 
 75   
 76      Keyword arguments: 
 77   
 78          group : str 
 79              name of HDF5 Group containing data object required. 
 80          start : LIGOTimeGPS 
 81              GPS start time of data requested, defaults to first data point. 
 82          duration : float 
 83              length of data (seconds) requested, default to all data. 
 84          datatype : int 
 85              LAL typecode for output datatype, defaults to type of data found. 
 86      """ 
 87      own = False 
 88      if not isinstance(h5file, h5py.File): 
 89         h5file = h5py.File(h5file, "r") 
 90         own = True 
 91       
 92       
 93      dataset, metadata = readArray(h5file, name, group=group)     
 94      if own: 
 95          h5file.close() 
 96   
 97       
 98      epoch = lal.LIGOTimeGPS(metadata.pop("epoch", 0)) 
 99      f0 = float(metadata.pop("f0", 0)) 
100      deltaT = float(metadata.pop("dx", 0)) 
101      sampleUnits = lal.lalDimensionlessUnit  
102   
103       
104      if datatype is None: 
105          datatype = _numpy_lal_typemap[dataset.dtype.type] 
106      TYPECODE = seriesutils._typestr[datatype] 
107      numpytype = _lal_numpy_typemap[datatype] 
108   
109       
110      if duration is None: 
111          length = dataset.size 
112      else: 
113          length = int(duration / deltaT) 
114      if start is None: 
115          startidx = 0 
116      else: 
117          start = float(epoch) + (float(start)-float(epoch))//deltaT*deltaT 
118          if start < epoch: 
119              start = epoch 
120          startidx = int(max(0, (float(start)-float(epoch))/deltaT)) 
121          epoch = lal.LIGOTimeGPS(start) 
122      endidx = min(dataset.size, startidx + length) 
123      length = endidx-startidx 
124   
125       
126      createTimeSeries = getattr(lal, "Create%sTimeSeries" % TYPECODE) 
127      series = createTimeSeries(name, epoch, f0, deltaT, sampleUnits,\ 
128                                length) 
129      series.data.data = dataset[startidx:endidx].astype(numpytype) 
130   
131      return series 
 132   
135      """ 
136      Read FrequencySeries object from HDF5 file. 
137   
138      Returns SWIG-bound LAL FrequencySeries. 
139   
140      Arguments: 
141   
142          h5file : [ h5py.File | str ] 
143              open HDF5 file object, or path to HDF5 file on disk. 
144          name : str 
145              name of data object in HDF5 file relative in it's group. 
146   
147      Keyword arguments: 
148   
149          group : str 
150              name of HDF5 Group containing data object required. 
151          fmin : float 
152              lower frequency bound on data returned 
153          fmax : float 
154              upper frequency bound on data returned 
155          datatype : int 
156              LAL typecode for output datatype, defaults to type of data found. 
157      """ 
158      own = False 
159      if not isinstance(h5file, h5py.File): 
160         h5file = h5py.File(h5file, "r") 
161         own = True 
162   
163       
164      dataset, metadata =  readArray(h5file, name, group=group) 
165      if own: 
166          h5file.close() 
167   
168       
169      epoch = lal.LIGOTimeGPS(metadata.pop("epoch", 0)) 
170      f0 = float(metadata.pop("f0", 0)) 
171      deltaF = float(metadata.pop("dx", 0)) 
172      sampleUnits = lal.lalDimensionlessUnit  
173   
174       
175      if not datatype: 
176          datatype = _numpy_lal_typemap[dataset.dtype.type] 
177      TYPECODE = seriesutils._typestr[datatype] 
178      numpytype = _lal_numpy_typemap[datatype] 
179   
180       
181      if fmin is None: 
182          fmin = f0 
183      else: 
184          fmin = f0 + (fmin-f0)//deltaF*deltaF 
185      startidx = int(max(0, (fmin-f0)/deltaF)) 
186      if fmax is None: 
187          fmax = f0 + dataset.size * deltaF 
188      else: 
189          fmax = f0 + (fmax-f0)//deltaF*deltaF 
190      endidx = int(min(dataset.size, (fmax-fmin)/deltaF)) 
191      length = endidx-startidx 
192       
193       
194      createFrequencySeries = getattr(lal, "Create%sFrequencySeries" % TYPECODE) 
195      series = createFrequencySeries(name, epoch, f0, deltaF, sampleUnits,\ 
196                                     length) 
197      series.data.data = dataset[startidx:endidx].astype(numpytype) 
198   
199      return series 
 200   
201 -def readVectorSequence(h5file, name, group=None, start=None, duration=None,\ 
202                         fmin=None, fmax=None, datatype=None): 
 203      """ 
204      Read VectorSequence object from HDF5 file. 
205   
206      Returns SWIG-bound LAL VectorSequence, LIGOTimeGPS epoch, float deltaT, 
207      float f0, float deltaF. 
208   
209      Arguments: 
210   
211          h5file : [ h5py.File | str ] 
212              open HDF5 file object, or path to HDF5 file on disk. 
213          name : str 
214              name of data object in HDF5 file relative in it's group. 
215   
216      Keyword arguments: 
217   
218          group : str 
219              name of HDF5 Group containing data object required. 
220          start : LIGOTimeGPS 
221              GPS start time of data requested, defaults to first data point. 
222          duration : float 
223              length of data (seconds) requested, default to all data. 
224          fmin : float 
225              lower frequency bound on data returned 
226          fmax : float 
227              upper frequency bound on data returned 
228          datatype : int 
229              LAL typecode for output datatype, defaults to type of data found. 
230      """ 
231      own = False 
232      if not isinstance(h5file, h5py.File): 
233         h5file = h5py.File(h5file, "r") 
234         own = True 
235   
236       
237      dataset, metadata =  readArray(h5file, name, group=group) 
238      if own: 
239          h5file.close() 
240   
241       
242      epoch = lal.LIGOTimeGPS(metadata.pop("epoch", 0)) 
243      deltaT = float(metadata.pop("dx", 0)) 
244      f0 = float(metadata.pop("f0", 0)) 
245      deltaF = float(metadata.pop("dy", 0)) 
246   
247       
248      if not datatype: 
249          datatype = _numpy_lal_typemap[dataset.dtype.type] 
250      TYPECODE = seriesutils._typestr[datatype] 
251      numpytype = _lal_numpy_typemap[datatype] 
252   
253       
254      if duration is None: 
255          length = dataset.shape[0] 
256      else: 
257          length = int(duration / deltaT) 
258      if start is None: 
259          x0 = 0 
260      else: 
261          start = float(epoch) + (float(start)-float(epoch))//deltaT*deltaT 
262          if start < epoch: 
263              start = epoch 
264          x0 = int(max(0, (float(start)-float(epoch))/deltaT)) 
265          epoch = lal.LIGOTimeGPS(start) 
266      length = min(dataset.size, x0 + length) - x0 
267      if fmin is None: 
268          fmin = f0 
269      else: 
270          fmin = f0 + (fmin-f0)//deltaF*deltaF 
271      y0 = int(max(0, (fmin-f0)/deltaF)) 
272      if fmax is None: 
273          fmax = f0 + dataset.shape[1] * deltaF 
274      else: 
275          fmax = f0 + ((fmax-f0)//deltaF)*deltaF 
276      vectorLength = int(min(dataset.size, (fmax-fmin)/deltaF)) - y0 
277   
278       
279      createVectorSequence = getattr(lal, "Create%sVectorSequence" % TYPECODE) 
280      sequence = createVectorSequence(length, vectorLength) 
281   
282      for i,x in enumerate(numpy.arange(length)+x0): 
283           
284          sequence.data[i] = dataset[x,:][y0:y0+vectorLength].astype(numpytype) 
285           
286      return sequence, epoch, deltaT, f0, deltaF 
287   
288      series.data.data = dataset[startidx:endidx].astype(numpytype) 
289   
290      return series 
 291   
293      """ 
294      Read numpy.ndarray from h5py.File object h5file. 
295   
296      Returns numpy.ndarray and metadata dict.  
297   
298      Arguments: 
299   
300          h5file : [ h5py.File | str ] 
301              open HDF5 file object, or path to HDF5 file on disk. 
302          name : str 
303              name of data object in HDF5 file relative in it's group. 
304   
305      Keyword arguments: 
306   
307          group : str 
308              name of HDF5 Group containing data object required. 
309      """ 
310       
311      if group.endswith(name): 
312          group = group[:len(name)] 
313      key = "%s/%s" % (group, name) 
314   
315       
316      dataset = h5file[key] 
317   
318      return dataset[...], dict(dataset.attrs) 
 319   
320   
321   
322   
323   
325      """ 
326      Write TimeSeries object to the given h5py.File object h5file. 
327   
328      No return. 
329   
330      Arguments: 
331   
332          h5file : h5py.File 
333              open HDF5 file object 
334          series : TimeSeries 
335              SWIG-bound LAL TimeSeries object 
336   
337      Keyword arguments: 
338   
339          group : str 
340              name of HDF5 Group to write to, group is generated if required. 
341   
342      All other keyword arguments are passed to 
343      h5py.highlevel.Group.create_dataset. 
344      """ 
345      h5group = _create_groups(h5file, group) 
346      seriesToDataset(h5group, series, **kwargs) 
347      return 
 348   
350      """ 
351      Write FrequencySeries object to the given h5py.File object h5file. 
352   
353      No return. 
354   
355      Arguments: 
356   
357          h5file : h5py.File 
358              open HDF5 file object 
359          series : FrequencySeries 
360              SWIG-bound LAL FrequencySeries object 
361   
362      Keyword arguments: 
363   
364          group : str 
365              name of HDF5 Group to write to, group is generated if required. 
366   
367      All other keyword arguments are passed to 
368      h5py.highlevel.Group.create_dataset. 
369      """ 
370      h5group = _create_groups(h5file, group) 
371      seriesToDataset(h5group, series, **kwargs) 
372      return 
 373   
375      """ 
376      Write {Time,Frequency}Series object to a new data set in the 
377      given h5py.Group object h5group. 
378   
379      Returns h5py.highlevel.Dataset. 
380   
381      Arguments: 
382   
383          h5group : h5py.highlevel.Group 
384              Group object inside an HDF5 file 
385          series : [ TimeSeries | FrequencySeries ] 
386              LAL Time or FrequencySeries object 
387   
388      All kwargs are passed to h5py.highlevel.Group.create_dataset. 
389      """ 
390       
391      metadata = dict() 
392      metadata["name"] = str(series.name) 
393      metadata["epoch"] = float(series.epoch) 
394      metadata["f0"] = float(series.f0) 
395      metadata["dx"] = float(hasattr(series, "deltaT") and series.deltaT\ 
396                       or series.deltaF) 
397       
398       
399       
400      data = series.data.data 
401       
402       
403      h5dataset = arrayToDataset(h5group, metadata["name"], data, metadata,\ 
404                                     **kwargs)  
405       
406      return h5dataset 
 407   
409      """ 
410      Write the given numpy array object to a new data set in the given 
411      h5py.highlevel.Group object h5group, including each element in the 
412      metadata dict. 
413   
414      Returns h5py.highlevel.Dataset. 
415   
416      Arguments: 
417   
418          h5group : h5py.highlevel.Group 
419              Group object inside an HDF5 file 
420          name : str 
421              descriptive name for the new dataset. 
422          array: numpy.ndarray 
423              data object to write to dataset 
424           
425      Keyword arguments: 
426   
427          metadata: dict  
428              dict containing metadata to write as attributes in the 
429              dataset, default={} (empty) 
430   
431      All kwargs are passed to h5py.highlevel.Group.create_dataset. 
432      """ 
433       
434      h5dataset = h5group.create_dataset(name, data=array, **kwargs) 
435       
436       
437      metadata = dict(metadata) 
438      for key,value in metadata.iteritems(): 
439          h5dataset.attrs.create(key, value) 
440   
441      return h5dataset 
 442   
444      """ 
445      Helper to return a group from an h5py.File object, creating all parents 
446      and the group itself if needed. 
447   
448      Returns a new h5py.highlevel.Group, except in the special case of 
449      group=None, in which case the original h5py.File is returned. 
450   
451      Argument: 
452   
453          h5file : [ h5py.File | str ] 
454              open HDF5 file object, or path to HDF5 file on disk. 
455          group : str 
456              name of Group to create. If a composite group is given 
457              (e.g. "/data/spectra") the full tree will be generated 
458              as appropriate. 
459      """ 
460      if group is None: 
461          return h5file 
462      group = group.lstrip("/") 
463      if group in h5file.keys(): 
464          h5group = h5file[group] 
465      else: 
466          groups = group.split("/") 
467          h5group = h5file 
468          for g in groups: 
469              try: 
470                  h5group = h5group.create_group(g) 
471              except ValueError: 
472                  pass 
473      return h5group 
 474