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

        /// <summary> 無機物肥料要素 </summary>
        protected McPatternRdvSndTranInfoPair m_csSndFertilizerCnnct = new McPatternRdvSndTranInfoPair();

        /// <summary> 分解・消化 </summary>
        protected McPatternRdvSndTranInfoPair m_csRcvDecomposeCnnct = new McPatternRdvSndTranInfoPair();   // <-- 此方を利用
        protected McPatternRdvSndTranInfoPair m_csSndDecomposeCnnct = new McPatternRdvSndTranInfoPair();   // <-- ダミー

        //---- ワーク -----
        //private double[] m_dFoodDcty = null;
        //private double[] m_dPredation = null;
        ////        private double[] m_dCapturedMass = null;
        private double[] m_dFoodDcty = 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_csSndFertilizerCnnct = this.PrepareSndPattern(MzOceanBaseDefine.BCT_FERTILIZER);

            // 分解・腐敗等
            (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;
        //}

        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_KBctInf.m_lLayerNumber; ll++)
                {
                    csCell[ll].m_dData[0] = m_KBctInf.m_TotalSelfMass[ll];
                    csCell[ll].m_dData[1] = m_KBctInf.m_O2[ll];
                    csCell[ll].m_dData[2] = m_KBctInf.m_CO2[ll];
                }
            }
        }

        protected override void ClearAllCalValue()
        {
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                m_csOcnBacedlInf.m_Death[ll] = 0.0;
                m_csOcnBacedlInf.m_N[ll] = 0.0;
                m_csOcnBacedlInf.m_P[ll] = 0.0;
                m_csOcnBacedlInf.m_Fe[ll] = 0.0;
                m_csOcnBacedlInf.m_Si[ll] = 0.0;
            }
        }

        /// <summary>
        /// 受信
        /// </summary>
        protected override void ReceiveData()
        {
            ClearAllCalValue();
            m_KBctInf.d_PreTotalMass = m_KBctInf.d_NowTotalMass;
            for(int ll=0;ll< m_KBctInf.m_lLayerNumber;ll++)
            {
                m_KBctInf.m_PrvTotalSelfMass[ll] = m_KBctInf.m_TotalSelfMass[ll];
            }

            // 呼吸関係
            ReceiveBREATHING();

            // 被捕食：プランクトンからの要求量の取得
            ReceiveReqPREDATION();

            // 捕食：デトリタス摂取
            ReceiveDECOMPOSE();

            m_KBctInf.d_TotalIN = 0.0;
            for (int i = 0; i < m_KBctInf.m_lLayerNumber; i++)
            {
                m_KBctInf.d_TotalIN += m_KBctInf.m_EatenMass[i];
            }

            return;
        }

        /// <summary>
        /// 送信例
        /// </summary>
        protected override void SendData()
        {
            // 被捕食：プランクトンに捕食される
            SendPREDATION(m_csOcnBacedlInf.m_dCapturedMass, 0.1, 0.005);

            // 捕食物:デトリタスを分解
            SendReqDECOMPOSE(m_csOcnBacedlInf.m_ReqFoodMass);

            // 呼吸
            SendBREATHING();

            // 死
            //SendEXCRETION_DEATH(m_csOcnBacedlInf.m_dExcretionDencity, m_csOcnBacedlInf.m_dBulkDensity);

            // 肥料要素
            SendFertilizer();

            // Debug
            SendDEBUG();

            //----- Debug Check ------
            double dChk = (m_KBctInf.d_NowTotalMass - m_KBctInf.d_PreTotalMass) - (m_KBctInf.d_TotalIN - m_KBctInf.d_TotalOUT - m_KBctInf.d_Discompose);
            McLog.DebugOut("MzOceanBacterias", "SendData", "細菌総量チェック:" + dChk.ToString() + " = "
                + (m_KBctInf.d_NowTotalMass - m_KBctInf.d_PreTotalMass).ToString() + " - " + (m_KBctInf.d_TotalIN - m_KBctInf.d_TotalOUT - m_KBctInf.d_Discompose).ToString());
            //------------------------

            return;
        }

        /// <summary>
        /// 細菌側が、デトリタスを捕食　受信
        /// </summary>
        protected virtual void ReceiveDECOMPOSE()
        {
            //-----------------------
            // 要求する側（捕食者側）：＝被捕食者から提供された量に基づいて自分が捕食したトータル量を累積する       
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                m_csOcnBacedlInf.m_EatenMass[ll] = 1E-64;
                m_csOcnBacedlInf.m_TotalFoodMass[ll] = 1E-64;
                m_dFoodDcty[ll] = 1E-64;
                m_KBctInf.m_SinkDetritusMass[ll] = 0.0;
            }
            for (int i = 0; i < m_csRcvDecomposeCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csCell = m_csRcvDecomposeCnnct.m_csRcvInfArry[i].GetInterpolatedCellD1();
                if (csCell != null)
                {
                    for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                    {
                        m_csOcnBacedlInf.m_EatenMass[ll] += csCell[ll].m_dData[0];
                        m_dFoodDcty[ll] += csCell[ll].m_dData[0] * csCell[ll].m_dData[3];
                        m_KBctInf.m_SinkDetritusMass[ll] += csCell[ll].m_dData[2];
                        m_csOcnBacedlInf.m_TotalFoodMass[ll] += csCell[ll].m_dData[1];
                        m_csRcvDecomposeCnnct.m_dRcvRatioData[i][ll] = csCell[ll].m_dData[1];   // 要求の為、資源量を覚えておく
                    }
                }
            }
            // 分配係数設定
            for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
            {
                for (int i = 0; i < m_csRcvDecomposeCnnct.m_RcvInfNum; i++)
                {
                    // 分配比計算
                    m_csRcvDecomposeCnnct.m_dSendRatioData[i][ll] = m_csRcvDecomposeCnnct.m_dRcvRatioData[i][ll] / m_csOcnBacedlInf.m_TotalFoodMass[ll];
                }
                m_dFoodDcty[ll] = m_dFoodDcty[ll] / m_csOcnBacedlInf.m_EatenMass[ll];
            }

            // 食べたものの比重を計算する
            if (m_csRcvDecomposeCnnct.m_RcvInfNum > 0)
            {
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    // 食べたものの比重を計算する
                    if (m_csOcnBacedlInf.m_EatenMass[ll] <= 0.0)
                    {
                        m_csOcnBacedlInf.m_dExcretionDencity[ll] = m_csOcnBacedlInf.m_dBulkDensity;
                    }
                    else
                    {
                        m_csOcnBacedlInf.m_dExcretionDencity[ll]
                            = (m_csOcnBacedlInf.m_dBulkDensity * m_csOcnBacedlInf.m_TotalSelfMass[ll] + m_dFoodDcty[ll] * m_csOcnBacedlInf.m_EatenMass[ll]) / (m_csOcnBacedlInf.m_TotalSelfMass[ll] + m_csOcnBacedlInf.m_EatenMass[ll]);
                    }

                }  // end of for(ll)
            }
            else
            {
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    m_dFoodDcty[ll] = m_csOcnBacedlInf.m_dBulkDensity;
                }
            }
        }
        /// <summary>
        /// 細菌側が要求量の送信
        /// </summary>
        /// <param name="dReqFoodDt">各レイヤー毎の要求書供物料</param>
        protected virtual void SendReqDECOMPOSE(double[] dReqFoodDt)
        {
            HySCellData[] csSndDt = null;

            for (int i = 0; i < m_csRcvDecomposeCnnct.m_RcvInfNum; i++)
            {
                csSndDt = m_csRcvDecomposeCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    csSndDt[ll].m_dData[0] = dReqFoodDt[ll] * m_csRcvDecomposeCnnct.m_dSendRatioData[i][ll];
                }
            }
        }


        /// <summary>
        /// 分解した肥料要素(無機物)を送信
        /// </summary>
        protected virtual void SendFertilizer()
        {
            for (int i = 0; i < m_csSndFertilizerCnnct.m_RcvInfNum; i++)
            {
                HySCellData[] csSndDt = m_csSndFertilizerCnnct.m_csSndInfArry[i].PrepareSendCellD1();
                if (csSndDt == null) { break; }
                for (int ll = 0; ll < m_csOcnBacedlInf.m_lLayerNumber; ll++)
                {
                    csSndDt[ll].m_dData[0] = m_KBctInf.m_N[ll];
                    csSndDt[ll].m_dData[1] = m_KBctInf.m_P[ll];
                    csSndDt[ll].m_dData[2] = m_KBctInf.m_Si[ll];
                    csSndDt[ll].m_dData[3] = m_KBctInf.m_Fe[ll];
                }
            }
        }

        /// <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)
            {   // 初期化情報有り
                this.InitMass(ref csInDt);

                m_KBctInf.d_NowTotalMass = 0.0;
                for (int ll = 0; ll < m_KBctInf.m_lLayerNumber; ll++)
                {
                    // ●次回要求する＝＝＝＝用
                    // 自分が要求するFood量
                    m_KBctInf.m_ReqFoodMass[ll] = m_KBctInf.m_dEatK * m_KBctInf.m_TotalSelfMass[ll] / m_KBctInf.m_dEexcretionRatio;
                    // 自分が要求するO2量
                    m_KBctInf.m_ReqO2[ll] = (1.0 / m_KBctInf.m_O2AbsRatio) * m_KBctInf.m_TotalSelfMass[ll] / m_KBctInf.m_dEexcretionRatio;

                    m_KBctInf.m_EatenMass[ll] = m_KBctInf.m_ReqFoodMass[ll];
                    m_KBctInf.m_O2[ll] = m_KBctInf.m_ReqO2[ll];

                    // 
                    m_csOcnBacedlInf.m_TotalReqedPredationMass[ll] = m_csOcnBacedlInf.m_TotalSelfMass[ll] * 0.1;
                    m_csOcnBacedlInf.m_dCapturedMass[ll] = m_csOcnBacedlInf.m_TotalSelfMass[ll] * 0.1;
                    m_csOcnBacedlInf.m_TotalSelfMass[ll] -= m_csOcnBacedlInf.m_dCapturedMass[ll];
                    m_KBctInf.d_TotalOUT += m_csOcnBacedlInf.m_dCapturedMass[ll];
                    m_KBctInf.d_NowTotalMass += m_KBctInf.m_TotalSelfMass[ll];
                }
                m_KBctInf.d_PreTotalMass = m_KBctInf.d_NowTotalMass;
            }
            return true;
        }

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

        /// <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
            )
        {
            m_KBctInf.d_Discompose = 0.0;

            double dT = m_csDltTime.GetTime() / (3600.0 * 24.0);

            // 後で論理を見直すこと
            // ★★　論理不足


            //// デトリタスの沈降に伴う沈降
            //for (int ll = 1; ll < m_KBctInf.m_lLayerNumber; ll++)
            //{   // 層数分繰り返し
            //    long iL = m_KBctInf.m_lLayerNumber - ll;
            //    double dMss = 0.5 * m_KBctInf.m_TotalSelfMass[iL - 1] * m_KBctInf.m_SinkDetritusMass[iL - 1];
            //    // デトリタスの約１／２に細菌がついているとする
            //    m_KBctInf.m_TotalSelfMass[iL - 1] -= dMss;
            //    m_KBctInf.m_TotalSelfMass[iL] += dMss;
            //}


            // 水深
            double dH = 0.0 ;

            // 摂食-排糞-排瀧-自然
            // デトリタスの腐敗等の計算を行う　
            // 腐敗は、粒度の小さいものほど早く行われる　表面積比に比例するとする
            for (int ll = 0; ll < m_KBctInf.m_lLayerNumber; ll++)
            {   // 層数分繰り返し
                double dMass = 1E-42;
                double dDeath = 0.0;
                double dFNecessity = 0.0;
                double dDeathE = 0.0;
                double dBNecessity = 0.0;
                double dDeathB = 0.0;
                // 水温
                double dTmpT = MzOceanModelElement.Temperature(dH + m_csOcnBacedlInf.m_dLayerLength[ll]/2.0);
                double dTmpTK = (dTmpT + 0.1) / 23.0;
                // 水圧　★水圧に関する考慮をしていない
                double dPrss = MzOceanModelElement.Presser(dH + m_csOcnBacedlInf.m_dLayerLength[ll] / 2.0);

                double dEatenFood = m_KBctInf.m_EatenMass[ll];

                //--------------------------------------
                // ●飢え死、窒息死
                if (m_KBctInf.m_TotalSelfMass[ll] > 0.0)
                {
                    dMass = m_KBctInf.m_TotalSelfMass[ll];
                    // 必要とするFood量
                    dFNecessity = dTmpTK * dMass * m_KBctInf.m_dEatK;
                    // 飢え死計算
                    double dFoodRatio = m_KBctInf.m_EatenMass[ll] / (dFNecessity + 1E-48);  // 摂食量より： 要求に対する摂食の実際量の割合
                    if (dFoodRatio < 1.0 - 1E-48)
                    {   // 現実のFoodが少ない時には飢え死にする
                        if (dFoodRatio < 1E-3) { dFoodRatio = 1E-3; }
                        // 飢え死
                        dDeathE = dMass * (1.0 - dFoodRatio);
                        //dDeath += m_KBctInf.m_TotalSelfMass[ll] * (1.0 - dFoodRatio);
                        //dMass -= dDeath;
                    }
                    
                    // 窒息死
                    //double dRqOx = m_KBctInf.m_ReqO2[ll] * (dMass / m_KBctInf.m_TotalSelfMass[ll]) + 1E-8;
                    //double dOxRatio = m_KBctInf.m_O2[ll] / dRqOx;
                    //if (dOxRatio < 0.0)
                    //{
                    //    dDeath += dMass;
                    //    dMass = 0.0;
                    //}
                    //else if (dOxRatio < 1.0)
                    //{
                    //    if (dOxRatio < 1E-3) { dOxRatio = 1E-3; }
                    //    // 窒息死
                    //    dAliveB = m_KBctInf.m_TotalSelfMass[ll] * dOxRatio;
                    //    dDeath += dMass * (1.0 - dOxRatio);
                    //    dMass -= dDeath;
                    //}
                    // 必要とするO2量
                    dBNecessity = dTmpTK * dMass * m_KBctInf.m_O2AbsRatio;
                    // 実際のO2の量と必要量の比
                    double dOxRatio = m_KBctInf.m_O2[ll] / (dBNecessity + 1E-48);
                    if (dOxRatio < 1.0 - 1E-48)
                    {   // 現実のO2量が非常に少ない時は窒息死する
                        if (dOxRatio < 1E-3) { dOxRatio = 1E-3; }
                        // 窒息死
                        dDeathB = dMass * (1.0 - dOxRatio);
                    }

                    // 餓死と窒息死のどちらか多い方が総死となる
                    if(dDeathE > dDeathB)
                    {
                        dDeath = dDeathE;
                    }
                    else
                    {
                        dDeath = dDeathB;
                    }
                    dMass -= dDeath;
                    if( dMass < 0.0) { dMass = 0.0; }
                }

                m_KBctInf.d_Discompose = 0.0;
                //--------------------------------------
                // ●体重増加分
                // 増殖に可能な食料と酸素量（個体維持から差し引いた分）
                double dPossibleE = m_KBctInf.m_EatenMass[ll] - dTmpTK * dMass * m_KBctInf.m_dEatK;
                double dPossibleB = m_KBctInf.m_O2[ll] - dTmpTK * dMass * m_KBctInf.m_O2AbsRatio;

                // 増殖量計算：温度考慮
                double dltMass = dTmpTK * dMass * m_KBctInf.m_dMaxProliferation; // * (1.0 - m_KBctInf.m_dEexcretionRatio);  // 温度考慮
                if ( dltMass > dPossibleE) // * (1.0 - m_KBctInf.m_dEexcretionRatio))
                { // 食べた体重以上には増えられない
                    dltMass = dPossibleE; // * (1.0 - m_KBctInf.m_dEexcretionRatio);
                }

                // 増殖量計算：温度考慮及び、最も小さい量に律速される
                double dltMassE =  dPossibleE; // * (1.0 - m_KBctInf.m_dEexcretionRatio); // * ここで、dTを掛けてははいけない; //(1.0 - m_KBctInf.m_dEexcretionRatio);
                if( dltMassE < dltMass) { dltMass = dltMassE; }
                double dltMassB =  dPossibleB; //  * (1.0 - m_KBctInf.m_dEexcretionRatio); // * ここで、dTを掛けてはいけない。;
                if ( dltMassB < dltMass) { dltMass = dltMassB; }

                if( dltMass < 0.0) { dltMass = 0.0; }

                ////double dDD = m_KBctInf.m_EatenMass[ll] * (1.0 - m_KBctInf.m_dEexcretionRatio);  // １００％の場合の体重増分
                ////dDD = dDD * (dTmp + 0.1) / 23.0;   // 温度の影響を考慮
                ////dltMass = dDD * dMass / (m_KBctInf.m_TotalSelfMass[ll] + 1E-8);    // 餓死等あり時の体重増加分
                //double dltMass = m_KBctInf.m_EatenMass[ll] - dMass * m_KBctInf.m_dEexcretionRatio;
                //if (dltMass > dMass * m_KBctInf.m_dMaxProliferation * (dTmpT + 0.1) / 23.0)   // 温度の影響を考慮)
                //{
                //    dltMass = dMass * m_KBctInf.m_dMaxProliferation * (dTmpT + 0.1) / 23.0;   // 温度の影響を考慮
                //}

                // ●分解分計算
                // 本体を維持
                double dDiscompose =  dMass * m_KBctInf.m_dEatK * m_KBctInf.m_dEexcretionRatio;
                // 増殖時の消費
                dDiscompose +=  dltMass * m_KBctInf.m_dEexcretionRatio;
                if(dDiscompose < 0.0) { dDiscompose = 0.0; }

                m_KBctInf.d_Discompose += dDiscompose;  // 分解量設定

                // ●呼吸 O2消費,CO2排出
                //double dMM = (dMass + dltMass) * m_KBctInf.m_dMetabolismK; 
                //dMass -= dMM;
                m_KBctInf.m_O2[ll] -= dTmpTK * m_KBctInf.m_O2AbsRatio * m_KBctInf.d_Discompose;
                m_KBctInf.m_CO2[ll] += dTmpTK * m_KBctInf.m_CO2GenRatio * m_KBctInf.d_Discompose;

                if (m_KBctInf.m_O2[ll] < 0.0) { m_KBctInf.m_O2[ll] = 0.0;  }
                if (m_KBctInf.m_CO2[ll] < 0.0) { m_KBctInf.m_CO2[ll] = 0.0; }

                //----------------------------
                // 固形排泄は無しで、すべて無機物レベルまで分解されるとする
                // ●分解した有機物からの無機物溶けだし
                m_KBctInf.m_N[ll] += m_KBctInf.d_Discompose * m_KBctInf.m_DkK_N;
                m_KBctInf.m_P[ll] += m_KBctInf.d_Discompose * m_KBctInf.m_DkK_P;
                m_KBctInf.m_Si[ll] += m_KBctInf.d_Discompose * m_KBctInf.m_DkK_Si;
                m_KBctInf.m_Fe[ll] += m_KBctInf.d_Discompose * m_KBctInf.m_DkK_Fe;

                //--------------------------------------
                // ●自然死
                m_KBctInf.m_TotalSelfMass[ll] = (dMass + dltMass) * (1.0 - m_csOcnBacedlInf.m_dDeathRatio);
                dDeath += (dMass + dltMass) * m_csOcnBacedlInf.m_dDeathRatio;
                // ゼロの場合には、僅かに残しておく
                if (m_KBctInf.m_TotalSelfMass[ll] < 1E-36) { m_KBctInf.m_TotalSelfMass[ll] = 1E-36; }
                m_KBctInf.m_Death[ll] = dDeath;
                // 死亡したものは全て溶けだすとする
                m_KBctInf.m_N[ll] += m_KBctInf.m_Death[ll] * m_KBctInf.m_DkK_N;
                m_KBctInf.m_P[ll] += m_KBctInf.m_Death[ll] * m_KBctInf.m_DkK_P;
                m_KBctInf.m_Si[ll] += m_KBctInf.m_Death[ll] * m_KBctInf.m_DkK_Si;
                m_KBctInf.m_Fe[ll] += m_KBctInf.m_Death[ll] * m_KBctInf.m_DkK_Fe;

                    m_KBctInf.m_O2[ll] -= m_KBctInf.m_O2AbsRatio * m_KBctInf.m_Death[ll];
                    m_KBctInf.m_CO2[ll] += m_KBctInf.m_CO2GenRatio * m_KBctInf.m_Death[ll];


                // ●排泄分 ＝ 食べ残し＝ 捕食量 ― 体重増加量　―　分解量  －  死;    //　－ 捕食量
                m_KBctInf.m_ExcretionMass[ll] = m_KBctInf.m_EatenMass[ll] - dltMass;   // (m_KBctInf.m_TotalSelfMass[ll] - m_KBctInf.m_PrvTotalSelfMass[ll]);
                m_KBctInf.m_ExcretionMass[ll] -= m_KBctInf.d_Discompose;
                m_KBctInf.m_ExcretionMass[ll] -= m_KBctInf.m_Death[ll];
                if (m_KBctInf.m_ExcretionMass[ll] < 0.0) { m_KBctInf.m_ExcretionMass[ll] = 0.0; }


                //---------------------------
                // 深度
                dH += m_csOcnBacedlInf.m_dLayerLength[ll];
            }

            //-------------------------------------
            // ●捕獲(被捕食者として)
            this.CalCapture();

            // 補正●排泄分 －＝ 捕食量
            for (int ll = 1; ll < m_KBctInf.m_lLayerNumber; ll++)
            {   // 層数分繰り返し               
                m_KBctInf.m_ExcretionMass[ll] -= m_KBctInf.m_dCapturedMass[ll]; // * m_csOcnBacedlInf.m_dEexcretionRatio;
                //m_KBctInf.m_ExcretionMass[ll] -= (m_KBctInf.m_TotalSelfMass[ll] - m_KBctInf.m_PrvTotalSelfMass[ll]);
                if (m_KBctInf.m_ExcretionMass[ll] < 0.0) { m_KBctInf.m_ExcretionMass[ll] = 0.0; }
            }

            // デトリタスの沈降に伴う沈降
            for (int ll = 1; ll < m_KBctInf.m_lLayerNumber; ll++)
            {   // 層数分繰り返し
                long iL = m_KBctInf.m_lLayerNumber - ll;
                double dMss = 0.5 * m_KBctInf.m_TotalSelfMass[iL - 1] * m_KBctInf.m_SinkDetritusMass[iL - 1];
                // デトリタスの約１／２に細菌がついているとする
                m_KBctInf.m_TotalSelfMass[iL - 1] -= dMss;
                m_KBctInf.m_TotalSelfMass[iL] += dMss;
            }

            // 要求量計算
            dH = 0.0;
            MzOceanAreaColumnModelCalInfo csColumInfo = this.GetOceanAreaColumnCalInfo();
            m_KBctInf.d_NowTotalMass = 0.0;
            m_KBctInf.d_TotalOUT = 0.0;
            for (int ll = 0; ll < m_KBctInf.m_lLayerNumber; ll++)
            {
                // 水温
                double dTmpT = MzOceanModelElement.Temperature(dH + m_csOcnBacedlInf.m_dLayerLength[ll] / 2.0);
                double dTmpTK = (dTmpT + 0.1) / 23.0;
                // ●次回要求する＝＝＝＝用
                double dNxtMass = m_KBctInf.m_TotalSelfMass[ll] * (1.0 + m_KBctInf.m_dMaxProliferation * dT);
                // 自分が要求するFood量
                m_KBctInf.m_ReqFoodMass[ll] = dTmpTK * 1.0 / m_KBctInf.m_dEatK * dNxtMass; // / m_KBctInf.m_dEexcretionRatio;
                // 自分が要求するO2量
                m_KBctInf.m_ReqO2[ll] = dTmpTK * m_KBctInf.m_O2AbsRatio * dNxtMass * m_KBctInf.m_dEexcretionRatio;  // / m_KBctInf.m_dEexcretionRatio;
                m_KBctInf.m_ReqO2[ll] -= m_KBctInf.m_O2[ll];
                if (m_KBctInf.m_ReqO2[ll] < 0.0) { m_KBctInf.m_ReqO2[ll] = 0.0;  }

                dH += m_csOcnBacedlInf.m_dLayerLength[ll];
            }

            // 集計値計算
            dH = 0.0;
            m_KBctInf.d_NowTotalMass = 0.0;
            m_KBctInf.d_TotalOUT = 0.0;
            for (int ll = 0; ll < m_KBctInf.m_lLayerNumber; ll++)
            {
                //  ??????????  ↓↓↓↓↓↓↓↓↓↓↓↓↓
                m_KBctInf.m_N[ll] += m_KBctInf.m_ExcretionMass[ll] * m_KBctInf.m_DkK_N;
                m_KBctInf.m_P[ll] += m_KBctInf.m_ExcretionMass[ll] * m_KBctInf.m_DkK_P;
                m_KBctInf.m_Si[ll] += m_KBctInf.m_ExcretionMass[ll] * m_KBctInf.m_DkK_Si;
                m_KBctInf.m_Fe[ll] += m_KBctInf.m_ExcretionMass[ll] * m_KBctInf.m_DkK_Fe;
                m_KBctInf.m_ExcretionMass[ll] = 0.0;
                {
                    m_KBctInf.m_O2[ll] -= m_KBctInf.m_O2AbsRatio * m_KBctInf.m_ExcretionMass[ll];
                    m_KBctInf.m_CO2[ll] += m_KBctInf.m_CO2GenRatio * m_KBctInf.m_ExcretionMass[ll];
                    if (m_KBctInf.m_O2[ll] < 0.0) { m_KBctInf.m_O2[ll] = 0.0; }
                    if (m_KBctInf.m_CO2[ll] < 0.0) { m_KBctInf.m_CO2[ll] = 0.0; }

                    m_KBctInf.m_ReqO2[ll] += m_KBctInf.m_O2AbsRatio * m_KBctInf.m_ExcretionMass[ll];
                }
                //  ??????????  ↑↑↑↑↑↑↑↑↑↑↑↑↑

                // 海水層モデルのデータ内に入れる（集計用）
                csColumInfo.m_TotalSelfMass[ll] += m_KBctInf.m_TotalSelfMass[ll];

                // チェック用
                m_KBctInf.d_NowTotalMass += m_KBctInf.m_TotalSelfMass[ll];
                m_KBctInf.d_TotalOUT +=  m_csOcnBacedlInf.m_dCapturedMass[ll] + m_csOcnBacedlInf.m_Death[ll]+ m_csOcnBacedlInf.m_ExcretionMass[ll];

                dH += m_csOcnBacedlInf.m_dLayerLength[ll];
            }

            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_KBctInf = (MzOceanBacteriasCalInfo)m_csCalInfo;

            // プロパティ設定
            McCellModelPropertyInfo csPrptyInfo = csCellMdlPropertyInfo as McCellModelPropertyInfo;
            if (csPrptyInfo != null)
            {
                // 演算ステップ時刻設定
                this.m_csDltTime = new HySTime(csPrptyInfo.GetStepTime());
                // 層設定
                this.SetLayerProperty(ref csPrptyInfo);
                // 代謝設定
                this.SetMetabolism(ref csPrptyInfo);
                this.SetMetabolism2(ref csPrptyInfo);
                this.SetEexcretion(ref csPrptyInfo);
                this.SetDeath(ref csPrptyInfo);
                csPrptyInfo.GetInfo("m_CapturedRatio", ref m_KBctInf.m_CapturedRatio);

                csPrptyInfo.GetInfo("m_DkK_N", ref m_KBctInf.m_DkK_N);
                csPrptyInfo.GetInfo("m_DkK_P", ref m_KBctInf.m_DkK_P);
                csPrptyInfo.GetInfo("m_DkK_Si", ref m_KBctInf.m_DkK_Si);
                csPrptyInfo.GetInfo("m_DkK_Fe", ref m_KBctInf.m_DkK_Fe);


                double dltT = m_csDltTime.TotalSec();
                double n = dltT / (24 * 3600);
                m_KBctInf.m_CapturedRatio = 1.0 - Math.Pow((1.0 - m_KBctInf.m_CapturedRatio), n);
                m_KBctInf.m_dDeathRatio = 1.0 - Math.Pow((1.0 - m_KBctInf.m_dDeathRatio), n);
                m_KBctInf.m_dMaxProliferation = Math.Pow(m_KBctInf.m_dMaxProliferation, n);
            }
            m_dFoodDcty = new double[m_csOcnBacedlInf.m_lLayerNumber];

            return true;
        }

    }
}
