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

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

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

using CommonMP.HYMCO.CoreOptionl.HymcoExpansionModel;
using CommonMP.HYMCO.Ocean.McOceanBaseModel;

namespace CommonMP.HYMCO.Ocean.McOceanSampleModels
{

    /// <summary><para>class outline:</para>
    /// <para> 栄養素（Nutrient) モデルクラス
    /// 海水中に栄養塩として存在するNとPの比をみると、やはり16：1であり、それは世界の海洋の表層から深海までに共通している。 この現象を発見した米国の研究者レッドフィールド（Alfred C. Redfield）の名をとって、このような原子比をレッドフィールド比という
    /// </para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2021/12/31][新規作成]</para>
    /// </remarks>
    public class MzOceanNutrient : MzOceanModelElement
    {
        /// <summary> 演算データ（キャスト用） </summary>
        MzOceanNutrientCalInfo m_OcLyrMdlInf = null; // 便利の為、キャスト用に定義しておく

        //========================================================
        /// <summary> 双方向結合：送受信：光合成肥料使用量： McOceanBaseDefine.PHOTOSYNTHESIS送信 </summary>
        protected McPatternRdvSndTranInfoPair m_csRcvPhytoCnnct = new McPatternRdvSndTranInfoPair();
        protected McPatternRdvSndTranInfoPair m_csSndPhytoCnnct = new McPatternRdvSndTranInfoPair();

        // 受信：人間による施肥料 ：     McOceanBaseDefine.HUMAN_FERTILIZER_KIND  
        protected McPatternRdvSndTranInfoPair m_csRcvHmnFertilizerCnnct = new McPatternRdvSndTranInfoPair();

        // 受信：バクテリア等からの肥料成分受信
        protected McPatternRdvSndTranInfoPair m_csRcvFertilizerCnnct = new McPatternRdvSndTranInfoPair();
        ////protected McPatternRdvSndTranInfoPair m_csSndFertilizerCnnct = new McPatternRdvSndTranInfoPair();

        // --- ワーク変数
        private double[][] m_CnctReqN;
        private double[][] m_CnctReqP;
        private double[][] m_CnctReqSi;
        private double[][] m_CnctReqFe;

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

        /// <summary><para>method outline:</para>
        /// <para>入力側の接続情報チェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = CheckReceiveDataConnection(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 CheckReceiveDataConnection(ref McStructErrorInfo csErrorInf, long lInputDataNum, McReceiveCellDataIF[] csInputCellData)
        {
            // 親クラスチェック処理
            bool bRtn = base.CheckReceiveDataConnection(ref csErrorInf, lInputDataNum, csInputCellData);

            // 双方向　送受信：光合成の為の養分補給
            (m_csRcvPhytoCnnct, m_csSndPhytoCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.PHOTOSYNTHESIS);

            // 受信側：人間による施肥料 ：  McOceanBaseDefine.HUMAN_FERTILIZER_KIND  
            m_csRcvHmnFertilizerCnnct = this.PrepareRcvPattern(MzOceanBaseDefine.HUMAN_FERTILIZER);

            // 受信側：バクテリア等からの肥料成分
            m_csRcvFertilizerCnnct = this.PrepareRcvPattern(MzOceanBaseDefine.BCT_FERTILIZER);

            // ワーク変数初期化
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                m_CnctReqN[ll] = new double[m_csSndPhytoCnnct.m_RcvInfNum];
                m_CnctReqP[ll] = new double[m_csSndPhytoCnnct.m_RcvInfNum];
                m_CnctReqSi[ll] = new double[m_csSndPhytoCnnct.m_RcvInfNum];
                m_CnctReqFe[ll] = new double[m_csSndPhytoCnnct.m_RcvInfNum];

                for(int j=0;j< m_csSndPhytoCnnct.m_RcvInfNum;j++)
                {
                    m_CnctReqN[ll][j] = 0.0;
                    m_CnctReqP[ll][j] = 0.0;
                    m_CnctReqSi[ll][j] = 0.0;
                    m_CnctReqFe[ll][j] = 0.0;
                }
            }

            //// ディバッグ用送信データ
            //m_csDebugSendCnnct = this.PrepareSndPattern(MzOceanBaseDefine.DEBUG_OUT);
            return bRtn;
        }
  
        ///// <summary><para>method outline:</para>
        ///// <para>出力側の接続情報チェック</para>
        ///// </summary>
        ///// <example><para>usage:</para>
        ///// <para>bool bRtn = CheckSendDataConnection(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 CheckSendDataConnection(ref McStructErrorInfo csErrorInf, long lOutputDataNum, McSendCellDataIF[] csOutputCellData)
        //{
        //    // チェック処理を入れる
        //    bool bRtn = base.CheckSendDataConnection(ref csErrorInf, lOutputDataNum, csOutputCellData);
        //    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>無し</para>
        /// </remarks>
        protected override bool Initialize(ref McPropertyInfoRoot csInitialData, long lInputDataNum, ref McReceiveCellDataIF[] csInputCellData)
        {
            m_OcLyrMdlInf.Clear();
            bool bRtn = base.Initialize(ref csInitialData, lInputDataNum, ref csInputCellData);
        
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                //for (int i = 0; i < m_csRcvFertilizerCnnct.m_RcvInfNum; i++)
                //{
                //    m_csRcvFertilizerCnnct.m_dRcvRatioData[i] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                //    m_csRcvFertilizerCnnct.m_dSendRatioData[i] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                //    for(int j=0;j< m_csOcnBacedlInf.m_lLayerNumber;j++)
                //    {
                //        m_csRcvFertilizerCnnct.m_dRcvRatioData[i][j] = 0.0;
                //        m_csRcvFertilizerCnnct.m_dSendRatioData[i][j] = 1.0;
                //    }
                //}
                //for (int i = 0; i < m_csSndPhytoCnnct.m_RcvInfNum; i++)
                //{
                //    m_csSndPhytoCnnct.m_dRcvRatioData[i] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                //    m_csSndPhytoCnnct.m_dSendRatioData[i] = new double[m_csOcnBacedlInf.m_lLayerNumber];
                //    for (int j = 0; j < m_csOcnBacedlInf.m_lLayerNumber; j++)
                //    {
                //        m_csSndPhytoCnnct.m_dRcvRatioData[i][j] = 0.0;
                //        m_csSndPhytoCnnct.m_dSendRatioData[i][j] = 1.0;
                //    }
                //}

                csInDt.GetInfo("N_TotalMass_L0", ref m_OcLyrMdlInf.m_N[0]);
                csInDt.GetInfo("N_TotalMass_L1", ref m_OcLyrMdlInf.m_N[1]);
                csInDt.GetInfo("P_TotalMass_L0", ref m_OcLyrMdlInf.m_P[0]);
                csInDt.GetInfo("P_TotalMass_L1", ref m_OcLyrMdlInf.m_P[1]);
                csInDt.GetInfo("Si_TotalMass_L0", ref m_OcLyrMdlInf.m_Si[0]);
                csInDt.GetInfo("Si_TotalMass_L1", ref m_OcLyrMdlInf.m_Si[1]);
                csInDt.GetInfo("Fe_TotalMass_L0", ref m_OcLyrMdlInf.m_Fe[0]);
                csInDt.GetInfo("Fe_TotalMass_L1", ref m_OcLyrMdlInf.m_Fe[1]);

                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    m_OcLyrMdlInf.m_AvailableN[ll] =  m_OcLyrMdlInf.m_N[ll];
                    m_OcLyrMdlInf.m_AvailableP[ll] =  m_OcLyrMdlInf.m_P[ll];
                    m_OcLyrMdlInf.m_AvailableSi[ll] =  m_OcLyrMdlInf.m_Si[ll];
                    m_OcLyrMdlInf.m_AvailableFe[ll] =  m_OcLyrMdlInf.m_Fe[ll];
                }
            }
            return bRtn;
        }

        //=======================
        // 演算実行処理関連メソッド
        //=======================
        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            ClearAllCalValue();

            // 海上からの人工施肥
            ReceiveHmnFertilize();

            // デトリタスの細菌による分解等から発生した養分吸収
            ReceiveFertilizer();

            // 植物プランクトンからの養分要求量
            ReceivePhotosynthesis();

            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            // 植物プランクトンへの養分送信
            SendPhotosynthesis();

            // Debug
            SendDEBUG();
            return;
        }

        /// <summary>
        /// 肥料関係：ミネラル受信
        /// </summary>
        protected virtual void ReceiveFertilizer()
        {
            for (int i = 0; i < m_csRcvFertilizerCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csRcvFertilizerCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    for (int ll = 0; ll < this.m_csOcnBacedlInf.m_lLayerNumber; ll++)
                    {
                        m_OcLyrMdlInf.m_N[ll] += csCell[ll].m_dData[0];
                        m_OcLyrMdlInf.m_P[ll] += csCell[ll].m_dData[1];
                        m_OcLyrMdlInf.m_Si[ll] += csCell[ll].m_dData[2];
                        m_OcLyrMdlInf.m_Fe[ll] += csCell[ll].m_dData[3];
                    }
                }
            }
        }

        /// <summary>
        /// 人間による施肥
        /// </summary>
        protected virtual void ReceiveHmnFertilize()
        {
            for (int i = 0; i < m_csRcvHmnFertilizerCnnct.m_RcvInfNum; i++)
            {   // 受信要素モデル数繰り返す

                // 人工施肥分を受信
                HySCellData[] csCell = m_csRcvHmnFertilizerCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    // ―――　最上部に配布する　―――
                    // ●N
                    m_OcLyrMdlInf.m_N[0] += csCell[0].m_dData[0];
                    // ●P
                    m_OcLyrMdlInf.m_P[0] += csCell[0].m_dData[1];
                    // ●Si
                    double DetritusMass = csCell[0].m_dData[2];
                    double SizeD = csCell[0].m_dData[3];
                    if (SizeD > 0.0)
                    {
                        // 受信サイズを中心に分布を持った大きさのSiが投入される
                        m_OcLyrMdlInf.AddIOPMass(MzOceanNutrientCalInfo.Si, 0, DetritusMass, SizeD, m_OcLyrMdlInf.m_Density_Si);
                    }
                    // ●Fe
                    DetritusMass = csCell[0].m_dData[4];
                    SizeD = csCell[0].m_dData[5];
                    if (SizeD > 0.0)
                    {
                        // 受信サイズを中心に分布を持った大きさのFeが投入される
                        m_OcLyrMdlInf.AddIOPMass(MzOceanNutrientCalInfo.Fe, 0, DetritusMass, SizeD, m_OcLyrMdlInf.m_Density_Fe);
                    }
                }
            }  // end of for(i)
        }

        /// <summary>
        /// 光合成での要求肥料受信
        /// </summary>
        protected virtual void ReceivePhotosynthesis()
        {
            for (int ll = 0; ll < this.m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                m_OcLyrMdlInf.m_ReqN[ll] = 1E-42;
                m_OcLyrMdlInf.m_ReqP[ll] = 1E-42;
                m_OcLyrMdlInf.m_ReqSi[ll] = 1E-42;
                m_OcLyrMdlInf.m_ReqFe[ll] = 1E-42;
            }

            for (int i = 0; i < m_csSndPhytoCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csSndPhytoCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    for (int ll = 0; ll < this.m_csOcnBacedlInf.m_lLayerNumber; ll++)
                    {
                        m_OcLyrMdlInf.m_ReqN[ll] += csCell[ll].m_dData[0];
                        m_OcLyrMdlInf.m_ReqP[ll] += csCell[ll].m_dData[1];
                        m_OcLyrMdlInf.m_ReqSi[ll] += csCell[ll].m_dData[2];
                        m_OcLyrMdlInf.m_ReqFe[ll] += csCell[ll].m_dData[3];
                        // 振り分けの為、要求量を覚えておく
                        m_CnctReqN[ll][i] = csCell[ll].m_dData[0] ;
                        m_CnctReqP[ll][i] = csCell[ll].m_dData[1] ;
                        m_CnctReqSi[ll][i] = csCell[ll].m_dData[2] ;
                        m_CnctReqFe[ll][i] = csCell[ll].m_dData[3] ;
                    }
                }
            }
        }

        /// <summary>
        /// 区合成での肥料送信
        /// </summary>
        protected virtual void SendPhotosynthesis()
        {
            // 要求された量の比率にしたがって振り分けて送信する
            // 要求量を送信
            for (int i = 0; i < m_csSndPhytoCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csSndPhytoCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    csSndDt[ll].m_dData[0] = m_OcLyrMdlInf.m_AvailableN[ll] * m_CnctReqN[ll][i] / m_OcLyrMdlInf.m_ReqN[ll];
                    csSndDt[ll].m_dData[1] = m_OcLyrMdlInf.m_AvailableP[ll] * m_CnctReqP[ll][i] / m_OcLyrMdlInf.m_ReqP[ll];
                    csSndDt[ll].m_dData[2] = m_OcLyrMdlInf.m_AvailableSi[ll] * m_CnctReqSi[ll][i] / m_OcLyrMdlInf.m_ReqSi[ll];
                    csSndDt[ll].m_dData[3] = m_OcLyrMdlInf.m_AvailableFe[ll] * m_CnctReqFe[ll][i] / m_OcLyrMdlInf.m_ReqFe[ll];
                }
            }
        }

        protected virtual void SendDEBUG()
        {
            for (int i = 0; i < m_csDebugSendCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csDebugSendCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                for (int ll = 0; ll < m_OcLyrMdlInf.m_lLayerNumber; ll++)
                {
                    csCell[ll].m_dData[0] = m_OcLyrMdlInf.m_N[ll]; //= m_OcLyrMdlInf.m_AvailableN[ll];
                    csCell[ll].m_dData[1] = m_OcLyrMdlInf.m_P[ll]; //= m_OcLyrMdlInf.m_AvailableP[ll];
                    csCell[ll].m_dData[2] = m_OcLyrMdlInf.m_Si[ll]; //= m_OcLyrMdlInf.m_AvailableSi[ll];
                    csCell[ll].m_dData[3] = m_OcLyrMdlInf.m_Fe[ll]; //= m_OcLyrMdlInf.m_AvailableFe[ll];
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = Calculate(ref csInputDataList)</para>
        /// </example>
        /// <param name="lOnlyReceveDataNum">入力だけの情報数</param>
        /// <param name="csOnlyReceiveCellData">入力だけの情報配列</param>
        /// <param name="lOnlySendDataNum">出力だけの情報数</param>
        /// <param name="csOnlySelDataCellData">出力だけの情報配列</param>
        /// <param name="lRcvSndDataNum">相互接続報数</param>
        /// <param name="csReceiveCellData">相互接続入力側情報配列</param>
        /// <param name="csSelDataCellData">相互接続出力側情報配列</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>派生クラス側で必ずオーバライドする必要がある</para>
        /// </remarks>
        protected override long Calculate(
            long lOnlyReceveDataNum, ref McReceiveOnlyTranInfo[] csOnlyReceiveCellData,
            long lOnlySendDataNum, ref McSendOnlyTranInfo[] csOnlySelDataCellData,
            long lRcvSndDataNum, ref McRdvSndTranInfoPair[] csRcvSndCelDataCellData
            )
        {
            double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);

            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {   // 各層について計算
                //------窒素分-------
                // 可能な量を計算
                if (m_OcLyrMdlInf.m_N[ll] > m_OcLyrMdlInf.m_ReqN[ll])
                {
                    m_OcLyrMdlInf.m_AvailableN[ll] = m_OcLyrMdlInf.m_ReqN[ll];
                }
                else
                {
                    m_OcLyrMdlInf.m_AvailableN[ll] = m_OcLyrMdlInf.m_N[ll];
                }
                if (m_OcLyrMdlInf.m_AvailableN[ll] < 1E-42) { m_OcLyrMdlInf.m_AvailableN[ll] = 0.0; }
                // 送る量だけ減らす
                m_OcLyrMdlInf.m_N[ll] -= m_OcLyrMdlInf.m_AvailableN[ll];
                //------リン分--------
                // 可能な量を計算
                if (m_OcLyrMdlInf.m_P[ll] > m_OcLyrMdlInf.m_ReqP[ll])
                {
                    m_OcLyrMdlInf.m_AvailableP[ll] = m_OcLyrMdlInf.m_ReqP[ll];
                }
                else
                {
                    m_OcLyrMdlInf.m_AvailableP[ll] = m_OcLyrMdlInf.m_P[ll];
                }
                if (m_OcLyrMdlInf.m_AvailableP[ll] < 1E-42) { m_OcLyrMdlInf.m_AvailableP[ll] = 0.0; }
                // 送る量だけ減らす
                m_OcLyrMdlInf.m_P[ll] -= m_OcLyrMdlInf.m_AvailableP[ll];
                //------珪素分-------
                // 可能な量を計算
                if (m_OcLyrMdlInf.m_Si[ll] > m_OcLyrMdlInf.m_ReqSi[ll])
                {
                    m_OcLyrMdlInf.m_AvailableSi[ll] = m_OcLyrMdlInf.m_ReqSi[ll];
                }
                else
                {
                    m_OcLyrMdlInf.m_AvailableSi[ll] = m_OcLyrMdlInf.m_Si[ll];
                }
                if (m_OcLyrMdlInf.m_AvailableSi[ll] < 1E-42) { m_OcLyrMdlInf.m_AvailableSi[ll] = 0.0; }
                // 送る量だけ減らす
                m_OcLyrMdlInf.m_Si[ll] -= m_OcLyrMdlInf.m_AvailableSi[ll];
                //-----鉄分-------
                // 可能な量を計算
                if (m_OcLyrMdlInf.m_Fe[ll] > m_OcLyrMdlInf.m_ReqFe[ll])
                {
                    m_OcLyrMdlInf.m_AvailableFe[ll] = m_OcLyrMdlInf.m_ReqFe[ll];
                }
                else
                {
                    m_OcLyrMdlInf.m_AvailableFe[ll] = m_OcLyrMdlInf.m_Fe[ll];
                }
                if (m_OcLyrMdlInf.m_AvailableFe[ll] < 1E-42) { m_OcLyrMdlInf.m_AvailableFe[ll] = 0.0; }
                // 送る量だけ減らす
                m_OcLyrMdlInf.m_Fe[ll] -= m_OcLyrMdlInf.m_AvailableFe[ll];
            }

            // 無機物沈降計算　＆　無機物溶けだし量計算
            this.SinkingParticle();

            return 0;
        }


        /// <summary>
        /// 無機物の沈降　＆　無機物溶けだし量計算
        /// </summary>
        /// <returns></returns>
        protected int SinkingParticle()
        {
            double dSec = GetDeltaTime().GetTime();
            double dDpth = 0.0;  // 沈降の深さ
            double dMass = 0.0;  // 量
            double dHH = m_OcLyrMdlInf.m_dDepth - m_OcLyrMdlInf.m_dLayerLength[m_OcLyrMdlInf.m_lLayerNumber - 1];
            for (long ll = m_OcLyrMdlInf.m_lLayerNumber - 2; ll >= 0; ll--)
            {
                // Fe 計算
                for (int ifS = 0; ifS < m_OcLyrMdlInf.m_iIOPSizeNum; ifS++)
                {
                    if (m_OcLyrMdlInf.m_Mass_Fe[ll][ifS] <= 0) { continue; }
                    // 沈降する深さ
                    dDpth = dSec * DroppingV((dHH + m_OcLyrMdlInf.m_dLayerLength[ll] / 2.0), m_OcLyrMdlInf.m_IOPSize[ifS], m_OcLyrMdlInf.m_Density_Fe);
                    if (dDpth >= 0.0)
                    {
                        // 沈降した量
                        dMass = m_OcLyrMdlInf.m_Mass_Fe[ll][ifS] * (dDpth / m_OcLyrMdlInf.m_dLayerLength[ll]);
                        // 補正（現在存在する量以上には減らせることは出来ない）
                        if (dMass > m_OcLyrMdlInf.m_Mass_Fe[ll][ifS]) { dMass = m_OcLyrMdlInf.m_Mass_Fe[ll][ifS]; }

                        // 現在の層からは少なくなる
                        m_OcLyrMdlInf.m_Mass_Fe[ll][ifS] -= dMass;
                        // 下の層には追加される
                        m_OcLyrMdlInf.m_Mass_Fe[ll + 1][ifS] += dMass;
                    }
                    //else
                    //{
                    //    // 浮上した量
                    //    dMass = -1.0 * m_OcLyrMdlInf.m_DetritusMass_Fe[k][i] * (dDpth / m_OcLyrMdlInf.m_dCelLength[k]);
                    //    // 補正（現在存在する量以上には減らせることは出来ない）
                    //    if (dMass > m_OcLyrMdlInf.m_DetritusMass_Fe[k][i]) { dMass = m_OcLyrMdlInf.m_DetritusMass_Fe[k][i]; }
                    //    if (k > 0)
                    //    {
                    //        // 現在の層からは少なくなる
                    //        m_OcLyrMdlInf.m_DetritusMass_Fe[k][i] -= dMass;
                    //        // 上の層には追加される
                    //        m_OcLyrMdlInf.m_DetritusMass_Fe[k - 1][i] += dMass;
                    //    }
                    //}
                }

                // Si 計算
                for (int isS = 0; isS < m_OcLyrMdlInf.m_iIOPSizeNum; isS++)
                {
                    if (m_OcLyrMdlInf.m_Mass_Si[ll][isS] <= 0) { continue; }
                    // 沈降する深さ
                    dDpth = dSec * DroppingV((dHH + m_OcLyrMdlInf.m_dLayerLength[ll] / 2.0), m_OcLyrMdlInf.m_IOPSize[isS], m_OcLyrMdlInf.m_Density_Si);
                    if (dDpth >= 0.0)
                    {
                        // 沈降した量
                        dMass = m_OcLyrMdlInf.m_Mass_Si[ll][isS] * (dDpth / m_OcLyrMdlInf.m_dLayerLength[ll]);
                        // 補正（現在存在する量以上には減らせることは出来ない）
                        if (dMass > m_OcLyrMdlInf.m_Mass_Si[ll][isS]) { dMass = m_OcLyrMdlInf.m_Mass_Si[ll][isS]; }

                        // 現在の層からは少なくなる
                        m_OcLyrMdlInf.m_Mass_Si[ll][isS] -= dMass;
                        // 下の層には追加される
                        m_OcLyrMdlInf.m_Mass_Si[ll + 1][isS] += dMass;
                    }
                    //else
                    //{
                    //    // 浮上した量
                    //    dMass = -1.0 * m_OcLyrMdlInf.m_DetritusMass_Si[k][i] * (dDpth / m_OcLyrMdlInf.m_dCelLength[k]);
                    //    // 補正（現在存在する量以上には減らせることは出来ない）
                    //    if (dMass > m_OcLyrMdlInf.m_DetritusMass_Si[k][i]) { dMass = m_OcLyrMdlInf.m_DetritusMass_Si[k][i]; }
                    //    if (k > 0)
                    //    {
                    //        // 現在の層からは少なくなる
                    //        m_OcLyrMdlInf.m_DetritusMass_Si[k][i] -= dMass;
                    //        // 上の層には追加される
                    //        m_OcLyrMdlInf.m_DetritusMass_Si[k - 1][i] += dMass;
                    //    }
                    //}
                }

                dHH -= m_OcLyrMdlInf.m_dLayerLength[ll];

            }  // end of for(層No)

            //------------------------
            // 水深
            double dH = 0.0;
            double dMM = 0.0;
            // ↓↓↓↓↓
            // 溶融量
            // ★★★　この部分は適当に作成されている　もっと正確な論理が必要
            for (long ll = 0; ll < m_OcLyrMdlInf.m_lLayerNumber; ll++)
            {
                // 水温
                double dTmpT = MzOceanModelElement.Temperature(dH + m_csOcnBacedlInf.m_dLayerLength[ll] / 2.0);
                // 溶融の温度依存性
                double dTmpTK = (dTmpT + 0.1) / 24.0;
                // 溶融計算  細かいものほど溶融しやすい
                for (int ipS = 0; ipS < m_OcLyrMdlInf.m_iIOPSizeNum; ipS++)
                {
                    dMM = dTmpTK * m_OcLyrMdlInf.m_SpdDetritusDISSOLVE[ll] * m_OcLyrMdlInf.m_Dissolve_Fe * m_OcLyrMdlInf.m_Mass_Fe[ll][ipS];
                    m_OcLyrMdlInf.m_Fe[ll] += dMM;
                    m_OcLyrMdlInf.m_Mass_Fe[ll][ipS] -= dMM;
                    dMM = dTmpTK * m_OcLyrMdlInf.m_SpdDetritusDISSOLVE[ll] * m_OcLyrMdlInf.m_Dissolve_Si * m_OcLyrMdlInf.m_Mass_Si[ll][ipS];
                    m_OcLyrMdlInf.m_Si[ll] += dMM;
                    m_OcLyrMdlInf.m_Mass_Si[ll][ipS] -= dMM;
                }

                dH += m_csOcnBacedlInf.m_dLayerLength[ll];
            } // end of for(層No)
            // ↑↑↑↑↑
            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>無し</para>
        /// </remarks>
        public override bool SetProperty(McCellModelPropertyIF csCellMdlPropertyInfo)
        {
            bool bRtn = base.SetProperty(csCellMdlPropertyInfo);
            // 使用しやすいようにキャストしておく
            m_OcLyrMdlInf = (MzOceanNutrientCalInfo)m_csCalInfo;

            m_CnctReqN = new double[m_OcLyrMdlInf.m_lLayerNumber][];
            m_CnctReqP = new double[m_OcLyrMdlInf.m_lLayerNumber][];
            m_CnctReqSi = new double[m_OcLyrMdlInf.m_lLayerNumber][];
            m_CnctReqFe = new double[m_OcLyrMdlInf.m_lLayerNumber][];

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                csPrptyInfo.GetInfo("m_Density_Si", ref m_OcLyrMdlInf.m_Density_Si);
                csPrptyInfo.GetInfo("m_Dissolve_Si", ref m_OcLyrMdlInf.m_Dissolve_Si);
                csPrptyInfo.GetInfo("m_Density_Fe", ref m_OcLyrMdlInf.m_Density_Fe);
                csPrptyInfo.GetInfo("m_Dissolve_Fe", ref m_OcLyrMdlInf.m_Dissolve_Fe);
            }

            return true;
        }
   
  
    }
}
