パラメータファイルに対するプリコンパイル

プリコンパイラ / プリコンパイラ

  • プリコンパイル :コンパイル前にファイルをテキスト処理し、 記述の効率性や再利用性を向上するコーディング技術.

  • プリコンパイラ :ソースコードを処理して別の形式のコードを生成するプログラム群.


パラメータファイルのプリコンパイル

(課題) パラメータファイルを取扱い容易に、可読性の向上

  • 技術計算系のソフトウェアは、入力ファイルとして 決められたフォーマット のファイルを与えることが多々ある.

    • (e.g.) Elmer, PHITS, EMSolution, gmsh, etc.

    • 記載中で、 変数の使用四則演算分割ファイル読み込み ができなければ、記載が煩雑になりがち.

  • 可読性 も下がる.


(解決方法) プリコンパイラを導入

  • 変数名を与えて、「ある数値 ( e.g. 1.602e19 )」 が 何を指すのか ( e.g. 電化素量 )を明瞭に.

  • 繰り返し現れる数値を 一括変更

  • 変数を使用した計算を可能にして、とあるパラメータを変更したときに、 別数値が連動して変更 されるように.

  • 分割ファイルで、パラメータファイルを 機能ごとに整理 、構成をわかりやすく.


使い方

  • パラメータファイル中で変更したい変数名を "@XXXX" と @マークから始まるように記載.

  • 変数の定義は次の通り

    1. .jsonファイル中で与える ( jsonの記事で記載 )

    2. # <define> @var1 = 1.0 のように <define>文を使用して定義する.

  • 変数は計算可能だが、ファイルの前方から順に処理していくため、 記載順には要注意

    • 一応、単なる数値等、1重呼び出し程度なら前後しても問題ないが、 多重に呼び出し、かつ、順番前後した変数定義は不可

      • 2重以上の変数呼び出しはしない ( etc. @var1=@var2, @var2=@var3, @var3=1.0 )

      • 2重以上の変数呼び出しだが、は前から順に宣言する.:

        #<define> @var3 = 1.0
        #<define> @var2 = @var3
        #<define> @var1 = @var2
        
  • jsonでの数式記述に関しては、別記事を参照.


コマンドラインからの実行

  • precompile__parameterFile.py を パスの通ったところにおいて、 ( e.g. /usr/local/bin/ )

  • 実行権限 を付与し、 ( e.g. $ chmod +x /usr/local/bin/precompile__parameterFile.py )

  • pythonの実行のおまじないをを先頭行に記載し、 ( e.g. #!/usr/bin/env python3.10 )

  • コマンドラインから実行すれば、 簡易実行可能

    • $ precompile__parameterFile.py sample_parameter.inp
      $ precompile__parameterFile.py sample_parameter.inp --comment_mark $ --outFile sample_parameter.out
      

コード

プリコンパイラエンジン

#!/usr/bin/env python3.10
# -*- coding: utf-8 -*-

import os, sys, argparse
import numpy                                   as np
import nkUtilities.include__dividedFile        as inc
import nkUtilities.replace__variableDefinition as rvd
import nkUtilities.json__formulaParser         as jfp
import nkUtilities.loadJSON__asVariableTable   as lja

# ========================================================= #
# ===  precompile__parameterFile.py                     === #
# ========================================================= #

def precompile__parameterFile( inpFile=None, outFile=None, lines=None, table=None, silent=True, \
                               priority=None, replace_expression=True, comment_mark="#", \
                               define_mark="<define>", include_mark="<include>",
                               loadJSON_mark="<loadJSON>", expr_var=None, \
                               escapeType ="UseEscapeSequence", variable_mark="@", \
                               append__variableList=True ):

    # ------------------------------------------------- #
    # --- [1] include divided Files                 --- #
    # ------------------------------------------------- #
    lines = inc.include__dividedFile( inpFile=inpFile, lines=lines, \
                                      comment_mark=comment_mark, include_mark=include_mark, \
                                      escapeType=escapeType, silent=silent )
    
    # ------------------------------------------------- #
    # --- [2] load json file                        --- #
    # ------------------------------------------------- #
    table = lja.loadJSON__asVariableTable( inpFile=inpFile, lines=lines, table=table, \
                                           loadJSON_mark=loadJSON_mark, \
                                           variable_mark=variable_mark, \
                                           comment_mark=comment_mark, escapeType=escapeType )
    
    # ------------------------------------------------- #
    # --- [3] include divided Files                 --- #
    # ------------------------------------------------- #
    lines = rvd.replace__variableDefinition( outFile=outFile, lines=lines, table=table,
                                             replace_expression=replace_expression, \
                                             comment_mark=comment_mark, \
                                             variable_mark=variable_mark, priority=priority, \
                                             escapeType=escapeType, silent=silent, \
                                             append__variableList=append__variableList )
    return( lines )


# ========================================================= #
# ===   Execution of Pragram                            === #
# ========================================================= #

if ( __name__=="__main__" ):

    mode = "normal"
    
    if ( mode == "test" ):
        table   = { "title":"TEST01" }
        inpFile = "test/precompile__parameterFile/sample_parameter.inp"
        outFile = "test/precompile__parameterFile/sample_parameter.out"
        ret     = precompile__parameterFile( inpFile=inpFile, outFile=outFile, \
                                             comment_mark="$", table=table )
        print()
        print( "".join( ret ) )
        print()
        sys.exit()

    elif ( mode == "normal" ):

        parser = argparse.ArgumentParser()
        parser.add_argument( "inpFile"       , help="input  file name." )
        parser.add_argument( "--outFile"     , help="output file name." )
        parser.add_argument( "--comment_mark", help="comment mark.", default="#" )
        args   = parser.parse_args()
        if ( args.inpFile is None ):
            print( "[precompile__parameterFile.py]  inpFile  must be given ..." )
            print( "precompile__parameterFile.py inpFile --outFile xxx --comment_mark X")

        ret = precompile__parameterFile( inpFile=args.inpFile, outFile=args.outFile,\
                                         comment_mark=args.comment_mark )
        print( "".join( ret ) )

パラメータファイルサンプル ( sample_parameter.inp )


$ This is a parameter file for some calculation

$ <define>  @var1 = 0.1
$ <include> filepath = "include.inp"
$$$ <include> filepath = "test/precompile__parameterFile/include.inp"

BEGIN{

  TITLE    = @title

  x,y,z    = ( @x, @y, @z )
  particle = @particle.type
  iterMax  = @iterMax

}END

パラメータファイルサンプル ( include.inp )


$ $ <loadJSON> filepath = "test/precompile__parameterFile/sample_parameter.json"
$ $ <define> @var2 = 0.2

$ <loadJSON> filepath = "sample_parameter.json"
$ <define> @var2 = 0.2

パラメータファイルサンプル ( sample_parameter.json )

{

    x: 0.0,
    y: 1.0,
    z: 2.0,
    iterMax:10,
    particle.type:"electron",

}

出力例 ( sample_parameter.out )


$ This is a parameter file for some calculation

$ <define>  @var1 = 0.1
$$$ <include> filepath = "include.inp"
$ <include> filepath = "test/precompile__parameterFile/include.inp"

$ <loadJSON> filepath = "test/precompile__parameterFile/sample_parameter.json"
$ <define> @var2 = 0.2

$$$ <loadJSON> filepath = "sample_parameter.json"
$$$ <define> @var2 = 0.2

BEGIN{

  TITLE    = TEST01

  x,y,z    = ( 0.0, 1.0, 2.0 )
  particle = electron
  iterMax  = 10

}END