// <summary>ソースコード：ＨＹＭＣＯ演算モデルクラス</summary>
// <author>CommonMP</author>


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

namespace CommonMP.HYMCO.OptionImple.GAModelSampleLIB
{
    /// <summary><para>class outline:</para>
    /// <para>KinematicWave河川モデルの実装部</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.3][2010/10/01][新規作成]</para>
    /// <para>
    /// KinematicWave河川モデルが複数連なった河川モデル（GAKinematicWaveEvolutionModel）の構成要素。
    /// 本クラス内に　CommonMPがサンプル提供している　要素モデル：McSampleKinematicWaveの
    /// 計算アルゴリズムが実装されている
    /// </para>
    /// </remarks>
    internal class GAKinematicWaveBox
    {
        /// <summary>セル数</summary>
        protected long m_lCelNumber = 5;
        /// <summary>Ｈ</summary>
        protected double[] m_dH = null;
        /// <summary>Ｖ</summary>
        protected double[] m_dV = null;
        /// <summary>Ｑ</summary>
        protected double[] m_dQ = null;

        /// <summary>祖度</summary>
        protected double m_dRough = 0.03;
        /// <summary>傾斜</summary>
        protected double m_dSlope = 1.0 / 2000.0;
        /// <summary>幅</summary>
        protected double m_dWidth = 50.0;

        /// <summary>長さ</summary>
        protected double m_dLength = 3000.0;

        /// <summary>セル長</summary>
        protected double m_dCelLength = 3000.0 / 5.0;
        /// <summary>演算(秒) </summary>
        protected double m_dTimeLag = 60;
        /// <summary>上流Box</summary>
        protected GAKinematicWaveBox m_csPrevBox = null;
        /// <summary>下流Box</summary>
        protected GAKinematicWaveBox m_csNextBox = null;

        /// <summary>上流端入力流量</summary>
        public double m_dQIn = 0.0;
        /// <summary>下流端出力流量</summary>
        public double m_dQOut = 0.0;
        /// <summary>下流端出力水位 </summary>
        public double m_dHOut = 0.0;
        /// <summary>下流端出力速度 </summary>
        public double m_dVOut = 0.0;

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>GAKinematicWaveBox csObj = new GAKinematicWaveBox(lCellNum)</para>
        /// </example>
        /// <param name="lCellNum">モデル内のセル数</param>
        /// <returns>GAKinematicWaveBox 生成されたインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public GAKinematicWaveBox(long lCellNum)
        {
            m_lCelNumber = lCellNum;
            m_dH = new double[m_lCelNumber];
            m_dV = new double[m_lCelNumber];
            m_dQ = new double[m_lCelNumber];
           
            m_dCelLength = m_dLength / (double)m_lCelNumber;

            for (long lLp = 0; lLp < m_lCelNumber; lLp++)
            {
                m_dH[lLp] = 1.2;
                m_dV[lLp] = 0.84;
                m_dQ[lLp] = 200.0;
            }
            m_dQOut = m_dQ[m_lCelNumber - 1];
            m_dHOut = m_dH[m_lCelNumber - 1];
            m_dVOut = m_dV[m_lCelNumber - 1];
        }

        /// <summary><para>method outline:</para>
        /// <para>上流のKinematicWave河川モデルの設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetPrev(ref csBox)</para>
        /// </example>
        /// <param name="csBox">上流のKinematicWave河川モデルインスタンス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetPrev(ref GAKinematicWaveBox csBox)
        {   m_csPrevBox = csBox;    }
        /// <summary><para>method outline:</para>
        /// <para>下流のKinematicWave河川モデルの設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetNext(ref csBox)</para>
        /// </example>
        /// <param name="csBox">下流のKinematicWave河川モデルインスタンス</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetNext( ref GAKinematicWaveBox csBox)
        {   m_csNextBox = csBox;    }

        /// <summary><para>method outline:</para>
        /// <para>モデルの粗度値設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetRough(dRough)</para>
        /// </example>
        /// <param name="dRough">粗度</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetRough(double dRough) { m_dRough = dRough; }
        /// <summary><para>method outline:</para>
        /// <para>モデルの勾配値設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetSlope(dSlope)</para>
        /// </example>
        /// <param name="dSlope">勾配</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetSlope(double dSlope) { m_dSlope = dSlope; }
        /// <summary><para>method outline:</para>
        /// <para>モデルの川幅値設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetWidth(dWidth)</para>
        /// </example>
        /// <param name="dWidth">川幅</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetWidth(double dWidth) { m_dWidth = dWidth; }
        /// <summary><para>method outline:</para>
        /// <para>モデルの長値設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetLehgth(dLength)</para>
        /// </example>
        /// <param name="dLength">長さ</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetLehgth(double dLength)
        {
            m_dLength = dLength;
            m_dCelLength = m_dLength / (double)m_lCelNumber;
        }
        /// <summary><para>method outline:</para>
        /// <para>計算時のδT設定</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>SetTimeLag(dTimeLag)</para>
        /// </example>
        /// <param name="dTimeLag">計算時のδT</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public void SetTimeLag(double dTimeLag) { m_dTimeLag = dTimeLag; }

        /// <summary><para>method outline:</para>
        /// <para>モデルを初期化する</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>Initialize()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>0 :正常 , -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public long Initialize()
        {
            double dDtH = 1.2;

            double dDtQ = 200.0 / m_dWidth;

            double dDtV = 0.84;


            for (long lLp = 0; lLp < m_lCelNumber; lLp++)
            {
                dDtH = Math.Pow(
                           (m_dRough * m_dRough * dDtQ * dDtQ) / m_dSlope
                             , 0.3);
                dDtV = dDtQ / dDtH;

                m_dH[lLp] = dDtH;
                m_dV[lLp] = dDtV;
                m_dQ[lLp] = dDtQ;
            }
            m_dQOut = m_dQ[m_lCelNumber - 1];
            m_dHOut = m_dH[m_lCelNumber - 1];
            m_dVOut = m_dV[m_lCelNumber - 1];
            return 0;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算</para>
        /// </summary>
        /// <example>
        /// <para>usage:</para>
        /// <para>long lRtn = Calculate()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>0 :正常 , -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 計算論理は、CommonMPにサンプルとして付属している「McSampleKinematicWave」クラス内の
        /// アルゴリズムを移植
        /// </para>
        /// </remarks>
        public long Calculate( )
        {
            //double dQTopTotalIn = m_dQIn; // 上流総合流入量セット
            //double dQin = dQTopTotalIn / m_dWidth;  // 上流端総合入力
            double dQin = m_dQIn / m_dWidth;  // 上流端総合入力

            //double dTimeLag = m_dTimeLag;
            
            double[] dH = new double[m_lCelNumber];

            // 始点
            dH[0] = Math.Pow(
                           (m_dRough * m_dRough * dQin * dQin) / m_dSlope
                             , 0.3);

            // 河道内の断面ごとの水位、流速、流量の算定
            double dFV = 0.0;
            for (long lLp = 1; lLp < m_lCelNumber; lLp++)
            {
                dFV = 5.0 / 3.0 * m_dV[lLp]
                    * (m_dH[lLp] - m_dH[lLp - 1])
                    / m_dCelLength;

                dH[lLp] = m_dH[lLp] - dFV * m_dTimeLag;
            }

            for (long lLp = 0; lLp < m_lCelNumber; lLp++)
            {
                m_dH[lLp] = dH[lLp];
                m_dV[lLp] = (1.0 / m_dRough)
                              * Math.Pow(m_dH[lLp], 2.0 / 3.0)
                              * Math.Pow(m_dSlope, 0.5);
                m_dQ[lLp] = m_dV[lLp] * m_dH[lLp] * m_dWidth;
            }

            m_dQOut = m_dQ[m_lCelNumber - 1];
            m_dHOut = m_dH[m_lCelNumber - 1];
            m_dVOut = m_dV[m_lCelNumber - 1];
            if (m_csNextBox != null)
            { m_csNextBox.m_dQIn = m_dQOut; }

            return 0;
        }

    }
}
