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> デトリタス（Detritus)  モデルクラス</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[2021/12/31][新規作成]</para>
    /// </remarks>
    public class MzOceanDetritus : MzOceanModelElement
    {
        /// <summary> 演算データ（キャスト用） </summary>
        MzOceanDetritusCalInfo m_DtrtsInf = null; // 便利の為、キャスト用に定義しておく

        //========================================================
        /// <summary> 排泄：excretion、または 死、関係：  McOceanBaseDefine.EXCRETION_DEATH </summary>
        protected McPatternRdvSndTranInfoPair m_csRcvExcretionDeathCnnct = new McPatternRdvSndTranInfoPair();

        /// <summary> 分解・消化 </summary>
        protected McPatternRdvSndTranInfoPair m_csRcvDecomposeCnnct = new McPatternRdvSndTranInfoPair();    // <-- ダミー
        protected McPatternRdvSndTranInfoPair m_csSndDecomposeCnnct = new McPatternRdvSndTranInfoPair();    // <-- 此方を利用
        ////// ディバッグ用送信データ
        ////protected McPatternRdvSndTranInfoPair m_csDebugSendCnnct = new McPatternRdvSndTranInfoPair();
        //---- ワーク -----
        private double[] m_dWorkSumLayer = null;

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


        /// <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_csRcvExcretionDeathCnnct = this.PrepareRcvPattern(MzOceanBaseDefine.EXCRETION_DEATH);
            
            // 分解・腐敗等
            ( m_csRcvDecomposeCnnct, m_csSndDecomposeCnnct) = this.PrepareRcvSndPattern(MzOceanBaseDefine.DECOMPOSE);

            // ディバッグ用送信データ
            //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)
        {
            bool bRtn = base.Initialize(ref csInitialData, lInputDataNum, ref csInputCellData);
            McInitialInfo csInDt = csInitialData as McInitialInfo;
            if (csInDt != null)
            {   // 初期化情報有り
                //MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();

                this.InitMass(ref csInDt);
                // デトリタスサイズ
                double dD = 0.0;
                csInDt.GetInfo("m_dDtrtsSize", ref dD);
                double dDcty = 0.0;
                csInDt.GetInfo("m_dDcty", ref dDcty);

                for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
                {
                    for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                    {
                        m_DtrtsInf.m_DetritusMass_1[ll][s] = 0.0; ;
                    }
                }
                for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
                {
                    m_DtrtsInf.AddDetritus(ll, m_DtrtsInf.m_TotalSelfMass[ll], dD, dDcty);
                }

                //// サイズ別の分解速度係数を計算
                //double dSpd = 0.0;
                //for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                //{
                //    m_DtrtsInf.m_SpdDetritusDECOMPOSE[s] = Math.Sqrt(0.1E-3 / m_DtrtsInf.m_DetritusSize[s]);
                //    dSpd += m_DtrtsInf.m_SpdDetritusDECOMPOSE[s];
                //}
                //for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                //{
                //    m_DtrtsInf.m_SpdDetritusDECOMPOSE[s] = m_DtrtsInf.m_SpdDetritusDECOMPOSE[s]/dSpd;
                //}


                //---------
                // ●捕獲(被捕食者として＝＝デトリタスをプランクトンを喰う)
                for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
                {
                    m_csOcnBacedlInf.m_TotalReqedPredationMass[ll] = m_csOcnBacedlInf.m_TotalSelfMass[ll] * 0.1;
                }
                this.CalCapture();

                m_DtrtsInf.d_NowTotalMass = 0.0;
                for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
                {
                    m_DtrtsInf.m_TotalSelfMass[ll] = m_DtrtsInf.m_SumDetritusMass[ll];
                    m_DtrtsInf.d_NowTotalMass += m_DtrtsInf.m_TotalSelfMass[ll];
                }
                m_DtrtsInf.d_PreTotalMass = m_DtrtsInf.d_NowTotalMass;
            }
            return true;
        }


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

        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            ClearAllCalValue();
            m_DtrtsInf.d_PreTotalMass = m_DtrtsInf.d_NowTotalMass;

            // デトリタス受信
            ReceiveEXCRETION_DEATH();
            // 細菌からの要求量取得
            ReceiveReqDECOMPOSE();
            // 捕食：要求量の取得
            ReceiveReqPREDATION();

            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            //　デトリタスが　細菌へ提供捕食量の送信
            SendDECOMPOSE(m_DtrtsInf.m_TotalDecomposeMass, 0.1, 0.005);
            // 被捕食
            SendPREDATION(m_csOcnBacedlInf.m_dCapturedMass, 0.1, 0.005);

            SendDEBUG();

            //----- Debug Check ------
            double dChk = (m_DtrtsInf.d_NowTotalMass - m_DtrtsInf.d_PreTotalMass) - (m_DtrtsInf.d_TotalIN - m_DtrtsInf.d_TotalOUT);
            McLog.DebugOut("MzOceanDetritus", "SendData", "デトリタス総量チェック:" + dChk.ToString() + " = "
                + (m_DtrtsInf.d_NowTotalMass - m_DtrtsInf.d_PreTotalMass).ToString() + " - " + (m_DtrtsInf.d_TotalIN - m_DtrtsInf.d_TotalOUT).ToString());
            //------------------------
            return;
        }

        /// <summary>
        /// デトリタスが　細菌からの要求捕食量を計算
        /// </summary>
        protected virtual void ReceiveReqDECOMPOSE()
        {
            //------------------------
            // 要求される側（非捕食者）
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                m_dWorkSumLayer[ll] = 1E-48;
                m_DtrtsInf.m_TotalReqedDecomposeMass[ll] = 0.0;
            }
            for (int i = 0; i < m_csSndDecomposeCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csSndDecomposeCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                    {
                        m_DtrtsInf.m_TotalReqedDecomposeMass[ll] += csCell[ll].m_dData[0];
                        m_csSndDecomposeCnnct.m_dRcvRatioData[i][ll] = csCell[ll].m_dData[0];   // 分配の為、要求量を覚えておく
                        m_dWorkSumLayer[ll] += csCell[ll].m_dData[0];
                    }
                }
            }
            // 送信時の分配
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                for (int i = 0; i < m_csSndDecomposeCnnct.m_RcvInfNum; i++)
                {
                    // 分配比計算
                    m_csSndDecomposeCnnct.m_dSendRatioData[i][ll] = m_csSndDecomposeCnnct.m_dRcvRatioData[i][ll] / m_dWorkSumLayer[ll];
                }
            }
        }
    
        /// <summary>
        /// デトリタスが　細菌へ提供捕食量の送信
        /// </summary>
        /// <param name="dSendFoodDt">各レイヤー毎のの捕獲された有機物数</param>
        /// <param name="dCRatio">有機物無機物比率</param>
        /// <param name="dMRatio">無機物無機物比率</param>
        protected virtual void SendDECOMPOSE(double[] dSendFoodDt, double dCRatio, double dMRatio)
        {
            HySCellData[] csSndDt = null;

            // 非捕食者：捕食者へ要求量を 与える
            for (int i = 0; i < m_csSndDecomposeCnnct.m_RcvInfNum; i++)
            {
                csSndDt = m_csSndDecomposeCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    csSndDt[ll].m_dData[0] = dSendFoodDt[ll] * m_csSndDecomposeCnnct.m_dSendRatioData[i][ll];
                    csSndDt[ll].m_dData[1] = m_csOcnBacedlInf.m_TotalSelfMass[ll];
                    csSndDt[ll].m_dData[2] = m_DtrtsInf.m_SinkDetritusMass[ll];
                    csSndDt[ll].m_dData[3] = m_DtrtsInf.m_Density_1[ll];

                    csSndDt[ll].m_dData[4] = dCRatio * csSndDt[ll].m_dData[0];
                    double dKK = dMRatio * csSndDt[ll].m_dData[0]/( m_csOcnBacedlInf.m_TotalSelfMass[ll] + 1E-42);
                    
                    csSndDt[ll].m_dData[5] = m_csOcnBacedlInf.m_N[ll] * dKK; 
                    csSndDt[ll].m_dData[6] = m_csOcnBacedlInf.m_P[ll] * dKK; 
                    csSndDt[ll].m_dData[7] = m_csOcnBacedlInf.m_Si[ll] * dKK; 
                    csSndDt[ll].m_dData[8] = m_csOcnBacedlInf.m_Fe[ll] * dKK; 
                }
            }
            // 送信した分量だけ減らす
            if (m_csSndDecomposeCnnct.m_RcvInfNum > 0)
            {
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    // m_csOcnBacedlInf.m_TotalSelfMass[ll] -= dSendDt[ll]; <-- 既に別の場所で行っている
                    m_DtrtsInf.m_TotalDecomposeMass[ll] = 0.0;
                }
            }
        }

        /// <summary>
        /// 排泄、死の送信
        /// </summary>
        /// <param name="dDensityExt">糞密度</param>
        /// <param name="dDensityDth">死体密度</param>
        protected virtual void ReceiveEXCRETION_DEATH()
        {
            m_DtrtsInf.d_TotalIN = 0.0;

            //// 海水層モデルのデータ内に入れる
            ////MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();
            
            for (int i = 0; i < m_csRcvExcretionDeathCnnct.m_RcvInfNum; i++)
            {   // 要素分繰り返す（植物プランクトン、動物プランクトン、ネクトン等からの入力）

                HySCellData[] csCell = m_csRcvExcretionDeathCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
                    {  // 層毎に計算
                        // 糞の受信
                        double dEXMass = csCell[ll].m_dData[0];  // 全体量
                        double dEXSize = csCell[ll].m_dData[2];  // 中心サイズ
                        double dEXDty = csCell[ll].m_dData[3];   // 密度
                        m_DtrtsInf.d_TotalIN += dEXMass;

                        // モデルのデータ内に入れる:平均サイズ：dEXSizeを中心としてそのサイズ近傍に分散保持する
                        m_DtrtsInf.AddDetritus(ll, dEXMass, dEXSize, dEXDty);

                        // 死骸の受信
                        double dDtMass = csCell[ll].m_dData[4];  // 全体量
                        double dDtSize = csCell[ll].m_dData[6];  // 中心サイズ
                        double dEDtDty = csCell[ll].m_dData[7];  // 密度
                        m_DtrtsInf.d_TotalIN += dDtMass;

                        // モデルのデータ内に入れる:平均サイズ：dDtSizeを中心としてそのサイズ近傍に分散保持する
                        m_DtrtsInf.AddDetritus(ll, dDtMass, dDtSize, dEDtDty);

                    }
                }
            }  // end of for(i)
            return ;
        }

        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_DtrtsInf.m_lLayerNumber; ll++)
                {
                    csCell[ll].m_dData[0] = m_DtrtsInf.m_TotalSelfMass[ll];
                    csCell[ll].m_dData[1] = m_DtrtsInf.m_CO2[ll];
                    csCell[ll].m_dData[2] = m_DtrtsInf.m_O2[ll];
                    csCell[ll].m_dData[3] = m_DtrtsInf.m_C[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);

            //------------------------------------------------
            // デトリタスの凝集作業計算　
            double dAWkMass = 0.0;
            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                for (int i = 0; i < m_DtrtsInf.m_iDetritusSizeNum-1; i++)
                {
                    int js = m_DtrtsInf.m_iDetritusSizeNum - 1 - i;
                    if (m_DtrtsInf.m_DetritusSize[js] > 1.0) { continue; }
                    else
                    {
                        if(m_DtrtsInf.m_DetritusMass_1[ll][js] <= 0.0) { continue;  }
                        if (m_DtrtsInf.m_DetritusSize[js] > 0.1)
                        {
                            dAWkMass = dT * m_DtrtsInf.m_DetritusMass_1[ll][js] * m_DtrtsInf.m_AggregationRatio1000;
                        }
                        else if (m_DtrtsInf.m_DetritusSize[js] > 0.01)
                        {
                            dAWkMass = dT * m_DtrtsInf.m_DetritusMass_1[ll][js] * m_DtrtsInf.m_AggregationRatio100;
                        }
                        else
                        {
                            dAWkMass = dT * m_DtrtsInf.m_DetritusMass_1[ll][js] * m_DtrtsInf.m_AggregationRatio10;
                        }
                        // 現在のサイズの量を減らし、一つ上のサイズの量を増やす
                        m_DtrtsInf.m_DetritusMass_1[ll][js] -= dAWkMass;
                        m_DtrtsInf.m_DetritusMass_1[ll][js + 1] += dAWkMass;
                    }
                }
            }
            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                m_DtrtsInf.m_SumDetritusMass[ll] = 0;
                for (int i = 0; i < m_DtrtsInf.m_iDetritusSizeNum; i++)
                {
                    m_DtrtsInf.m_SumDetritusMass[ll] += m_DtrtsInf.m_DetritusMass_1[ll][i];
                }
            }

            //----------------------------------------------------
            // 沈降
            this.SinkingParticle();

            //-------------------------------------
            // ●捕獲(被捕食者として＝＝デトリタスをプランクトンが喰う)
            //                          デトリタスの腐敗等の計算は、MzOceanBacteriasで行う。
            this.CalDecompose();  // <-- 細菌による分解
            this.CalCapture();  // <-- 細菌以外による捕食

            // 最終的なデトリタスの総和を保持しておく
            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                m_DtrtsInf.m_TotalSelfMass[ll] = m_DtrtsInf.m_SumDetritusMass[ll]; //.m_DetritusMass_1[][ll];
            }

            // 現在のデトリタス量を取得
            MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();

            m_DtrtsInf.d_NowTotalMass = 0.0;
            // 海水層モデルのデータ内に入れる（集計用）
            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                csColumInfo.m_TotalSelfMass[ll] += m_DtrtsInf.m_SumDetritusMass[ll];
                m_DtrtsInf.d_NowTotalMass += m_DtrtsInf.m_SumDetritusMass[ll];
            }

            return 0;
        }

        /// <summary>
        /// 要求に応じて提供できる捕獲量
        /// </summary>
        /// <returns></returns>
        protected override double[] CalCapture()
        {
            m_DtrtsInf.d_TotalOUT = 0.0;
            // 現在のデトリタス量を取得
            //MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();
            double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);

            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                if (m_DtrtsInf.m_SumDetritusMass[ll] > m_DtrtsInf.m_TotalReqedPredationMass[ll] / m_DtrtsInf.m_CapturedRatio)
                {   // 要求量に対して、十分な量がある時
                    m_DtrtsInf.m_dCapturedMass[ll] = m_DtrtsInf.m_TotalReqedPredationMass[ll];
                }
                else
                {   // 要求量に対して、不足するとき
                    m_DtrtsInf.m_dCapturedMass[ll] = m_DtrtsInf.m_SumDetritusMass[ll] * m_DtrtsInf.m_CapturedRatio;
                }

                double dltCatch = 0.0;
                // 小さなデトリタスほど、捕獲されやすいものとする
                double dSum = m_DtrtsInf.m_dCapturedMass[ll];
                for (int n = 0; n < 10; n++)
                {
                    //for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                    for (int s = 6; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                    {   // 動物プランクトン以上は　あまりにも小さなものは捕食できないとする　5μメータ以下のもの
                        dltCatch = m_DtrtsInf.m_SpdDetritusDECOMPOSE[s] * m_csOcnBacedlInf.m_TotalReqedPredationMass[ll];
                        if (m_DtrtsInf.m_DetritusMass_1[ll][s] > dltCatch)
                        {
                            if(dSum < dltCatch) { dSum = dltCatch; }
                            dSum -= dltCatch;
                            m_DtrtsInf.m_DetritusMass_1[ll][s] -= dltCatch;
                            m_DtrtsInf.d_TotalOUT += dltCatch;
                        }
                        else if(m_DtrtsInf.m_DetritusMass_1[ll][s] > 0.0)
                        {
                            dltCatch = m_DtrtsInf.m_DetritusMass_1[ll][s];
                            if (dSum < dltCatch) { dSum = dltCatch; }
                            dSum -= dltCatch;
                            m_DtrtsInf.m_DetritusMass_1[ll][s] = 0.0;
                            m_DtrtsInf.d_TotalOUT += dltCatch;
                        }
                        else
                        {
                            // Do Nothing
                        }
                        if (dSum <= 0.0)
                        {
                            break;
                        }
                    }
                    if (dSum <= 0.0)
                    {
                        break;
                    }
                }
                if( dSum > 0.0 )
                {
                    m_DtrtsInf.m_dCapturedMass[ll] -= dSum;
                }
                m_DtrtsInf.m_SumDetritusMass[ll] = 0.0;
                for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                {
                    m_DtrtsInf.m_SumDetritusMass[ll] += m_DtrtsInf.m_DetritusMass_1[ll][s];
                }
            }   // end of for( ll )
            return m_csOcnBacedlInf.m_dCapturedMass;
        }

        /// <summary>
        /// 細菌による分解
        /// </summary>
        /// <returns></returns>
        protected virtual double[] CalDecompose()
        {
            m_DtrtsInf.d_TotalOUT = 0.0;
            // 現在のデトリタス量を取得
            //MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();
            double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);

            for (int ll = 0; ll < m_DtrtsInf.m_lLayerNumber; ll++)
            {
                if (m_DtrtsInf.m_SumDetritusMass[ll] > m_DtrtsInf.m_TotalReqedDecomposeMass[ll] / m_DtrtsInf.m_CapturedRatio)
                {   // 要求量に対して、十分な量がある時
                    m_DtrtsInf.m_TotalDecomposeMass[ll] = m_DtrtsInf.m_TotalReqedDecomposeMass[ll];
                }
                else
                {   // 要求量に対して、不足するとき
                    m_DtrtsInf.m_TotalDecomposeMass[ll] = m_DtrtsInf.m_SumDetritusMass[ll] * m_DtrtsInf.m_CapturedRatio;
                }

                double dltCatch = 0.0;
                // 小さなデトリタスほど、捕獲されやすいものとする
                double dSum = m_DtrtsInf.m_TotalDecomposeMass[ll];
                for (int n = 0; n < 10; n++)
                {
                    for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                    {
                        dltCatch = m_DtrtsInf.m_SpdDetritusDECOMPOSE[s] * m_csOcnBacedlInf.m_TotalReqedPredationMass[ll];
                        if (m_DtrtsInf.m_DetritusMass_1[ll][s] > dltCatch)
                        {
                            if (dSum < dltCatch) { dSum = dltCatch; }
                            dSum -= dltCatch;
                            m_DtrtsInf.m_DetritusMass_1[ll][s] -= dltCatch;
                            m_DtrtsInf.d_TotalOUT += dltCatch;
                        }
                        else if (m_DtrtsInf.m_DetritusMass_1[ll][s] > 0.0)
                        {
                            dltCatch = m_DtrtsInf.m_DetritusMass_1[ll][s];
                            if (dSum < dltCatch) { dSum = dltCatch; }
                            dSum -= dltCatch;
                            m_DtrtsInf.m_DetritusMass_1[ll][s] = 0.0;
                            m_DtrtsInf.d_TotalOUT += dltCatch;
                        }
                        else
                        {
                            // Do Nothing
                        }
                        if (dSum <= 0.0)
                        {
                            break;
                        }
                    }
                    if (dSum <= 0.0)
                    {
                        break;
                    }
                }

                m_DtrtsInf.m_SumDetritusMass[ll] = 0.0;
                for (int s = 0; s < m_DtrtsInf.m_iDetritusSizeNum; s++)
                {
                    m_DtrtsInf.m_SumDetritusMass[ll] += m_DtrtsInf.m_DetritusMass_1[ll][s];
                }
            }   // end of for( ll )
            return m_DtrtsInf.m_TotalDecomposeMass;
        }

        /// <summary>
        /// デトリタスの沈降
        /// </summary>
        /// <returns></returns>
        protected int SinkingParticle()
        {
            double dSec = GetDeltaTime().GetTime();
            double dDpth = 0.0;  // 沈降の深さ
            double dMass = 0.0;  // 量
            double dHH = m_DtrtsInf.m_dDepth - m_DtrtsInf.m_dLayerLength[m_DtrtsInf.m_lLayerNumber - 1];
            for (long k = m_DtrtsInf.m_lLayerNumber - 2; k >= 0; k--)
            {
                m_DtrtsInf.m_SinkDetritusMass[k] = 0.0;
                // デトリタス1（Detritus1) 計算
                for (int i = 0; i < m_DtrtsInf.m_iDetritusSizeNum; i++)
                {
                    if(m_DtrtsInf.m_DetritusMass_1[k][i] <= 0) { continue; }
                    // 沈降する深さ
                    dDpth = dSec * DroppingV((dHH + m_DtrtsInf.m_dLayerLength[k] / 2.0), m_DtrtsInf.m_DetritusSize[i], m_DtrtsInf.m_Density_1[k]);
                    if (dDpth >= 0.0)
                    {
                        // 沈降した量
                        dMass = m_DtrtsInf.m_DetritusMass_1[k][i] * (dDpth / m_DtrtsInf.m_dLayerLength[k]);
                        // 補正（現在存在する量以上には減らせることは出来ない）
                        if (dMass > m_DtrtsInf.m_DetritusMass_1[k][i]) { dMass = m_DtrtsInf.m_DetritusMass_1[k][i]; }

                        // 現在の層からは少なくなる
                        m_DtrtsInf.m_DetritusMass_1[k][i] -= dMass;
                        // 下の層には追加される
                        m_DtrtsInf.m_DetritusMass_1[k + 1][i] += dMass;

                        m_DtrtsInf.m_SinkDetritusMass[k] += dMass;   // 沈降した量
                    }
                    else
                    {
                        // 浮上した量
                        dMass = -1.0 * m_DtrtsInf.m_DetritusMass_1[k][i] * (dDpth / m_DtrtsInf.m_dLayerLength[k]);
                        // 補正（現在存在する量以上には減らせることは出来ない）
                        if (dMass > m_DtrtsInf.m_DetritusMass_1[k][i]) { dMass = m_DtrtsInf.m_DetritusMass_1[k][i]; }
                        if (k > 0)
                        {
                            // 現在の層からは少なくなる
                            m_DtrtsInf.m_DetritusMass_1[k][i] -= dMass;
                            // 上の層には追加される
                            m_DtrtsInf.m_DetritusMass_1[k - 1][i] += dMass;
                        }
                    }   // end of for(i)

                }   // end of for(k)

                dHH -= m_DtrtsInf.m_dLayerLength[k];

            }  // end of for(層No)

            //------------------------
            // データの集計
            for (long k = 0; k < m_DtrtsInf.m_lLayerNumber; k++)
            {
                // 沈降量：割合
                m_DtrtsInf.m_SinkDetritusMass[k] = m_DtrtsInf.m_SinkDetritusMass[k] / (m_DtrtsInf.m_SumDetritusMass[k] + 1E-48);
                if (m_DtrtsInf.m_SinkDetritusMass[k] < 0.0) { m_DtrtsInf.m_SinkDetritusMass[k] = 0.0; }
                if (m_DtrtsInf.m_SinkDetritusMass[k] > 0.99) { m_DtrtsInf.m_SinkDetritusMass[k] = 0.99; }
                m_DtrtsInf.m_SumDetritusMass[k] = 0;
                // デトリタス1（Detritus1) 計算
                for (int i = 0; i < m_DtrtsInf.m_iDetritusSizeNum; i++)
                {
                    m_DtrtsInf.m_SumDetritusMass[k] += m_DtrtsInf.m_DetritusMass_1[k][i];
                }
            }
            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)
        {
            base.SetProperty(csCellMdlPropertyInfo);
            // 使用しやすいようにキャストしておく
            m_DtrtsInf = (MzOceanDetritusCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                csPrptyInfo.GetInfo("m_CapturedRatio", ref m_DtrtsInf.m_CapturedRatio);
                // プロパティ設定
                csPrptyInfo.GetInfo("m_AggregationRatio10", ref m_DtrtsInf.m_AggregationRatio10);
                csPrptyInfo.GetInfo("m_AggregationRatio100", ref m_DtrtsInf.m_AggregationRatio100);
                csPrptyInfo.GetInfo("m_AggregationRatio1000", ref m_DtrtsInf.m_AggregationRatio1000);
            }
            m_dWorkSumLayer = new double[m_csOcnBacedlInf.m_lLayerNumber];
            return true;
        }

    }
}
