JRODataIO.py
1235 lines
| 40.3 KiB
| text/x-python
|
PythonLexer
|
r9 | ''' | ||
Created on 23/01/2012 | ||||
|
r16 | @author $Author$ | ||
@version $Id$ | ||||
|
r58 | @version $Id$ | ||
|
r9 | ''' | ||
|
r58 | |||
|
r49 | import os, sys | ||
import glob | ||||
import time | ||||
import numpy | ||||
|
r50 | import fnmatch | ||
import time, datetime | ||||
|
r9 | |||
|
r49 | path = os.path.split(os.getcwd())[0] | ||
sys.path.append(path) | ||||
|
r9 | |||
|
r49 | from Model.JROHeader import * | ||
|
r50 | from Model.JROData import JROData | ||
|
r49 | |||
|
r50 | def checkForRealPath(path, year, doy, set, ext): | ||
|
r49 | """ | ||
Por ser Linux Case Sensitive entonces checkForRealPath encuentra el nombre correcto de un path, | ||||
Prueba por varias combinaciones de nombres entre mayusculas y minusculas para determinar | ||||
el path exacto de un determinado file. | ||||
Example : | ||||
|
r50 | nombre correcto del file es .../.../D2009307/P2009307367.ext | ||
|
r49 | |||
Entonces la funcion prueba con las siguientes combinaciones | ||||
|
r50 | .../.../x2009307/y2009307367.ext | ||
.../.../x2009307/Y2009307367.ext | ||||
.../.../X2009307/y2009307367.ext | ||||
.../.../X2009307/Y2009307367.ext | ||||
|
r49 | siendo para este caso, la ultima combinacion de letras, identica al file buscado | ||
Return: | ||||
Si encuentra la cobinacion adecuada devuelve el path completo y el nombre del file | ||||
caso contrario devuelve None como path y el la ultima combinacion de nombre en mayusculas | ||||
para el filename | ||||
""" | ||||
filepath = None | ||||
find_flag = False | ||||
filename = None | ||||
|
r50 | |||
if ext.lower() == ".r": #voltage | ||||
|
r58 | header1 = "dD" | ||
header2 = "dD" | ||||
|
r50 | elif ext.lower() == ".pdata": #spectra | ||
|
r58 | header1 = "dD" | ||
header2 = "pP" | ||||
|
r50 | else: | ||
return None, filename | ||||
|
r58 | for dir in header1: #barrido por las dos combinaciones posibles de "D" | ||
for fil in header2: #barrido por las dos combinaciones posibles de "D" | ||||
|
r49 | doypath = "%s%04d%03d" % ( dir, year, doy ) #formo el nombre del directorio xYYYYDDD (x=d o x=D) | ||
|
r50 | filename = "%s%04d%03d%03d%s" % ( fil, year, doy, set, ext ) #formo el nombre del file xYYYYDDDSSS.ext | ||
|
r49 | filepath = os.path.join( path, doypath, filename ) #formo el path completo | ||
if os.path.exists( filepath ): #verifico que exista | ||||
find_flag = True | ||||
break | ||||
if find_flag: | ||||
break | ||||
if not(find_flag): | ||||
return None, filename | ||||
return filepath, filename | ||||
|
r50 | def isNumber(str): | ||
|
r49 | """ | ||
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 isThisFileinRange(filename, startUTSeconds, endUTSeconds): | ||||
""" | ||||
|
r50 | Esta funcion determina si un archivo de datos se encuentra o no dentro del rango de fecha especificado. | ||
|
r49 | |||
Inputs: | ||||
filename : nombre completo del archivo de datos en formato Jicamarca (.r) | ||||
startUTSeconds : fecha inicial del rango seleccionado. La fecha esta dada en | ||||
segundos contados desde 01/01/1970. | ||||
endUTSeconds : fecha final del rango seleccionado. La fecha esta dada en | ||||
segundos contados desde 01/01/1970. | ||||
Return: | ||||
Boolean : Retorna True si el archivo de datos contiene datos en el rango de | ||||
fecha especificado, de lo contrario retorna False. | ||||
Excepciones: | ||||
Si el archivo no existe o no puede ser abierto | ||||
Si la cabecera no puede ser leida. | ||||
""" | ||||
m_BasicHeader = BasicHeader() | ||||
try: | ||||
fp = open(filename,'rb') | ||||
except: | ||||
raise IOError, "The file %s can't be opened" %(filename) | ||||
|
r53 | sts = m_BasicHeader.read(fp) | ||
|
r49 | fp.close() | ||
|
r53 | if not(sts): | ||
print "Skipping the file %s because it has not a valid header" %(filename) | ||||
return 0 | ||||
|
r58 | if not ((startUTSeconds <= m_BasicHeader.utc) and (endUTSeconds > m_BasicHeader.utc)): | ||
|
r49 | return 0 | ||
return 1 | ||||
|
r53 | def getlastFileFromPath(path, ext): | ||
|
r49 | """ | ||
|
r53 | Depura el fileList dejando solo los que cumplan el formato de "PYYYYDDDSSS.ext" | ||
|
r49 | al final de la depuracion devuelve el ultimo file de la lista que quedo. | ||
Input: | ||||
|
r53 | fileList : lista conteniendo todos los files (sin path) que componen una determinada carpeta | ||
|
r49 | ext : extension de los files contenidos en una carpeta | ||
Return: | ||||
|
r53 | El ultimo file de una determinada carpeta, no se considera el path. | ||
|
r49 | """ | ||
|
r53 | validFilelist = [] | ||
fileList = os.listdir(path) | ||||
|
r49 | # 0 1234 567 89A BCDE | ||
|
r58 | # H YYYY DDD SSS .ext | ||
|
r49 | |||
|
r53 | for file in fileList: | ||
try: | ||||
year = int(file[1:5]) | ||||
doy = int(file[5:8]) | ||||
|
r58 | |||
if (os.path.splitext(file)[-1].upper() != ext.upper()) : continue | ||||
|
r53 | except: | ||
continue | ||||
|
r49 | |||
|
r53 | validFilelist.append(file) | ||
|
r49 | |||
|
r58 | if validFilelist: | ||
|
r53 | validFilelist = sorted( validFilelist, key=str.lower ) | ||
return validFilelist[-1] | ||||
|
r49 | |||
|
r53 | return None | ||
|
r49 | |||
|
r98 | class JRODataIO: | ||
|
r50 | |||
|
r89 | #speed of light | ||
c = 3E8 | ||||
|
r49 | |||
m_BasicHeader = BasicHeader() | ||||
m_SystemHeader = SystemHeader() | ||||
m_RadarControllerHeader = RadarControllerHeader() | ||||
m_ProcessingHeader = ProcessingHeader() | ||||
|
r107 | dataOutObj = None | ||
|
r77 | |||
|
r49 | online = 0 | ||
|
r53 | fp = None | ||
|
r49 | |||
|
r89 | dataType = None | ||
|
r53 | fileSizeByHeader = None | ||
|
r49 | |||
|
r53 | filenameList = [] | ||
|
r49 | |||
filename = None | ||||
fileSize = None | ||||
firstHeaderSize = 0 | ||||
basicHeaderSize = 24 | ||||
|
r89 | nTotalBlocks = 0 | ||
ippSeconds = 0 | ||||
|
r49 | |||
|
r89 | blocksize = 0 | ||
|
r49 | |||
|
r53 | set = 0 | ||
|
r49 | |||
|
r53 | ext = None | ||
|
r9 | |||
|
r53 | path = None | ||
|
r49 | |||
|
r89 | maxTimeStep = 30 | ||
|
r64 | delay = 3 #seconds | ||
|
r49 | |||
|
r53 | nTries = 3 #quantity tries | ||
|
r49 | |||
|
r89 | nFiles = 3 #number of files for searching | ||
|
r53 | |||
|
r89 | flagNoMoreFiles = 0 | ||
|
r53 | |||
|
r58 | flagIsNewFile = 1 | ||
|
r89 | |||
|
r58 | flagResetProcessing = 0 | ||
flagIsNewBlock = 0 | ||||
|
r89 | def __init__(self): | ||
pass | ||||
class JRODataReader(JRODataIO): | ||||
""" | ||||
Esta clase es usada como la clase padre de las clases VoltageReader y SpectraReader. | ||||
Contiene todos lo metodos necesarios para leer datos desde archivos en formato | ||||
jicamarca o pdata (.r o .pdata). La lectura de los datos siempre se realiza por bloques. Los datos | ||||
leidos son array de 3 dimensiones: | ||||
|
r58 | |||
|
r89 | Para Voltajes - perfiles * alturas * canales | ||
Para Spectra - paresCanalesIguales * alturas * perfiles (Self Spectra) | ||||
paresCanalesDiferentes * alturas * perfiles (Cross Spectra) | ||||
canales * alturas (DC Channels) | ||||
y son almacenados en su buffer respectivo. | ||||
Esta clase contiene instancias (objetos) de las clases BasicHeader, SystemHeader, | ||||
RadarControllerHeader y DataObj. Los tres primeros se usan para almacenar informacion de la | ||||
cabecera de datos (metadata), y el cuarto (DataObj) para obtener y almacenar los datos desde | ||||
el buffer de datos cada vez que se ejecute el metodo "getData". | ||||
""" | ||||
|
r77 | |||
|
r89 | nReadBlocks = 0 | ||
|
r49 | |||
|
r107 | def __init__(self, dataOutObj=None): | ||
|
r89 | |||
|
r77 | raise ValueError, "This class can't be instanced" | ||
def hasNotDataInBuffer(self): | ||||
|
r89 | |||
|
r77 | raise ValueError, "Not implemented" | ||
|
r89 | |||
def getBlockDimension(self): | ||||
raise ValueError, "No implemented" | ||||
|
r77 | def readBlock(self): | ||
|
r89 | |||
self.nTotalBlocks += 1 | ||||
self.nReadBlocks += 1 | ||||
|
r77 | raise ValueError, "This method has not been implemented" | ||
|
r89 | |||
|
r77 | def getData( self ): | ||
|
r89 | |||
|
r77 | raise ValueError, "This method has not been implemented" | ||
|
r89 | |||
|
r107 | def createObjByDefault(self): | ||
""" | ||||
Los objetos creados por defecto por cada clase (Voltaje o Espectro) difieren en el tipo | ||||
raise ValueError, "This method has not been implemented | ||||
""" | ||||
raise ValueError, "This method has not been implemented" | ||||
def setup(self, dataOutObj=None, path=None, startDateTime=None, endDateTime=None, set=0, expLabel = "", ext = None, online = 0): | ||||
""" | ||||
setup configura los parametros de lectura de la clase DataReader. | ||||
Si el modo de lectura es offline, primero se realiza una busqueda de todos los archivos | ||||
que coincidan con los parametros especificados; esta lista de archivos son almacenados en | ||||
self.filenameList. | ||||
Input: | ||||
path : Directorios donde se ubican los datos a leer. Dentro de este | ||||
directorio deberia de estar subdirectorios de la forma: | ||||
path/D[yyyy][ddd]/expLabel/P[yyyy][ddd][sss][ext] | ||||
startDateTime : Fecha inicial. Rechaza todos los archivos donde | ||||
file end time < startDatetime (obejto datetime.datetime) | ||||
endDateTime : Fecha final. Si no es None, rechaza todos los archivos donde | ||||
file end time < startDatetime (obejto datetime.datetime) | ||||
set : Set del primer archivo a leer. Por defecto None | ||||
expLabel : Nombre del subdirectorio de datos. Por defecto "" | ||||
ext : Extension de los archivos a leer. Por defecto .r | ||||
online : Si es == a 0 entonces busca files que cumplan con las condiciones dadas | ||||
Return: | ||||
0 : Si no encuentra files que cumplan con las condiciones dadas | ||||
1 : Si encuentra files que cumplan con las condiciones dadas | ||||
Affected: | ||||
self.startUTCSeconds | ||||
self.endUTCSeconds | ||||
self.startYear | ||||
self.endYear | ||||
self.startDoy | ||||
self.endDoy | ||||
self.pathList | ||||
self.filenameList | ||||
self.online | ||||
""" | ||||
if path == None: | ||||
raise ValueError, "The path is not valid" | ||||
if ext == None: | ||||
ext = self.ext | ||||
if dataOutObj == None: | ||||
dataOutObj = self.createObjByDefault() | ||||
self.dataOutObj = dataOutObj | ||||
if online: | ||||
print "Searching files ..." | ||||
doypath, file, year, doy, set = self.__searchFilesOnLine(path, startDateTime, endDateTime, expLabel, ext) | ||||
if not(doypath): | ||||
for nTries in range( self.nTries ): | ||||
print '\tWaiting %0.2f sec for valid file in %s: try %02d ...' % (self.delay, path, nTries+1) | ||||
time.sleep( self.delay ) | ||||
doypath, file, year, doy, set = self.__searchFilesOnLine(path, startDateTime, endDateTime, expLabel, ext) | ||||
if doypath: | ||||
break | ||||
if not(doypath): | ||||
print "There 'isn't valied files in %s" % path | ||||
return None | ||||
self.year = year | ||||
self.doy = doy | ||||
self.set = set - 1 | ||||
self.path = path | ||||
else: # offline | ||||
pathList, filenameList = self.__searchFilesOffLine(path, startDateTime, endDateTime, set, expLabel, ext) | ||||
if not(pathList): | ||||
print "No files in range: %s - %s" %(startDateTime.ctime(), endDateTime.ctime()) | ||||
return None | ||||
self.fileIndex = -1 | ||||
self.pathList = pathList | ||||
self.filenameList = filenameList | ||||
self.online = online | ||||
self.ext = ext | ||||
ext = ext.lower() | ||||
if not( self.setNextFile() ): | ||||
if (startDateTime != None) and (endDateTime != None): | ||||
print "No files in range: %s - %s" %(startDateTime.ctime(), endDateTime.ctime()) | ||||
elif startDateTime != None: | ||||
print "No files in : %s" % startDateTime.ctime() | ||||
else: | ||||
print "No files" | ||||
return None | ||||
if startDateTime != None: | ||||
self.startUTCSeconds = time.mktime(startDateTime.timetuple()) | ||||
self.startYear = startDateTime.timetuple().tm_year | ||||
self.startDoy = startDateTime.timetuple().tm_yday | ||||
if endDateTime != None: | ||||
self.endUTCSeconds = time.mktime(endDateTime.timetuple()) | ||||
self.endYear = endDateTime.timetuple().tm_year | ||||
self.endDoy = endDateTime.timetuple().tm_yday | ||||
#call fillHeaderValues() - to Data Object | ||||
self.updateDataHeader() | ||||
return self.dataOutObj | ||||
|
r50 | |||
def __rdSystemHeader(self, fp=None): | ||||
|
r49 | |||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r49 | |||
self.m_SystemHeader.read(fp) | ||||
|
r50 | |||
|
r49 | |||
|
r50 | def __rdRadarControllerHeader(self, fp=None): | ||
|
r49 | if fp == None: | ||
|
r53 | fp = self.fp | ||
|
r49 | |||
self.m_RadarControllerHeader.read(fp) | ||||
|
r50 | |||
|
r49 | |||
|
r50 | def __rdProcessingHeader(self, fp=None): | ||
|
r49 | if fp == None: | ||
|
r53 | fp = self.fp | ||
|
r49 | |||
self.m_ProcessingHeader.read(fp) | ||||
|
r50 | |||
|
r49 | def __rdBasicHeader(self, fp=None): | ||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r49 | |||
self.m_BasicHeader.read(fp) | ||||
|
r77 | |||
|
r49 | def __readFirstHeader(self): | ||
|
r50 | """ | ||
Lectura del First Header, es decir el Basic Header y el Long Header | ||||
Affected: | ||||
self.m_BasicHeader | ||||
self.m_SystemHeader | ||||
self.m_RadarControllerHeader | ||||
self.m_ProcessingHeader | ||||
self.firstHeaderSize | ||||
|
r53 | self.dataType | ||
self.fileSizeByHeader | ||||
self.ippSeconds | ||||
|
r50 | |||
Return: | ||||
None | ||||
""" | ||||
|
r49 | self.__rdBasicHeader() | ||
self.__rdSystemHeader() | ||||
self.__rdRadarControllerHeader() | ||||
self.__rdProcessingHeader() | ||||
self.firstHeaderSize = self.m_BasicHeader.size | ||||
|
r89 | datatype = int(numpy.log2((self.m_ProcessingHeader.processFlags & PROCFLAG.DATATYPE_MASK))-numpy.log2(PROCFLAG.DATATYPE_CHAR)) | ||
if datatype == 0: | ||||
datatype_str = numpy.dtype([('real','<i1'),('imag','<i1')]) | ||||
|
r49 | |||
|
r89 | elif datatype == 1: | ||
datatype_str = numpy.dtype([('real','<i2'),('imag','<i2')]) | ||||
|
r49 | |||
|
r89 | elif datatype == 2: | ||
datatype_str = numpy.dtype([('real','<i4'),('imag','<i4')]) | ||||
|
r49 | |||
|
r89 | elif datatype == 3: | ||
datatype_str = numpy.dtype([('real','<i8'),('imag','<i8')]) | ||||
|
r49 | |||
|
r89 | elif datatype == 4: | ||
datatype_str = numpy.dtype([('real','<f4'),('imag','<f4')]) | ||||
|
r49 | |||
|
r89 | elif datatype == 5: | ||
datatype_str = numpy.dtype([('real','<f8'),('imag','<f8')]) | ||||
|
r49 | |||
else: | ||||
raise ValueError, 'Data type was not defined' | ||||
|
r89 | self.dataType = datatype_str | ||
|
r53 | self.ippSeconds = 2 * 1000 * self.m_RadarControllerHeader.ipp / self.c | ||
|
r49 | |||
|
r89 | self.fileSizeByHeader = self.m_ProcessingHeader.dataBlocksPerFile * self.m_ProcessingHeader.blockSize + self.firstHeaderSize + self.basicHeaderSize*(self.m_ProcessingHeader.dataBlocksPerFile - 1) | ||
|
r107 | self.dataOutObj.channelList = numpy.arange(self.m_SystemHeader.numChannels) | ||
self.dataOutObj.channelIndexList = numpy.arange(self.m_SystemHeader.numChannels) | ||||
|
r53 | self.getBlockDimension() | ||
|
r89 | |||
|
r94 | |||
|
r89 | def __setNewBlock(self): | ||
""" | ||||
Lee el Basic Header y posiciona le file pointer en la posicion inicial del bloque a leer | ||||
Affected: | ||||
self.m_BasicHeader | ||||
self.flagNoContinuousBlock | ||||
self.ns | ||||
Return: | ||||
0 : Si el file no tiene un Basic Header que pueda ser leido | ||||
1 : Si se pudo leer el Basic Header | ||||
""" | ||||
if self.fp == None: | ||||
return 0 | ||||
if self.flagIsNewFile: | ||||
return 1 | ||||
self.lastUTTime = self.m_BasicHeader.utc | ||||
currentSize = self.fileSize - self.fp.tell() | ||||
neededSize = self.m_ProcessingHeader.blockSize + self.basicHeaderSize | ||||
#If there is enough data setting new data block | ||||
if ( currentSize >= neededSize ): | ||||
self.__rdBasicHeader() | ||||
return 1 | ||||
#si es OnLine y ademas aun no se han leido un bloque completo entonces se espera por uno valido | ||||
if self.online and (self.nReadBlocks < self.m_ProcessingHeader.dataBlocksPerFile): | ||||
fpointer = self.fp.tell() | ||||
for nTries in range( self.nTries ): | ||||
#self.fp.close() | ||||
print "\tWaiting %0.2f seconds for the next block, try %03d ..." % (self.delay, nTries+1) | ||||
time.sleep( self.delay ) | ||||
#self.fp = open( self.filename, 'rb' ) | ||||
#self.fp.seek( fpointer ) | ||||
self.fileSize = os.path.getsize( self.filename ) | ||||
currentSize = self.fileSize - fpointer | ||||
if ( currentSize >= neededSize ): | ||||
self.__rdBasicHeader() | ||||
return 1 | ||||
#Setting new file | ||||
if not( self.setNextFile() ): | ||||
return 0 | ||||
deltaTime = self.m_BasicHeader.utc - self.lastUTTime # check this | ||||
self.flagResetProcessing = 0 | ||||
if deltaTime > self.maxTimeStep: | ||||
self.flagResetProcessing = 1 | ||||
return 1 | ||||
def readNextBlock(self): | ||||
""" | ||||
Establece un nuevo bloque de datos a leer y los lee, si es que no existiese | ||||
mas bloques disponibles en el archivo actual salta al siguiente. | ||||
Affected: | ||||
self.lastUTTime | ||||
|
r50 | |||
|
r89 | Return: None | ||
""" | ||||
if not(self.__setNewBlock()): | ||||
return 0 | ||||
if not(self.readBlock()): | ||||
return 0 | ||||
return 1 | ||||
|
r58 | |||
|
r50 | def __setNextFileOnline(self): | ||
|
r49 | """ | ||
Busca el siguiente file que tenga suficiente data para ser leida, dentro de un folder especifico, si | ||||
no encuentra un file valido espera un tiempo determinado y luego busca en los posibles n files | ||||
siguientes. | ||||
Affected: | ||||
|
r53 | self.flagIsNewFile | ||
|
r49 | self.filename | ||
self.fileSize | ||||
|
r53 | self.fp | ||
self.set | ||||
|
r49 | self.flagNoMoreFiles | ||
Return: | ||||
0 : si luego de una busqueda del siguiente file valido este no pudo ser encontrado | ||||
1 : si el file fue abierto con exito y esta listo a ser leido | ||||
Excepciones: | ||||
Si un determinado file no puede ser abierto | ||||
""" | ||||
|
r64 | nFiles = 0 | ||
|
r50 | fileOk_flag = False | ||
|
r64 | firstTime_flag = True | ||
self.set += 1 | ||||
|
r49 | |||
|
r64 | #busca el 1er file disponible | ||
file, filename = checkForRealPath( self.path, self.year, self.doy, self.set, self.ext ) | ||||
if file: | ||||
if self.__verifyFile(file, False): | ||||
fileOk_flag = True | ||||
#si no encuentra un file entonces espera y vuelve a buscar | ||||
if not(fileOk_flag): | ||||
for nFiles in range(self.nFiles+1): #busco en los siguientes self.nFiles+1 files posibles | ||||
if firstTime_flag: #si es la 1era vez entonces hace el for self.nTries veces | ||||
tries = self.nTries | ||||
else: | ||||
tries = 1 #si no es la 1era vez entonces solo lo hace una vez | ||||
for nTries in range( tries ): | ||||
if firstTime_flag: | ||||
|
r58 | print "\tWaiting %0.2f sec for new \"%s\" file, try %03d ..." % ( self.delay, filename, nTries+1 ) | ||
|
r53 | time.sleep( self.delay ) | ||
|
r64 | else: | ||
print "\tSearching next \"%s%04d%03d%03d%s\" file ..." % (self.optchar, self.year, self.doy, self.set, self.ext) | ||||
file, filename = checkForRealPath( self.path, self.year, self.doy, self.set, self.ext ) | ||||
if file: | ||||
if self.__verifyFile(file): | ||||
fileOk_flag = True | ||||
break | ||||
if fileOk_flag: | ||||
break | ||||
firstTime_flag = False | ||||
print "\tSkipping the file \"%s\" due to this file doesn't exist yet" % filename | ||||
self.set += 1 | ||||
if nFiles == (self.nFiles-1): #si no encuentro el file buscado cambio de carpeta y busco en la siguiente carpeta | ||||
self.set = 0 | ||||
self.doy += 1 | ||||
|
r50 | |||
if fileOk_flag: | ||||
self.fileSize = os.path.getsize( file ) | ||||
|
r49 | self.filename = file | ||
|
r53 | self.flagIsNewFile = 1 | ||
if self.fp != None: self.fp.close() | ||||
self.fp = open(file) | ||||
|
r58 | self.flagNoMoreFiles = 0 | ||
|
r49 | print 'Setting the file: %s' % file | ||
else: | ||||
self.fileSize = 0 | ||||
self.filename = None | ||||
|
r64 | self.flagIsNewFile = 0 | ||
|
r53 | self.fp = None | ||
|
r58 | self.flagNoMoreFiles = 1 | ||
|
r49 | print 'No more Files' | ||
|
r50 | return fileOk_flag | ||
|
r49 | |||
def __setNextFileOffline(self): | ||||
|
r50 | """ | ||
Busca el siguiente file dentro de un folder que tenga suficiente data para ser leida | ||||
Affected: | ||||
|
r53 | self.flagIsNewFile | ||
self.fileIndex | ||||
|
r50 | self.filename | ||
self.fileSize | ||||
|
r53 | self.fp | ||
|
r50 | |||
Return: | ||||
0 : si un determinado file no puede ser abierto | ||||
1 : si el file fue abierto con exito | ||||
|
r49 | |||
|
r50 | Excepciones: | ||
Si un determinado file no puede ser abierto | ||||
""" | ||||
|
r53 | idFile = self.fileIndex | ||
|
r90 | |||
|
r49 | while(True): | ||
idFile += 1 | ||||
|
r53 | if not(idFile < len(self.filenameList)): | ||
|
r49 | self.flagNoMoreFiles = 1 | ||
|
r50 | print 'No more Files' | ||
|
r49 | return 0 | ||
|
r53 | filename = self.filenameList[idFile] | ||
|
r90 | |||
if not(self.__verifyFile(filename)): | ||||
|
r49 | continue | ||
|
r90 | |||
fileSize = os.path.getsize(filename) | ||||
fp = open(filename,'rb') | ||||
|
r49 | break | ||
|
r90 | |||
|
r53 | self.flagIsNewFile = 1 | ||
self.fileIndex = idFile | ||||
|
r49 | self.filename = filename | ||
self.fileSize = fileSize | ||||
|
r53 | self.fp = fp | ||
|
r49 | |||
print 'Setting the file: %s'%self.filename | ||||
return 1 | ||||
|
r50 | |||
|
r49 | |||
|
r58 | def setNextFile(self): | ||
|
r49 | """ | ||
Determina el siguiente file a leer y si hay uno disponible lee el First Header | ||||
Affected: | ||||
self.m_BasicHeader | ||||
self.m_SystemHeader | ||||
self.m_RadarControllerHeader | ||||
self.m_ProcessingHeader | ||||
self.firstHeaderSize | ||||
Return: | ||||
0 : Si no hay files disponibles | ||||
1 : Si hay mas files disponibles | ||||
""" | ||||
|
r53 | if self.fp != None: | ||
self.fp.close() | ||||
|
r49 | |||
if self.online: | ||||
newFile = self.__setNextFileOnline() | ||||
else: | ||||
newFile = self.__setNextFileOffline() | ||||
|
r50 | |||
|
r49 | if not(newFile): | ||
return 0 | ||||
self.__readFirstHeader() | ||||
|
r89 | self.nReadBlocks = 0 | ||
|
r49 | return 1 | ||
|
r58 | def __searchFilesOnLine(self, path, startDateTime=None, endDateTime=None, expLabel = "", ext = None): | ||
|
r49 | """ | ||
Busca el ultimo archivo de la ultima carpeta (determinada o no por startDateTime) y | ||||
devuelve el archivo encontrado ademas de otros datos. | ||||
Input: | ||||
path : carpeta donde estan contenidos los files que contiene data | ||||
startDateTime : punto especifico en el tiempo del cual se requiere la data | ||||
ext : extension de los files | ||||
Return: | ||||
year : el anho | ||||
doy : el numero de dia del anho | ||||
set : el set del archivo | ||||
filename : el ultimo file de una determinada carpeta | ||||
directory : eL directorio donde esta el file encontrado | ||||
""" | ||||
dirList = [] | ||||
|
r64 | pathList = [] | ||
directory = None | ||||
|
r53 | for thisPath in os.listdir(path): | ||
if os.path.isdir(os.path.join(path,thisPath)): | ||||
dirList.append(thisPath) | ||||
|
r49 | |||
|
r58 | if not(dirList): | ||
return None, None, None, None, None | ||||
|
r64 | dirList = sorted( dirList, key=str.lower ) | ||
if startDateTime: | ||||
|
r53 | thisDateTime = startDateTime | ||
if endDateTime == None: endDateTime = startDateTime | ||||
|
r49 | |||
|
r53 | while(thisDateTime <= endDateTime): | ||
year = thisDateTime.timetuple().tm_year | ||||
doy = thisDateTime.timetuple().tm_yday | ||||
match = fnmatch.filter(dirList, '?' + '%4.4d%3.3d' % (year,doy)) | ||||
if len(match) == 0: | ||||
thisDateTime += datetime.timedelta(1) | ||||
continue | ||||
pathList.append(os.path.join(path,match[0], expLabel)) | ||||
thisDateTime += datetime.timedelta(1) | ||||
|
r58 | |||
|
r64 | if not(pathList): | ||
print "\tNo files in range: %s - %s" %(startDateTime.ctime(), endDateTime.ctime()) | ||||
return None, None, None, None, None | ||||
directory = pathList[0] | ||||
else: | ||||
directory = dirList[-1] | ||||
directory = os.path.join(path,directory) | ||||
|
r49 | |||
|
r58 | filename = getlastFileFromPath(directory, ext) | ||
if not(filename): | ||||
|
r53 | return None, None, None, None, None | ||
|
r49 | |||
|
r53 | if not(self.__verifyFile(os.path.join(directory, filename))): | ||
return None, None, None, None, None | ||||
|
r58 | |||
|
r53 | year = int( filename[1:5] ) | ||
doy = int( filename[5:8] ) | ||||
set = int( filename[8:11] ) | ||||
|
r49 | |||
|
r53 | return directory, filename, year, doy, set | ||
|
r49 | |||
def __searchFilesOffLine(self, path, startDateTime, endDateTime, set=None, expLabel = "", ext = ".r"): | ||||
""" | ||||
Realiza una busqueda de los archivos que coincidan con los parametros | ||||
especificados y se encuentren ubicados en el path indicado. Para realizar una busqueda | ||||
correcta la estructura de directorios debe ser la siguiente: | ||||
...path/D[yyyy][ddd]/expLabel/D[yyyy][ddd][sss].ext | ||||
[yyyy]: anio | ||||
[ddd] : dia del anio | ||||
[sss] : set del archivo | ||||
Inputs: | ||||
path : Directorio de datos donde se realizara la busqueda. Todos los | ||||
ficheros que concidan con el criterio de busqueda seran | ||||
almacenados en una lista y luego retornados. | ||||
startDateTime : Fecha inicial. Rechaza todos los archivos donde | ||||
file end time < startDateTime (obejto datetime.datetime) | ||||
endDateTime : Fecha final. Rechaza todos los archivos donde | ||||
file start time > endDateTime (obejto datetime.datetime) | ||||
set : Set del primer archivo a leer. Por defecto None | ||||
expLabel : Nombre del subdirectorio de datos. Por defecto "" | ||||
ext : Extension de los archivos a leer. Por defecto .r | ||||
Return: | ||||
(pathList, filenameList) | ||||
pathList : Lista de directorios donde se encontraron archivos dentro | ||||
de los parametros especificados | ||||
filenameList : Lista de archivos (ruta completa) que coincidieron con los | ||||
parametros especificados. | ||||
Variables afectadas: | ||||
|
r53 | self.filenameList: Lista de archivos (ruta completa) que la clase utiliza | ||
|
r49 | como fuente para leer los bloque de datos, si se termina | ||
de leer todos los bloques de datos de un determinado | ||||
archivo se pasa al siguiente archivo de la lista. | ||||
Excepciones: | ||||
""" | ||||
print "Searching files ..." | ||||
dirList = [] | ||||
for thisPath in os.listdir(path): | ||||
if os.path.isdir(os.path.join(path,thisPath)): | ||||
dirList.append(thisPath) | ||||
|
r58 | if not(dirList): | ||
return None, None | ||||
|
r49 | pathList = [] | ||
thisDateTime = startDateTime | ||||
while(thisDateTime <= endDateTime): | ||||
year = thisDateTime.timetuple().tm_year | ||||
doy = thisDateTime.timetuple().tm_yday | ||||
match = fnmatch.filter(dirList, '?' + '%4.4d%3.3d' % (year,doy)) | ||||
if len(match) == 0: | ||||
thisDateTime += datetime.timedelta(1) | ||||
continue | ||||
pathList.append(os.path.join(path,match[0],expLabel)) | ||||
thisDateTime += datetime.timedelta(1) | ||||
startUtSeconds = time.mktime(startDateTime.timetuple()) | ||||
endUtSeconds = time.mktime(endDateTime.timetuple()) | ||||
filenameList = [] | ||||
for thisPath in pathList: | ||||
fileList = glob.glob1(thisPath, "*%s" %ext) | ||||
fileList.sort() | ||||
for file in fileList: | ||||
filename = os.path.join(thisPath,file) | ||||
if isThisFileinRange(filename, startUtSeconds, endUtSeconds): | ||||
filenameList.append(filename) | ||||
|
r58 | if not(filenameList): | ||
return None, None | ||||
|
r53 | self.filenameList = filenameList | ||
|
r49 | |||
return pathList, filenameList | ||||
|
r58 | def __verifyFile(self, filename, msgFlag=True): | ||
|
r49 | """ | ||
|
r58 | Verifica que el filename tenga data valida, para ello leo el FirstHeader del file | ||
|
r49 | |||
Return: | ||||
0 : file no valido para ser leido | ||||
1 : file valido para ser leido | ||||
""" | ||||
|
r90 | msg = None | ||
|
r58 | try: | ||
fp = open( filename,'rb' ) #lectura binaria | ||||
|
r90 | currentPosition = fp.tell() | ||
|
r58 | except: | ||
if msgFlag: | ||||
print "The file %s can't be opened" % (filename) | ||||
|
r90 | return False | ||
neededSize = self.m_ProcessingHeader.blockSize + self.firstHeaderSize | ||||
|
r58 | |||
|
r90 | if neededSize == 0: | ||
m_BasicHeader = BasicHeader() | ||||
m_SystemHeader = SystemHeader() | ||||
m_RadarControllerHeader = RadarControllerHeader() | ||||
m_ProcessingHeader = ProcessingHeader() | ||||
try: | ||||
if not( m_BasicHeader.read(fp) ): raise ValueError | ||||
if not( m_SystemHeader.read(fp) ): raise ValueError | ||||
if not( m_RadarControllerHeader.read(fp) ): raise ValueError | ||||
if not( m_ProcessingHeader.read(fp) ): raise ValueError | ||||
data_type = int(numpy.log2((m_ProcessingHeader.processFlags & PROCFLAG.DATATYPE_MASK))-numpy.log2(PROCFLAG.DATATYPE_CHAR)) | ||||
neededSize = m_ProcessingHeader.blockSize + m_BasicHeader.size | ||||
except: | ||||
if msgFlag: | ||||
print "\tThe file %s is empty or it hasn't enough data" % filename | ||||
fp.close() | ||||
return False | ||||
|
r58 | |||
|
r90 | else: | ||
msg = "\tSkipping the file %s due to it hasn't enough data" %filename | ||||
|
r58 | fp.close() | ||
|
r90 | fileSize = os.path.getsize(filename) | ||
currentSize = fileSize - currentPosition | ||||
|
r58 | |||
|
r90 | if currentSize < neededSize: | ||
if msgFlag and (msg != None): | ||||
print msg #print"\tSkipping the file %s due to it hasn't enough data" %filename | ||||
return False | ||||
return True | ||||
|
r89 | def updateDataHeader(self): | ||
|
r107 | self.dataOutObj.m_BasicHeader = self.m_BasicHeader.copy() | ||
self.dataOutObj.m_ProcessingHeader = self.m_ProcessingHeader.copy() | ||||
self.dataOutObj.m_RadarControllerHeader = self.m_RadarControllerHeader.copy() | ||||
self.dataOutObj.m_SystemHeader = self.m_SystemHeader.copy() | ||||
|
r53 | |||
|
r107 | self.dataOutObj.dataType = self.dataType | ||
self.dataOutObj.updateObjFromHeader() | ||||
|
r58 | |||
|
r89 | |||
class JRODataWriter(JRODataIO): | ||||
|
r58 | |||
|
r50 | """ | ||
Esta clase permite escribir datos a archivos procesados (.r o ,pdata). La escritura | ||||
de los datos siempre se realiza por bloques. | ||||
""" | ||||
|
r77 | |||
nWriteBlocks = 0 | ||||
setFile = None | ||||
|
r107 | def __init__(self, dataOutObj=None): | ||
|
r77 | raise ValueError, "Not implemented" | ||
def hasAllDataInBuffer(self): | ||||
raise ValueError, "Not implemented" | ||||
def setBlockDimension(self): | ||||
raise ValueError, "Not implemented" | ||||
def writeBlock(self): | ||||
raise ValueError, "No implemented" | ||||
def putData(self): | ||||
raise ValueError, "No implemented" | ||||
|
r58 | |||
|
r50 | def __writeFirstHeader(self): | ||
""" | ||||
Escribe el primer header del file es decir el Basic header y el Long header (SystemHeader, RadarControllerHeader, ProcessingHeader) | ||||
Affected: | ||||
__dataType | ||||
Return: | ||||
None | ||||
""" | ||||
self.__writeBasicHeader() | ||||
self.__wrSystemHeader() | ||||
self.__wrRadarControllerHeader() | ||||
self.__wrProcessingHeader() | ||||
|
r107 | self.dataType = self.dataOutObj.dataType | ||
|
r50 | |||
def __writeBasicHeader(self, fp=None): | ||||
""" | ||||
Escribe solo el Basic header en el file creado | ||||
Return: | ||||
None | ||||
""" | ||||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r50 | |||
|
r107 | self.dataOutObj.m_BasicHeader.write(fp) | ||
|
r50 | |||
def __wrSystemHeader(self, fp=None): | ||||
""" | ||||
Escribe solo el System header en el file creado | ||||
Return: | ||||
None | ||||
""" | ||||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r50 | |||
|
r107 | self.dataOutObj.m_SystemHeader.write(fp) | ||
|
r50 | |||
def __wrRadarControllerHeader(self, fp=None): | ||||
""" | ||||
Escribe solo el RadarController header en el file creado | ||||
Return: | ||||
None | ||||
""" | ||||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r50 | |||
|
r107 | self.dataOutObj.m_RadarControllerHeader.write(fp) | ||
|
r50 | |||
def __wrProcessingHeader(self, fp=None): | ||||
""" | ||||
Escribe solo el Processing header en el file creado | ||||
Return: | ||||
None | ||||
""" | ||||
if fp == None: | ||||
|
r53 | fp = self.fp | ||
|
r50 | |||
|
r107 | self.dataOutObj.m_ProcessingHeader.write(fp) | ||
|
r50 | |||
|
r58 | def setNextFile(self): | ||
|
r50 | """ | ||
Determina el siguiente file que sera escrito | ||||
Affected: | ||||
self.filename | ||||
|
r53 | self.subfolder | ||
self.fp | ||||
self.setFile | ||||
self.flagIsNewFile | ||||
|
r50 | |||
Return: | ||||
0 : Si el archivo no puede ser escrito | ||||
1 : Si el archivo esta listo para ser escrito | ||||
""" | ||||
|
r53 | ext = self.ext | ||
path = self.path | ||||
|
r50 | |||
|
r53 | if self.fp != None: | ||
self.fp.close() | ||||
|
r50 | |||
|
r107 | timeTuple = time.localtime( self.dataOutObj.m_BasicHeader.utc ) | ||
|
r50 | subfolder = 'D%4.4d%3.3d' % (timeTuple.tm_year,timeTuple.tm_yday) | ||
|
r89 | doypath = os.path.join( path, subfolder ) | ||
if not( os.path.exists(doypath) ): | ||||
os.mkdir(doypath) | ||||
|
r53 | self.setFile = -1 #inicializo mi contador de seteo | ||
|
r50 | else: | ||
|
r89 | filesList = os.listdir( doypath ) | ||
|
r50 | if len( filesList ) > 0: | ||
filesList = sorted( filesList, key=str.lower ) | ||||
filen = filesList[-1] | ||||
# el filename debera tener el siguiente formato | ||||
# 0 1234 567 89A BCDE (hex) | ||||
|
r58 | # x YYYY DDD SSS .ext | ||
|
r50 | if isNumber( filen[8:11] ): | ||
|
r53 | self.setFile = int( filen[8:11] ) #inicializo mi contador de seteo al seteo del ultimo file | ||
|
r50 | else: | ||
|
r53 | self.setFile = -1 | ||
|
r50 | else: | ||
|
r53 | self.setFile = -1 #inicializo mi contador de seteo | ||
|
r50 | |||
|
r53 | setFile = self.setFile | ||
|
r50 | setFile += 1 | ||
|
r53 | file = '%s%4.4d%3.3d%3.3d%s' % (self.optchar, | ||
timeTuple.tm_year, | ||||
timeTuple.tm_yday, | ||||
setFile, | ||||
ext ) | ||||
|
r50 | |||
filename = os.path.join( path, subfolder, file ) | ||||
fp = open( filename,'wb' ) | ||||
|
r89 | self.nWriteBlocks = 0 | ||
|
r49 | |||
|
r50 | #guardando atributos | ||
self.filename = filename | ||||
|
r53 | self.subfolder = subfolder | ||
self.fp = fp | ||||
self.setFile = setFile | ||||
self.flagIsNewFile = 1 | ||||
|
r50 | |||
print 'Writing the file: %s'%self.filename | ||||
self.__writeFirstHeader() | ||||
return 1 | ||||
def __setNewBlock(self): | ||||
""" | ||||
Si es un nuevo file escribe el First Header caso contrario escribe solo el Basic Header | ||||
Return: | ||||
0 : si no pudo escribir nada | ||||
1 : Si escribio el Basic el First Header | ||||
""" | ||||
|
r53 | if self.fp == None: | ||
|
r58 | self.setNextFile() | ||
|
r50 | |||
|
r53 | if self.flagIsNewFile: | ||
|
r50 | return 1 | ||
|
r89 | if self.nWriteBlocks < self.m_ProcessingHeader.dataBlocksPerFile: | ||
|
r50 | self.__writeBasicHeader() | ||
return 1 | ||||
|
r58 | if not( self.setNextFile() ): | ||
|
r50 | return 0 | ||
return 1 | ||||
def writeNextBlock(self): | ||||
""" | ||||
Selecciona el bloque siguiente de datos y los escribe en un file | ||||
Return: | ||||
0 : Si no hizo pudo escribir el bloque de datos | ||||
1 : Si no pudo escribir el bloque de datos | ||||
""" | ||||
if not( self.__setNewBlock() ): | ||||
return 0 | ||||
|
r53 | self.writeBlock() | ||
|
r50 | |||
return 1 | ||||
|
r58 | |||
|
r50 | |||
|
r89 | def getDataHeader(self): | ||
|
r50 | """ | ||
Obtiene una copia del First Header | ||||
Affected: | ||||
self.m_BasicHeader | ||||
self.m_SystemHeader | ||||
self.m_RadarControllerHeader | ||||
self.m_ProcessingHeader | ||||
|
r53 | self.dataType | ||
|
r50 | |||
Return: | ||||
None | ||||
""" | ||||
|
r107 | self.dataOutObj.updateHeaderFromObj() | ||
|
r89 | |||
|
r107 | self.m_BasicHeader = self.dataOutObj.m_BasicHeader.copy() | ||
self.m_SystemHeader = self.dataOutObj.m_SystemHeader.copy() | ||||
self.m_RadarControllerHeader = self.dataOutObj.m_RadarControllerHeader.copy() | ||||
self.m_ProcessingHeader = self.dataOutObj.m_ProcessingHeader.copy() | ||||
|
r89 | |||
|
r107 | self.dataType = self.dataOutObj.dataType | ||
|
r89 | |||
|
r58 | |||
|
r53 | def setup(self, path, set=0, ext=None): | ||
|
r50 | """ | ||
Setea el tipo de formato en la cual sera guardada la data y escribe el First Header | ||||
Inputs: | ||||
path : el path destino en el cual se escribiran los files a crear | ||||
format : formato en el cual sera salvado un file | ||||
set : el setebo del file | ||||
Return: | ||||
0 : Si no realizo un buen seteo | ||||
1 : Si realizo un buen seteo | ||||
""" | ||||
|
r53 | if ext == None: | ||
ext = self.ext | ||||
|
r50 | |||
|
r53 | ext = ext.lower() | ||
self.path = path | ||||
self.setFile = set - 1 | ||||
self.ext = ext | ||||
|
r58 | #self.format = format | ||
|
r89 | self.getDataHeader() | ||
|
r50 | |||
|
r53 | self.setBlockDimension() | ||
|
r50 | |||
|
r58 | if not( self.setNextFile() ): | ||
|
r53 | print "There isn't a next file" | ||
|
r50 | return 0 | ||
|
r53 | return 1 | ||