#!
# coding: utf-8
# Copyright (C) 2016 TOPS SYSTEMS
### @file fmatTranspose.py
### @brief transpose Data dumper FLT matrix.
###
### DataDumperによりダンプされた配列を整形する
### (1) 転置
### (2) レジスタ長にあわせたゼロフィル
###
### Contact: izumida@topscom.co.jp
###
### @author: M.Izumida
### @date: December 2, 2016
###
# v01r01 newly created
# v01r02 2016/12/14 (2)の機能を追加
#
# Written for Python 2.7 (NOT FOR 3.x)
#=======================================================================
# インポート宣言
import sys
import re
import argparse
import os
import struct
from datetime import datetime
#=======================================================================
# バージョン文字列
versionSTR = "fmatTranspose.py v01r02b Tops Systems (pgm by mpi)"
#=======================================================================
# 共通サブルーチン
#-------------------------------------------------------------------
def errPrint(mes, opt=True):
"""errPrint.
エラー出力へのメッセージ表示
optがTrueであれば改行も行う
後の始末はその後で別に書くこと
"""
sys.stderr.write(mes)
if opt:
sys.stderr.write('\n')
#-------------------------------------------------------------------
def stdExceptionHandler(mes):
"""standard Exception Handler.
エラーメッセージを送出し、デバッグのための情報を出力する
"""
errPrint("Exception Captured: " + str(mes))
errPrint("0:" + str(sys.exc_info()[0]))
errPrint("1:" + str(sys.exc_info()[1]))
errPrint("2:" + str(sys.exc_info()[2]))
#-------------------------------------------------------------------
def tryIntParse(st, dval, radix=10):
"""try Parse string to Integer
文字列stをパースして整数化できれば値を返す、できなければデフォルト値dvalを返す
"""
try:
work = int(st, radix)
except:
return dval
return work
#=======================================================================
# 解析オプション クラス
class Options:
"""Options Class.
グローバルオプションを保持するクラス
"""
pass
#=======================================================================
# FLTファイルリーダライタ クラス
[ドキュメント]class FltFileReaderWriter:
"""FltFile ReaderWriter Class.
FLTファイルを読みとり、ターゲットの配列であれば
いったん配列として内部に保持し、
転置してから出力する。
そうでない行についてはそのままスルーで出力する。
"""
#--------------------------------------------------------------------
def __init__(self, inputFnam, outputFnam, targetArrayName, mode=0):
"""FLT File Reader Constructor
コンストラクタ
入力ファイル名 inputFnam
処理対象配列名 targetArrayName
"""
self.iFname = inputFnam
self.oFname = outputFnam
self.tName = targetArrayName
self.aNameT = ""
self.md = mode
self.ZERO = 0
# レコードヘッダ、トレイラの検索表現
self.headerRE = re.compile("^\@([a-zA-Z_][a-zA-Z0-9_]*)\<FLOAT\>\[([0-9]+)\,\s*([0-9]+)\]\s*\{")
self.trailerRE = re.compile("^}\s*nREC\=([0-9]+)\,\s*CONV_ERR_CODE\=([0-9]+)\,\s*CONV_ERR_COUNT\=([0-9]+)");
# 配列データ保持構造
self.clearArray()
self.inData = False
# ファイルデータ保持構造
self.Buffer = []
self.nLine = 0
# 反転モード
self.REV = False
# debug
self.debug = False
self.verbose = False
#--------------------------------------------------------------------
[ドキュメント] def clearArray(self):
"""Clear Array method
配列の一時記憶構造を初期化する
"""
self.Array = []
self.iX = 0
self.iY = 0
self.nData = 0
self.xCnt = 0
self.yCnt = 0
self.tempLine = []
#--------------------------------------------------------------------
[ドキュメント] def read(self):
"""Read method
FLTファイルを読み込むメソッド
"""
try:
with open(self.iFname, 'r') as f:
for line in f:
if self.rLine(line):
return False
except:
stdExceptionHandler("Error: in file reading = " + self.iFname)
return False
return True
#--------------------------------------------------------------------
[ドキュメント] def rLine(self, lin):
"""Read Line method
読み取った1行を処理するメソッド
inData フラグが立っていれば、
.. ①レコード末尾行であればパラメータを読み取ってチェックする
.. チェック結果で問題あればエラー終了
.. 問題なければ貯めてある配列をmodeに応じて整形したバッファに出力する
.. inDataフラグを下す
.. ②レコード末尾行でなければデータ行として、配列にため込む
inData フラグが立っていなければ
.. ①配列ヘッダ行であればパラメータを読み取って該当か否か判断する。
.. 該当データであれば inData フラグを立て、配列を初期化して処理に進む。
.. ②それ以外であればそのままバッファに転送する
問題発生するとエラーメッセージをstderrに書いた後、Trueを返す
"""
if self.inData:
trailer = self.trailerRE.match(lin)
if trailer:
if self.xCnt != 0:
print "WARNING: X=", self.xCnt, " Y=", self.yCnt
nREC = tryIntParse(trailer.group(1), 0)
if self.nData != nREC:
errPrint("ERROR: " + lin )
errPrint("ERROR: Trailer size mismatch. Actual=" + str(self.nData) + " nREC=" + str(nREC))
return True
if self.md == 1:
self.zerofill()
else:
self.transpose()
self.inData = False
else:
dlis = lin.split(",")
for item in dlis:
fdata = item.strip()
if '.' not in fdata:
continue
self.tempLine.append(fdata)
self.nData += 1
self.xCnt +=1
if self.xCnt >= self.iX:
if self.debug:
print "Y:" + str(self.yCnt) + " X:" + str(self.xCnt) + ":" + str(self.iX) + ":#=" + str(self.nData)
self.Array.append(self.tempLine)
self.yCnt += 1
if self.yCnt > self.iY:
errPrint("ERROR: Too much data Y=" + str(self.yCnt) + ":" + str(self.iY))
return True
self.xCnt = 0
self.tempLine = []
else:
header = self.headerRE.match(lin)
if header:
aname = header.group(1)
if self.verbose:
print "Find header:" + aname
if aname.startswith(self.tName):
self.clearArray()
if self.md == 1:
self.aNameT = aname + "Z"
else:
self.aNameT = aname + "T"
self.iX = tryIntParse(header.group(2), 0)
self.iY = tryIntParse(header.group(3), 0)
if (self.iX * self.iY) < 1:
errPrint("ERROR: Unexpected Array size ?=" + lin)
return True
self.inData = True
if self.verbose:
print "-->" + self.aNameT
else:
self.Buffer.append(lin)
self.nLine += 1
else:
self.Buffer.append(lin)
self.nLine += 1
return False
#--------------------------------------------------------------------
[ドキュメント] def transpose(self):
"""Transpose method
配列を転置してバッファに送るメソッド
"""
lineBuffer = "@" + self.aNameT + "<FLOAT>[" + str(self.iY) + ", " + str(self.iX) + "] {\n"
self.Buffer.append(lineBuffer)
idx = 0
lineBuffer = ""
for v in range(0, self.iX):
for u in range(0, self.iY):
BLK = self.Array[u]
ELEM = BLK[v]
lineBuffer += ELEM + ", "
idx += 1
if (idx % 16) == 0:
lineBuffer += "\n"
self.Buffer.append(lineBuffer)
lineBuffer = ""
if (idx % 16) != 0:
self.Buffer.append(lineBuffer + "\n")
lineBuffer = "} nREC=" + str(self.nData) + ", CONV_ERR_CODE=0, CONV_ERR_COUNT=0\n"
self.Buffer.append(lineBuffer)
#--------------------------------------------------------------------
[ドキュメント] def zerofill(self):
"""Zero Fill method
データ要素+ZEROフィル指定個数分の0で16要素となるようにしてバッファに送るメソッド
横方向iX個毎にこの操作を行う。iXに余りがでる場合も残りはゼロフィル
"""
dNum = 16 - self.ZERO #1行に入れるデータ要素の個数
if (self.iX % dNum) == 0:
nLine = self.iX / dNum #ゼロフィルによって作るべき行数
else:
nLine = (self.iX / dNum) + 1 #ゼロフィルによって作るべき行数
lineBuffer = "@" + self.aNameT + "<FLOAT>[" + str(nLine*16) + ", " + str(self.iY) + "] {\n"
self.Buffer.append(lineBuffer)
idx = 0
lineBuffer = ""
for u in range(0, self.iY):
for v in range(0, self.iX):
BLK = self.Array[u]
ELEM = BLK[v]
lineBuffer += ELEM + ", "
idx += 1
if (v % dNum) == (dNum - 1):
for i in range(0, self.ZERO):
lineBuffer += "0, "
idx += 1
if (idx % 16) == 0:
lineBuffer += "\n"
self.Buffer.append(lineBuffer)
lineBuffer = ""
if (idx % 16) != 0:
for i in range(0, 16 - (idx % 16)):
lineBuffer += "0, "
self.Buffer.append(lineBuffer + "\n")
lineBuffer = "} nREC=" + str(nLine * 16 * self.iY) + ", CONV_ERR_CODE=0, CONV_ERR_COUNT=0\n"
self.Buffer.append(lineBuffer)
#--------------------------------------------------------------------
[ドキュメント] def write(self):
"""Write method.
バッファをファイルを出力する
"""
try:
with open(self.oFname, 'w') as f:
for lin in self.Buffer:
f.write(lin)
except:
stdExceptionHandler("ERROR: in file writing = " + self.oFname)
return False
return True
#=======================================================================
# メインプログラム
def main():
"""main.
メインプログラム
"""
#-----------------------------------------------------------------------
# コマンドラインオプション処理
#
parser = argparse.ArgumentParser(description='fmatTranspose.')
parser.add_argument('--IN', nargs=1, help='Specify FLT input file name.')
parser.add_argument('--OUT', nargs=1, help='Specify FLT output file name.')
parser.add_argument('--TA', nargs=1, help='Specify Target array name.')
parser.add_argument('--ZERO', nargs=1, help='Specify number of zerofill(1-15).')
parser.add_argument('-r', dest='rev', help='Reverse mode(NOT SUPPORTED YET).', action='store_true', default=False)
parser.add_argument('-d', dest='debug', help='Debug mode, print debug information.', action='store_true', default=False)
parser.add_argument('-v', dest='verbose', help='Verbose mode.', action='store_true', default=False)
parser.add_argument('-V', dest='VERSION', help='Show Version, then exit', action='store_true', default=False)
args = parser.parse_args()
#-----------------------------------------------------------------------
# Version 表示
#
print versionSTR
if args.VERSION:
sys.exit(0)
#-----------------------------------------------------------------------
# ファイル名処理
#
if args.IN is None:
errPrint('ERROR: NO input file!!!')
sys.exit(1)
else:
inFname = args.IN[0]
if not os.path.isfile(inFname):
errPrint('ERROR: INPUT file, NOT EXIST.')
sys.exit(1)
#-----------------------------------------------------------------------
# パラメータ処理
# mode = 0 ... transpose, 1...zero fill, 2...Separate Channel
if args.TA is None:
errPrint('ERROR: NO target array name!!!')
sys.exit(1)
else:
ta = args.TA[0]
mode = 0 # Default transpose
dfext = "_transpose.flt"
if args.ZERO is not None:
mode = 1
zero = tryIntParse(args.ZERO[0], 0)
if (zero < 1) or (zero > 15):
errPrint('ERROR: number of Zero fill. ?=' + args.ZERO[0])
sys.exit(1)
dfext = "_zero.flt"
else:
zero = 0
if args.OUT is None:
outFname = ta + dfext
else:
outFname = args.OUT[0]
#-----------------------------------------------------------------------
# 実処理
#
flt = FltFileReaderWriter(inFname, outFname, ta, mode)
flt.verbose = args.verbose
flt.debug = args.debug
flt.ZERO = zero
flt.REV = args.rev
if flt.read():
if not flt.write():
sys.exit(1)
else:
sys.exit(1)
#終了メッセージ
today = datetime.today()
print "-" * 50
print today.strftime("FINISH: %Y/%m/%d %H:%M:%S")
#-----------------------------------------------------------------------
# 正常終了
#
sys.exit(0)
#=======================================================================
# メインプログラムの起動
if __name__ == "__main__":
main()