Dsl (Digital Simulation Library) for .Net

このトピックスは以下のセクションを含みます。

カスケード接続した液面レベル系

イメージ

説明

例題2

エレメント名

意味

Pin

入力パイプ

ADD

合流器

P1

TANK1に流れ込むパイプ

TANK1

1番目のタンク(内容は前例と同じ)

VALVE1

TANK1から流れ出る流量を決定するバルブ

P1to2

TANK1からTANK2に流れるパイプ

TANK2

2番目のタンク(内容は前例と同じ)

VALVE2

TANK2から流れ出る流量を決定するバルブ

P2

TANK2から流れ出るパイプ

DIV

P2を還流(PbackOut)と出力(Pout)に分ける分流器

PbackOut

TANK2からTANK1に還流するために分流器によって分けられたパイプ。

PipeDelay

還流するパイプに時間遅れを与えるための簡単な概念装置。

PbackIn

時間遅れを伴ってTANK2からTANK1に還流するパイプ。

  コピー イメージコードをコピー
                      // 
// カスケード接続した液面レベル系.
// 
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;

using Dsl; // Dsl.Dll を参照.
using DslDialog;
using DslSerializer;

namespace Test
{
    class Program
    {
        // 
        // [STAThread] を指定しないと DslDialogBox 中の DataGridView から Clipboard にアクセスできない.
        // 
        [STAThread]
        static void Main(string[] args)
        {
            CascadeTankModel();
        }

        /// <summary>
        /// カスケード接続されたタンクと時間遅れを取り入れたリサイクルパイプのモデル.
        /// </summary>
        static void CascadeTankModel()
        {
            // Processor の作成
            CascadeTankModelProcessor pr = new CascadeTankModelProcessor();

            // DslDialogBox() の作成.
            DslDialogBox dlg = new DslDialogBox();

            dlg.VariableFilter = delegate(Processor proc, Variable v)
            {
                if (!v.IsAlive())     return null; // 計算から無視された変数は一覧から除外する.
                if (v.IsConstant())   return "";   // 時間に依存しない変数は折れ線グラフ出力はしない.
                if (v.IsIntegrated()) return "積分変数";  // <I>型変数はまとめて一つのグラフにする.
                if (v.IsDerivative()) return "微分変数";
                return "通常の変数";
            };

            // 各エレメントの作成.
            Pipe Pin          = Pipe.Create(pr, "Pin");
            Pipe P1           = Pipe.Create(pr, "P1");
            Pipe P1to2        = Pipe.Create(pr, "P1to2");
            Pipe P2           = Pipe.Create(pr, "P2");
            Pipe PbackOut     = Pipe.Create(pr, "PbackOut");
            Pipe PbackIn      = Pipe.Create(pr, "PbackIn");
            Pipe Pout         = Pipe.Create(pr, "Pout");
            Tank tank1        = Tank.Create(pr, "TANK1", P1, P1to2);
            Tank tank2        = Tank.Create(pr, "TANK2", P1to2, P2);
            Valve valve1      = Valve.Create(pr, "VALVE1", P1to2, tank1.H);
            Valve valve2      = Valve.Create(pr, "VALVE2", P2, tank2.H);
            Connecter Cadd    = Connecter.Create(pr, "ADD", Pin, PbackIn, P1);
            Divider Div       = Divider.Create(pr, "DIV", P2, PbackOut, Pout);
            DelayDevice Delay = DelayDevice.Create(pr, "PipeDelay", PbackOut, PbackIn);

            // 属性の設定.
            Pin.Flow.Value        = 10.0; Pin.Flow.Flag        = USERFLAG.SET; // 入力流量.
            valve1.R.Value        = 1.0;  valve1.R.Flag        = USERFLAG.SET; // バルブ抵抗.
            valve2.R.Value        = 1.0;  valve2.R.Flag        = USERFLAG.SET;
            tank1.S.Value         = 1.0;  tank1.S.Flag         = USERFLAG.SET; // タンク1底面積.
            tank2.S.Value         = 1.0;  tank2.S.Flag         = USERFLAG.SET; // タンク2底面積.
            Div.R.Value           = 0.1;  Div.R.Flag           = USERFLAG.SET; // 分配率.
            Delay.DelayTime.Value = 10;   Delay.DelayTime.Flag = USERFLAG.SET; // 遅れ時間.

            // Required の指定.
            tank1.H.SetFlag(USERFLAG.REQUIRED | USERFLAG.DIVISIBLE);
            tank2.H.SetFlag(USERFLAG.REQUIRED | USERFLAG.DIVISIBLE);
            P1to2.Flow.SetFlag(USERFLAG.REQUIRED);
            P2.Flow.SetFlag (USERFLAG.REQUIRED);
            PbackOut.Flow.SetFlag(USERFLAG.REQUIRED);
            Pout.Flow.SetFlag (USERFLAG.REQUIRED);

            // 結果の出力.
            StreamWriter wr = new StreamWriter(Application.ExecutablePath + ".Txt"); // 自分用の出力ファイル.
            StreamWriter lf = new StreamWriter(Application.ExecutablePath + ".Log"); // ログ出力ファイル.
            wr.WriteLine("time\tP1.Q\ttank1.H\tP1to2.Q\ttank2.H\tPout\tPbackOut\tPbackIn");
            pr.AfterAlgebraicComputation = delegate(Processor gp, double time, double step, FLAG f)
            {
                wr.WriteLine("" + time + "\t" + P1.Flow.Value + "\t" + tank1.H.Value + "\t" + P1to2.Flow.Value + "\t" + tank2.H.Value + "\t" + Pout.Flow.Value + "\t" + PbackOut.Flow.Value + "\            t" + PbackIn.Flow.Value);
            };

            pr.LogFile = lf; // ログファイルを設定.

            // pr.IntegrationMethod = INTEGRATOR.BW_EULER;
            // pr.IntegrationMethod = INTEGRATOR.RUNGE_KUTTA;
            // pr.IntegrationMethod = INTEGRATOR.EULER;

            if (pr.DeterminateOrder() == RESULT.OK)
            {
                // Save()/Restore() の例:
                //     一旦、このときの状態をファイルにダンプしておく.
                StreamWriter sw = new StreamWriter(Application.ExecutablePath + ".dump");
                pr.Save(null, sw);
                pr.SaveContents(null, sw);
                sw.Close();
                //     再び読み込んで全てを元に戻す.
                StreamReader sr = new StreamReader(Application.ExecutablePath + ".dump");
                pr.Restore(null, sr);
                pr.RestoreContents(null, sr);
                sr.Close();

                // DslDialog を通して積分を実行(Run()メソッドは DslDialogBox を表示しません).
                dlg.Run( pr, 0, 100, 2);

                // ここで定常状態を計算する.
                if (pr.DeterminateOrder(true) == RESULT.OK)
                {
                     // 時刻 100.0 の時の定常状態を計算する.
                     // 一度計算すればいいので終了時刻=開始時刻とする.
                     dlg.Show(null,pr,100.0, 100.0, 0.0); // 時刻0~100までの結果を定常状態まで含めて表示.
                }
            }
            // Log file のクローズ.
            lf.Close();
            // 結果ファイルのクローズ.
            wr.Close();
        }

        /// <summary>
        /// PipeやTankといった自作モデルもProsessorのSave/Restoreに応じてSerializeできるようにするためのインターフェイス(CascadeTankModelProcessorのBeSerializedを参照).
        /// </summary>
        public interface ICascadeTankModel : IDslSerializable
        {
            /// <summary>
            /// 自作オブジェクト(PipeやValve等)の名前.
            /// </summary>
            string Name { get; set; }

            /// <summary>
            /// 自作オブジェクトも Processor(=CascadeTankModelProcessor) の BeSerialized[] に登録されるので、その Index を保持します.
            /// </summary>
            int Index { get; set; }

            /// <summary>
            /// オブジェクトが保持する Variable 自体(と右辺変数)は自動的に Save/Restore されますが ComupeValueAt() 等の delegate は Save/Restore されないのでその設定を実行します.
            /// </summary>
            void Setup();
        }

        /// <summary>
        /// CascadeTankModel を処理する Processor.
        /// Variable 以外にも Save/Restore する子オブジェクト(Pipe等)を持ちます.
        /// </summary>
        public class CascadeTankModelProcessor: Processor
        {
            /// <summary>
            /// Variable 以外にも Save/Restore する自作の子オブジェクト(Pipe等)の配列.
            /// </summary>
            public List<IDslSerializable>
            BeSerialized = new List<IDslSerializable>();

            /// <summary>
            /// (Pipe等の自作子オブジェクトも含めた)子オブジェクトを Save します.
            /// </summary>
            /// <param name="parent">任意</param>
            /// <param name="sw">TextWriter</param>
            public override void Save(object parent, TextWriter sw)
            {
                // Processor の子オブジェクト(Variable等)をSaveします.Save()は子オブジェクトの作成情報を出力します.
                // 逆の処理として出力された情報は後の Restore() で読み込まれ子オブジェクトが作成されます(作成だけでまだ初期状態です).
                // 子オブジェクトのプロパティ値等は後のSaveContents()呼び出しで出力されます.
                // 逆にRestoreContents()でプロパティ値等が読み込まれて、書き込み時の状態に戻ることになります.
                base.Save(parent, sw);

               // 後の Restore で各オブジェクト(Pipe等の自作オブジェクト)を作成できるようにオブジェクトの作成情報を書き込みます.
               // ここでは作成情報だけで、プロパティ等の値は後のSaveContents()呼び出しで出力されます.
               DIO.WriteListRecord<IDslSerializable>(sw, "BeSerialized=", BeSerialized, DIO.ObjectToString);

               // 次に各自作オブジェクトが子オブジェクトを保持している場合を考慮して、Saveを呼び出します.
               sw.WriteLine("\n// Begin: CascadeTankModelProcessor Save() \n//\n");
               for (int i = 0; i < BeSerialized.Count; ++i)
               {
                   ((ICascadeTankModel)BeSerialized[i]).Index = i;
                   BeSerialized[i].Save(this, sw);
               }
               sw.WriteLine("\n// End: CascadeTankModelProcessor Save() \n//\n");
            }

            /// <summary>
            /// Pipe等の自作子オブジェクトの内容を SaveContents します.
            /// </summary>
            /// <param name="parent">任意</param>
            /// <param name="sw">TextWriter</param>
            public override void SaveContents(object parent, TextWriter sw)
            {
                base.SaveContents(parent, sw);
                sw.WriteLine("\n// Begin: CascadeTankModelProcessor SaveContents() \n//\n");
                for (int i = 0; i < BeSerialized.Count; ++i)
                {
                    BeSerialized[i].SaveContents(this, sw);
                }
                sw.WriteLine("\n// End: CascadeTankModelProcessor SaveContents() \n//\n");
            }

            /// <summary>
            /// Pipe等の追加の子オブジェクトを Restore します.
            /// </summary>        /// <param name="parent">任意</param>
            /// <param name="sr">TextReader</param>
            public override void Restore(object parent, TextReader sr)
            {
                base.Restore(parent, sr);
                BeSerialized = DIO.ReadListRecord<IDslSerializable>(sr, "BeSerialized=", null, DIO.ParseDslSerializable);
                for (int i = 0; i < BeSerialized.Count; ++i)
                {
                    ((ICascadeTankModel)BeSerialized[i]).Index = i;
                    BeSerialized[i].Restore(this, sr);
                }
            }

            /// <summary>
            /// Pipe等の追加の子オブジェクトを RestoreContents します.
            /// </summary>        /// <param name="parent">任意</param>
            /// <param name="sr">TextReader</param>
            public override void RestoreContents(object parent, TextReader sr)
            {
                base.RestoreContents(parent, sr);
                for (int i = 0; i < BeSerialized.Count; ++i)
                {
                    BeSerialized[i].RestoreContents(this, sr);
                }
                // 各変数は新規に作成されます.
                // 新規作成された各変数のプロパティ値等はファイルから設定.
                // delegate 等のファイルに出力できない設定を元に戻すために各オブジェクトの Setup() を呼び出します.
                for (int i = 0; i < BeSerialized.Count; ++i)
                {
                    ((ICascadeTankModel)BeSerialized[i]).Setup();
                }
            }
        }

        /// <summary>
        /// 単一成分の流れを持つ簡略化したパイプ.
        /// パイプの径や摩擦損失等流量を決定する因子は無視.
        /// </summary>
        public class Pipe : ICascadeTankModel
        {
            private Variable m_Flow= new Variable();

            private intm_Index = -1;
            private string m_Name= "";

            /// <summary>
            /// 名前(ICascadeTankModel要素).
            /// </summary>
            public string Name
            {
                get { return m_Name; }
                set { m_Name = value; }
            }

            /// <summary>
            /// 自身が格納されている親の配列に対するインデックス(ICascadeTankModel要素).
            /// </summary>
            public int Index
            {
                get { return m_Index; }
                set { m_Index = value; }
            }

            /// <summary>
            /// デフォルトのコンストラクター.
            /// </summary>
            public Pipe()
            {
            }

            /// <summary>
            /// パイプの作成と内部で使用する変数の Processor 登録を実行する.
            /// 初期設定ではInFlowとOutFlowは同じものとする.
            /// </summary>
            /// <param name="pr">Processor</param>
            /// <param name="name">パイプの名前</param>
            /// <returns>Pipeオブジェクト</returns>
            public static Pipe Create(CascadeTankModelProcessor pr, string name)
            {
                Pipe pipe = new Pipe();
                pipe.Name = name;
                pr.AddVariables(pipe.Flow);
                pipe.Flow.Name = name + ".Flow";
                pipe.Setup();
                pr.BeSerialized.Add(pipe);
                return pipe;
            }

            /// <summary>
            /// 右辺や左辺の関係や計算式を確定させます.
            /// (パイプ系やパイプ長は考慮していないので)流れは外部から決定される.
            /// 従って、ここでは何もしない.
            /// </summary>
            public virtual void Setup()
            {
            }

            /// <summary>
            /// パイプ流量.
            /// </summary>
            public virtual Variable Flow
            {
                get { return m_Flow;}
                set { m_Flow = value;}
            }

            /// <summary>
            ///IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
            ///子オブジェクトは持たないので単にリターンする.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public virtual void Save(object parent, TextWriter tw)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public virtual void SaveContents(object parent, TextWriter tw)
            {
                DIO.WriteArrayRecord<string>(tw, "Pipe info=", new string[] { Name, "" + Index }, null);
                DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { Flow.Index }, null);
            }

            /// <summary>
            ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
            ///子オブジェクトは持たないので単にリターンする.
            /// </summary>        /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public virtual void Restore(object parent, TextReader tr)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
            /// </summary>        /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public virtual void RestoreContents(object parent, TextReader tr)
            {
                Processor pr = (Processor)parent;
                string [] sts = DIO.ReadVectorRecord<string>(tr, "Pipe info=", null,DIO.ParseString);
                Name = sts[0];
                Debug.Assert(""+Index == sts[1]);
                int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                Flow = pr.Variables[ix[0]];
            }
        }

        /// <summary>
        ///パイプの時間遅れ(Delay)を実現させるための仮想デバイス.
        /// </summary>
        public class DelayDevice: ICascadeTankModel
        {
            private Pipem_InPipe= null;
            private Pipem_OutPipe = null;
            private Variablem_DelayTime = null;
            private Variablem_MinimumSamplingTime = null;
            private DelayedVariable m_DelayVariable = null;
            private stringm_Name= "";
            private int m_Index = -1;

            public string Name
            {
                get {return m_Name;}
                set {m_Name = value;}
            }

            public int Index
            {
                get {return m_Index;}
                set { m_Index = value;}
            }

            public Pipe InPipe
            {
                get { return m_InPipe; }
                set { m_InPipe = value; }
            }

            public Pipe OutPipe
            {
                get { return m_OutPipe; }
                set { m_OutPipe = value; }
            }

            /// <summary>
            /// 右辺や左辺の関係や計算式を確定させます.
            /// </summary>
            public void Setup()
            {
                OutPipe.Flow.ComputeValueAt = delegate(Processor pr, Variable self, double time, double step)
                {
                    return self.RightSideVariables[0].Value;
                };
            }

            /// <summary>
            /// DelayDeviceの作成と Processor への登録をする.
            /// </summary>
            /// <param name="pr">Processor</param>
            /// <param name="name">パイプの名前</param>
            /// <returns>DelayedPipeオブジェクト</returns>
            public static DelayDevice Create(CascadeTankModelProcessor pr, string name,Pipe in_pipe,Pipe out_pipe)
            {
                DelayDevice delay = new DelayDevice();
                delay.Name = name;
                delay.InPipe= in_pipe;
                delay.OutPipe = out_pipe;

                delay.DelayTime = new Variable(pr);
                delay.DelayTime.Name = name + ".DelayTime";
                delay.DelayVariable = new DelayedVariable(pr);
                delay.DelayVariable.Name = name + ".DelayVariable";
                delay.MinimumSamplingTime = new Variable(pr);
                delay.MinimumSamplingTime.Name = name + ".MinimumSamplingTime";
                delay.MinimumSamplingTime.Flag = USERFLAG.SET;
                delay.MinimumSamplingTime.Value = 0.5;
                delay.DelayVariable.SetRightSideVariables(delay.InPipe.Flow, delay.DelayTime, delay.MinimumSamplingTime);
                delay.DelayVariable.Init(10); // 時系列データは10個までサンプリングされます.
                delay.OutPipe.Flow.SetRightSideVariables(delay.DelayVariable);
                delay.Setup();
                pr.BeSerialized.Add(delay);
                return delay;
            }

            /// <summary>
            /// 遅れ時間を与える Variable
            /// </summary>
            public Variable DelayTime
            {
                get { return m_DelayTime; }
                set { m_DelayTime = value; }
            }

            /// <summary>
            /// 最低サンプリング時間刻みを与える Variable
            /// </summary>
            public Variable MinimumSamplingTime
            {
                get { return m_MinimumSamplingTime; }
                set { m_MinimumSamplingTime = value; }
            }

            /// <summary>
            /// 時間遅れを計算する Variable.InFlowの時間遅れを計算してOutFlowの値を設定します.
            /// </summary>
            public DelayedVariable DelayVariable
            {
                get { return m_DelayVariable; }
                set { m_DelayVariable = value; }
            }

            /// <summary>
            /// デフォルトのコンストラクター.
            /// </summary>
            public DelayDevice()
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public void Save(object parent, TextWriter tw)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
            /// </summary>        /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public void SaveContents(object parent, TextWriter tw)
            {
                DIO.WriteArrayRecord<string>(tw, "DelayDevice info=", new string[] { Name, "" + Index }, null);
                DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { m_DelayTime.Index, m_MinimumSamplingTime.Index,m_DelayVariable.Index,InPipe.Index,OutPipe.Index }, null);
            }

            /// <summary>
            ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public void Restore(object parent, TextReader tr)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public void RestoreContents(object parent, TextReader tr)
            {
                CascadeTankModelProcessor pr = (CascadeTankModelProcessor)parent;

                string[] sts = DIO.ReadVectorRecord<string>(tr, "DelayDevice info=", null, DIO.ParseString);
                Name = sts[0];
                Debug.Assert("" + Index == sts[1]);

                int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                DelayTime = pr.Variables[ix[0]];
                MinimumSamplingTime = pr.Variables[ix[1]];
                DelayVariable = (DelayedVariable)pr.Variables[ix[2]];
                InPipe = (Pipe)pr.BeSerialized[ix[3]];
                OutPipe = (Pipe)pr.BeSerialized[ix[4]];
            }

        }

        /// <summary>
        /// タンクの液面高(H)から流出流量を決める単純なバルブモデル.
        /// </summary>
        public class Valve : ICascadeTankModel
        {
            private Variable m_Flow = null;
            private Variable m_H= null;
            private Variable m_R= null;

            private intm_Index = -1;
            private string m_Name= "";

            /// <summary>
            /// 名前(ICascadeTankModel要素).
            /// </summary>
            public string Name
            {
                get { return m_Name; }
                set { m_Name = value; }
            }

            /// <summary>
            /// 自身が格納されている親の配列に対するインデックス(ICascadeTankModel要素).
            /// </summary>
            public int Index
            {
                get { return m_Index; }
                set { m_Index = value; }
            }

            /// <summary>
            /// 右辺や左辺の関係や計算式を確定させます.
            /// </summary>
            public void Setup()
            {
                m_Flow.ComputeValueAt = delegate(Processor p, Variable self, double time, double step)
                {
                    double v = self.RightSideVariables[0].Value;
                    if (v <= 0.0) return 0.0;
                    double r = self.RightSideVariables[1].Value;
                    if (Math.Abs(r) == 0.0) return 0.0; // 設定ミスの場合.
                    return Math.Sqrt(v) / r; // Q = Sqrt(H)/R
                };
            }

            /// <summary>
            /// 流出流量.
            /// </summary>
            public Variable Flow
            {
                get { return m_Flow; }
                set { m_Flow = value; }
            }

            /// <summary>
            /// 液面高.
            /// </summary>
            public VariableH
            {
                get { return m_H; }
                set { m_H = value; }
            }

            /// <summary>
            /// バルブ抵抗.
            /// </summary>
            public Variable R
            {
                get { return m_R; }
                set { m_R = value; }
            }

            /// <summary>
            /// IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
            /// 子オブジェクトは全てProcessorが管理する.独自に管理するものは無いので単にリターンする.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public void Save(object parent, TextWriter tw)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
            public void SaveContents(object parent, TextWriter tw)
            {
                DIO.WriteArrayRecord<string>(tw, "Valve info=", new string[] { Name, "" + Index }, null);
                DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { Flow.Index, H.Index, R.Index }, null);
            }

            /// <summary>
            ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
            ///独自に管理する子オブジェクトは持たないので単にリターンする.
            /// </summary>
            /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public void Restore(object parent, TextReader tr)
            {
            }

            /// <summary>
            ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
            /// </summary>        /// <param name="parent">Processor オブジェクト</param>
            /// <param name="tr">読み込み元の TextReader オブジェクト</param>
            public void RestoreContents(object parent, TextReader tr)
            {
                Processor pr = (Processor)parent;
                string[] sts = DIO.ReadVectorRecord<string>(tr, "Valve info=", null, DIO.ParseString);
                Name = sts[0];
                Debug.Assert("" + Index == sts[1]);
                int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                Flow = pr.Variables[ix[0]];
                H= pr.Variables[ix[1]];
                R= pr.Variables[ix[2]];
            }

            /// <summary>
            /// バルブの作成と Processor への登録をする.
            /// </summary>
            /// <param name="pr">Processor</param>
            /// <param name="name">バルブの名前</param>
            /// <param name="pipe">参照パイプ</param>
            /// <param name="H">液面高</param>
            /// <returns>Valve オブジェクト</returns>
            public static Valve Create(CascadeTankModelProcessor pr, string name, Pipe pipe, Variable H)
            {
                Valve valve = new Valve();
                valve.Name = name;
                valve.Flow = pipe.Flow;
                valve.H= H;
                valve.R= new Variable(pr);
                valve.R.Name = name + ".R";
                valve.Flow.SetRightSideVariables(valve.H, valve.R);
                valve.Setup();
                pr.BeSerialized.Add(valve);
                return valve;
            }

            /// <summary>
            /// デフォルトのコンストラクター.
            /// </summary>
            public Valve()
            {
            }

            /// <summary>
            /// 一つのパイプを分流比(R)に従って2つに分ける簡単な分流器モデル.
            /// </summary>
            public class Divider : ICascadeTankModel
            {
                private Pipe m_InPipe = null;
                private Pipe m_OutPipe1 = null;
                private Pipe m_OutPipe2 = null;
                private Variable m_R= null;

                private intm_Index = -1;
                private string m_Name= "";


                /// <summary>
                /// 名前(ICascadeTankModel要素).
                /// </summary>
                public string Name
                {
                    get { return m_Name; }
                    set { m_Name = value; }
                }

                /// <summary>
                /// 自身が格納されている親の配列に対するインデックス(ICascadeTankModel要素).
                /// </summary>
                public int Index
                {
                    get { return m_Index; }
                    set { m_Index = value; }
                }

                /// <summary>
                /// 右辺や左辺の関係や計算式を確定させます.
                /// </summary>
                public void Setup()
                {
                    m_OutPipe1.Flow.ComputeValueAt = delegate(Processor pr, Variable self, double time, double step)
                    {
                        return self.RightSideVariables[0].Value * self.RightSideVariables[1].Value;
                    };
                    m_OutPipe2.Flow.ComputeValueAt = delegate(Processor pr, Variable self, double time, double step)
                    {
                        return self.RightSideVariables[0].Value - self.RightSideVariables[1].Value;
                    };
                }

                /// <summary>
                /// 入力パイプ.
                /// </summary>
                publicPipe InPipe
                {
                    get { return m_InPipe; }
                    set { m_InPipe = value;}
                }

                /// <summary>
                /// 出力パイプ1.
                /// </summary>
                publicPipe OutPipe1
                {
                    get { return m_OutPipe1; }
                    set { m_OutPipe1 = value; }
                }

                /// <summary>
                /// 出力パイプ2.
                /// </summary>
                public Pipe OutPipe2
                {
                    get { return m_OutPipe2; }
                    set { m_OutPipe2 = value; }
                }

                /// <summary>
                /// 分流比.
                /// </summary>
                publicVariableR
                {
                    get { return m_R;}
                    set { m_R = value;}
                }

                /// <summary>
                /// IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
                /// 子オブジェクトは全てProcessorが管理する.独自に管理するものは無いので単にリターンする.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                public void Save(object parent, TextWriter tw)
                {
                }

                /// <summary>
                ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                public void SaveContents(object parent, TextWriter tw)
                {
                    DIO.WriteArrayRecord<string>(tw, "Divider info=", new string[] { Name, "" + Index }, null);
                    DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { InPipe.Index, OutPipe1.Index,OutPipe2.Index, R.Index }, null);
                }

                /// <summary>
                ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
                ///独自に管理する子オブジェクトは持たないので単にリターンする.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                public void Restore(object parent, TextReader tr)
                {
                }

                /// <summary>
                ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                public void RestoreContents(object parent, TextReader tr)
                {
                    CascadeTankModelProcessor pr = (CascadeTankModelProcessor)parent;

                    string[] sts = DIO.ReadVectorRecord<string>(tr, "Divider info=", null, DIO.ParseString);
                    Name = sts[0];
                    Debug.Assert("" + Index == sts[1]);
                    int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                    InPipe = (Pipe)pr.BeSerialized[ix[0]];
                    OutPipe1 = (Pipe)pr.BeSerialized[ix[1]];
                    OutPipe2 = (Pipe)pr.BeSerialized[ix[2]];
                    R = pr.Variables[ix[3]];
                }

                /// <summary>
                /// 分流器の作成と Processor への登録をする.
                /// </summary>
                /// <param name="pr">Processor</param>
                /// <param name="name">分流器の名前</param>
                /// <param name="in_pipe">入力パイプ</param>
                /// <param name="out_pipe1">出力パイプ1</param>
                /// <param name="out_pipe2">出力パイプ2</param>
                /// <returns>分流器オブジェクト</returns>
                public static Divider Create(CascadeTankModelProcessor pr, string name, Pipe in_pipe, Pipe out_pipe1, Pipe out_pipe2)
                {
                    Divider divider = new Divider();
                    divider.Name = name;
                    divider.InPipe = in_pipe;
                    divider.OutPipe1 = out_pipe1;
                    divider.OutPipe2 = out_pipe2;
                    divider.R = new Variable(pr);
                    divider.R.Name = name + ".R";
                    divider.OutPipe1.Flow.SetRightSideVariables(divider.InPipe.Flow, divider.R);
                    divider.OutPipe2.Flow.SetRightSideVariables(divider.InPipe.Flow, divider.OutPipe1.Flow);
                    divider.Setup();
                    pr.BeSerialized.Add(divider);
                    return divider;
                }

                /// <summary>
                /// デフォルトのコンストラクター.
               /// </summary>
               public Divider()
                 : base()
               {
               }
            }

            /// <summary>
            /// 2つのパイプを一つにする合流器の簡略モデル.
            /// </summary>
            public class Connecter : ICascadeTankModel
            {
                private Pipe m_InPipe1 = null;
                private Pipe m_InPipe2 = null;
                private Pipe m_OutPipe = null;

                private intm_Index = -1;
                private string m_Name= "";

                /// <summary>
                /// 名前(ICascadeTankModel要素).
                /// </summary>
                public string Name
                {
                    get { return m_Name; }
                    set { m_Name = value; }
                }

                /// <summary>
                /// 自身が格納されている親の配列に対するインデックス(ICascadeTankModel要素).
                /// </summary>
                public int Index
                {
                    get { return m_Index; }
                    set { m_Index = value; }
                }

                /// <summary>
                /// IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
                /// 子オブジェクトは全てProcessorが管理する.独自に管理するものは無いので単にリターンする.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                public void Save(object parent, TextWriter tw)
                {
                }

                /// <summary>
                ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                public void SaveContents(object parent, TextWriter tw)
                {
                    DIO.WriteArrayRecord<string>(tw, "Connecter info=", new string[] { Name, "" + Index }, null);
                    DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { InPipe1.Index, InPipe2.Index, OutPipe.Index }, null);
                }

                /// <summary>
                ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
                ///独自に管理する子オブジェクトは持たないので単にリターンする.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                public void Restore(object parent, TextReader tr)
                {
                }

                /// <summary>
                ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
                /// </summary>
                /// <param name="parent">Processor オブジェクト</param>
                /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                public void RestoreContents(object parent, TextReader tr)
                {
                    CascadeTankModelProcessor pr = (CascadeTankModelProcessor)parent;

                    string[] sts = DIO.ReadVectorRecord<string>(tr, "Connecter info=", null, DIO.ParseString);
                    Name = sts[0];
                    Debug.Assert("" + Index == sts[1]);
                    int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                    InPipe1 = (Pipe)pr.BeSerialized[ix[0]];
                    InPipe2 = (Pipe)pr.BeSerialized[ix[1]];
                    OutPipe = (Pipe)pr.BeSerialized[ix[2]];
                }

                /// <summary>
                /// 右辺や左辺の関係や計算式を確定させます.
                /// </summary>
                public void Setup()
                {
                    m_OutPipe.Flow.ComputeValueAt = delegate(Processor pr, Variable self, double time, double step)
                    {
                        return self.RightSideVariables[0].Value + self.RightSideVariables[1].Value;
                    };
                }

                /// <summary>
                /// 入力パイプ1.
                /// </summary>
                public Pipe InPipe1
                {
                    get { return m_InPipe1; }
                    set { m_InPipe1 = value;}
                }

                /// <summary>
                /// 入力パイプ2.
                /// </summary>
                public Pipe InPipe2
                {
                    get { return m_InPipe2; }
                    set { m_InPipe2 = value;}
                }

                /// <summary>
                /// 出力パイプ.
                /// </summary>
                public Pipe OutPipe
                {
                    get { return m_OutPipe; }
                    set { m_OutPipe = value; }
                }

                /// <summary>
                /// 合流器の作成と Processor への登録をする.
                /// </summary>
                /// <param name="pr">CascadeTankModelProcessor</param>
                /// <param name="name">合流器の名前</param>
                /// <param name="in_pipe1">入力パイプ1</param>
                /// <param name="in_pipe2">入力パイプ2</param>
                /// <param name="out_pipe">出力パイプ</param>
                /// <returns>合流器オブジェクト</returns>
                public static Connecter Create(CascadeTankModelProcessor pr, string name, Pipe in_pipe1, Pipe in_pipe2, Pipe out_pipe)
                {
                    Connecter connecter = new Connecter();
                    connecter.Name = name;
                    connecter.OutPipe = out_pipe;
                    connecter.InPipe1 = in_pipe1;
                    connecter.InPipe2 = in_pipe2;
                    connecter.OutPipe.Flow.SetRightSideVariables(connecter.InPipe1.Flow, connecter.InPipe2.Flow);
                    connecter.Setup();
                    pr.BeSerialized.Add(connecter);
                    return connecter;
                }

                /// <summary>
                /// デフォルトのコンストラクター.
                /// </summary>
                public Connecter()
                 : base()
                {
                }
            }

            /// <summary>
            /// 入力パイプと液面高と底面積に応じて流れ出る簡略したタンクモデル.
            /// </summary>
            public class Tank : ICascadeTankModel
            {
                 private Pipe m_InPipe  = null;
                 private Pipe m_OutPipe = null;
                 private Variable m_H   = null;
                 private Variable m_DHDT= null;
                 private Variable m_S   = null;

                 private intm_Index     = -1;
                 private string m_Name  = "";

                 /// <summary>
                 /// 名前(ICascadeTankModel要素).
                 /// </summary>
                 public string Name
                 {
                     get { return m_Name; }
                     set { m_Name = value; }
                 }

                 /// <summary>
                 /// 自身が格納されている親の配列に対するインデックス(ICascadeTankModel要素).
                 /// </summary>
                 public int Index
                 {
                     get { return m_Index; }
                     set { m_Index = value; }
                 }

                 /// <summary>
                 /// 右辺や左辺の関係や計算式を確定させます.
                 /// </summary>
                 public void Setup()
                 {
                     m_DHDT.ComputeValueAt = delegate(Processor p, Variable self, double time, double step)
                     {
                        double qin= self.RightSideVariables[0].Value; // Qin
                        double qout = self.RightSideVariables[1].Value; // Qout
                        double s= self.RightSideVariables[2].Value; // S
                        return (qin - qout) / s; // dH/dt = (Qin - Qout)/S
                     };
                 }

                 /// <summary>
                 /// IDslSerializableメンバー.子オブジェクトの作成情報を出力する.
                 /// 子オブジェクトは全てProcessorが管理する.独自に管理するものは無いので単にリターンする.
                 /// </summary>
                 /// <param name="parent">Processor オブジェクト</param>
                 /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                 public void Save(object parent, TextWriter tw)
                 {
                 }

                 /// <summary>
                 ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を出力する.
                 /// </summary>
                 /// <param name="parent">Processor オブジェクト</param>
                 /// <param name="tw">書き込み先の TextWriter オブジェクト</param>
                 public void SaveContents(object parent, TextWriter tw)
                 {
                     DIO.WriteArrayRecord<string>(tw, "Tank info=", new string[] { Name, "" + Index }, null);
                     DIO.WriteArrayRecord<int>(tw, "Child indeces=", new int[] { InPipe.Index, OutPipe.Index, m_H.Index,m_DHDT.Index,m_S.Index }, null);
                 }

                 /// <summary>
                 ///IDslSerializableメンバー.子オブジェクトの作成情報を読み込み作成する.
                 ///独自に管理する子オブジェクトは持たないので単にリターンする.
                 /// </summary>
                 /// <param name="parent">Processor オブジェクト</param>
                 /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                 public void Restore(object parent, TextReader tr)
                 {
                 }

                 /// <summary>
                 ///IDslSerializableメンバー.オブジェクト(子オブジェクトを含む)のプロパティ情報等を読み込んで、書き込み時点の状態に戻す.
                 /// </summary>
                 /// <param name="parent">Processor オブジェクト</param>
                 /// <param name="tr">読み込み元の TextReader オブジェクト</param>
                 public void RestoreContents(object parent, TextReader tr)
                 {
                     CascadeTankModelProcessor pr = (CascadeTankModelProcessor)parent;

                     string[] sts = DIO.ReadVectorRecord<string>(tr, "Tank info=", null, DIO.ParseString);
                     Name = sts[0];
                     Debug.Assert("" + Index == sts[1]);
                     int[] ix = DIO.ReadVectorRecord<int>(tr, "Child indeces=", null, DIO.ParseInt);
                     InPipe = (Pipe)pr.BeSerialized[ix[0]];
                     OutPipe= (Pipe)pr.BeSerialized[ix[1]];
                     m_H= pr.Variables[ix[2]];
                     m_DHDT = pr.Variables[ix[3]];
                     m_S= pr.Variables[ix[4]];
                 }

                 /// <summary>
                 /// 入力パイプ.
                 /// </summary>
                 public Pipe InPipe
                 {
                     get { return m_InPipe; }
                     set { m_InPipe = value; }
                 }

                 /// <summary>
                 /// 出力パイプ.
                 /// </summary>
                 public Pipe OutPipe
                 {
                     get { return m_OutPipe; }
                     set { m_OutPipe = value; }
                 }

                 /// <summary>
                 /// 液面高.
                 /// </summary>
                 public Variable H
                 {
                     get { return m_H; }
                     set { m_H = value; }
                 }

                 /// <summary>
                 /// 液面高変化率.
                 /// </summary>
                 publicVariableDHDT
                 {
                     get { return m_DHDT; }
                     set { m_DHDT = value; }
                 }

                 /// <summary>
                 /// タンク底面積.
                 /// </summary>
                 public Variable S
                 {
                     get { return m_S; }
                     set { m_S = value; }
                 }

                 /// <summary>
                 /// タンクの作成と Processor への登録をする.
                 /// </summary>
                 /// <param name="pr">Processor</param>
                 /// <param name="name">タンクの名前</param>
                 /// <param name="in_pipe">入力パイプ</param>
                 /// <param name="out_pipe">出力パイプ</param>
                 /// <returns>タンクオブジェクト</returns>
                 public static Tank Create(CascadeTankModelProcessor pr, string name, Pipe in_pipe, Pipe out_pipe)
                 {
                    Tank tank = new Tank();
                    tank.Name = name;
                    tank.InPipe = in_pipe;
                    tank.OutPipe = out_pipe;
                    tank.H = new Variable(pr);
                    tank.H.Name = name+ ".H";
                    tank.DHDT = new Variable(pr);
                    tank.DHDT.Name = name + ".DH/DT";
                    tank.S = new Variable(pr);
                    tank.S.Name = name + ".S";
                    tank.H.SetRightSideVariables(tank.DHDT); // H = Integral(dH/dt)
                    tank.H.Flag = USERFLAG.INTEGRATED;
                    tank.DHDT.SetRightSideVariables(tank.InPipe.Flow,tank.OutPipe.Flow,tank.S);
                    tank.DHDT.Flag = USERFLAG.VOLATILE;

                    tank.Setup();
                    pr.BeSerialized.Add(tank);
                    return tank;
                 }

                 /// <summary>
                 /// デフォルトのコンストラクター.
                 /// </summary>
                 public Tank()
                 {
                 }
            }
        }
    }
}

計算結果:

例題2の結果

参照

先頭へ