(前頁)<<      >>(次頁)          (Up)

6章 再び要素モデルの作成
6.2 色々な要素モデル   〜 水理以外の要素モデル作成とCommonMP適応モデル作成例 〜
(CommonMPを用いた 「湖の食物連鎖シミュレーション」


 CommonMPとはシミュレーションを行うためのプラットフォームであり、水理モデル以外にも応用することは可能です。
 ここでは、水理以外の要素モデルの例として、淡水湖の中の3種類の生物の食物連鎖シミュレーションを行ってみます。
 但し、此処では、CommonMPを応用したモデル作成の例を示すことが目的であり、精密なモデルの作成が目的ではありません。
 ここでの要素モデルを参考例として、CommonMPの計算モデルプラットフォームとしての能力を活かして、もっと幅広く使用して下さい。


        
    
 上図の様に湖には、動物プランクトン、小魚、大魚が住んでいます。 湖は季節が有り季節に応じて水温が変化します。 ただし、水深の深いところは水温の変化が少ないものとします。
 
 食物の連鎖としては、 動物プランクトンを小魚が喰い、その小魚を大魚が喰うという3種類の生物の連鎖のみを考えます。 実際には、参加する生物も多く、死骸の腐敗者も必要ですが、このモデルの制作目的が、食物連鎖モデルの制作例を示す事なので、単純なモデルとしています。

      


 さて、食物連鎖をモデル化するに当り、要素モデルとしては、

・「湖」要素モデル  ・・・・・・・・・・・・・・・・ 水温変化、プランクトンの繁殖を計算
・「小魚」要素モデル ・・・・・・・・・・・・・・・・・・・ メッシュ間の移動、繁殖、死(餓死、病死、寿命死)
・「大魚」要素モデル ・・・・・・・・・・・・・・・・・・・ メッシュ間の移動、繁殖、死(餓死、病死、寿命死)
・「生存競争」要素モデル ・・・・・・・・・・・・・・・ 3種類の生物の喰う/喰われる


を準備し、 各要素モデルを下図の様に 接続します。
 各要素モデル間の伝送情報としては、各生物の数(及び生物の行動に影響を与える水温)とします。
  
     

 湖は、下図の様に100×100のメッシュに分割し、各要素モデルはメッシュ内に存在する個体数の増減を計算します。 但し、小魚、大魚はメッシュ間を移動します。


     
 
 
 モデルの概要が決まったので、上記の通りに要素モデルを作成していきたいと思います。

 
 いつもと同じ通りに、先ずはスタブを作成します。( スタブ作成の例 )
 クラス名は
 ・小魚:    MySmallFishModel
 ・大魚:    MyBigFishModel
 ・湖:      MyLakeEnvModel
 ・生存競争: MyStruggleModel 
 として、各モデルの定義を MyLakeModelDefine 内に定義します。
 また、各モデルへの入出力のIDも定義します。(  定義作成の例  )
  

     public class MyLakeModelDefine
    {

        //********************************
        //===== ファクトリ関連定義 ========
        //********************************
        /// <summary>モデルファクトリ識別子</summary>
        public static HySID MODEL_FACTORY_LIB_ID = new HySID("xx.yy.zz.MyLakeModelFactory");

        //********************************
        //===== モデル関連定義 ========
        //********************************
        /// <summary>小魚用モデル種別</summary>
        public static readonly HySObjectKind MY_SMALL_FISH_MODEL_KIND = new HySObjectKind("MySmallFishModel");
        /// <summary>小魚用モデル名称</summary>
        public static readonly HySString MY_SMALL_FISH_MODEL_NAME = new HySString("小型の魚");
        /// <summary>大魚用モデル種別</summary>
        public static readonly HySObjectKind MY_BIG_FISH_MODEL_KIND = new HySObjectKind("MyBigFishModel");
        /// <summary>大魚用モデル名称</summary>
        public static readonly HySString MY_BIG_FISH_MODEL_NAME = new HySString("大型の魚");
        /// <summary>生存競争用モデル種別</summary>
        public static readonly HySObjectKind MY_STRUGGLE_MODEL_KIND = new HySObjectKind("MyStruggle_for_Existence");
        /// <summary>生存競争モデル名称</summary>
        public static readonly HySString MY_STRUGGLE_MODEL_NAME = new HySString("生存競争");
        /// <summary>湖環境用モデル種別</summary>
        public static readonly HySObjectKind MY_LAKE_ENV_MODEL_KIND = new HySObjectKind("MyLakeEnvModel");
        /// <summary>湖環境用モデル名称</summary>
        public static readonly HySString MY_LADE_ENV_MODEL_NAME = new HySString("湖環境");

        //********************************
        //===== 入出力パターン関連定義 ========
        //********************************
        /// <summary>生存競争出力</summary>
        public static readonly HySID OUT_STRUGGLE_D2 = new HySID("OutStruggleDim2");
        /// <summary>小魚数</summary>
        public static readonly HySID SMALL_FISH_NUM_D2 = new HySID("SmallFishNumDim2");
        /// <summary>大魚数</summary>
        public static readonly HySID BIG_FISH_NUM_D2 = new HySID("BigFishNumDim2");
        /// <summary>湖環境</summary>
        public static readonly HySID LAKE_ENV_D2 = new HySID("LakeEnvDim2");
        /// <summary>トータル数</summary>
        public static readonly HySID OUT_TOTAL_D0 = new HySID("OutTotalD0");
    }


 各要素モデルはお互いに相互の結合がある(ループ有り)なので、全体を「同期」動作させ、各要素モデルは「未来予測型」で作成します
  
 以前に紹介したように 型紙プロジェクト「MyModel」内の 「MyModel.cs」または「MyHydraulicsModel.cs」をコピーして 名称を変更して新しいクラススタブを作成します。  その他に必要なクラススタブも同様に作成します。

小魚スタブ(MySmallFishModel)スタブ作成例

    public class MySmallFishModel : McForecastModelBase
    {
        /// <summary> 演算データ(キャスト用) </summary>
        MySmallFishCalInfo m_csMyInf = null;   // 便利の為、キャスト用に定義しておく

        Random csRandom = new System.Random();
        // 前シミュレーション時刻
        HySTime csPrvSimTime = new HySTime(0);

        // 構成DataFusionを行った目印フラグ
        bool m_bForceDataFusionFlg = false;

。。。。。。。
    } 

 
 
 スタブが作成し終わったならば、ディバッグ用CommonMPを起動して、 ライブラリ管理画面内に 作成した、 「小魚」、「大魚」、「湖」、「生存競争」 の要素モデルが存在していることを確認します。
ディバッグ用CommonMPを起動方法
  
 
 スタブ作成が終了したならば、次に、各要素モデルのメソッドを完成させます。
 各要素モデルの タイムステップ:δt は1日(3600*24sec)とします。

<湖要素モデル>
 湖の温度は 1年を1周期とした sin カーブを描くものとします。
 また、湖内の プランクトン繁殖数:儕 = (Max数−現在プランクトン数)*温度の関数
 とします。  温度が高いほど繁殖数も高くします。
<小魚要素モデル>
 食べたプランクトン数が多いほど繁殖率を高く、死亡率は低くします。 但し、寿命を考えて、一定量は必ず死亡させます。 また、絶食状態でずっと時間が経過するとやがて餓死します。
 個体は、メッシュからメッシュへ移動しますが、なるべく 湖全体に広がるように移動していきます。
<大魚要素モデル>
 小魚と同様に 小魚を多く食べると、繁殖率が高く、死亡率は低くなります。 寿命や餓死も同様です。 個体はメッシュからメッシュへ移動しますが、小魚と同様に一様に広がるように移動するとともに、多少小魚が多い方に移動します。
<生存競争要素モデル>
 各要素モデルが計算した各メッシュ内の個体数を元に次のような喰う・喰われるの関係を計算し、喰われた個体数を減少させます。
  ・プランクトン−小魚
     喰われるプランクトン数 ∝ (プランクトン数)×(小魚数) とします。
  ・小魚 − 大魚
     喰われる小魚数 ∝ (メッシュ内で小魚と大魚が遭遇する確率)×(小魚捕食成功確率)とします。
     メッシュ内の小魚数、大魚数が多いほど、喰われる小魚数は大きくなります。

 上記の内容を 各クラスの Calculate()メソッド内に組み込みます。(作成例は本ページの下からダウンロードできます。)


 但し、ここで「注意すべき点」が有ります。

 同期型の要素モデルの計算処理を考えてみます。 CommonMPの計算制御方式では、同期型は下図(PAD図)のように制御されています。

     
 各要素は全てδt後の計算を行います。(この時には DataFusionは行っていません)
 したがって、全ての要素モデルが使用するデータの時刻は同じで、既に別の要素モデルが計算してしまった情報を使用することは有りません。
 全ての要素モデルの計算が終了した時点で、要素モデルが一斉に計算結果を出力します。
 この時、同期型の要素モデル間で 同じ情報をループして交換する場合を考えてみます。
 
        
 要素モデル:A は 入力:Xに−3して Yとして出力します。
 一方、要素モデル:Bは 入力:Yに+5して Xとして出力します。
 
 
 このように、同期型計算制御でループが存在する時、同じ変数を異なる要素モデルの間で別々に管理していると、出力がハンチングすることがあります。
 これを防ぐためには 同期型計算でも、計算(Calculateメソッド)直後に直ちにDataFusionメソッドがコールできるようにします。

     

 このために、Calculateメソッドから DataFusionメソッドをコールします。
 この時のコーディング例を示します。

    public class MySmallFishModel : McForecastModelBase
    {
        // 強制DataFusionを行った目印フラグ
        bool m_bForceDataFusionFlg = false;

      。。。。。。

    /// <summary><para>method outline:</para>
        /// <para>モデル演算</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = Calculate(ref csInputCellData)</para>
        /// </example>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override long Calculate(long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
        {
            // 入力情報を取得
            。。。。。。。。。。。。。。

            // 強制 DataFusion
            m_bForceDataFusionFlg = true;
            this.DataFusion(m_lOutputDataNum, ref m_OutputCellData);
            m_bForceDataFusionFlg = false;

            return 0;
         } 

        /// <summary><para>method outline:</para>
        /// <para>モデル演算結果を外部のエレメントに対して公開する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = DataFusion( lOutputDataNum, ref csOutputCellData)</para>
        /// </example>
        /// <param name="lOutputDataNum">出力情報数</param>
        /// <param name="csOutputCellData">出力情報配列</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override long DataFusion(long lOutputDataNum, ref McSendCellDataIF[] csOutputCellData)
        {
            HySCellData[,] csSndCellData2 = null;

            for (long lLp = 0; lLp < lOutputDataNum; lLp++)
            {   // 出力する伝送データ数分繰り返します。
                if (m_bForceDataFusionFlg == true)
                {

                    //csOutputCellData[lLp].SetCurrentTime(this.m_csSimTime - this.m_csDltTime);  演算子はスピード低下の元
                    csPrvSimTime.SetTime(m_csSimTime.GetTime() - m_csDltTime.GetTime());
                    csOutputCellData[lLp].SetCurrentTime(csPrvSimTime);
                }
                。。。。。。。。。
                                        

                if (m_bForceDataFusionFlg == true)
                {
                    m_OutputCellData[lLp].SendData();
                }
            } // end of for(lLp)

            return 0;
        }


 計算直後に DataFusionをコールしますが、強制出力の場合には、出力時刻を δt前に戻しておく必要があります。 
 要素モデルが持っているシミュレーション時刻とは異なる時刻のデータを出力する時の方法は 4章の4.5節で説明してあります。

 コーディングが終了した時点で、モデルを作成します。 
 プロジェクトの動作を 同期型とする必要があります。



  
             同期型設定の例

 「全体型」のタグを右クリックし、ポップアップメニューから「パラメータ設定」を選択します。 
 表示されたダイアローグの演算制御を「同期」とします。  


 

 プロジェクトを作成し、作成した要素モデルを用いて、生態系モデルを作成します。

     

 各要素間の接続は、 2次元のメッシュデータを用います。
 此処で作成している要素モデルは未完成であり、100×100に固定されています。
 (多少とも汎用的な要素モデルとするためには、メッシュ数をプロパティ画面から設定したり、湖の深さ情報を外部ファイルから読み込んだりできるようにする必要がありますが、この例ではそこまでの実装を行っていません。)
 

 計算期間を6年として計算を行っている例を下図に示します。

    
       (内部のパラメータ値によって、出力結果は異なります)



  ↓ パラメータを変更して、計算させた例 ↓
 






<動作例1: 湖に魚が1匹も居ない時のプランクトン数の変化>
  2年間分計算
     



<動作例1: 湖にプランクトンと小魚が存在する場合>
  2年間分計算
     



<動作例3: 湖にプランクトンと、小魚、大魚が存在する時>
  2年間分計算
       
 
  <動作例:3>のモデルに、別のところで製作したバイナリファイル出力要素モデルを接続し、出力した結果を、バイナリーファイル出力要素モデルと共に制作したツールを用いて、湖内の小魚と大魚の分布を示した例を以下に示します。(CommonMP計算プロジェクトは MyExerciseStep2内の「Ex22_湖その4.cmprj」を使用 )
 
               出力例: 魚の分布 季節:夏 (赤:大魚、 青:小魚)
   


               出力例: 魚の分布 季節:冬 (赤:大魚、 青:小魚)
   
 
 現実は兎も角、 本シミュレーション内では、冬は大きな魚が湖中心に分布し、夏には、周辺部に移動している結果となりました。



 本例では、要素モデルは計算論理部分のみ実装してあります。(その他のメソッドは未完成です。)
 計算論理も正確ではないので、現実の世界と一致するとは言えません。
 此処で示したかったことは、CommonMPは「生態系のシミュレーション」の様な応用の可能性もあるということです。
 単なる例ですので、別な考え方で作成しした要素モデル、あるいは別な構造のモデリング方法もあると思います。 CommonMPの応用範囲を広げるきっかけに、このサンプルが少しでも役に立てば幸いです。


 ここで作成した要素モデル開発プロジェクト(Ex20_CommonMP.lzh

 ダウンロードしたら解凍して生成されたフォルダー「MyLakeModel」を \CommonMP\Source\HYMCO\OptionImpl\ 下に置きます。   
 解凍して生成されたプロジェクト:MyLakeModel.csproj を ディバッグ用ソリューションに追加し、スタートアッププロジェクト(TestModelDeveloperMainExp)の依存関係に追加します。 
 また、 解凍して生成された、「MyExerciseStep2」フォルダーを \CommonMP\CommonMPData\ 下に置きます。



(前頁)<<      >>(次頁) 

初版:2013/10/01 |