// <summary>ソースコード：収束演算制御クラス(収束演算制御のコーディング例))</summary>
// <author>CommonMP</author>

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

using CommonMP.HYSSOP.Interface.HSData;
using CommonMP.HYSSOP.Interface.HSViewer;
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.Interface.Controller;
using CommonMP.HYMCO.CoreImpl.Data;
using CommonMP.HYMCO.CoreImpl.Tool;
using CommonMP.HYMCO.CoreImpl.Model;

namespace CommonMP.HYMCO.OptionImpl.McConvergenceSample
{
    /// <summary><para>class outline:</para>
    /// <para>収束演算制御クラス(収束演算制御のコーディング例)</para>
    /// </summary>
    /// <remarks><para>history:</para>
    /// <para>[CommonMP][ver 1.0.0][2009/10/01][新規作成]</para>
    /// </remarks>
    public class McSampleCnvrgncIteration : McCnvrgncIterationCtlBase
    {
        /// <summary>収束判別情報</summary>
        McSampleCnvrgncIterationCalInfo m_csMyItrationInf = null;

        /// <summary><para>method outline:</para>
        /// <para>コンストラクタ</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>McSampleCnvrgncIteration bRtn = new McSampleCnvrgncIteration()</para>
        /// </example>
        /// <param name="">無し</param>
        /// <returns>生成されたインスタンス</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public McSampleCnvrgncIteration()
        {
            m_lMaxIterationNum = 100;
            m_eInitializeLevel = McDefine.ElementMemoryLevel.ELEMENT_MEMORY_ALL;
            //m_eInitializeLevel = McDefine.ElementMemoryLevel.ELEMENT_MEMORY_SNDPORT_ONLY;
        }

        /// <summary><para>method outline:</para>
        /// <para>グループ内の要素が自分が期待している要素か否かをチェック</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = InnerElementCheck(ref csErrorInf)</para>
        /// </example>
        /// <param name="csErrorInf">エラー出力</param>
        /// <returns>=true:正常、=false:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>ループ内の要素に指定がある場合、収束演算を行う処理は本チェックにおいて、
        /// 予定外要素が　グループ内に存在しないことを確認する。</para>
        /// </remarks>
        public override bool InnerElementCheck(ref McStructErrorInfo csErrorInf)
        {
            bool bRtn = true;
            for (long lLp = 0; lLp < m_lInnerElementNum; lLp++)
            {
                if ((m_csInnerElement[lLp].GetCalInfo() is McCnvElmSampleTestCalInfo) == false)
                {
                    bRtn = false;
                   // ver1.5 エラートレース日本語対応
                    csErrorInf.AddCheckErrorData(this.m_csElement.GetID(), McConvergenceSampleDefine.TEST_CNV_ELM_MODEL,
                        Properties.Resources.STATEMENT_UNEXPECT_ELEMENT + m_csInnerElement[lLp].GetID().ToString() );
                   // csErrorInf.AddCheckErrorData(this.m_csElement.GetID(), McConvergenceSampleDefine.TEST_CNV_ELM_MODEL,
                   //     "Unexpected Elmenet exist in this Group. ElementID=" + m_csInnerElement[lLp].GetID().ToString());
                }

            }
            return bRtn;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデルを初期化する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Initialize(ref csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool Initialize(ref McPropertyInfoRoot csInitialData)
        {

            McInitialInfo csInDt = csInitialData as  McInitialInfo;
            if (csInDt != null)
            {
                csInDt.GetInfo("m_dDltStp", ref m_csMyItrationInf.m_dDltStp);
                csInDt.GetInfo("m_dEps", ref m_csMyItrationInf.m_dEps);
            }
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算実行中断中のモデルを初期化</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>Initialize(ref csInitialData)</para>
        /// </example>
        /// <param name="csInitialData">初期化設定情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>演算中断中にプロパティ、初期値等を変更して動作させ場合等に使用する</para>
        /// </remarks>
        protected override bool OnlineInitialize(ref McPropertyInfoRoot csInitialData)
        {
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = IsConverged(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>=true:収束完了 =false:未収束</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool IsConverged(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            bool bRtn = false;
            McSampleCnvrgncIterationCalInfo csInf = csConvergeCondInfo as McSampleCnvrgncIterationCalInfo;
            if (csInf.m_dDltStp < csInf.m_dEps)
            {
                bRtn = true;
            }

            return bRtn;
        }

        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束判別初期設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetUpConvergenceInf(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>=0:正常 -1:異常</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>系全体で次の計算を行う場合に呼ばれる</para>
        /// </remarks>
        protected override void SetUpConvergenceInf(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        { 
            // 系の「次のタイムステップ」に移行したため、次の条件を設定する
            McSampleCnvrgncIterationCalInfo csMyCnvInf = csConvergeCondInfo as McSampleCnvrgncIterationCalInfo;
            McInitialInfo csInitInfo = this.m_csCnvItrInfo.GetCtlInitInfo();
            if (csInitInfo != null)
            {
                csInitInfo.GetInfo("m_dDltStp", ref csMyCnvInf.m_dDltStp);
                csInitInfo.GetInfo("m_dEps",ref csMyCnvInf.m_dEps);
            }
            McPropertyInfo csPrptyInfo = this.m_csCnvItrInfo.GetCtlPropertyInfo();
            if (csPrptyInfo != null)
            {
                csPrptyInfo.GetInfo("m_dMaxVal", ref csMyCnvInf.m_dMaxVal);
            }

            long lElmNum = csConvergeCondInfo.GetElementNum();
           
            for (long lLp = 0; lLp < lElmNum; lLp++)
            {
                if (m_eInitializeLevel == McDefine.ElementMemoryLevel.ELEMENT_MEMORY_ALL)
                {   // 初期化Initializeまで行うときは　このルートを通るという　コーディング例
                    McCnvElmSampleTestCalInfo csInDt = csConvergeCondInfo.GetElementCalInfo(lLp) as McCnvElmSampleTestCalInfo;
                    if (csInDt != null)
                    {
                        if (csInDt.m_sObjID == "X")
                        {
                            csInDt.m_X = 0.5;
                            csInDt.m_dOutDt = 0.5;
                            McInitialInfo csInitDt = csConvergeCondInfo.GetElementInitialInfo(lLp) as McInitialInfo;
                            csInitDt.SetInfo("m_dOutDt", csInDt.m_dOutDt);
                        }
                        else
                        {
                            csInDt.m_Y = 9.5;
                            csInDt.m_dOutDt = 9.5;
                            McInitialInfo csInitDt = csConvergeCondInfo.GetElementInitialInfo(lLp) as McInitialInfo;
                            csInitDt.SetInfo("m_dOutDt", csInDt.m_dOutDt);
                        }
                    }
                }
                else
                {   // 初期化Initializeを行わないときは、このルートを通るという　コーディング例
                    McCnvElmSampleTestCalInfo csInDt = csConvergeCondInfo.GetElementCalInfo(lLp) as McCnvElmSampleTestCalInfo;
                    if (csInDt != null)
                    {
                        //csInDt.m_dTtlLimit = 1000.0; // csInDt.m_dTtlLimit * 1.2;
                        //csInDt.m_dOutDt = 0.1;
                    }
                }
            }
        }
        /// <summary><para>method outline:</para>
        /// <para>モデル演算における収束値変更</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>ModifyConvergenceInf(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>系全体で次の計算を行う場合に呼ばれる</para>
        /// </remarks>
        protected override void ModifyConvergenceInf(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            McSampleCnvrgncIterationCalInfo csInf = csConvergeCondInfo as McSampleCnvrgncIterationCalInfo;
            double dTtlVal = 0.0;
            McCnvElmSampleTestCalInfo csCalDt=null;
            long lElmNum = csConvergeCondInfo.GetElementNum();
            for (long lLoop = 0; lLoop < lElmNum; lLoop++)
            {
                csCalDt = csConvergeCondInfo.GetElementCalInfo(lLoop) as McCnvElmSampleTestCalInfo;
                if (csCalDt != null)
                {
                    dTtlVal += csCalDt.m_dTtlVal;
                }
            }
            if (dTtlVal > csInf.m_dMaxVal) { csInf.m_dMaxVal = dTtlVal; }

            double dDltStpEchMdl = csInf.m_dDltStp;

            for (long lLLp = 0; lLLp < lElmNum; lLLp++)
            //long lLLp = 0;// lElmNum - 1;
            {
                csCalDt = csConvergeCondInfo.GetElementCalInfo(lLLp) as McCnvElmSampleTestCalInfo;
                if (csCalDt != null)
                {
                    dDltStpEchMdl = csInf.m_dDltStp;

                    if (csCalDt.m_sObjID == "X")
                    {
                        if (dTtlVal < csInf.m_dMaxVal)
                        {
                            csCalDt.m_dOutDt -= dDltStpEchMdl * 2.0;
                            //if (lLp == 0)
                            //{
                            dDltStpEchMdl = dDltStpEchMdl / 5.0;
                            //}
                        }
                        csCalDt.m_dOutDt += dDltStpEchMdl;
                    }
                    else 
                    {
                        if (dTtlVal < csInf.m_dMaxVal)
                        {
                            csCalDt.m_dOutDt += dDltStpEchMdl * 2.0;
                            //if (lLp == 0)
                            //{
                            dDltStpEchMdl = dDltStpEchMdl / 5.0;
                            //}
                        }
                        csCalDt.m_dOutDt -= dDltStpEchMdl;
                    }
                    //if (m_eInitializeLevel == McDefine.ElementMemoryLevel.ELEMENT_MEMORY_ALL)
                    //{   // 初期化Initializeまで行うときは　このルートを通る
                    //    McModelInitialInfo csInitDt = csConvergeCondInfo.GetElementInitialInfo(lLLp) as McModelInitialInfo;
                    //    csInitDt.SetInfo("m_dOutDt", csCalDt.m_dOutDt);
                    //}
                    //break;
                }
            }
            csInf.m_dDltStp = dDltStpEchMdl;
            for (long lLp = 0; lLp < lElmNum; lLp++)
            {
                csCalDt = csConvergeCondInfo.GetElementCalInfo(lLp) as McCnvElmSampleTestCalInfo;
                if (csCalDt != null)
                {
                    if (m_eInitializeLevel == McDefine.ElementMemoryLevel.ELEMENT_MEMORY_ALL)
                    {   // この例においては、初期化Initializeまで行うときは　前の演算結果を初期条件に覚えさせておく
                        McInitialInfo csInitDt = csConvergeCondInfo.GetElementInitialInfo(lLp) as McInitialInfo;
                        csInitDt.SetInfo("m_dOutDt", csCalDt.m_dOutDt);
                    }
                    //break;
                }
            }
        }

        /// <summary><para>method outline:</para>
        /// <para>計算前状態復帰直後処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>PostRemenber(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>収束演算中に計算前状態へ戻された直後に呼ばれる</para>
        /// </remarks>
        protected override void PostRemenber(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            McSampleCnvrgncIterationCalInfo csInf = csConvergeCondInfo as McSampleCnvrgncIterationCalInfo;

            long lElmNum = csConvergeCondInfo.GetElementNum();
            for (long lLp = 0; lLp < lElmNum; lLp++)
            {
                McCnvElmSampleTestCalInfo csCalDt = csConvergeCondInfo.GetElementCalInfo(lLp) as McCnvElmSampleTestCalInfo;

                if (m_eInitializeLevel == McDefine.ElementMemoryLevel.ELEMENT_MEMORY_ALL)
                {   // この例においては、初期化Initializeまで行うときは　前の演算結果を初期条件に覚えさせておく
                    McInitialInfo csInitDt = csConvergeCondInfo.GetElementInitialInfo(lLp) as McInitialInfo;
                    csInitDt.GetInfo("m_dOutDt",ref csCalDt.m_dOutDt);
                }

            }
        }

        /// <summary><para>method outline:</para>
        /// <para>非収束時の処理</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>long lRtn = NotConvergedOperation(ref csConvergeCondInfo)</para>
        /// </example>
        /// <param name="csConvergeCondInfo">収束条件情報</param>
        /// <returns>long </returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>規定回数トライしたものの結局収束できなかった場合に　行うベキ処理を記述</para>
        /// </remarks>
        protected override long NotConvergedOperation(ref McCnvrgncIterationInfoBase csConvergeCondInfo)
        {
            return McDefine.CALCULATION_FORCE_STOP_RETURN;
        }

        /// <summary><para>method outline:</para>
        /// <para>収束演算用：プロパティ情報を設定する</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>SetCnvrgncProperty(csPropertyInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        protected override bool SetCnvrgncProperty(McPropertyInfoRoot csPropertyInfo)
        {
            // 便利の為キャストしておく
            m_csMyItrationInf = this.m_csCnvItrInfo as McSampleCnvrgncIterationCalInfo;

            McPropertyInfo csMyPrpty = csPropertyInfo as McPropertyInfo;
            if (csMyPrpty != null)
            {
                csMyPrpty.GetInfo("m_dMaxVal", ref m_csMyItrationInf.m_dMaxVal);
            }
            //McGroupPropertyInfo csInfo = (McGroupPropertyInfo)csPropertyInfo;
            //m_csElementList　のエレメント順番を設定する
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>演算実行中断中のプロパティ等情報設定</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = SetOnlineProperty(csPropertyInfo)</para>
        /// </example>
        /// <param name="csPropertyInfo">プロパティ情報</param>
        /// <returns>無し</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>演算中断中にプロパティ、初期値等を変更して動作させ場合等に使用する</para>
        /// </remarks>
        public override bool SetOnlineProperty(McPropertyInfoRoot csPropertyInfo)
        {
            return true;
        }
        /// <summary><para>method outline:</para>
        /// <para>ファイルにモデル内情報を全て書き出す</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = FileOUT(csData)</para>
        /// </example>
        /// <param name="csData">演算要素データ</param>
        /// <returns>false</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool FileOUT(HySDataRoot csData)
        {
            return false;
        }

        /// <summary><para>method outline:</para>
        /// <para>ファイルからモデル情報を全て読み出す</para>
        /// </summary>
        /// <example><para>usage:</para>
        /// <para>bool bRtn = FileIN(csData)</para>
        /// </example>
        /// <param name="csData">演算要素データ</param>
        /// <returns>false</returns>
        /// <exception cref="">無し</exception>
        /// <remarks><para>remarks:</para>
        /// <para>無し</para>
        /// </remarks>
        public override bool FileIN(HySDataRoot csData)
        {
            return false;
        }
    }
}
