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

2章 準備勉強
2.2 FORTRANのモデルをC#で制作する (その1)



 最初からいきなり、CommonMP対応の要素モデルを作成するのでは無く、
@ C#で水理関係のモデルを作成する。
A @で作成してモデルをCommonMPの要素モデル化する。
 という手順を踏んで勉強することにします。
 この章では @まで行い、3章でAを行います。

<モデル作成(水理公式集より)>
 「土木学会編 水理公式集(平成11年版) 例題プログラム集
  第2編 河川編
   例題 2−2 不定流計算 (執筆者:池田裕一先生)
  Dynamic Wave, Kinematic Wave 」
 で紹介されている FORTRANプログラムを C#へ移植してみます。

      


 先ず、モデル作成用のプロジェクトを作成します。

   
   
 コンソールアプリケーションモデルとして作成します。

   
 
 モデルは一つのクラスにしたい為、新規にクラスを追加します。

    

  DynamicWaveモデルを作成します。

    

 作成されたモデルの型紙ができています。

   



 
 ここで、FORTRANプログラムをC#に移植したソースを以下に示します。
<DynamicWaveModelクラス>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.IO;

namespace DynamicWaveLine
{
    // DynamicWaveModel クラス
    class DynamicWaveModel
    {
        // COMMON 領域内の変数をメンバー変数にする
        // PARAMETER(NXX=500)
        // COMMON /MESH/DT,DX,X(0:NXX)
        // *     H(0:NXX),H1(0:NXX),Q(0:NXX),Q1(Q:NXX),V(0,NXX) をC#で下記の通りに記述
        long NXX = 500;
        double DT;
        double DX;
        double[] X;
        double[] H;
        double[] H1;
        double[] Q;
        double[] Q1;
        double[] V;
        // COMMON /COND/TL,NT,NSKIP,XL,NX,SLOPE,WIDTH,ROUGH,QB,QP,TP,CP をC#で下記の通り記述
        double TL;
        double XL;
        long NT;
        long NSKIP;
        long NX;
        double SLOPE;
        double WIDTH;
        double ROUGH;
        double QB;
        double QP;
        double TP;
        double CP;
        // COMMON /CNST/G をC#で下記の通り記述
        double G;

        // PROGRAM   DYNAMIC  をC#で下記の通り記述
        public void DYNAMIC ()
        {
            INPUT();
            INITIAL();
            OUTPUT(0, 0.0);

            for (long J = 0; J <= NT - 1; J++)
            {
                long J1 = J + 1;
                double T1 = (double)J1 * DT;

                double dQIN = QIN(T1);
                Q1[0] = dQIN;
                H1[0] = H[0] + (1.5 * Q[0] - 2.0 * Q[1] + 0.5 * Q[2]) * DT / DX;

                for (long I = 1; I <= NX; I++)
                {
                    double FQ = 0.0;
                    double FV = 0.0;
                    double FP = 0.0;
                    double FF = 0.0;
                    COEFF(I, ref FQ, ref FV, ref FP, ref FF);

                    H1[I] = H[I] - FQ * DT;
                    Q1[I] = (Q1[I] + (FP - FV) * DT) / (1.0 + FF * DT);
                }

                for (long I = 0; I <= NX; I++)
                {
                    H[I] = H1[I];
                    Q[I] = Q1[I];
                    V[I] = Q[I] / H[I];
                }

                if ((NSKIP * (long)(J1 / NSKIP) - J1) == 0)
                {
                    OUTPUT(J1, T1);
                }
            }// end of for(J)
        } // end of DYNAMIC

        //-----------------
        // SUBROUTINE INPUT をC#で下記の通り記述
        public void INPUT ()
        {
            X = new double[NXX];
            H = new double[NXX];
            H1 = new double[NXX];
            Q = new double[NXX];
            Q1 = new double[NXX];
            V = new double[NXX];

            G = 9.8;
            TL = 48.0 * 3600.0;
            NT = 2400;
            DT = TL / ((double)NT);
            NSKIP = 240;

            XL = 100.0 * 1000.0;
            NX = 50;
            DX = XL / ((double)NX);

            SLOPE = 1.0 / 2000.0;
            WIDTH = 200.0;
            ROUGH = 0.03;

            QB = 200.0;
            QP = 2000.0;
            TP = 12.0 * 3600.0;
            CP = 10.0;
        } // end of INPUT
       
        //-------------------
        // SUBROUTINE  INITIAL をC#で下記の通り記述
        public void INITIAL ()
        {
            double QINIT = QIN(0.0);
            double HINIT = Math.Pow((Math.Pow(ROUGH, 2.0) * Math.Pow(QINIT, 2.0) / SLOPE), 0.3);
            double VINIT = QINIT / HINIT;
            for (long I = 0; I <= NX; I++)
            {
                X[I] = I * DX;
                Q[I] = QINIT;
                H[I] = HINIT;
                V[I] = VINIT;
            }
        } // end of INITIAL

        //------------------
        // SUBROUTINE  OUTPUT をC#で下記の通り記述
        public void OUTPUT (long J, double T)
        {
            FileStream csFile = new FileStream("Dynamic_out.csv", FileMode.Append, FileAccess.Write, FileShare.Read);
            StreamWriter csStreamWriter = new StreamWriter(csFile, Encoding.Default);

            string sMsg = "";
            sMsg = T.ToString();
            double outQ = 0.0;
            for (long I = 0; I <= NX; I++)
            {
                outQ = Q[I] * WIDTH;
                sMsg += "," + outQ.ToString();
            }
            csStreamWriter.WriteLine(sMsg);
            csStreamWriter.Flush();

            csStreamWriter.Close();
            csFile.Close();

        } // end of OUTPUT

        //-------------
        // FUNCTION  QIN をC#で下記の通り記述
        public double QIN (double T)
        {
            double TAU = T / TP;
            // QIN=(QB+(QP-QB) * (TAU*EXP(1-TAU))**CP)/WIDTH
            double dQin = (QB + (QP-QB)* Math.Pow( (TAU*Math.Exp(1-TAU)),CP ) )/WIDTH;
            return dQin;
        } // end of QIN

        // -------------
        // FUNCTION  COEFF をC#で下記の通り記述
        public void COEFF (long I,ref double FQ, ref double FV, ref double FP, ref double FF)
        {
            if (I < NX)
            {
                FQ = (Q[I + 1] - Q[I - 1]) / 2.0 / DX;
                FP = G * H[I] * (SLOPE - (H[I + 1] - H[I - 1]) / 2.0 / DX);
            }
            else
            {
                FQ = (Q[I] - Q[I - 1]) / DX;
                FP = G * H[I] * (SLOPE - (H[I] - H[I - 1]) / DX);
            }
            FV = (V[I] * Q[I] - V[I - 1] * Q[I - 1]) / DX;
            FF = G * Math.< /STRONG > Pow(ROUGH, 2.0) * Q[I] / Math.Pow(H[I], (7.0 / 3.0));
        } // end of COEEF

    } // end of class DynamicWaveModel
}


<メイン関数側>
       static void Main(string[] args)
        {
            DynamicWaveModel csMdl = new DynamicWaveModel();
            csMdl. DYNAMIC();
        }

  プロジェクト: DynamicWaveLine.lzh


 FORTRANプログラム中 COMMON領域に定義された変数をそのまま クラス「DyanamicWaveModel」のメンバー変数にしています。 メインプログラムから、制作したクラス「DynamicWaveModel」のインスタンスを生成し、そのインスタンスに対して メソッド:DYNAMIC( ) をコールし、計算を行なっています。 内部の処理は FORTRANプログラムと同じです。

       

 同様にして KinematicWaveのモデルも作成してみます。
 プロジェクト: KinematicWaveLine.lzh

(補足)「クラス」と「インスタンス
 ここで、もう一度「クラス」と「インスタンス」について整理します。
 「クラス」とは、あるカテゴリーを表す単位です。 例えば、「犬」、「猫」という概念が「クラス」に相当します。
 一方、「インスタンス」は クラス「犬」を具体化した実体であり、ハチ公、ポチ、などに相当します。 クラス「猫」のインスタンスは バロン、タマ などになります。
  犬  ハチ公 = new 犬();
  猫 タマ = new 猫();  の様にして インスタンスを生成します。




<DLL化>

 CommonMPでは 自作したモデルはDLLの形で提供されます。DLLとは、プログラムライブラリですが、それを使用する側がコンパイルすることなしに使用できるライブラリです。
 そこで、DLLの製作に慣れる為に、ここで制作したモデルをDLL化してみます。
 ソリューションエクスプローラー画面からプロジェクトを選択し、右クリックで表示されたポップアップルメニューの「プロパティ」を選択します。

    

 表示されたプロパティ画面の「出力の種類」を「コンソールアプリケーション」から「クラスライブラリ」に変更します。

    


 これでコンパイルを行えば、DLLが作成されます。しかし、前節でも示したように class DynamicWaveModel はデフォルト状態では namespece の外部には公開されていません。 そこで、クラス定義の前に public 宣言を追加します。

    
 プロジェクト: DynamicWaveDLL.lzh

 同様に、KinematicWaveMode もDLL化します。
 プロジェクト: KinematicWaveDLL.lzh
 

 DLLはプログラムライブラリですので、単体では動作させることはできません。(必ず、ライブラリを動作させるメインプログラムが必要です) そこで、制作した2つのDLLを動作させるためのメインプログラムを作成します。

 Microsoft Visual C# 「ファイル」−「新規プロジェクト」を選択して コンソールアプリケーションとしてメインプログラムを作成します。 プログラム名は「ModelMain」 とします。

     

 すると、これまでと同様に プログラムの型紙が作成されます。

    

 このメインプログラムで先ほど作成した2つのDLLを動作させるため、2つのDLL作成用プロジェクトを取り込みます。ソリューションを選択しマウスを右クリックして表示されたポップアップメニューから「追加」−「既存プロジェクト」を選択します。


    

 開いたダイアローグから、作成した DynamicWaveLine.csprj 及び KinematicWaveLine.csproj を1個づつそれぞれ選びソリューションに追加します。 

    

 ソリューションエクスプローラーに 下図のように DynamicWaveLine, KinematicWaveLine のプロジェクトが追加されています。つまり、ソリューション 「ModelMain」 は、「Modelmain」、「DynamicWaveLine」、「KinematicWaveLine」の3つのプロジェクトから構成されています。

    

 

 依存関係の設定
  ソリューションにDLL作成用のプロジェクトを追加ただけでは、ディバッグ環境でそれらを動作させることができません。 ディバッグ環境で動作させる為には、メインプログラムにDLLの存在を知らしめる必要があります。 そこで、メインプログラムが存在する「ModelMain」プロジェクトの参照設定を選択し、マウス右クリックにより表示されたポップアップメニューから「参照の追加」を選択します。

    

 表示されたダイアローグの「プロジェクト」のタグから、追加したプロジェクトを選択し「OK」を押下します。

    

 プロジェクトの参照設定に2つのDLLプロジェクト「DynamicWaveLine」、「KinematicWaveLine」が追加されています。

    

 これで、複数のプロジェクトを利用してのディバッグの準備が整いました。
 これから、内容が空のメインプログラムを改造して DLL提供された 2つのモデルを動作させるようにします。 メインプログラムに下記の通りコードを記述します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ModelMain
{
    class Program
    {
        static void Main(string[] args)
        {
            DynamicWaveModel csDynMdl = new DynamicWaveModel();
            csDynMdl.DYNAMIC();

            KinematicWaveModel csKinMdl = new KinematicWaveModel();
            csKinMdl. KINEMATIC();
        }
    }
}


 コンパイルすると エラーが表示されました。

    

 原因は、class Program が 2つのクラスを認識できない事です。 すなわち、プロジェクトの「参照の追加」に2つのDLLプロジェクトを追加したものの、コードレベルでは2つのDLLを認識できていません。 そこで、
 using 文を使用して 各モデルが所属する namespace 名称を追加します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DynamicWaveLine;
using KinematicWaveLine;

namespace ModelMain
{
    class Program
    {
        static void Main(string[] args)
        {
            DynamicWaveModel csDynMdl = new DynamicWaveModel();
            csDynMdl.DYNAMIC();

            KinematicWaveModel csKinMdl = new KinematicWaveModel();
            csKinMdl. KINEMATIC();
        }
    }
}

 

 すると、メインプログラム側が各モデルを認識できるようになりました。

    

 コンパイルしてもエラーは発生しません。

    

 Microsoft Visual C# 「デバッグ」−「ディバッグ開始」から各モデルのディバッグが行えます。 もしも下記の様な警告が出た場合には、メインプログラムが「スタートアッププロジェクト」(=プログラムを開始すると スタートアッププロジェクトのメインプログラムから開始する)に設定されていない可能性があります。

    

 下記の様にプロジェクト「ModelMain」を選択しポップアップメニューの「スタートアッププロジェクトに設定」を選んで 「ModelMain」をスタータアッププロジェクトに設定して下さい。
    

    制作したソリューション: CSSMDL.lzh (解凍したファイルの\MDL\ModelMain.sln を Microsoft Visual C# の「ファイル」−「プロジェクトを開く」から開いて下さい)


 ディバッグ実行するプロジェクトの実行ディレクトリは 「.\MDL\ModelMain\ModelMain\bin\Debug」です。 プログラム実行によって出力されたファイルはこの位置に生成されます。

 ところで、各モデルのINPUT( ) はモデルの定数を設定する部分です。 ここで、定数をモデル内にハードコーディングするのでは無く、コールする側で定数を設定できるようにしたいと思います。 そのために INPUT( ) の引数に 定数を受け渡すクラスを与えるようにします。 先ず、情報を引き渡す為の「DynamicWavePrptyInf」というクラスを追加します。

 


 外部からは、分割数、長さ、傾き、粗さ、及び結果出力ファイル名称 を与えることにします。 従って、 データの受け渡しを行うクラス(プロパティ情報クラスと呼ぶことにします)を下記のように定義します。 内部に設定した情報は何処からでも見れるように 全てのメンバー変数を public にします。

    public class DynamicWavePrptyInf
    {
        // 分割数
        public long   NX = 50;
        // 長さ
        public double XL = 100.0 * 1000.0;
        // 傾き
        public double SLOPE = 1.0 / 2000.0;
        // 粗さ
        public double ROUGH = 0.03;
        // 出力ファイル名称
        public string OutFileName = "outfile.csv";
    }


 次に、「DynamicWaveModel」クラスのメンバー関数「INPUT()」に 引数を追加します。

        //-----------------
        // SUBROUTINE INPUT
        public void INPUT (DynamicWavePrptyInf csPrptyInf)
        {
            X = new double[NXX];
            H = new double[NXX];
            H1 = new double[NXX];
            Q = new double[NXX];
            Q1 = new double[NXX];
            V = new double[NXX];

            G = 9.8;
            TL = 48.0 * 3600.0;
            NT = 2400;
            DT = TL / ((double)NT);

            NSKIP = 240;
            //XL = 100.0 * 1000.0;
            XL = csPrptyInf.XL;
            // NX = 50;
            NX = csPrptyInf.NX;
            DX = XL / ((double)NX);

            //SLOPE = 1.0 / 2000.0;
            SLOPE = csPrptyInf.SLOPE;
            WIDTH = 200.0;
            //ROUGH = 0.03;
            ROUGH = csPrptyInf.ROUGH;

            QB = 200.0;
            QP = 2000.0;
            TP = 12.0 * 3600.0;
            CP = 10.0;

            m_sOutFileName = csPrptyInf.OutFileName;
        }


 最後に、DYNAMIC( ) 内の INPUT( )をコメントアウトします。
       public void DYNAMIC()
        {
            // INPUT();
            INITIAL();
            OUTPUT(0, 0.0);
        。。。。。。

 コールする側は、プロパティ情報クラスを生成し、引き渡す情報を設定して INPUT( )メソッドをコールする処理を追加します。

        static void Main(string[] args)
        {
            // モデルインスタンス生成
            DynamicWaveModel csDynMdl = new DynamicWaveModel();

            // プロパティ情報インスタンス生成
            DynamicWavePrptyInf csDynPrp = new DynamicWavePrptyInf();

            // プロパティ情報を設定(正式に開発する場合にはGUI等から設定できると良い)
            csDynPrp.NX = 60;
            csDynPrp.XL = 100.0 * 1500.0;
            csDynPrp.ROUGH = 0.034;
            csDynPrp.OutFileName = "Dynamic_out.csv";
            csDynMdl.INPUT (csDynPrp);

            // 計算開始
            csDynMdl.DYNAMIC ();

 



 同様に KinematicWaveModelにもプロパティ情報を追加します。
 制作したソリューションを以下に置きます。
     CSSMDL2.lzh (解凍したファイルの\MDL\ModelMain.sln を Microsoft Visual C# の「ファイル」−「プロジェクトを開く」から開いて下さい)



 ここまでで、2つのモデルをDLLとして制作し、メインプログラムに取り込んで、動作するところまで来ました。 しかしながら、この状態では、2つのモデルが単に順番に動作しているだけです。 オブジェクト指向の醍醐味はここからになります。



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

初版:2013/06/12 |