##// END OF EJS Templates
test 3.0
test 3.0

File last commit:

r1191:f1f11d1fc586
r1222:8e3e1ad5000f v3.0-devel
Show More
jroIO_heispectra.py
848 lines | 24.9 KiB | text/x-python | PythonLexer
'''
Created on Jul 3, 2014
@author: roj-idl71
'''
import os, sys
import time, datetime
import numpy
import fnmatch
import glob
from time import sleep
try:
import pyfits
except ImportError as e:
print("Fits data cannot be used. Install pyfits module")
from xml.etree.ElementTree import ElementTree
from .jroIO_base import isRadarFolder, isNumber
from schainpy.model.data.jrodata import Fits
from schainpy.model.proc.jroproc_base import Operation, ProcessingUnit, MPDecorator
from schainpy.utils import log
class PyFits(object):
name=None
format=None
array =None
data =None
thdulist=None
prihdr=None
hdu=None
def __init__(self):
pass
def setColF(self,name,format,array):
self.name=name
self.format=format
self.array=array
a1=numpy.array([self.array],dtype=numpy.float32)
self.col1 = pyfits.Column(name=self.name, format=self.format, array=a1)
return self.col1
# def setColP(self,name,format,data):
# self.name=name
# self.format=format
# self.data=data
# a2=numpy.array([self.data],dtype=numpy.float32)
# self.col2 = pyfits.Column(name=self.name, format=self.format, array=a2)
# return self.col2
def writeData(self,name,format,data):
self.name=name
self.format=format
self.data=data
a2=numpy.array([self.data],dtype=numpy.float32)
self.col2 = pyfits.Column(name=self.name, format=self.format, array=a2)
return self.col2
def cFImage(self,idblock,year,month,day,hour,minute,second):
self.hdu= pyfits.PrimaryHDU(idblock)
self.hdu.header.set("Year",year)
self.hdu.header.set("Month",month)
self.hdu.header.set("Day",day)
self.hdu.header.set("Hour",hour)
self.hdu.header.set("Minute",minute)
self.hdu.header.set("Second",second)
return self.hdu
def Ctable(self,colList):
self.cols=pyfits.ColDefs(colList)
self.tbhdu = pyfits.new_table(self.cols)
return self.tbhdu
def CFile(self,hdu,tbhdu):
self.thdulist=pyfits.HDUList([hdu,tbhdu])
def wFile(self,filename):
if os.path.isfile(filename):
os.remove(filename)
self.thdulist.writeto(filename)
class ParameterConf:
ELEMENTNAME = 'Parameter'
def __init__(self):
self.name = ''
self.value = ''
def readXml(self, parmElement):
self.name = parmElement.get('name')
self.value = parmElement.get('value')
def getElementName(self):
return self.ELEMENTNAME
class Metadata(object):
def __init__(self, filename):
self.parmConfObjList = []
self.readXml(filename)
def readXml(self, filename):
self.projectElement = None
self.procUnitConfObjDict = {}
self.projectElement = ElementTree().parse(filename)
self.project = self.projectElement.tag
parmElementList = self.projectElement.getiterator(ParameterConf().getElementName())
for parmElement in parmElementList:
parmConfObj = ParameterConf()
parmConfObj.readXml(parmElement)
self.parmConfObjList.append(parmConfObj)
class FitsWriter(Operation):
def __init__(self, **kwargs):
Operation.__init__(self, **kwargs)
self.isConfig = False
self.dataBlocksPerFile = None
self.blockIndex = 0
self.flagIsNewFile = 1
self.fitsObj = None
self.optchar = 'P'
self.ext = '.fits'
self.setFile = 0
def setFitsHeader(self, dataOut, metadatafile=None):
header_data = pyfits.PrimaryHDU()
header_data.header['EXPNAME'] = "RADAR DATA"
header_data.header['DATATYPE'] = "SPECTRA"
header_data.header['COMMENT'] = ""
if metadatafile:
metadata4fits = Metadata(metadatafile)
for parameter in metadata4fits.parmConfObjList:
parm_name = parameter.name
parm_value = parameter.value
header_data.header[parm_name] = parm_value
header_data.header['DATETIME'] = time.strftime("%b %d %Y %H:%M:%S", dataOut.datatime.timetuple())
header_data.header['CHANNELLIST'] = str(dataOut.channelList)
header_data.header['NCHANNELS'] = dataOut.nChannels
#header_data.header['HEIGHTS'] = dataOut.heightList
header_data.header['NHEIGHTS'] = dataOut.nHeights
header_data.header['IPPSECONDS'] = dataOut.ippSeconds
header_data.header['NCOHINT'] = dataOut.nCohInt
header_data.header['NINCOHINT'] = dataOut.nIncohInt
header_data.header['TIMEZONE'] = dataOut.timeZone
header_data.header['NBLOCK'] = self.blockIndex
header_data.writeto(self.filename)
self.addExtension(dataOut.heightList,'HEIGHTLIST')
def setup(self, dataOut, path, dataBlocksPerFile=100, metadatafile=None):
self.path = path
self.dataOut = dataOut
self.metadatafile = metadatafile
self.dataBlocksPerFile = dataBlocksPerFile
def open(self):
self.fitsObj = pyfits.open(self.filename, mode='update')
def addExtension(self, data, tagname):
self.open()
extension = pyfits.ImageHDU(data=data, name=tagname)
#extension.header['TAG'] = tagname
self.fitsObj.append(extension)
self.write()
def addData(self, data):
self.open()
extension = pyfits.ImageHDU(data=data, name=self.fitsObj[0].header['DATATYPE'])
extension.header['UTCTIME'] = self.dataOut.utctime
self.fitsObj.append(extension)
self.blockIndex += 1
self.fitsObj[0].header['NBLOCK'] = self.blockIndex
self.write()
def write(self):
self.fitsObj.flush(verbose=True)
self.fitsObj.close()
def setNextFile(self):
ext = self.ext
path = self.path
timeTuple = time.localtime( self.dataOut.utctime)
subfolder = 'd%4.4d%3.3d' % (timeTuple.tm_year,timeTuple.tm_yday)
fullpath = os.path.join( path, subfolder )
if not( os.path.exists(fullpath) ):
os.mkdir(fullpath)
self.setFile = -1 #inicializo mi contador de seteo
else:
filesList = os.listdir( fullpath )
if len( filesList ) > 0:
filesList = sorted( filesList, key=str.lower )
filen = filesList[-1]
if isNumber( filen[8:11] ):
self.setFile = int( filen[8:11] ) #inicializo mi contador de seteo al seteo del ultimo file
else:
self.setFile = -1
else:
self.setFile = -1 #inicializo mi contador de seteo
setFile = self.setFile
setFile += 1
thisFile = '%s%4.4d%3.3d%3.3d%s' % (self.optchar,
timeTuple.tm_year,
timeTuple.tm_yday,
setFile,
ext )
filename = os.path.join( path, subfolder, thisFile )
self.blockIndex = 0
self.filename = filename
self.setFile = setFile
self.flagIsNewFile = 1
print('Writing the file: %s'%self.filename)
self.setFitsHeader(self.dataOut, self.metadatafile)
return 1
def writeBlock(self):
self.addData(self.dataOut.data_spc)
self.flagIsNewFile = 0
def __setNewBlock(self):
if self.flagIsNewFile:
return 1
if self.blockIndex < self.dataBlocksPerFile:
return 1
if not( self.setNextFile() ):
return 0
return 1
def writeNextBlock(self):
if not( self.__setNewBlock() ):
return 0
self.writeBlock()
return 1
def putData(self):
if self.flagIsNewFile:
self.setNextFile()
self.writeNextBlock()
def run(self, dataOut, path, dataBlocksPerFile=100, metadatafile=None, **kwargs):
if not(self.isConfig):
self.setup(dataOut, path, dataBlocksPerFile=dataBlocksPerFile, metadatafile=metadatafile, **kwargs)
self.isConfig = True
self.putData()
@MPDecorator
class FitsReader(ProcessingUnit):
# __TIMEZONE = time.timezone
expName = None
datetimestr = None
utc = None
nChannels = None
nSamples = None
dataBlocksPerFile = None
comments = None
lastUTTime = None
header_dict = None
data = None
data_header_dict = None
def __init__(self):#, **kwargs):
ProcessingUnit.__init__(self)#, **kwargs)
self.isConfig = False
self.ext = '.fits'
self.setFile = 0
self.flagNoMoreFiles = 0
self.flagIsNewFile = 1
self.flagDiscontinuousBlock = None
self.fileIndex = None
self.filename = None
self.fileSize = None
self.fitsObj = None
self.timeZone = None
self.nReadBlocks = 0
self.nTotalBlocks = 0
self.dataOut = self.createObjByDefault()
self.maxTimeStep = 10# deberia ser definido por el usuario usando el metodo setup()
self.blockIndex = 1
def createObjByDefault(self):
dataObj = Fits()
return dataObj
def isFileinThisTime(self, filename, startTime, endTime, useLocalTime=False):
try:
fitsObj = pyfits.open(filename,'readonly')
except:
print("File %s can't be opened" %(filename))
return None
header = fitsObj[0].header
struct_time = time.strptime(header['DATETIME'], "%b %d %Y %H:%M:%S")
utc = time.mktime(struct_time) - time.timezone #TIMEZONE debe ser un parametro del header FITS
ltc = utc
if useLocalTime:
ltc -= time.timezone
thisDatetime = datetime.datetime.utcfromtimestamp(ltc)
thisTime = thisDatetime.time()
if not ((startTime <= thisTime) and (endTime > thisTime)):
return None
return thisDatetime
def __setNextFileOnline(self):
raise NotImplementedError
def __setNextFileOffline(self):
idFile = self.fileIndex
while (True):
idFile += 1
if not(idFile < len(self.filenameList)):
self.flagNoMoreFiles = 1
print("No more Files")
return 0
filename = self.filenameList[idFile]
# if not(self.__verifyFile(filename)):
# continue
fileSize = os.path.getsize(filename)
fitsObj = pyfits.open(filename,'readonly')
break
self.flagIsNewFile = 1
self.fileIndex = idFile
self.filename = filename
self.fileSize = fileSize
self.fitsObj = fitsObj
self.blockIndex = 0
print("Setting the file: %s"%self.filename)
return 1
def __setValuesFromHeader(self):
self.dataOut.header = self.header_dict
self.dataOut.expName = self.expName
self.dataOut.timeZone = self.timeZone
self.dataOut.dataBlocksPerFile = self.dataBlocksPerFile
self.dataOut.comments = self.comments
# self.dataOut.timeInterval = self.timeInterval
self.dataOut.channelList = self.channelList
self.dataOut.heightList = self.heightList
self.dataOut.nCohInt = self.nCohInt
self.dataOut.nIncohInt = self.nIncohInt
self.dataOut.ipp_sec = self.ippSeconds
def readHeader(self):
headerObj = self.fitsObj[0]
self.header_dict = headerObj.header
if 'EXPNAME' in list(headerObj.header.keys()):
self.expName = headerObj.header['EXPNAME']
if 'DATATYPE' in list(headerObj.header.keys()):
self.dataType = headerObj.header['DATATYPE']
self.datetimestr = headerObj.header['DATETIME']
channelList = headerObj.header['CHANNELLIST']
channelList = channelList.split('[')
channelList = channelList[1].split(']')
channelList = channelList[0].split(',')
channelList = [int(ch) for ch in channelList]
self.channelList = channelList
self.nChannels = headerObj.header['NCHANNELS']
self.nHeights = headerObj.header['NHEIGHTS']
self.ippSeconds = headerObj.header['IPPSECONDS']
self.nCohInt = headerObj.header['NCOHINT']
self.nIncohInt = headerObj.header['NINCOHINT']
self.dataBlocksPerFile = headerObj.header['NBLOCK']
self.timeZone = headerObj.header['TIMEZONE']
# self.timeInterval = self.ippSeconds * self.nCohInt * self.nIncohInt
if 'COMMENT' in list(headerObj.header.keys()):
self.comments = headerObj.header['COMMENT']
self.readHeightList()
def readHeightList(self):
self.blockIndex = self.blockIndex + 1
obj = self.fitsObj[self.blockIndex]
self.heightList = obj.data
self.blockIndex = self.blockIndex + 1
def readExtension(self):
obj = self.fitsObj[self.blockIndex]
self.heightList = obj.data
self.blockIndex = self.blockIndex + 1
def setNextFile(self):
if self.online:
newFile = self.__setNextFileOnline()
else:
newFile = self.__setNextFileOffline()
if not(newFile):
return 0
self.readHeader()
self.__setValuesFromHeader()
self.nReadBlocks = 0
# self.blockIndex = 1
return 1
def searchFilesOffLine(self,
path,
startDate,
endDate,
startTime=datetime.time(0,0,0),
endTime=datetime.time(23,59,59),
set=None,
expLabel='',
ext='.fits',
walk=True):
pathList = []
if not walk:
pathList.append(path)
else:
dirList = []
for thisPath in os.listdir(path):
if not os.path.isdir(os.path.join(path,thisPath)):
continue
if not isRadarFolder(thisPath):
continue
dirList.append(thisPath)
if not(dirList):
return None, None
thisDate = startDate
while(thisDate <= endDate):
year = thisDate.timetuple().tm_year
doy = thisDate.timetuple().tm_yday
matchlist = fnmatch.filter(dirList, '?' + '%4.4d%3.3d' % (year,doy) + '*')
if len(matchlist) == 0:
thisDate += datetime.timedelta(1)
continue
for match in matchlist:
pathList.append(os.path.join(path,match,expLabel))
thisDate += datetime.timedelta(1)
if pathList == []:
print("Any folder was found for the date range: %s-%s" %(startDate, endDate))
return None, None
print("%d folder(s) was(were) found for the date range: %s - %s" %(len(pathList), startDate, endDate))
filenameList = []
datetimeList = []
for i in range(len(pathList)):
thisPath = pathList[i]
fileList = glob.glob1(thisPath, "*%s" %ext)
fileList.sort()
for thisFile in fileList:
filename = os.path.join(thisPath,thisFile)
thisDatetime = self.isFileinThisTime(filename, startTime, endTime)
if not(thisDatetime):
continue
filenameList.append(filename)
datetimeList.append(thisDatetime)
if not(filenameList):
print("Any file was found for the time range %s - %s" %(startTime, endTime))
return None, None
print("%d file(s) was(were) found for the time range: %s - %s" %(len(filenameList), startTime, endTime))
print()
for i in range(len(filenameList)):
print("%s -> [%s]" %(filenameList[i], datetimeList[i].ctime()))
self.filenameList = filenameList
self.datetimeList = datetimeList
return pathList, filenameList
def setup(self, path=None,
startDate=None,
endDate=None,
startTime=datetime.time(0,0,0),
endTime=datetime.time(23,59,59),
set=0,
expLabel = "",
ext = None,
online = False,
delay = 60,
walk = True):
if path == None:
raise ValueError("The path is not valid")
if ext == None:
ext = self.ext
if not(online):
print("Searching files in offline mode ...")
pathList, filenameList = self.searchFilesOffLine(path, startDate=startDate, endDate=endDate,
startTime=startTime, endTime=endTime,
set=set, expLabel=expLabel, ext=ext,
walk=walk)
if not(pathList):
print("No *%s files into the folder %s \nfor the range: %s - %s"%(ext, path,
datetime.datetime.combine(startDate,startTime).ctime(),
datetime.datetime.combine(endDate,endTime).ctime()))
sys.exit(-1)
self.fileIndex = -1
self.pathList = pathList
self.filenameList = filenameList
self.online = online
self.delay = delay
ext = ext.lower()
self.ext = ext
if not(self.setNextFile()):
if (startDate!=None) and (endDate!=None):
print("No files in range: %s - %s" %(datetime.datetime.combine(startDate,startTime).ctime(), datetime.datetime.combine(endDate,endTime).ctime()))
elif startDate != None:
print("No files in range: %s" %(datetime.datetime.combine(startDate,startTime).ctime()))
else:
print("No files")
sys.exit(-1)
def readBlock(self):
dataObj = self.fitsObj[self.blockIndex]
self.data = dataObj.data
self.data_header_dict = dataObj.header
self.utc = self.data_header_dict['UTCTIME']
self.flagIsNewFile = 0
self.blockIndex += 1
self.nTotalBlocks += 1
self.nReadBlocks += 1
return 1
def __jumpToLastBlock(self):
raise NotImplementedError
def __waitNewBlock(self):
"""
Return 1 si se encontro un nuevo bloque de datos, 0 de otra forma.
Si el modo de lectura es OffLine siempre retorn 0
"""
if not self.online:
return 0
if (self.nReadBlocks >= self.dataBlocksPerFile):
return 0
currentPointer = self.fp.tell()
neededSize = self.processingHeaderObj.blockSize + self.basicHeaderSize
for nTries in range( self.nTries ):
self.fp.close()
self.fp = open( self.filename, 'rb' )
self.fp.seek( currentPointer )
self.fileSize = os.path.getsize( self.filename )
currentSize = self.fileSize - currentPointer
if ( currentSize >= neededSize ):
self.__rdBasicHeader()
return 1
print("\tWaiting %0.2f seconds for the next block, try %03d ..." % (self.delay, nTries+1))
sleep( self.delay )
return 0
def __setNewBlock(self):
if self.online:
self.__jumpToLastBlock()
if self.flagIsNewFile:
return 1
self.lastUTTime = self.utc
if self.online:
if self.__waitNewBlock():
return 1
if self.nReadBlocks < self.dataBlocksPerFile:
return 1
if not(self.setNextFile()):
return 0
deltaTime = self.utc - self.lastUTTime
self.flagDiscontinuousBlock = 0
if deltaTime > self.maxTimeStep:
self.flagDiscontinuousBlock = 1
return 1
def readNextBlock(self):
if not(self.__setNewBlock()):
return 0
if not(self.readBlock()):
return 0
return 1
def printInfo(self):
pass
def getData(self):
if self.flagNoMoreFiles:
self.dataOut.flagNoData = True
return (0, 'No more files')
self.flagDiscontinuousBlock = 0
self.flagIsNewBlock = 0
if not(self.readNextBlock()):
return (1, 'Error reading data')
if self.data is None:
self.dataOut.flagNoData = True
return (0, 'No more data')
self.dataOut.data = self.data
self.dataOut.data_header = self.data_header_dict
self.dataOut.utctime = self.utc
# self.dataOut.header = self.header_dict
# self.dataOut.expName = self.expName
# self.dataOut.nChannels = self.nChannels
# self.dataOut.timeZone = self.timeZone
# self.dataOut.dataBlocksPerFile = self.dataBlocksPerFile
# self.dataOut.comments = self.comments
# # self.dataOut.timeInterval = self.timeInterval
# self.dataOut.channelList = self.channelList
# self.dataOut.heightList = self.heightList
self.dataOut.flagNoData = False
# return self.dataOut.data
def run(self, **kwargs):
if not(self.isConfig):
self.setup(**kwargs)
self.isConfig = True
self.getData()
@MPDecorator
class SpectraHeisWriter(Operation):
# set = None
setFile = None
idblock = None
doypath = None
subfolder = None
def __init__(self):#, **kwargs):
Operation.__init__(self)#, **kwargs)
self.wrObj = PyFits()
# self.dataOut = dataOut
self.nTotalBlocks=0
# self.set = None
self.setFile = None
self.idblock = 0
self.wrpath = None
self.doypath = None
self.subfolder = None
self.isConfig = False
def isNumber(str):
"""
Chequea si el conjunto de caracteres que componen un string puede ser convertidos a un numero.
Excepciones:
Si un determinado string no puede ser convertido a numero
Input:
str, string al cual se le analiza para determinar si convertible a un numero o no
Return:
True : si el string es uno numerico
False : no es un string numerico
"""
try:
float( str )
return True
except:
return False
def setup(self, dataOut, wrpath):
if not(os.path.exists(wrpath)):
os.mkdir(wrpath)
self.wrpath = wrpath
# self.setFile = 0
self.dataOut = dataOut
def putData(self):
name= time.localtime( self.dataOut.utctime)
ext=".fits"
if self.doypath == None:
self.subfolder = 'F%4.4d%3.3d_%d' % (name.tm_year,name.tm_yday,time.mktime(datetime.datetime.now().timetuple()))
self.doypath = os.path.join( self.wrpath, self.subfolder )
os.mkdir(self.doypath)
if self.setFile == None:
# self.set = self.dataOut.set
self.setFile = 0
# if self.set != self.dataOut.set:
## self.set = self.dataOut.set
# self.setFile = 0
#make the filename
thisFile = 'D%4.4d%3.3d_%3.3d%s' % (name.tm_year,name.tm_yday,self.setFile,ext)
filename = os.path.join(self.wrpath,self.subfolder, thisFile)
idblock = numpy.array([self.idblock],dtype="int64")
header=self.wrObj.cFImage(idblock=idblock,
year=time.gmtime(self.dataOut.utctime).tm_year,
month=time.gmtime(self.dataOut.utctime).tm_mon,
day=time.gmtime(self.dataOut.utctime).tm_mday,
hour=time.gmtime(self.dataOut.utctime).tm_hour,
minute=time.gmtime(self.dataOut.utctime).tm_min,
second=time.gmtime(self.dataOut.utctime).tm_sec)
c=3E8
deltaHeight = self.dataOut.heightList[1] - self.dataOut.heightList[0]
freq=numpy.arange(-1*self.dataOut.nHeights/2.,self.dataOut.nHeights/2.)*(c/(2*deltaHeight*1000))
colList = []
colFreq=self.wrObj.setColF(name="freq", format=str(self.dataOut.nFFTPoints)+'E', array=freq)
colList.append(colFreq)
nchannel=self.dataOut.nChannels
for i in range(nchannel):
col = self.wrObj.writeData(name="PCh"+str(i+1),
format=str(self.dataOut.nFFTPoints)+'E',
data=10*numpy.log10(self.dataOut.data_spc[i,:]))
colList.append(col)
data=self.wrObj.Ctable(colList=colList)
self.wrObj.CFile(header,data)
self.wrObj.wFile(filename)
#update the setFile
self.setFile += 1
self.idblock += 1
return 1
def run(self, dataOut, **kwargs):
if not(self.isConfig):
self.setup(dataOut, **kwargs)
self.isConfig = True
self.putData()
return dataOut