#!/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]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)