演習2:ユーザーサブルーチンの追加
このステップでは、PythonユーザーサブルーチンをMotionViewモデルに追加します。
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サブルーチンをインプリメントします。
Pythonスクリプトの記述:
- 新規のPythonファイルを開きます。
-
“def SPLINE_READ():"
を使い、SPLINE_READという名称の関数を定義します。使用される入力と出力は、id, file_name
とblock_name
です。 -
関数の定義後、
import csv
を含めることで、Python CSVパッケージをインポートします。 -
関数内のpressure_curve.csvを開き、変数としてファイルをPythonスクリプトとして読み込みます。関数
“variable = open(‘pressure_curve.csv’,’r’)”
を使用します。 -
この変数のフォーマットを変更するために、新しい変数を定義します。
csv.reader()
を使って、変数ファイルを読み出します。 -
pressure_curveデータ値を保管するための空のリスト
“L”
を定義します。“for item in curv:”
を使って、リストを反復します。別個のリスト値として各アイテムに“L.append(item)”
を付加します。 -
リストの最後まで、2つ目の値からリストを再定義することにより、csvファイルからヘッダーを削除します。これは、
“L = L[1:]”
で行うことができます。 - 後に使用されるカウンター変数を定義します。
-
“L”
の半分の長さの2つのリストを定義し、それらをゼロに設定します。-
そのためには、x値とy値をそれぞれ用いて
“x = 16*[0.0]”
を2度使用します。
-
そのためには、x値とy値をそれぞれ用いて
- カウンター変数がリストの長さから1引いたものより小さくなるようwhileループを作成します。
-
ループの各反復で、
“L”
データセットの各半分のフロート値として、インデックス“i”
についてx値とy値を定義します。これは、“x[i] = float(L[i][0])”および “y[i] = float(L[i][1])”
のように見えるはずです。カウンター変数を1増やします。 -
z変数を、0.0のフロート値で定義し、csvファイルを閉じます。
注: 次に使用する関数は、x、yおよびz変数を要するため、z変数の定義は必要です。
-
put_spline MotionSolve関数を使って、
“id”
および値の1列と2列とz変数を含んだリストを返します。これは、“errflg = py_put_spline(id,x,y,z)”
、続いて“return errflg”
によって行われます。 -
モデルを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
-
Pythonスクリプトをインプリメントします:
- MotionViewで、(Curve)ボタンをクリックします。
- ProjectブラウザでForce_Pressureカーブを探します。
- Propertiesタブで、User-definedボックスにチェックマークを入れます。
- Attributesタブで、Linear extrapolationにチェックマークが入っていることを確認します。
- User-Definedタブをクリックし、(ファイルブラウザ)を使ってpressure_curve.csvファイルを選択します。
- Function TypeをドロップダウンメニューでDLLからPythonに変更し、SPLINE_READとなっていることを確認します。本チュートリアルでは必要ないので、Block nameに何も入力する必要はありません。
-
Use local file and function
nameのボックスにチェックマークを入れます。(ファイルブラウザ)を使ってmot_nonlin.pyファイルを探して選択します。
REQSUBを使った出力のリクエスト
このステップでは、REQSUBユーザーサブルーチンを使ってピストンの変位の大きさの値を返します。
Pythonスクリプトの記述:
-
新規のPythonファイルを作成し、適切な入力および出力を与えて、REQSUBという名称の関数を定義します。
次のシンタックスを使用します:
“def REQSUB(id, time, par, npar, iflag)”
. -
sysfncユーティリティを使って、1つ目と2つ目の入力パラメータに“DM”(変位の大きさ)関数をインプリメントし、
“[D, errflg] = py_sysfnc(“DM”,[par[0],par[1]])”
と記述することで変数とエラーフラグを定義します。 -
8つの値のリストを返します。ここで、2つ目の値はユーザーの変数、残りの値は0です。
これは結果変数で、
“result = [0,D,0,0,0,0,0,0]”
のように見えるはずです。 -
このファイルを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
-
Pythonスクリプトをインプリメントします。
- MotionViewで、(Outputs)パネルをクリックします。
- Projectブラウザ内で、Output_Conrod_Lengthを探します。
- Outputsパネルで、ドロップダウンメニューからUser definedを選択します。
- Outputと書かれたテキスト欄をクリックし、ボタンをクリックしてExpression Builderを開きます。テキスト欄で、波括弧のセットを2つ(“{},{}”)追加します。
- Jointsフォルダーから、idstringをクリックします。1つ目の括弧のセット内をクリックし、Addをクリックして j_0.i.idstringを挿入します。
-
2つ目の括弧のセット内をクリックし、式j_1.i.idstringを追加します。
- OKをクリックします。
- Use local file and function nameボックスを選択し、Function TypeドロップダウンメニューからPythonを選択します。
-
(Local File)ファイルブラウザを使ってreq_nonlin.pyスクリプトを選択し、Function nameテキスト欄がREQSUBとなっていることを確認します。
フォースエンティティを置き換えるためのGFOSUBの使用
このステップでは、GFOSUBを使用してユーザー定義のPythonスクリプトでフォースエンティティを置き換えます。
Pythonスクリプトの記述:
- 新規のPythonファイルを開きます。
-
“def GFOSUB(id, time, par, npar, dflag, iflag):”
と入力して関数GFOSUBを定義します。 -
“from math import pi”
を使って"pi"
をPython“math”
ライブラリからインポートします。 - sysfncコマンドで、z方向の角度の“AZ”関数を使用し、変数として保存します。これは、“[A, errflg] = py_sysfnc(“AZ”,[par[1],par[2]])”と入力することで行います。
-
Step 4で定義された変数を度に変換します。モデルが原点から負のy方向に伸びているため、-1で掛ける必要があります。
注: 本チュートリアルで使用される方法は、。
“B = ((-1)*A*180)/pi”
です。 -
カーブからフォースの値を補間する“akispl”ユーティリティを使って、別の変数を定義します。角
“B”
の入力引数、1つの2次元カーブを指定するための0、およびカーブの入力と次数のための0が必要です。注: この行は、“[C, errflg] = py_akispl(B,0,par[0],0)”
のように記述されます。 -
3要素長のリストを返します。ここで、2番目の要素はAkima補間関数で定義された変数です。補間からのデータは第1列に補間されるため、
“return [0,C[0],0]”
を使用します。 -
このファイルを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
-
Pythonスクリプトをインプリメントします。
- MotionViewで、(Force)アイコンをクリックします。
- Projectブラウザ内で、Force_Gas_Pressureフォースを探します。
-
ConnectivityタブでUser-defined
propertiesチェックボックスをクリックします。
-
User-Definedタブで、Expression Builderを使ってForceの値をcurve idstring、crank marker idstringおよびground marker idstringを含むよう編集します。
- OKをクリックします。
- Use local file and function nameボックスを選択し、Function TypeドロップダウンメニューからPythonを選択します。
-
を使って、自身の<作業ディレクトリ>からgfo_nonlin.pyを選択します。
要確認: Function nameがGFOSUBに設定されていることを確認します。
MOTSUBを用いてモーションを定義
このステップでは、MOTSUBユーザーサブルーチンを用いてモーションを定義します。
Pythonスクリプトの記述:
- 新規のPythonファイルを開きます。
-
必要な入力を含めて、MOTSUB関数を定義します。このための正しいシンタックスは、
“def MOTSUB(id, time, par, npar, iord, iflag):”
です。 -
MOTSUBユーザーサブルーチンは関数または式、および1次導関数と2次導関数を必要とします。関数次数変数
“iord”
を使って条件ステートメントを作成し、関数およびその1次導関数と2次導関数を“if iord==0:”, “elif iord==1:”
と“else:”
で定義します。 -
関数とその導関数は、同じ変数名で定義されなくてはなりません。本チュートリアルで使用される関数は、
“A = 10.0461*time”
です。これにより、1次導関数は“A = 10.0461”
、2次導関数は“A = 0.0”
となります。 - “return A”で関数変数を返します。
-
このファイルを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
-
Pythonスクリプトをインプリメントします。
- Projectブラウザで、Motion_Crankモーションをクリックします。
-
Motionsパネルで、User-defined
propertiesボックスにチェックマークを入れます。
-
User-Definedタブをクリックします。
注: 関数はPythonスクリプトで定義されたため、USER()テキスト欄は修正する必要がありません。
- Use local file and function nameボックスをチェックします。
- Function TypeドロップダウンメニューからPythonを選択します。
-
を使って、mot_nonlin_pyファイルを開きます。
DMPSUBを使ったカスタム弾性体減衰の追加
このステップでは、DMPSUBユーザーサブルーチンを使って、カスタム弾性体減衰を追加します。
Pythonスクリプトの記述:
- 新規のPythonファイルを開きます。
-
DMPSUB関数を
“def DMPSUB():”
で、入力“id, time, par, npar, freq, nmode, h”
を使って定義します。 -
“nmode”
を使って、“cratios = nmode*[0.0]
”の長さのリストを定義します。“nmode”
は、弾性体内のモード数です。 -
弾性体内のモードのリストを反復する
“if”
ステートメントを作成します。ここでは“range()”
関数を使用することができ、“for I in range(nmode):”
を得ます。 -
ループの各反復内で、
“cratios[i] = 1.0”
を追加することにより、変数内の各インデックスを1に設定します。 -
スクリプトの最後で、
“return cratios”
でリスト変数を返します。 -
スクリプトを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
-
Pythonスクリプトをインプリメントします。
- Projectブラウザから、Conrodボディ(モデル内の弾性体)をクリックします。
-
Propertiesタブから、Modes...ボタンをクリックします。
-
Modesダイアログで、ドロップダウンメニューからUser
Function Dampingを選択します。Usersub欄に式'USER()’を入力します。
dmp_nonlin.py script内で減衰を定義したため、USER()式を変更する必要はありません。
- (Run)ボタンをクリックします。
-
パネル内で、End timeを5.0に、Print intervalを0.01に変更します。
-
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." />