Source code for tesfdmtools.hdf.h2x

#!/usr/bin/env python3
#
'''
.. module:: hdf2xdf
   :synopsis: Convert HDF5 files to old format xdf files.
.. moduleauthor:: Cor de Vries <c.p.de.vries@sron.nl>

Convert hdf5 files to xdf files.

   Use:  Hdf2Xdf [-h] [hdfdir] [xdfdir]

         When directories containing the hdf files and directories where the xdf should go are not given,
         pop-up selection tools appear:
           - select the approprate files interactively (multiple file selection allowed).
           - select the directory to which to write to the xdf data file(s).

         Otherwise provide the directories with the hdf (.h5) files and the
         directory where the xdf files should go 

         Both I and Q data are written into the xdf file.
'''

import sys,os
import numpy,struct
import datetime

from tesfdmtools.hdf.HMUX import HMUX

# xdf header structure and keywords to be filled

LONG=0
ULONG=1
DOUBLE=2
STRING=3

hinfo={}
hinfo[0] =( 0,  8,  LONG,  'RUNNUM','run number')
hinfo[1] =( 1,  8,  LONG,  'FILNUM','file number')
hinfo[2] =( 2,  8,STRING,    'DATE','date')
hinfo[3] =( 3,  8,STRING,    'TIME','time')
hinfo[4] =( 4, 32,STRING,'DETECTOR','detector')
hinfo[5] =( 5, 32,STRING,   'SQUID','squid')
hinfo[6] =(28,256,STRING, 'COMMENT','comment')
hinfo[7] =( 6,  1, ULONG,   'NCHAN','number of channels')
hinfo[8] =( 7,  8, ULONG,'SMPLSCHN','samples per channel')
hinfo[9] =( 8,  8, ULONG,'SMPLRATE','sample rate')
hinfo[28]=( 9,  8,STRING, 'NUMBITS','number of bits')
hinfo[10]=(10,  8, ULONG, 'NEVENTS','number of events')
hinfo[11]=(11,  8, ULONG,'PTRIGSMP','number of pretrigger samples')
hinfo[12]=(12,  3,STRING,'TRIGSRCE','trigger source')
hinfo[13]=(13,  3,STRING,'TRIGSLOP','trigger slope')
hinfo[14]=(14,  2,STRING,'TRIGCOPL','trigger coupling')
hinfo[15]=(15,  8,DOUBLE, 'TRIGLVL','trigger level')
hinfo[16]=(16,  8,  LONG,'TRIGTMOT','trigger timeout')
hinfo[17]=(17,  2,STRING,'ACHCOUPL','channel A coupling')
hinfo[18]=(18,  3,DOUBLE,'ACHRANGE','channel A range')
hinfo[19]=(19,  2,STRING,'BCHCOUPL','channel B coupling')
hinfo[20]=(20,  3,DOUBLE,'BCHRANGE','channel B range')
hinfo[21]=(21,  2,STRING,'CCHCOUPL','channel C coupling')
hinfo[22]=(22,  3,DOUBLE,'CCHRANGE','channel C range')
hinfo[23]=(23,  2,STRING,'DCHCOUPL','channel D coupling')
hinfo[24]=(24,  3,DOUBLE,'DCHRANGE','channel D range')
hinfo[25]=(25,  8,STRING,  'CARDID','card identifier')
hinfo[26]=(26, 16,STRING,'ACQPRGID','aquisition program identifier')
hinfo[27]=(27,  3,  LONG,'ACQPRGVR','aquisition program version')

[docs]def xdfheader(h5attrs): ''' Assemble xdf header Args: * `h5attrs` = dictionary with the critcal HDF5 attributes for the xdf file Returns: * `header` = the xdf header (byte string) ''' fmt="" # format for structure packing hh=[] # values in same order as format blen=0 for i in numpy.arange(len(hinfo)): value=" " if hinfo[i][3] in h5attrs: value=h5attrs[hinfo[i][3]] fmt=fmt+("%ds" % hinfo[i][1]) vfmt="%%%d.%ds" % (hinfo[i][1],hinfo[i][1]) hh.append(str.encode(vfmt % str(value))) blen=blen+hinfo[i][1] rr=1024-blen if rr > 0: # append structure to 1024 bytes fmt=fmt+"%ds" % rr hh.append(str.encode(" ")) header=struct.pack(fmt,*hh) # pack structure in header return header
[docs]class Xdf: ''' New Xdf datafile object Args: * `xdfname` = file name of the xdf file to be written * `h5attrs` = dictionary with the critcal HDF5 attributes for the xdf file ''' def __init__(self,xdfname,h5attrs): ''' Write Xdf file Args: * `xdfname` = file name of the xdf file to be written * `h5attrs` = dictionary with the critcal HDF5 attributes for the xdf file ''' # start writing xdf file self.h5attrs=h5attrs header=xdfheader(self.h5attrs) print("Write xdf file: ",os.path.basename(xdfname)) self.xdffile=open(xdfname,"wb") # open xdf file self.xdffile.write(header) # write header self.nrec=0 return #
[docs] def write(self,recno,record): ''' Write an xdf data record Args: * `recno` = number of the record to be written * `record` = HDF5 FDM record object, containing I and Q data plus attributes ''' tstamp=record.attrs["event_time"] # for record header rhead=str.encode("%8d%12.12sOK%10s" % (recno,tstamp," ")) # make record header idata=numpy.array(record[:,0] >> 4,dtype=">i2") # shift to get 22 ADC data into 16 bit numbers for XDF qdata=numpy.array(record[:,1] >> 4,dtype=">i2") # shift to get 22 ADC data into 16 bit numbers for XDF self.xdffile.write(rhead) # write record header idata.tofile(self.xdffile) # write i-data qdata.tofile(self.xdffile) # write q-data if (self.nrec % 1000) == 0: print("Write xdf record: ",recno) self.nrec=self.nrec+1 return
[docs] def close(self): ''' Close the xdf file. Rewrite header with actual number of events written. ''' if self.xdffile is None: return print("Close xdf file. Total number of records: ",self.nrec) self.xdffile.seek(0) # rewind file self.h5attrs['NEVENTS']=self.nrec # get true number of events header=xdfheader(self.h5attrs) # insert in header self.xdffile.write(header) # rewrite header for true number of events self.xdffile.close() self.xdffile=None
def __del__(self): self.close()
#=========
[docs]def hdf2xdf(hdfname,xdfdir): ''' Convert HDF5 FDM datafile to the old xdf file format. Multiple xdf files will be written. One file for each channel and pixel. Args: * `hdfname` = name of the HDF5 file * `xdfdir` = directory where the new xd ffiles should go Returns: `none` ''' hdf=HMUX(filename=hdfname) hdfbnam=os.path.basename(hdfname).split('.')[0] xdfbnam=xdfdir.rstrip(' /\n')+'/'+hdfbnam channels=hdf.channels for channel in channels: freqs=hdf.channel[channel].freqs for freq in freqs: pixdata=hdf.channel[channel].freq[freq] h5attrs={} h5attrs['NEVENTS']=hdf.channel[channel].attrs['Nevents'] date=datetime.datetime.fromtimestamp(float(hdf.attrs['time_start_utc'])) h5attrs['DATE']=date.strftime('%y/%m/%d') h5attrs['TIME']=date.strftime('%H:%M:%S') h5attrs['NCHAN']=2 h5attrs['SMPLSCHN']=len(pixdata.rec0) h5attrs['SMPLRATE']=int(pixdata.attrs['sample_rate']) h5attrs['NUMBITS']=16 h5attrs['PTRIGSMP']=pixdata.attrs['pretrig_samples'] for key in h5attrs: print(("%10.10s:" % key),h5attrs[key]) xdfname="%s_ch%2.2d_px%2.2d.xdf" % (xdfbnam,channel,freq) xdf=Xdf(xdfname,h5attrs) j=0 for record in pixdata: if numpy.ptp(record) > 0: xdf.write(j,record) j=j+1 xdf.close()
#========================================================================================= if __name__ == "__main__": from tesfdmtools.utils.widgets.filechooser import getfile,getdir from tesfdmtools.utils.tesfdm_defaults import Tesfdm_Defaults from glob import glob defs=Tesfdm_Defaults() # last locations for files if len(sys.argv) > 1: if sys.argv[1] == '-h': print(__doc__) sys.exit() if len(sys.argv) != 3: sys.exit("Error, provide both input hdf and output xdf directories") if os.path.isdir(sys.argv[1]) and os.path.isdir(sys.argv[2]): from glob import glob hdffiles=glob(sys.argv[1]+'/*.h5') if len(hdffiles) == 0: sys.exit("Error, no hdf files found") hdir=sys.argv[2] else: sys.exit("Error, given parameters are no directories") else: print("select Hdf files...") hdffiles=getfile(path=defs.get_filepath('h5'),pattern='*.h5',multiple=True) if len(hdffiles) == 0: sys.exit() defs.set_filepath(hdffiles[0]) print("select directory for new xdf files") xdfdir=getdir(path=os.path.dirname(defs.get_filepath('xdf'))) if xdfdir == '': sys.exit() for hdffile in hdffiles: print("Convert HDF file: ",os.path.basename(hdffile)) hdf2xdf(hdffile,xdfdir)