演習2:ユーザーサブルーチンの追加

このステップでは、PythonユーザーサブルーチンをMotionViewモデルに追加します。

Pythonは、一定のシンタックスのルールに従うと、多くのMotionSolve関数および入力を使用することが可能です。AKISPLSYSFNCといったMotionSolve関数を使用する際、初めに文字列“py_”を加える必要があります。例えば、“py_sysfnc(...”は、PythonでのSYSFNCの正しい用い方です。Pythonでユーザーサブルーチン関数を定義する際、関数と入力の名称は、MotionSolveのオンラインヘルプページに概説されているそれらと完全に一致しなくてはなりません。SYSFNC等の関数を介してPython内のモデルデータにアクセスする場合、“id”のように二重引用符で囲まれた正確な名称を使用します。関数定義でPythonに渡されるモデルプロパティには、スクリプト全体を通してアクセスすることができ、追加の定義を使用する必要はありません。使用されるこれらのシンタックスルールの1例を以下に示します:
def REQSUB(id, time, par, npar, iflag):
     [A, errflg] = py_sysfnc(“DX”,[par[0],par[1]])
return A

カーブエンティティを置き換えるためのSPLINE_READの使用

このステップでは、SPLINE_READサブルーチンをインプリメントします。

このユーザーサブルーチンは、SPLINE_READ関数を用いて、含まれるpressure_curve.csvファイルからカーブを返します。SPLINE_READは、MotionViewでのカーブエンティティに対応したユーザーサブルーチンです。これは、外部ファイル内のデータポイントを使ってカーブを作成し、そのカーブは他のエンティティによって使用されることが可能です。

Pythonスクリプトの記述:

  1. 新規のPythonファイルを開きます。
  2. “def SPLINE_READ():"を使い、SPLINE_READという名称の関数を定義します。使用される入力と出力は、 id, file_nameblock_nameです。
  3. 関数の定義後、import csvを含めることで、Python CSVパッケージをインポートします。
  4. 関数内のpressure_curve.csvを開き、変数としてファイルをPythonスクリプトとして読み込みます。関数“variable = open(‘pressure_curve.csv’,’r’)”を使用します。
  5. この変数のフォーマットを変更するために、新しい変数を定義します。csv.reader()を使って、変数ファイルを読み出します。
  6. pressure_curveデータ値を保管するための空のリスト“L”を定義します。“for item in curv:”を使って、リストを反復します。別個のリスト値として各アイテムに“L.append(item)”を付加します。
  7. リストの最後まで、2つ目の値からリストを再定義することにより、csvファイルからヘッダーを削除します。これは、“L = L[1:]”で行うことができます。
  8. 後に使用されるカウンター変数を定義します。
  9. “L”の半分の長さの2つのリストを定義し、それらをゼロに設定します。
    1. そのためには、x値とy値をそれぞれ用いて “x = 16*[0.0]”を2度使用します。
  10. カウンター変数がリストの長さから1引いたものより小さくなるようwhileループを作成します。
  11. ループの各反復で、“L”データセットの各半分のフロート値として、インデックス“i”についてx値とy値を定義します。これは、“x[i] = float(L[i][0])”および “y[i] = float(L[i][1])”のように見えるはずです。カウンター変数を1増やします。
  12. z変数を、0.0のフロート値で定義し、csvファイルを閉じます。
    注: 次に使用する関数は、x、yおよびz変数を要するため、z変数の定義は必要です。
  13. put_spline MotionSolve関数を使って、“id”および値の1列と2列とz変数を含んだリストを返します。これは、“errflg = py_put_spline(id,x,y,z)”、続いて“return errflg”によって行われます。
  14. モデルをnonlin_spline.pyとして作業ディレクトリ<working directory>に保存します。
    スクリプトは次のようになっているはずです:
    def SPLINE_READ(id, file_name, block_name):
    import csv
    ifile= open('pressure_curve.csv','r') ## opens data file as
    readable variable
    curv = csv.reader(ifile) ## reads csv data, stores as
    useable var.
    L = [] ## creates empty list
    for item in curv:
    L.append(item) ## separates file values into list
    L = L[1:] ## removes block names from list
    i=0 ## creates counter
    x = 16*[0.0]
    y = 16*[0.0] ## splits list into x and y lists
    while i < (len(L)-1):
    x[i] = float(L[i][0]) ## changes values from str to float
    y[i] = float(L[i][1])
    i+=1 ## counter increment
    z = 0.0 ## defines z value
    ifile.close() ## closes data file
    errflg = py_put_spline(id,x,y,z) ## var to create MotionSolve
    spline
    return errflg ## returns var
  15. Pythonスクリプトをインプリメントします:
    1. MotionViewで、(Curve)ボタンをクリックします。
    2. ProjectブラウザでForce_Pressureカーブを探します。
    3. Propertiesタブで、User-definedボックスにチェックマークを入れます。
    4. Attributesタブで、Linear extrapolationにチェックマークが入っていることを確認します。
    5. User-Definedタブをクリックし、(ファイルブラウザ)を使ってpressure_curve.csvファイルを選択します。
    6. Function TypeをドロップダウンメニューでDLLからPythonに変更し、SPLINE_READとなっていることを確認します。本チュートリアルでは必要ないので、Block nameに何も入力する必要はありません。
    7. Use local file and function nameのボックスにチェックマークを入れます。(ファイルブラウザ)を使ってmot_nonlin.pyファイルを探して選択します。
      図 1. SPLINE_READユーザーサブルーチンを使ったカーブパネル

REQSUBを使った出力のリクエスト

このステップでは、REQSUBユーザーサブルーチンを使ってピストンの変位の大きさの値を返します。

このユーザーサブルーチンは、Pythonを使って、どの値を返すかを指定します。

Pythonスクリプトの記述:

  1. 新規のPythonファイルを作成し、適切な入力および出力を与えて、REQSUBという名称の関数を定義します。
    次のシンタックスを使用します:“def REQSUB(id, time, par, npar, iflag)”.
  2. sysfncユーティリティを使って、1つ目と2つ目の入力パラメータに“DM”(変位の大きさ)関数をインプリメントし、“[D, errflg] = py_sysfnc(“DM”,[par[0],par[1]])”と記述することで変数とエラーフラグを定義します。
  3. 8つの値のリストを返します。ここで、2つ目の値はユーザーの変数、残りの値は0です。
    これは結果変数で、“result = [0,D,0,0,0,0,0,0]”のように見えるはずです。
  4. このファイルをreq_nonlin.pyとして<作業ディレクトリ>に保存します。
    スクリプトは次のようになっているはずです:
    def REQSUB(id, time, par, npar, iflag):
    [D, errflg] = py_sysfnc("DM",[par[0],par[1]]) ## sets "D" as piston
    displacement mag
    result = [0,D,0,0,0,0,0,0] ## lists results for output
    return
    return result ## sends list with results to motionsolve as
    output
  5. Pythonスクリプトをインプリメントします。
    1. MotionViewで、(Outputs)パネルをクリックします。
    2. Projectブラウザ内で、Output_Conrod_Lengthを探します。
    3. Outputsパネルで、ドロップダウンメニューからUser definedを選択します。
    4. Outputと書かれたテキスト欄をクリックし、ボタンをクリックしてExpression Builderを開きます。テキスト欄で、波括弧のセットを2つ(“{},{}”)追加します。
    5. Jointsフォルダーから、idstringをクリックします。1つ目の括弧のセット内をクリックし、Addをクリックして j_0.i.idstringを挿入します。
    6. 2つ目の括弧のセット内をクリックし、式j_1.i.idstringを追加します。


      図 2. Expression Builderダイアログ
    7. OKをクリックします。
    8. Use local file and function nameボックスを選択し、Function TypeドロップダウンメニューからPythonを選択します。
    9. (Local File)ファイルブラウザを使ってreq_nonlin.pyスクリプトを選択し、Function nameテキスト欄がREQSUBとなっていることを確認します。


      図 3. REQSUBを使ったOutputsパネル

フォースエンティティを置き換えるためのGFOSUBの使用

このステップでは、GFOSUBを使用してユーザー定義のPythonスクリプトでフォースエンティティを置き換えます。

ここで使用されるGFOSUBは、SPLINE_READで定義されたカーブデータを取り、カーブに従ったコネクティングロッド角に応じて変化します。

Pythonスクリプトの記述:

  1. 新規のPythonファイルを開きます。
  2. “def GFOSUB(id, time, par, npar, dflag, iflag):”と入力して関数GFOSUBを定義します。
  3. “from math import pi”を使って "pi"Python“math”ライブラリからインポートします。
  4. sysfncコマンドで、z方向の角度の“AZ”関数を使用し、変数として保存します。これは、“[A, errflg] = py_sysfnc(“AZ”,[par[1],par[2]])”と入力することで行います。
  5. Step 4で定義された変数を度に変換します。モデルが原点から負のy方向に伸びているため、-1で掛ける必要があります。
    注: 本チュートリアルで使用される方法は、“B = ((-1)*A*180)/pi”です。
  6. カーブからフォースの値を補間する“akispl”ユーティリティを使って、別の変数を定義します。角“B”の入力引数、1つの2次元カーブを指定するための0、およびカーブの入力と次数のための0が必要です。
    注: この行は、“[C, errflg] = py_akispl(B,0,par[0],0)”のように記述されます。
  7. 3要素長のリストを返します。ここで、2番目の要素はAkima補間関数で定義された変数です。補間からのデータは第1列に補間されるため、“return [0,C[0],0]”を使用します。
  8. このファイルをgfo_nonlin.pyとして<作業ディレクトリ>に保存します。
    スクリプトは次のようになっているはずです:
    def GFOSUB(id, time, par, npar, dflag, iflag):
    from math import pi
    [A, errflg] = py_sysfnc("AZ",[par[1],par[2]]) ## retreives conrod
    angle
    B = ((-1)*A*180)/pi ## converts radians
    to degrees
    [C, errflg] = py_akispl(B,0,par[0],0) ## interpolates data to fit
    curve
    return [0,C[0],0] ## returns C data as force values
  9. Pythonスクリプトをインプリメントします。
    1. MotionViewで、(Force)アイコンをクリックします。
    2. Projectブラウザ内で、Force_Gas_Pressureフォースを探します。
    3. ConnectivityタブでUser-defined propertiesチェックボックスをクリックします。
      図 4.
    4. User-Definedタブで、Expression Builderを使ってForceの値をcurve idstring、crank marker idstringおよびground marker idstringを含むよう編集します。


      図 5.
    5. OKをクリックします。
    6. Use local file and function nameボックスを選択し、Function TypeドロップダウンメニューからPythonを選択します。
    7. を使って、自身の<作業ディレクトリ>からgfo_nonlin.pyを選択します。
      要確認: Function nameがGFOSUBに設定されていることを確認します。


      図 6.

MOTSUBを用いてモーションを定義

このステップでは、MOTSUBユーザーサブルーチンを用いてモーションを定義します。

Pythonスクリプトの記述:

  1. 新規のPythonファイルを開きます。
  2. 必要な入力を含めて、MOTSUB関数を定義します。このための正しいシンタックスは、 “def MOTSUB(id, time, par, npar, iord, iflag):”です。
  3. MOTSUBユーザーサブルーチンは関数または式、および1次導関数と2次導関数を必要とします。関数次数変数“iord”を使って条件ステートメントを作成し、関数およびその1次導関数と2次導関数を“if iord==0:”, “elif iord==1:”“else:”で定義します。
  4. 関数とその導関数は、同じ変数名で定義されなくてはなりません。本チュートリアルで使用される関数は、“A = 10.0461*time”です。これにより、1次導関数は“A = 10.0461”、2次導関数は“A = 0.0”となります。
  5. “return A”で関数変数を返します。
  6. このファイルをmot_nonlin.pyとして<作業ディレクトリs>に保存します。
    スクリプトは次のようになるはずです:
    def MOTSUB(id, time, par, npar, iord, iflag):
    if iord==0: ## function
    A = 10.0461*time
    elif iord==1: ## first derivative
    A = 10.0461
    else: ## second derivative
    A = 0.0
    return A ## returns function based on iord input
  7. Pythonスクリプトをインプリメントします。
    1. Projectブラウザで、Motion_Crankモーションをクリックします。
    2. Motionsパネルで、User-defined propertiesボックスにチェックマークを入れます。


      図 7.
    3. User-Definedタブをクリックします。
      注: 関数はPythonスクリプトで定義されたため、USER()テキスト欄は修正する必要がありません。
    4. Use local file and function nameボックスをチェックします。
    5. Function TypeドロップダウンメニューからPythonを選択します。
    6. を使って、mot_nonlin_pyファイルを開きます。


      図 8.

DMPSUBを使ったカスタム弾性体減衰の追加

このステップでは、DMPSUBユーザーサブルーチンを使って、カスタム弾性体減衰を追加します。

Pythonスクリプトの記述:

  1. 新規のPythonファイルを開きます。
  2. DMPSUB関数を“def DMPSUB():”で、入力“id, time, par, npar, freq, nmode, h”を使って定義します。
  3. “nmode”を使って、“cratios = nmode*[0.0]”の長さのリストを定義します。
    “nmode”は、弾性体内のモード数です。
  4. 弾性体内のモードのリストを反復する“if”ステートメントを作成します。ここでは“range()”関数を使用することができ、“for I in range(nmode):”を得ます。
  5. ループの各反復内で、“cratios[i] = 1.0”を追加することにより、変数内の各インデックスを1に設定します。
  6. スクリプトの最後で、“return cratios”でリスト変数を返します。
  7. スクリプトをdmp_nonlin.pyとして保存します。
    スクリプトは次のようになっているはずです:
    def DMPSUB(id, time, par, npar, freq, nmode, h):
    cratios = nmode*[0.0] ## makes preallocated list for markers
    for i in range(nmode):
    cratios[i] = 1.0 ## sets marker damping to 1
    return cratios ## returns damping values
  8. Pythonスクリプトをインプリメントします。
    1. Projectブラウザから、Conrodボディ(モデル内の弾性体)をクリックします。
    2. Propertiesタブから、Modes...ボタンをクリックします。


      図 9.
    3. Modesダイアログで、ドロップダウンメニューからUser Function Dampingを選択します。Usersub欄に式'USER()’を入力します。


      図 10.
      dmp_nonlin.py script内で減衰を定義したため、USER()式を変更する必要はありません。
    4. (Run)ボタンをクリックします。
    5. パネル内で、End timeを5.0に、Print intervalを0.01に変更します。


      図 11.
    6. MotionSolveファイルをエクスポートするために、メニューバー内でFile > Export > Solver Deckをクリックします。
      注: 現時点では、弾性体減衰を定義するDAMPSUBファイルを指定するためのGUIオプションは用意されていません。したがって、弾性体定義に以下のステートメントを追加して、dmp_nonlin.pyを手動でMotionSolveファイル(*.xml)に付加する必要があります。
      is_user_damp = "TRUE"
      usrsub_param_string = "USER()"
      interpreter = "Python"
      script_name = "dmp_nonlin.py"
      usrsub_fnc_name = "DMPSUB"
      弾性体定義は次のようになるはずです:
      <Body_Flexible
      id = "30104"
      lprf_id = "30104002"
      mass = "7.424574879203591E-02"
      inertia_xx = "1.471824534365642E+02"
      inertia_yy = "4.505004745855096E+00"
      inertia_zz = "1.501914135052064E+02"
      inertia_xy = "-5.546373592613223E-03"
      inertia_yz = "-1.984540442733755E-03"
      inertia_xz = "1.557626595859531E-03"
      cm_x = "1.191728011928773E-03"
      cm_y = "-2.225471002399553E+01"
      cm_z = "5.469513396916666E-05"
      h3d_file = "conrod.h3d"
      is_user_damp = "TRUE"
      usrsub_param_string = "USER()"
      interpreter = "Python"
      script_name = "dmp_nonlin.py"
      usrsub_fnc_name = "DMPSUB"
      flexdata_id = "30104"
      animation_scale = "1."
      />