MV-7006:MotionSolve用のPythonユーザーサブルーチン

本チュートリアルでは、Pythonを使ってMotionSolve用のユーザーサブルーチンを作成し、Cで書かれた6個のSFOSUBを含むモデルをPythonユーザーサブルーチンに変換します。

注: PythonおよびMotionSolve XMLシンタックスに精通していることを前提としています。

Pythonのようなスクリプト言語を使用することによって、ユーザーは、煩雑さの軽減とパワーを得ることができます。これらのスクリプトは変換処理され、コンパイルの必要はありません。したがって、サブルーチンを構築するためのツールを要しません。さらに、スクリプトは読んだり理解するのがより簡単で、より速いプロトタイピングに使用することが可能です。

プログラミングの経験があまりない場合でも、ユーザーサブルーチン用のスクリプトを書くことは、Cコードを書くよりも簡単です。Cユーザーにとっては、この使用法は、いっそうシンプルです。Pythonの言語シンタックスに従うこと以外では、CコードをPythonスクリプトに変換するためのルールに従うことだけが必要です。

参照用として、Pythonユーザーサブルーチンのサンプルセットが、hwsolvers\motionsolve\usersub\py_srcフォルダーに用意されています。

Pythonユーザーサブルーチンを書くためのルール

下記のルールの助けを得て、c_*カウンターパートの使用法からpy_*ユーティリティ関数の使い方を容易に理解できます。
  1. 1. 出力の引数は、左側に移動する必要があります。
    c_datout(&istat); 

    は、次のようになります;

    istat = py_datout()

    Cユーティリティ関数では、入力引数および出力引数は、引数リスト内に組み合わされています。 Pythonでは、py_*ユーティリティ関数の引数は厳密に入力引数です。出力引数はすべて、関数コールの戻し値として、左側に移動する必要があります。

  2. Cユーティリティ関数では、入力または出力配列引数の後ろには通常、配列のサイズ用の整数の引数が続きます。Pythonユーティリティ関数では、配列のサイズ用の整数の引数は必要がないため、削除されます。
    ipar[0] = (int)par[0];
    ipar[1] = (int)par[1];
    c_sysfnc("DM", ipar, 2, &dm, &errflg);
    は単に、次のようになります;
    [dm, errflg] = py_sysfnc("DM", [par[0],par[1]])
    また
    ipar[0] = (int)par[1];
    ipar[1] = (int)par[0];
    c_sysary("TDISP", ipar, 2, u1, &nstates, &errflg);
    は、次のようになります;
    [u1, errflg] = py_sysary("TDISP", [par[1],par[0]])
  3. 関数名を、c_* からpy_*に変更します。
    c_rcnvrt(sys1, coord1, sys2, coord2, &istate);
    は、次のようになります;
    [coord2, istate] = py_rcnvrt(sys1, coord1, sys2)

CサブルーチンのPythonサブルーチンへの変換

  1. この例では、下に示すとおり、モデルはCコードで書かれた6つのSFOSUBを使用しています。
    DLLFUNC void STDCALL SFOSUB (int *id, double *time, double
     *par, int *npar, int *dflag, int *iflag, double *result)
    {
    // --- Add your local definitions here ---------------------
         double vector[3],dm,vm;
         int ipar[2], iord;
         int errflg;
    // --- Add your executable code here -----------------------
         int itype  = (int)par[0];
         iord = 0;
         if (itype==50)
         {
             ipar[0] = (int)par[1];
             ipar[1] = (int)par[2];
             c_sysfnc("DM", ipar, 2, &dm, &errflg);
             ipar[0] = (int)par[3];
             ipar[1] = (int)par[4];
             c_sysfnc("VM", ipar, 2, &vm, &errflg);
             c_impact(dm, vm, par[5], par[6], par[7], par[8], par[9], iord,
               vector, &errflg);
             *result = vector[0];
         }
    }
  2. 最後のセクションで指定されているルールに従い、対応するPythonスクリプトは以下のとおりとなります:
    def SFOSUB (id, time, par, npar, dflag, iflag):
    
    [dm, errflg] = py_sysfnc("DM", [par[0],par[1]])
    [vm, errflg] = py_sysfnc("VM", [par[2],par[3]])
    [vector, errflg] = py_impact(dm, vm, par[4], par[5], 
                       par[6], par[7],par[8],0
    )return vector[0]
  3. Pythonスクリプトに加え、ユーザーサブルーチン内で使用されるPythonスクリプトをXMLモデル内で指定する必要があります。MotionSolveは、uysrsubを定義することのできる対応する要素内に、2つの属性を介してこの定義を提供します。
    1. interpreter = " Python"
    2. script_name = " script_name.py

    この組み合わせは、その要素内の属性“usrsub_dll_name”に取って代わります。

  4. 下の図は、本例におけるCユーザーサブルーチン使用とPythonユーザーサブルーチン使用の差異を示したものです:


    図 1.
  5. 元のモデルには、Cで書かれたSFOSUBを使用する6つのForce_Scalar_TwoBody要素が存在します:
    <Force_Scalar_TwoBody
         id                  = "30701"
         type                = "Force"
         i_marker_id         = "30701010"
         j_marker_id         = "30701011"
         usrsub_param_string = 
    "USER(50,30301010,30401010,30301010,30401010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
      <Force_Scalar_TwoBody
         id                  = "30801"
         type                = "Force"
         i_marker_id         = "30801010"
         j_marker_id         = "30801011"
         usrsub_param_string = "
    USER
    (50,30301010,30501010,30301010,30501010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
      <Force_Scalar_TwoBody
         id                  = "30901"
         type                = "Force"
         i_marker_id         = "30901010"
         j_marker_id         = "30901011"
         usrsub_param_string = 
    "USER
    (50,30301010,30601010,30301010,30601010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
      <Force_Scalar_TwoBody
         id                  = "31001"
         type                = "Force"
         i_marker_id         = "31001010"
         j_marker_id         = "31001011"
         usrsub_param_string = 
    "USER(50,30401010,30501010,30401010,30501010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
      <Force_Scalar_TwoBody
         id                  = "31101"
         type                = "Force"
         i_marker_id         = "31101010"
         j_marker_id         = "31101011"
         usrsub_param_string = 
    "USER(50,30401010,30601010,30401010,30601010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
      <Force_Scalar_TwoBody
         id                  = "31201"
         type                = "Force"
         i_marker_id         = "31201010"
         j_marker_id         = "31201011"
         usrsub_param_string = 
    "USER(50,30501010,30601010,30501010,30601010,10,10,2.0,0.001,0.01)"
         usrsub_dll_name     = "NULL"
         usrsub_fnc_name     = "SFOSUB"
       />
    
  6. C SFOSUBをPython SFOSUBに変更した後、上記のXMLコンテンツは、下記のものに置き換えられます:
    <Force_Scalar_TwoBody
         id                  = "30701"
         type                = "Force"
         i_marker_id         = "30701010"
         j_marker_id         = "30701011"
         usrsub_param_string = "USER(30301010,30401010,30301010,30401010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"
      />
      <Force_Scalar_TwoBody
         id                  = "30801"
         type                = "Force"
         i_marker_id         = "30801010"
         j_marker_id         = "30801011"
         usrsub_param_string = "USER
    (30301010,30501010,30301010,30501010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"     
      />
      <Force_Scalar_TwoBody
         id                  = "30901"
         type                = "Force"
         i_marker_id         = "30901010"
         j_marker_id         = "30901011"
         usrsub_param_string = "USER(30301010,30601010,30301010,30601010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"     
      />
      <Force_Scalar_TwoBody
         id                  = "31001"
         type                = "Force"
         i_marker_id         = "31001010"
         j_marker_id         = "31001011"
         usrsub_param_string = "USER(30401010,30501010,30401010,30501010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"     
      />
      <Force_Scalar_TwoBody
         id                  = "31101"
         type                = "Force"
         i_marker_id         = "31101010"
         j_marker_id         = "31101011"
         usrsub_param_string = "USER(30401010,30601010,30401010,30601010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"     
      />
      <Force_Scalar_TwoBody
         id                  = "31201"
         type                = "Force"
         i_marker_id         = "31201010"
         j_marker_id         = "31201011"
         usrsub_param_string = "USER(30501010,30601010,30501010,30601010,10,10,2.0,0.001,0.01)"
         interpreter         = "Python"
         script_name         = "script/sfosub.py"
         usrsub_fnc_name     = "SFOSUB"     
      />
  7. これらの変更(CコードからPythonコードおよびXMLモデルへの変更)をもって、Pythonユーザーサブルーチンを有するモデルは、MotionSolveでの実行が整ったことになります。