// <summary>ソースコード：サンプル演算モデルクラス</summary>
// <author>CommonMP</author>

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

using CommonMP.HYSSOP.CoreImpl;
using CommonMP.HYSSOP.CoreImpl.HSData;
using CommonMP.HYSSOP.CoreImpl.HSTools;

using CommonMP.HYMCO.Interface;
using CommonMP.HYMCO.Interface.Model;
using CommonMP.HYMCO.Interface.Data;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Tool;



namespace CommonMP.HYMCO.OptionImple.McHyHdFormulaSampleH13
{
    /// <summary><para>class outline:</para>
    /// <para>水理公式集例題２－２より　不定流計算（Dynamic wave)モデルクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.2.0][2011/11/11][新規作成]</para>
    /// <para>remarks</para>
    /// <para> </para>
    /// </remarks>
    public class McDynamicWaveLane : McForecastModelBase
    {
        /// <summary> 演算データ（キャスト用） </summary>
        McDynamicWaveLaneCalInfo m_KMdlInf = null; // 便利の為、キャスト用に定義しておく

        //=========================
        // 演算実行前処理関連メソッド
        //=========================

        /// <summary><para>method outline:</para>
        /// <para>入力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = ReceiveConnectionCheck(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>受信するデータが自モデルが期待している情報か否かをチェックする</para>
        /// </remarks>
        protected override bool ReceiveConnectionCheck(ref McStructErrorInfo csErrorInf, long lInputDataNum, McReceiveCellDataIF[] csInputCellData)
        {
            bool bRtn = true;

            if (lInputDataNum == 0)
            {
                // 入力が無い場合
                // エラー
                csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND, "No receive data.");
                bRtn = false;
            }
            for (long lP = 0; lP < lInputDataNum; lP++)
            {   // 入力データ数分
                if (McHyHdFormulaSampleH13Define.IN_PATTERN_TOP.Equals(csInputCellData[lP].GetReceivePatternID()) == true)
                {
                    // Do Nothing
                }
                else
                {
                    csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                        "Unexpected receive data type. (Received from " + csInputCellData[lP].GetUpperElementID().ToString() + ")");
                    bRtn = false;
                }
                long lD1 = 0; long lD2 = 0; long lD3 = 0; long lCellDataNum = 0;
                long lCellDim = csInputCellData[lP].GetDimension(ref lD1, ref lD2, ref lD3, ref lCellDataNum);

                if (lCellDim == 1 && lD1 == 1)
                {   // 1次元の１セルでならば
                    if (lCellDataNum < 1)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                            "Variable number in the Cells is too short. (Received from " + csInputCellData[lP].GetUpperElementID().ToString() + ")");
                        bRtn = false;
                    }
                }
            }
            return bRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>出力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = SendConnectionCheck(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <param name="lOutputDataNum">出力情報数</param>
        /// <param name="csOutputCellData">出力情報配列</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>送信端子に設定されている伝送データが自モデルが期待している情報か否かをチェックする</para>
        /// </remarks>
        protected override bool SendConnectionCheck(ref McStructErrorInfo csErrorInf, long lOutputDataNum, McSendCellDataIF[] csOutputCellData)
        {
            bool bRtn = true;

            if (lOutputDataNum == 0)
            {
                // 警告（エラーではない）
                csErrorInf.AddCheckWarningData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND, "No send port.");
            }
            for (long lP = 0; lP < lOutputDataNum; lP++)
            {   // 出力側接続線数分チェックを行う
                if (McHyHdFormulaSampleH13Define.OUT_PATTERN_BOTTOM.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // 最終セルだけの出力ならば
                    // Do Nothing
                }
                else if (McHyHdFormulaSampleH13Define.OUT_PATTERN_ALL.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // 全体出力ならば
                    // Do Nothing
                }
                else
                {
                    // エラー
                    csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                        "Unexpected send data type.");
                    bRtn = false;
                }

                long lD1 = 0; long lD2 = 0; long lD3 = 0; long lCellDataNum = 0;
                long lCellDim = csOutputCellData[lP].GetDimension(ref lD1, ref lD2, ref lD3, ref lCellDataNum);

                if (lCellDim == 1 && lD1 == 1)
                {   // １次元配列の１セルならば
                    // セル配列数が１ならば、最終セルのみ出力するものとする
                    // セル内の変数の数をチェック
                    if (lCellDataNum < 3)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                            "Variable number in the Cells is too short. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                        bRtn = false;
                    }
                }
                else if (lCellDim == 1 && lD1 > 1)
                {   // １次元配列で複数セルならば
                    // セル配列数が複数ならば、全セルの出力とする
                    // 伝送セルの配列数が　モデル内のセルの配列数よりも小さいならば
                    if (m_KMdlInf.m_lCelNumber+1 > lD1)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                                                "Cell dimention(" + csOutputCellData[lP].GetTranInfoKind().ToString() + ") is too short. (send to " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                        bRtn = false;
                    }
                    // セル内の変数の数をチェック
                    if (lCellDataNum < 3)
                    {
                        csErrorInf.AddCheckErrorData(this.GetID(), McHyHdFormulaSampleH13Define.DYNAMIC_WAVE_LANE_KIND,
                            "Variable number in the Cells is too short. (Send To " + csOutputCellData[lP].GetLowerElementID().ToString() + ")");
                        bRtn = false;
                    }
                }
            }
            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデルを初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Initialize(csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <param name="lInputDataNum">入力情報数</param>
        /// <param name="csInputCellData">演算に必要な入力情報配列</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 水理公式集例題２－２　dynamic.for 内の
        /// !*****************************************************************************
        /// !
        /// !  SUBROUTINE: INITIAL
        /// !
        /// !  PURPOSE:  SET INITAL CONDITION
        /// !
        /// !*****************************************************************************
        /// に相当する部分
        /// </para>
        /// </remarks>
        protected override bool Initialize(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
        {
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                double dDtQ = 0.0;
                csInDt.GetInfo("Q_Initial", ref dDtQ);
                dDtQ = dDtQ / m_KMdlInf.m_dWidth;

                double dDtH = Math.Pow(
                    (m_KMdlInf.m_dRough * m_KMdlInf.m_dRough * dDtQ * dDtQ / m_KMdlInf.m_dSlope)
                                , 0.3);
                double dDtV = dDtQ / dDtH;

                for (long lLp = 0; lLp <= m_KMdlInf.m_lCelNumber; lLp++)
                {
                    m_KMdlInf.m_dH[lLp] = dDtH;
                    m_KMdlInf.m_dH1[lLp] = dDtH;
                    m_KMdlInf.m_dV[lLp] = dDtV;
                    m_KMdlInf.m_dQ[lLp] = dDtQ;
                    m_KMdlInf.m_dQ1[lLp] = dDtQ;
                }
            }
            return true;
        }

        //=======================
        // 演算実行処理関連メソッド
        //=======================

        /// <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>
        /// 水理公式集例題２－２　dynamic.for 内の
        /// !*****************************************************************************
        /// !
        /// !  PROGRAM: DYNAMIC
        /// !
        /// !  PURPOSE:  FLOOD ROUTING WITH DYNAMIC WAVE MODEL
        /// !
        /// !*****************************************************************************
        /// の計算処理部分に相当する部分
        /// </para>
        /// </remarks>
        protected override long Calculate(long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
        {
            double dElmIn = 0.0; // 個別流入量
            double dQTopTotalIn = 0.0; // 上流総合流入量リセット
            long lQIdx = 0;  // 流量は０番目

            HySCellData csCell = null;  // 取得するセル
            for (long lP = 0; lP < m_lInputDataNum; lP++)
            {   // 入力データ数分
                csCell = csInputCellData[lP].GetInterpolatedCell(0); // セル配列の０番目のセルを取得
                dElmIn = csInputCellData[lP].Data(csCell, lQIdx);   // セル内の０番目の変数値を取得

                if (McHyHdFormulaSampleH13Define.IN_PATTERN_TOP.Equals(csInputCellData[lP].GetReceivePatternID()) == true)
                {   // 上流端入力ならば
                    dQTopTotalIn += dElmIn;
                }
            }

            double dQin = dQTopTotalIn / m_KMdlInf.m_dWidth;  // 上流端総合入力


            double dTimeLag = m_csDltTime.GetTime();

            //始点
            m_KMdlInf.m_dQ1[0] = dQin;
            m_KMdlInf.m_dH1[0] = m_KMdlInf.m_dH[0] + (1.5 * m_KMdlInf.m_dQ[0] - 2.0 * m_KMdlInf.m_dQ[1] + 0.5 * m_KMdlInf.m_dQ[2]) * dTimeLag / m_KMdlInf.m_dCelLength;

            // 河道内の断面ごとの水位、流速、流量の算定
            double dFQ = 0.0;
            double dFV = 0.0;
            double dFP = 0.0;
            double dFF = 0.0;

            for (long lLp = 1; lLp <= m_KMdlInf.m_lCelNumber; lLp++)
            {
                this.COEFF(lLp, ref dFQ, ref dFV, ref dFP, ref dFF);

                m_KMdlInf.m_dH1[lLp] = m_KMdlInf.m_dH[lLp] - dFQ * dTimeLag;
                m_KMdlInf.m_dQ1[lLp] = (m_KMdlInf.m_dQ1[lLp] + (dFP - dFV) * dTimeLag) / (1.0 + dFF * dTimeLag);
            }

            for (long lLp = 0; lLp <= m_KMdlInf.m_lCelNumber; lLp++)
            {
                m_KMdlInf.m_dH[lLp] = m_KMdlInf.m_dH1[lLp];
                m_KMdlInf.m_dQ[lLp] = m_KMdlInf.m_dQ1[lLp];
                m_KMdlInf.m_dV[lLp] = m_KMdlInf.m_dQ[lLp] / m_KMdlInf.m_dH[lLp];
            }

            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>
        /// 水理公式集例題２－２　dynamic.for 内の
        /// !*****************************************************************************
        /// !
        /// !  FUNCTION: OUTPUT
        /// !
        /// !  PURPOSE:  DATA OUTPUT TO FILE
        /// !
        /// !*****************************************************************************
        /// の計算処理部分に相当する部分
        /// </para>
        /// </remarks>
        protected override long DataFusion(long lOutputDataNum, ref McSendCellDataIF[] csOutputCellData)
        {
            HySCellData[] csSndCellData = null; // 送信セル
            for (long lP = 0; lP < m_lOutputDataNum; lP++)
            {   // 送信データ数繰り返し
                csSndCellData = csOutputCellData[lP].PrepareSendCellD1();

                if (McHyHdFormulaSampleH13Define.OUT_PATTERN_BOTTOM.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // 最終セルだけの出力ならば
                    csSndCellData[0].m_dData[0] = m_KMdlInf.m_dQ[m_KMdlInf.m_lCelNumber] * m_KMdlInf.m_dWidth;
                    csSndCellData[0].m_dData[1] = m_KMdlInf.m_dH[m_KMdlInf.m_lCelNumber];
                    csSndCellData[0].m_dData[2] = m_KMdlInf.m_dV[m_KMdlInf.m_lCelNumber];
                }
                else if (McHyHdFormulaSampleH13Define.OUT_PATTERN_ALL.Equals(csOutputCellData[lP].GetSendPatternID()) == true)
                {   // 全体出力ならば
                    for (long lLp = 0; lLp <= m_KMdlInf.m_lCelNumber; lLp++)
                    {
                        csSndCellData[lLp].m_dData[0] = m_KMdlInf.m_dQ[lLp] * m_KMdlInf.m_dWidth;
                        csSndCellData[lLp].m_dData[1] = m_KMdlInf.m_dH[lLp];
                        csSndCellData[lLp].m_dData[2] = m_KMdlInf.m_dV[lLp];
                    }
                }
            }
            return 0;
        }

        //====================
        // その他必要なメソッド
        //====================

        /// <summary><para>method outline:</para>
        /// <para>プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetProperty(csCellMdlPropertyInfo)</para>
        /// </example>
        /// <param name="csCellMdlPropertyInfo">セル型プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 水理公式集例題２－２　dynamic.for 内の
        /// !*****************************************************************************
        /// !
        /// !  FUNCTION: INPUT
        /// !
        /// !  PURPOSE:  SET PARAMETERS
        /// !
        /// !*****************************************************************************
        /// の計算処理部分に相当する部分
        /// </para>
        /// </remarks>
        public override bool SetProperty(McCellModelPropertyIF csCellMdlPropertyInfo)
        {
            bool bRtn = false;
            // 使用しやすいようにキャストしておく
            m_KMdlInf = (McDynamicWaveLaneCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                bRtn = true;

                // 演算ステップ時刻設定
                this.m_csDltTime = new HySTime(csPrptyInfo.GetStepTime());

                // 各種係数設定
                csPrptyInfo.GetInfo("m_lCelNumber", ref m_KMdlInf.m_lCelNumber);
                double dRough = 0.03;
                csPrptyInfo.GetInfo("m_dRough", ref dRough);
                m_KMdlInf.m_dRough = dRough;
                double dSloop = 2000.0;
                csPrptyInfo.GetInfo("m_dSlope", ref dSloop);
                m_KMdlInf.m_dSlope = dSloop;

                m_KMdlInf.m_dH = new double[m_KMdlInf.m_lCelNumber+1];
                m_KMdlInf.m_dH1 = new double[m_KMdlInf.m_lCelNumber+1];
                m_KMdlInf.m_dV = new double[m_KMdlInf.m_lCelNumber+1];
                m_KMdlInf.m_dQ = new double[m_KMdlInf.m_lCelNumber+1];
                m_KMdlInf.m_dQ1 = new double[m_KMdlInf.m_lCelNumber+1];
                for (long lLp = 0; lLp <= m_KMdlInf.m_lCelNumber; lLp++)
                {
                    m_KMdlInf.m_dH[lLp] = 1.0;
                    m_KMdlInf.m_dH1[lLp] = 1.0;
                    m_KMdlInf.m_dV[lLp] = 0.0;
                    m_KMdlInf.m_dQ[lLp] = 0.0;
                    m_KMdlInf.m_dQ1[lLp] = 0.0;
                }
                csPrptyInfo.GetInfo("m_dLength", ref m_KMdlInf.m_dLength);
                m_KMdlInf.m_dCelLength = m_KMdlInf.m_dLength / (double)(m_KMdlInf.m_lCelNumber);

                csPrptyInfo.GetInfo("m_dWidth", ref m_KMdlInf.m_dWidth);
            }
            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>各種係数を計算する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>COEFF( lCelItem, ref  dFQ, ref  dFV, ref  dFP, ref  dFF);</para>
        /// </example>
        /// <param name="lCelItem">セルアイテム番号（０相対）</param>
        /// <param name="dFQ">Fortranﾌﾟﾛｸﾞﾗﾑ例内：FQ</param>
        /// <param name="dFV">Fortranﾌﾟﾛｸﾞﾗﾑ例内：FV</param>
        /// <param name="dFP">Fortranﾌﾟﾛｸﾞﾗﾑ例内：FP</param>
        /// <param name="dFF">Fortranﾌﾟﾛｸﾞﾗﾑ例内：FF</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>
        /// 水理公式集例題２－２　dynamic.for 内の
        /// !*****************************************************************************
        /// !
        /// !  SUBROUTINE: COEFF
        /// !
        /// !  PURPOSE:  COEFFICIENT OF THE EQUATION
        /// !
        /// !*****************************************************************************
        /// の計算処理部分に相当する部分
        /// </para>
        /// </remarks>
        protected virtual void COEFF(long lCelItem, ref double dFQ, ref double dFV, ref double dFP, ref double dFF)
        {
            if (lCelItem < m_KMdlInf.m_lCelNumber)
            {
                dFQ = (m_KMdlInf.m_dQ[lCelItem + 1] - m_KMdlInf.m_dQ[lCelItem - 1]) / 2.0 / m_KMdlInf.m_dCelLength;
                dFP = m_KMdlInf.m_dGrvty * m_KMdlInf.m_dH[lCelItem] * (m_KMdlInf.m_dSlope - (m_KMdlInf.m_dH[lCelItem + 1] - m_KMdlInf.m_dH[lCelItem - 1]) / 2.0 / m_KMdlInf.m_dCelLength);
            }
            else
            {
                dFQ = (m_KMdlInf.m_dQ[lCelItem] - m_KMdlInf.m_dQ[lCelItem - 1]) / m_KMdlInf.m_dCelLength;
                dFP = m_KMdlInf.m_dGrvty * m_KMdlInf.m_dH[lCelItem] * (m_KMdlInf.m_dSlope - (m_KMdlInf.m_dH[lCelItem] - m_KMdlInf.m_dH[lCelItem - 1]) / m_KMdlInf.m_dCelLength);
            }
            dFV = (m_KMdlInf.m_dV[lCelItem] * m_KMdlInf.m_dQ[lCelItem] - m_KMdlInf.m_dV[lCelItem - 1] * m_KMdlInf.m_dQ[lCelItem - 1]) / m_KMdlInf.m_dCelLength;
            dFF = m_KMdlInf.m_dGrvty * m_KMdlInf.m_dRough * m_KMdlInf.m_dRough * m_KMdlInf.m_dQ[lCelItem] / Math.Pow(m_KMdlInf.m_dH[lCelItem], 7.0 / 3.0);
        }
    }
}
