コード例 #1
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="timeIndex">時刻のインデックス</param>
        /// <param name="timeLoopCnt">時間計算回数</param>
        /// <param name="newmarkBeta">Newmarkβ法のβ</param>
        /// <param name="timeDelta">時刻刻み</param>
        /// <param name="gaussianT0">ガウシアンパルスの遅延時間</param>
        /// <param name="gaussianTp">ガウシアンパルスの時間幅</param>
        /// <param name="NormalizedFreqSrc">励振するモードの規格化周波数</param>
        /// <param name="VIdRefList">観測点の頂点ID(= 節点番号 + 1)</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">導波路幅</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループのフィールドID</param>
        /// <param name="FieldForceBcId">強制境界のフィールドID</param>
        /// <param name="FieldPortBcIdList">ポート1、ポート2、励振面の境界のフィールドID</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="node_cnt">節点数(強制境界を含む)</param>
        /// <param name="sortedNodes">ソート済み節点番号リスト</param>
        /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param>
        /// <param name="sortedNodes_Port_List">境界のソート済み節点番号リスト(ポート1,ポート2,励振面)</param>
        /// <param name="toSorted_Port_List">境界の節点番号→ソート済み節点インデックスマップ(ポート1,ポート2,励振面)</param>
        /// <param name="KMat">剛性行列</param>
        /// <param name="MMat">質量行列</param>
        /// <param name="QbMatList">境界質量行列</param>
        /// <param name="betaXSrcList">境界の伝搬定数(ポート1、ポート2、励振面)</param>
        /// <param name="profileSrcList">境界のモード分布(ポート1、ポート2、励振面)</param>
        /// <param name="AMat">係数行列(逆行列)</param>
        /// <param name="Ez_Pz">電界分布(現在)</param>
        /// <param name="Ez_Pz_Prev">電界分布(1つ前)</param>
        /// <param name="Ez_Pz_Prev2">電界分布(2つ前)</param>
        /// <param name="EzTimeAryPort1">ポート1観測点の電界リスト(時間変化)</param>
        /// <param name="EzTimeAryPort2">ポート2観測点の電界リスト(時間変化)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            bool IsSolveStraightWg,
            ref int timeIndex,
            int timeLoopCnt,
            double newmarkBeta,
            double timeDelta,
            double gaussianT0,
            double gaussianTp,
            double NormalizedFreqSrc,
            double NormalizedFreq1,
            double NormalizedFreq2,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            IList<uint> FieldPortBcIdList,
            IList<uint> VIdRefList,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            bool IsShowAbsField,
            int node_cnt,
            IList<uint> sortedNodes,
            Dictionary<uint, uint> toSorted,
            IList<IList<uint>> sortedNodes_Port_List,
            IList<Dictionary<uint, uint>> toSorted_Port_List,
            double[] KMat,
            double[] MMat,
            IList<double[]> QbMatList,
            IList<double[]> RbMatList,
            IList<double[]> TbMatList,
            IList<double> betaXSrcList,
            IList<double[]> profileSrcList,
            IList<double[]> velo_List,
            IList<double> b0_abc_List,
            IList<double[]> a_abc_List,
            IList<double[]> b_abc_List,
            double[] AMat,
            ref double[] Ez_Pz,
            ref double[] Ez_Pz_Prev,
            ref double[] Ez_Pz_Prev2,
            ref IList<double> EzTimeAryPort1,
            ref IList<double> EzTimeAryPort2,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;

            // ポート数
            //  励振面の分を引く
            int portCnt = FieldPortBcIdList.Count - 1;

            // 時刻の取得
            if (timeIndex == -1)
            {
                return success;
            }
            if (timeIndex >= timeLoopCnt)
            {
                timeIndex = -1;
                return success;
            }
            // 以下curTimeIndexに対する計算
            double curTime = timeIndex * timeDelta;

            double dt = timeDelta;

            try
            {
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);

                // 励振源のパラメータ
                // 波数
                double k0Src = NormalizedFreqSrc * pi / WaveguideWidth;
                // 波長
                double waveLengthSrc = 2.0 * pi / k0Src;
                // 周波数
                double freqSrc = c0 / waveLengthSrc;
                // 角周波数
                double omegaSrc = 2.0 * pi * freqSrc;

                //--------------------------------------------------------------
                // 電界
                //--------------------------------------------------------------
                uint free_node_cnt = (uint)sortedNodes.Count;
                uint free_node_cnt_all = free_node_cnt;
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    uint nodeCntB_f = (uint)sortedNodes_Port_List[portIndex].Count;
                    free_node_cnt_all += nodeCntB_f * (ABC_order - 1);
                }
                System.Diagnostics.Debug.Assert(Ez_Pz.Length == free_node_cnt_all);

                Ez_Pz_Prev.CopyTo(Ez_Pz_Prev2, 0);
                Ez_Pz.CopyTo(Ez_Pz_Prev, 0);
                for (int ino = 0; ino < free_node_cnt_all; ino++)
                {
                    Ez_Pz[ino] = 0.0;
                }

                //--------------------------------------------------------------
                // 残差
                //--------------------------------------------------------------
                double[] resVec = new double[free_node_cnt_all];

                double[] vec_MMat = new double[free_node_cnt];
                double[] vec_KMat = new double[free_node_cnt];
                for (int ino = 0; ino < free_node_cnt; ino++)
                {
                    vec_MMat[ino] = (2.0 / (dt * dt)) * Ez_Pz_Prev[ino] - (1.0 / (dt * dt)) * Ez_Pz_Prev2[ino];
                    vec_KMat[ino] = -(1.0 - 2.0 * newmarkBeta) * Ez_Pz_Prev[ino] - newmarkBeta * Ez_Pz_Prev2[ino];
                }
                vec_MMat = MyMatrixUtil.product_native(
                    MMat, (int)free_node_cnt, (int)free_node_cnt,
                    vec_MMat, (int)free_node_cnt);
                vec_KMat = MyMatrixUtil.product_native(
                    KMat, (int)free_node_cnt, (int)free_node_cnt,
                    vec_KMat, (int)free_node_cnt);
                double[] resVec_0 = MyMatrixUtil.plus(vec_MMat, vec_KMat);
                resVec_0.CopyTo(resVec, 0);

                // 吸収境界
                // Φ1の開始位置
                int[] nodeIndex_Pz1_List = new int[portCnt];
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    if (portIndex == 0)
                    {
                        nodeIndex_Pz1_List[portIndex] = (int)free_node_cnt;
                    }
                    else
                    {
                        int nodeCntB_f_PrevPort = sortedNodes_Port_List[portIndex - 1].Count;
                        nodeIndex_Pz1_List[portIndex] = nodeIndex_Pz1_List[portIndex - 1] + nodeCntB_f_PrevPort  * (ABC_order - 1);
                    }
                }

                // Ezに関する式
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    // 境界の節点番号リスト
                    IList<uint> sortedNodes_Port = sortedNodes_Port_List[portIndex];
                    // 境界の節点数(強制境界を含まない)
                    int nodeCntB_f = sortedNodes_Port.Count;
                    double[] QbMat = QbMatList[portIndex];
                    System.Diagnostics.Debug.Assert(QbMat.Length == (nodeCntB_f * nodeCntB_f));
                    double b0_abc = b0_abc_List[portIndex];

                    double[] work_Ez_Prev2 = new double[nodeCntB_f];
                    double[] work_Pz_order_2_Prev = new double[nodeCntB_f];
                    double[] work_Pz_order_2_Prev2 = new double[nodeCntB_f];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        // Ez
                        work_Ez_Prev2[ino] = 0.0;
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            //強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        work_Ez_Prev2[ino] = Ez_Pz_Prev2[ino_f];
                    }

                    if (ABC_order > 1)
                    {
                        for (int ino = 0; ino < nodeCntB_f; ino++)
                        {
                            // Φ1
                            int ino_f = ino + nodeIndex_Pz1_List[portIndex];
                            work_Pz_order_2_Prev[ino] = Ez_Pz_Prev[ino_f];
                            work_Pz_order_2_Prev2[ino] = Ez_Pz_Prev2[ino_f];
                        }
                    }

                    double[] vec_QbMat = new double[nodeCntB_f];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        vec_QbMat[ino] = (b0_abc / (2.0 * dt)) * work_Ez_Prev2[ino];
                        if (ABC_order > 1)
                        {
                            vec_QbMat[ino] +=
                                (1.0 - 2.0 * newmarkBeta) * work_Pz_order_2_Prev[ino]
                                + newmarkBeta * work_Pz_order_2_Prev2[ino];
                        }
                    }
                    vec_QbMat = MyMatrixUtil.product_native(
                        QbMat, nodeCntB_f, nodeCntB_f,
                        vec_QbMat, nodeCntB_f);

                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            //強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        resVec[ino_f] += vec_QbMat[ino];
                    }
                }

                // Φ1 ~ Φ(ABC_order - 1)
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    IList<uint> sortedNodes_Port = sortedNodes_Port_List[portIndex];
                    int nodeCntB_f = sortedNodes_Port.Count;
                    double[] QbMat = QbMatList[portIndex];
                    double[] RbMat = RbMatList[portIndex];
                    double[] TbMat = TbMatList[portIndex];
                    double[] velo = velo_List[portIndex];
                    double b0_abc = b0_abc_List[portIndex];
                    //double[] a_abc = a_abc_List[portIndex]; // 一様媒質の場合
                    double[] b_abc = b_abc_List[portIndex];

                    // Φorderに関する式
                    for (int order = 0; order < (ABC_order - 1); order++)
                    {
                        double[] work_Pz_order_0_Prev2 = new double[nodeCntB_f];
                        double[] work_Pz_order_1_Prev = new double[nodeCntB_f];
                        double[] work_Pz_order_1_Prev2 = new double[nodeCntB_f];
                        double[] work_Pz_order_2_Prev = new double[nodeCntB_f];
                        double[] work_Pz_order_2_Prev2 = new double[nodeCntB_f];
                        for (int ino = 0; ino < nodeCntB_f; ino++)
                        {
                            int ino_f = 0;
                            // Φorder
                            ino_f = ino + nodeCntB_f * (order) + nodeIndex_Pz1_List[portIndex];
                            work_Pz_order_0_Prev2[ino] = Ez_Pz_Prev2[ino_f];

                            // Φorder-1
                            ino_f = 0;
                            if (order == 0)
                            {
                                // Φ0 (Ez)
                                uint ino_global = sortedNodes_Port[ino];
                                if (!toSorted.ContainsKey(ino_global))
                                {
                                    //強制境界は除外済み
                                    System.Diagnostics.Debug.Assert(false);
                                    continue;
                                }
                                ino_f = (int)toSorted[ino_global];
                            }
                            else
                            {
                                ino_f = ino + nodeCntB_f * (order - 1) + nodeIndex_Pz1_List[portIndex];
                            }
                            work_Pz_order_1_Prev[ino] = Ez_Pz_Prev[ino_f];
                            work_Pz_order_1_Prev2[ino] = Ez_Pz_Prev2[ino_f];

                            // Φ(order + 1)
                            if (order == (ABC_order - 2))
                            {
                                // なし
                                work_Pz_order_2_Prev[ino] = 0.0;
                                work_Pz_order_2_Prev2[ino] = 0.0;
                            }
                            else
                            {
                                ino_f = ino + nodeCntB_f * (order + 1) + nodeIndex_Pz1_List[portIndex];
                                work_Pz_order_2_Prev[ino] = Ez_Pz_Prev[ino_f];
                                work_Pz_order_2_Prev2[ino] = Ez_Pz_Prev2[ino_f];
                            }
                        }
                        double[] vec_QbMat = new double[nodeCntB_f];
                        double[] vec_RbMat = new double[nodeCntB_f];
                        double[] vec_TbMat = new double[nodeCntB_f]; // 媒質定数がy方向に変化する場合
                        for (int ino = 0; ino < nodeCntB_f; ino++)
                        {
                            // 一様媒質の場合
                            //vec_QbMat[ino] =
                            //    (b_abc[order] / (2.0 * dt)) * work_Pz_order_0_Prev2[ino]
                            //    + (a_abc[order] / (dt * dt)) * (
                            //      -2.0 * work_Pz_order_1_Prev[ino] + work_Pz_order_1_Prev2[ino]
                            //      )
                            //    + (
                            //      (1.0 - 2.0 * newmarkBeta) * work_Pz_order_2_Prev[ino]
                            //      + newmarkBeta * work_Pz_order_2_Prev2[ino]
                            //      );
                            // 媒質定数がy方向に変化する場合
                            vec_QbMat[ino] =
                                (b_abc[order] / (2.0 * dt)) * work_Pz_order_0_Prev2[ino]
                                + (1.0 / (velo[order] * velo[order] * dt * dt)) * (
                                  -2.0 * work_Pz_order_1_Prev[ino] + work_Pz_order_1_Prev2[ino]
                                  )
                                + (
                                  (1.0 - 2.0 * newmarkBeta) * work_Pz_order_2_Prev[ino]
                                  + newmarkBeta * work_Pz_order_2_Prev2[ino]
                                  );
                            // 媒質定数がy方向に変化する場合
                            vec_TbMat[ino] =
                                (-1.0 / (c0 * c0 * dt * dt)) * (
                                  -2.0 * work_Pz_order_1_Prev[ino] + work_Pz_order_1_Prev2[ino]
                                  );
                            // 共用
                            vec_RbMat[ino] =
                                -1.0 * (
                                    (1.0 - 2.0 * newmarkBeta) * work_Pz_order_1_Prev[ino]
                                    + newmarkBeta * work_Pz_order_1_Prev2[ino]
                                  );
                        }
                        vec_QbMat = MyMatrixUtil.product_native(
                            QbMat, nodeCntB_f, nodeCntB_f,
                            vec_QbMat, nodeCntB_f);
                        vec_RbMat = MyMatrixUtil.product_native(
                            RbMat, nodeCntB_f, nodeCntB_f,
                            vec_RbMat, nodeCntB_f);
                        vec_TbMat = MyMatrixUtil.product_native(
                            TbMat, nodeCntB_f, nodeCntB_f,
                            vec_TbMat, nodeCntB_f);

                        for (int ino = 0; ino < nodeCntB_f; ino++)
                        {
                            int ino_f = ino + nodeCntB_f * (order) + nodeIndex_Pz1_List[portIndex];
                            resVec[ino_f] = vec_QbMat[ino] + vec_RbMat[ino] + vec_TbMat[ino];
                        }
                    }
                }

                //--------------------------------------------------------------
                // 励振源
                //--------------------------------------------------------------
                {
                    int portIndex = portCnt; // ポートリストの最後の要素が励振境界
                    // 境界の節点番号リスト
                    IList<uint> sortedNodes_Port = sortedNodes_Port_List[portIndex];
                    // 境界の節点数(強制境界を含まない)
                    int nodeCntB_f = sortedNodes_Port.Count;
                    double[] QbMat = QbMatList[portIndex];
                    double betaXSrc = betaXSrcList[portIndex];
                    double[] profileSrc = profileSrcList[portIndex];

                    double srcF1 = 0.0;
                    double srcF2 = 0.0;
                    double srcF0 = 0.0;

                    int n = timeIndex;
                    // ガウシアンパルス
                    if ((n * dt) <= (2.0 * gaussianT0 + dt))
                    {
                        /*
                        // ガウシアンパルス
                        srcF1 = Math.Exp(-1.0 * ((n + 1) * dt - gaussianT0) * ((n + 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF2 = Math.Exp(-1.0 * ((n - 1) * dt - gaussianT0) * ((n - 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF0 = Math.Exp(-1.0 * ((n) * dt - gaussianT0) * ((n) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                         */

                        // 正弦波変調ガウシアンパルス
                        srcF1 = Math.Cos(omegaSrc * ((n + 1) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n + 1) * dt - gaussianT0) * ((n + 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF2 = Math.Cos(omegaSrc * ((n - 1) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n - 1) * dt - gaussianT0) * ((n - 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF0 = Math.Cos(omegaSrc * ((n) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n) * dt - gaussianT0) * ((n) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                    }

                    /*
                    // 正弦波
                    srcF1 = Math.Sin(omegaSrc * (n + 1) * dt);
                    srcF2 = Math.Sin(omegaSrc * (n - 1) * dt);
                    srcF0 = Math.Sin(omegaSrc * (n) * dt);
                     */

                    // 境界積分
                    double[] srcdFdt = new double[nodeCntB_f];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        double normalizeFactor = -1.0;
                        srcdFdt[ino] = normalizeFactor * profileSrc[ino] * (srcF1 - srcF2) / (2.0 * dt);
                    }
                    double vpx = omegaSrc / betaXSrc;
                    double[] vec_QbMat = MyMatrixUtil.product((-2.0 / vpx), srcdFdt);
                    vec_QbMat = MyMatrixUtil.product_native(
                        QbMat, nodeCntB_f, nodeCntB_f,
                        vec_QbMat, nodeCntB_f);
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            // 強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        resVec[ino_f] += vec_QbMat[ino];
                    }

                    /*
                    // 領域積分
                    double[] srcdFdt2_f = new double[free_node_cnt];
                    double[] srcF_f = new double[free_node_cnt];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            // 強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        double normalizeFactor = -1.0;
                        //double normalizeFactor = -omegaSrc * myu0 / betaXSrc;
                        srcF_f[ino_f] = normalizeFactor * profileSrc[ino] * srcF0;
                        srcdFdt2_f[ino_f] = normalizeFactor * profileSrc[ino] * (srcF1 - 2.0 * srcF0 + srcF2) / (dt * dt);
                    }
                    double[] vec_MMatSrc = MyMatrixUtil.product_native(
                        MMat, (int)free_node_cnt, (int)free_node_cnt,
                        srcdFdt2_f, (int)free_node_cnt
                        );
                    double[] vec_KMatSrc = MyMatrixUtil.product_native(
                        KMat, (int)free_node_cnt, (int)free_node_cnt,
                        srcF_f, (int)free_node_cnt
                        );
                    for (int ino = 0; ino < free_node_cnt; ino++)
                    {
                        resVec[ino] += vec_MMatSrc[ino] + vec_KMatSrc[ino];
                    }
                     */
                }

                //------------------------------------------------------------------
                // Ezを求める
                //------------------------------------------------------------------
                /*
                // 連立方程式を解く
                {
                    int matLen = (int)free_node_cnt_all;
                    double[] A = new double[matLen * matLen];
                    AMat.CopyTo(A, 0); // コピーを取る
                    double[] B = resVec;

                    double[] X = null;
                    int x_row = matLen;
                    int x_col = 1;
                    int a_row = matLen;
                    int a_col = matLen;
                    int b_row = matLen;
                    int b_col = 1;
                    KrdLab.clapack.Function.dgesv(ref X, ref x_row, ref x_col, A, a_row, a_col, B, b_row, b_col);

                    X.CopyTo(Ez_Pz, 0);
                }
                 */

                // 逆行列を用いる
                Ez_Pz = MyMatrixUtil.product_native(
                    AMat, (int)free_node_cnt_all, (int)free_node_cnt_all,
                    resVec, (int)free_node_cnt_all
                    );

                // 電界を取得
                double[] Ez = new double[free_node_cnt];
                for (int ino = 0; ino < free_node_cnt; ino++)
                {
                    Ez[ino] = Ez_Pz[ino];
                }

                // 観測点
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    // 頂点IDから1を引いたものが節点番号
                    uint nodeNumber = VIdRefList[portIndex] - 1;
                    int ino_f = (int)toSorted[nodeNumber];
                    double fVal = Ez[ino_f];
                    if (portIndex == 0)
                    {
                        if (EzTimeAryPort1 != null)
                        {
                            EzTimeAryPort1.Add(fVal);
                        }
                    }
                    else if (portIndex == 1)
                    {
                        if (EzTimeAryPort2 != null)
                        {
                            EzTimeAryPort2.Add(fVal);
                        }
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                    }
                }

                // 解ベクトルをワールド座標系にセット
                WgUtil.SetFieldValueForDisplay(World, FieldValId, Ez, toSorted);

                if ((timeIndex + 1) % 50 == 0)
                {
                    Console.WriteLine("{0}", (timeIndex + 1));
                }

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, IsSolveStraightWg, Camera);
                }
                success = true;

            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
            }
            return success;
        }
コード例 #2
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="betaIndex"></param>
        /// <param name="Beta1"></param>
        /// <param name="Beta2"></param>
        /// <param name="BetaDelta"></param>
        /// <param name="initFlg"></param>
        /// <param name="WaveguideWidth"></param>
        /// <param name="WaveModeDv"></param>
        /// <param name="IsPCWaveguide"></param>
        /// <param name="latticeA"></param>
        /// <param name="periodicDistance"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="CalcModeIndex"></param>
        /// <param name="isSVEA"></param>
        /// <param name="PrevModalVec"></param>
        /// <param name="IsShowAbsField"></param>
        /// <param name="MinNormalizedFreq"></param>
        /// <param name="MaxNormalizedFreq"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="FieldLoopId"></param>
        /// <param name="FieldForceBcId"></param>
        /// <param name="FieldPortBcId1"></param>
        /// <param name="FieldPortBcId2"></param>
        /// <param name="Medias"></param>
        /// <param name="LoopDic"></param>
        /// <param name="EdgeDic"></param>
        /// <param name="EigenValueList"></param>
        /// <param name="DrawerAry"></param>
        /// <param name="Camera"></param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int betaIndex,
            double Beta1,
            double Beta2,
            double BetaDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            bool IsPCWaveguide,
            double latticeA,
            double periodicDistance,
            IList<IList<uint>> PCWaveguidePorts,
            int CalcModeIndex,
            bool isSVEA,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            bool IsShowAbsField,
            double MinNormalizedFreq,
            double MaxNormalizedFreq,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            ref IList<Complex> EigenValueList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            bool showException = true;
            try
            {
                // 緩慢変化包絡線近似 SVEA(slowly varying envelope approximation)で表現?
                //  true: v = v(x, y)exp(-jβx)と置いた場合
                //  false: 直接Bloch境界条件を指定する場合
                //bool isSVEA = false; // falseの時の方が妥当な解が得られる
                //bool isSVEA = false;
                // モード追跡する?
                bool isModeTrace = true;
                if (!IsPCWaveguide)
                {
                    isModeTrace = false;
                }
                System.Diagnostics.Debug.WriteLine("isSVEA: {0}", isSVEA);
                System.Diagnostics.Debug.WriteLine("isModeTrace: {0}, CalcModeIndex: {1}", isModeTrace, CalcModeIndex);

                if (betaIndex == 0)
                {
                    PrevModalVec = null;
                }

                // 規格化伝搬定数
                double beta = getBeta(
                    ref betaIndex,
                    Beta1,
                    Beta2,
                    BetaDelta);
                if (betaIndex == -1)
                {
                    return success;
                }
                System.Diagnostics.Debug.WriteLine("beta: {0}    beta*d/(2.0 * pi): {1}",
                    beta,
                    beta * periodicDistance / (2.0 * pi));

                if (probNo == 3)
                {
                    /*
                    // probNo == 3 theta = 45 defectRodCnt = 3 even 1st
                    if (beta < 0.32 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                     */

                    /*
                    // probNo == 3 theta = 60 defectRodCnt = 1 r = 0.30 even
                    if (beta < 0.20 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                     */

                    /*
                    // probNo == 3 theta = 30 defectRodCnt = 1 r = 0.30 n = 3.4 even
                    if (beta < 0.08 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.92 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */

                    /*
                    // probNo == 3 theta = 60 defectRodCnt = 1 r = 0.35 even
                    if (beta < 0.08 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.92 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */
                    /*
                    // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 even 1st
                    if (beta < 0.16 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                     */
                    /*
                    // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 even 2nd
                    if (beta > 0.39 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */
                    /*
                    // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 odd 2nd
                    if (beta > 0.20 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */

                    if (beta < 0.10 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }

                }
                else if (probNo == 5)
                {
                    /*
                    // for latticeTheta = 60 r = 0.30a  n = 3.4 air hole even 1st above decoupling point
                    // for latticeTheta = 60 r = 0.30a  n = 3.4 air hole odd 1st above decoupling point
                    if (beta < 0.13 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.2501 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */
                    /*
                    // for latticeTheta = 60 r = 0.30a air hole  n = 3.4 even 1st below decoupling point
                    // for latticeTheta = 60 r = 0.30a air hole  n = 3.4 odd 1st below decoupling point
                    if (beta < 0.2501 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.4801 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */

                    /*
                    // for latticeTheta = 60 r = 0.30a  n = 2.76 air hole even 1st above & below decoupling point
                    if (beta < 0.1601 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.4801 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */
                    /*
                    // for latticeTheta = 60 r = 0.30a  n = 2.76 air hole odd 1st above decoupling point
                    if (beta < 0.1601 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.2601 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }
                     */

                    // for latticeTheta = 60 r = 0.30a air hole  n = 2.76 even 1st below decoupling point
                    // for latticeTheta = 60 r = 0.30a air hole  n = 2.76 odd 1st below decoupling point
                    if (beta < 0.2601 * (2.0 * pi / periodicDistance))
                    {
                        showException = false;
                        throw new Exception();
                    }
                    if (beta > 0.4801 * (2.0 * pi / periodicDistance))
                    {
                        betaIndex = -1;
                        return success;
                    }

                }

                // 全節点数を取得する
                uint node_cnt = 0;
                node_cnt = WgUtilForPeriodicEigenBetaSpecified.GetNodeCnt(World, FieldLoopId);

                System.Diagnostics.Debug.WriteLine("node_cnt: {0}", node_cnt);

                // 境界の節点リストを取得する
                uint[] no_c_all_fieldForceBcId = null;
                Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out no_c_all_fieldForceBcId, out to_no_boundary_fieldForceBcId);
                }
                uint[] no_c_all_fieldPortBcId1 = null;
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = null;
                WgUtil.GetBoundaryNodeList(World, FieldPortBcId1, out no_c_all_fieldPortBcId1, out to_no_boundary_fieldPortBcId1);
                uint[] no_c_all_fieldPortBcId2 = null;
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = null;
                WgUtil.GetBoundaryNodeList(World, FieldPortBcId2, out no_c_all_fieldPortBcId2, out to_no_boundary_fieldPortBcId2);

                // 節点のソート
                IList<uint> sortedNodes = new List<uint>();
                Dictionary<uint, int> toSorted = new Dictionary<uint, int>();
                //   境界1と境界2は周期構造条件より同じ界の値をとる
                // ポート境界1
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点を追加
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc1)) continue;
                    }
                    sortedNodes.Add(nodeNumberPortBc1);
                    int nodeIndex = sortedNodes.Count - 1;
                    toSorted.Add(nodeNumberPortBc1, nodeIndex);
                }
                uint boundary_node_cnt = (uint)sortedNodes.Count; // 境界1
                // 内部領域
                for (uint nodeNumber = 0; nodeNumber < node_cnt; nodeNumber++)
                {
                    // 追加済み節点はスキップ
                    //if (toSorted.ContainsKey(nodeNumber)) continue;
                    // 境界1は除く
                    if (to_no_boundary_fieldPortBcId1.ContainsKey(nodeNumber)) continue;
                    // 境界2は除く
                    if (to_no_boundary_fieldPortBcId2.ContainsKey(nodeNumber)) continue;
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumber)) continue;
                    }
                    sortedNodes.Add(nodeNumber);
                    toSorted.Add(nodeNumber, sortedNodes.Count - 1);
                }
                uint free_node_cnt = (uint)sortedNodes.Count;  // 境界1 + 内部領域
                for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
                {
                    // 境界2の節点を追加
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i];
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc2)) continue;
                    }
                    sortedNodes.Add(nodeNumberPortBc2);
                    int nodeIndex = sortedNodes.Count - 1;
                    toSorted.Add(nodeNumberPortBc2, nodeIndex);
                }
                uint free_node_cnt0 = (uint)sortedNodes.Count;  // 境界1 + 内部領域 + 境界2

                // 剛性行列、質量行列を作成
                KrdLab.clapack.Complex[] KMat0 = null;
                KrdLab.clapack.Complex[] MMat0 = null;
                {
                    KrdLab.clapack.Complex betaForMakingMat = 0.0;
                    if (isSVEA)
                    {
                        betaForMakingMat = new KrdLab.clapack.Complex(beta, 0.0); // v = v(x, y)exp(-jβx)と置いた場合
                    }
                    else
                    {
                        betaForMakingMat = 0.0; // 直接Bloch境界条件を指定する場合
                    }
                    WgUtilForPeriodicEigenBetaSpecified.MkPeriodicHelmholtzMat(
                        betaForMakingMat,
                        false, // isYDirectionPeriodic: false
                        World,
                        FieldLoopId,
                        Medias,
                        LoopDic,
                        node_cnt,
                        free_node_cnt0,
                        toSorted,
                        out KMat0,
                        out MMat0);
                }

                // 境界2の節点は境界1の節点と同一とみなす
                //   境界上の分割が同じであることが前提条件
                KrdLab.clapack.Complex[] KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
                KrdLab.clapack.Complex[] MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
                /*
                // v = v(x, y)exp(-jβx)と置いた場合
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                    }
                }
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] += KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        MMat[i + free_node_cnt * j] += MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                    }
                }
                for (int i = 0; i < boundary_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                    }
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                    }
                }
                 */
                // 直接Bloch境界条件を指定する場合
                KrdLab.clapack.Complex expA = 1.0;
                if (isSVEA)
                {
                    expA = 1.0;
                }
                else
                {
                    expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * beta * periodicDistance);
                }
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                    }
                }
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] += expA * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        MMat[i + free_node_cnt * j] += expA * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                    }
                }
                for (int i = 0; i < boundary_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] += (1.0 / expA) * KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] += (1.0 / expA) * MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                    }
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        //KMat[i + free_node_cnt * j] += (1.0 / expA) * expA * KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        //MMat[i + free_node_cnt * j] += (1.0 / expA) * expA * MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        //より下記と等価
                        KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                    }
                }

                // 規格化周波数
                KrdLab.clapack.Complex complexNormalizedFreq_ans = 0.0;
                // 界ベクトルは全節点分作成
                KrdLab.clapack.Complex[] resVec = null;
                resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点

                {
                    int matLen = (int)free_node_cnt;
                    KrdLab.clapack.Complex[] evals = null;
                    KrdLab.clapack.Complex[,] evecs = null;
                    KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[KMat.Length];
                    KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[MMat.Length];
                    for (int i = 0; i < matLen * matLen; i++)
                    {
                        A[i] = KMat[i];
                        B[i] = MMat[i];
                    }
                    /*
                    // 一般化複素固有値解析
                    //   [A],[B]は内部で書き換えられるので注意
                    KrdLab.clapack.Complex[] ret_evals = null;
                    KrdLab.clapack.Complex[][] ret_evecs = null;
                    System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev");
                    KrdLab.clapack.FunctionExt.zggev(A, matLen, matLen, B, matLen, matLen, ref ret_evals, ref ret_evecs);

                    evals = ret_evals;
                    System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length);
                    // 2次元配列に格納する
                    evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen];
                    for (int i = 0; i < ret_evecs.Length; i++)
                    {
                        KrdLab.clapack.Complex[] ret_evec = ret_evecs[i];
                        for (int j = 0; j < ret_evec.Length; j++)
                        {
                            evecs[i, j] = ret_evec[j];
                        }
                    }
                     */
                    // エルミートバンド行列の固有値解析
                    {
                        KrdLab.clapack.Complex[] ret_evals = null;
                        KrdLab.clapack.Complex[,] ret_evecs = null;
                        solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref ret_evals, ref ret_evecs);
                        evals = ret_evals;
                        evecs = ret_evecs;
                    }

                    // 固有値のソート
                    WgUtilForPeriodicEigenBetaSpecified.Sort1DEigenMode(evals, evecs);
                    /*
                    // check
                    for (int imode = 0; imode < evals.Length; imode++)
                    {
                        // 固有周波数
                        KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]);
                        // 規格化周波数
                        KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi));
                        System.Diagnostics.Debug.WriteLine("a/λ  ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i ");
                    }
                     */
                    // 欠陥モードを取得
                    IList<int> defectModeIndexList = new List<int>();
                    // フォトニック結晶導波路解析用
                    if (IsPCWaveguide)
                    {
                        int hitModeIndex = -1;
                        double hitNorm = 0.0;
                        for (int imode = 0; imode < evals.Length; imode++)
                        {
                            // 固有周波数
                            KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]);
                            // 規格化周波数
                            KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi));
                            // 界ベクトル
                            KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode);

                            // フォトニック結晶導波路の導波モードを判定する
                            System.Diagnostics.Debug.Assert(free_node_cnt == fieldVec.Length);
                            bool isHitDefectMode = isDefectModeBetaSpecified(
                                free_node_cnt,
                                sortedNodes,
                                toSorted,
                                PCWaveguidePorts,
                                MinNormalizedFreq,
                                MaxNormalizedFreq,
                                complexNormalizedFreq,
                                fieldVec);

                            if (isHitDefectMode
                                && isModeTrace && PrevModalVec != null)
                            {
                                // 同じ固有モード?
                                double ret_norm = 0.0;
                                bool isHitSameMode = isSameModeBetaSpecified(
                                    node_cnt,
                                    PrevModalVec,
                                    free_node_cnt,
                                    sortedNodes,
                                    toSorted,
                                    PCWaveguidePorts,
                                    MinNormalizedFreq,
                                    MaxNormalizedFreq,
                                    complexNormalizedFreq,
                                    fieldVec,
                                    out ret_norm);
                                if (isHitSameMode)
                                {
                                    // より分布の近いモードを採用する
                                    if (Math.Abs(ret_norm - 1.0) < Math.Abs(hitNorm - 1.0))
                                    {
                                        hitModeIndex = imode;
                                        hitNorm = ret_norm;
                                        System.Diagnostics.Debug.WriteLine("PC defectMode(ModeTrace): a/λ  ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i ");
                                    }
                                }
                            }
                            if (isHitDefectMode)
                            {
                                System.Diagnostics.Debug.WriteLine("PC defectMode: a/λ  ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i ");
                                if (!isModeTrace || PrevModalVec == null) // モード追跡でないとき、またはモード追跡用の参照固有モードベクトルがないとき
                                {
                                    defectModeIndexList.Add(imode);
                                }
                            }
                        }
                        if (isModeTrace && hitModeIndex != -1)
                        {
                            System.Diagnostics.Debug.Assert(defectModeIndexList.Count == 0);
                            System.Diagnostics.Debug.WriteLine("hitModeIndex: {0}", hitModeIndex);
                            defectModeIndexList.Add(hitModeIndex);
                        }
                    }
                    // 基本モードを取得する(k0^2最小値)
                    int tagtModeIndex = 0;
                    // フォトニック結晶導波路解析用
                    if (IsPCWaveguide)
                    {
                        tagtModeIndex = -1;
                        if (isModeTrace && PrevModalVec != null)
                        {
                            if (defectModeIndexList.Count > 0)
                            {
                                tagtModeIndex = defectModeIndexList[0];
                            }
                        }
                        else
                        {
                            if (defectModeIndexList.Count > 0)
                            {
                                if ((defectModeIndexList.Count - 1) >= CalcModeIndex)
                                {
                                    tagtModeIndex = defectModeIndexList[CalcModeIndex];
                                }
                                else
                                {
                                    tagtModeIndex = -1;
                                }
                            }
                            else
                            {
                                tagtModeIndex = -1;
                                System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not converged photonic crystal waveguide mode");
                            }
                        }
                    }
                    if (tagtModeIndex == -1)
                    {
                        System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode");
                        complexNormalizedFreq_ans = 0;
                        for (int i = 0; i < resVec.Length; i++)
                        {
                            resVec[i] = 0;
                        }
                    }
                    else
                    {
                        // 伝搬定数、固有ベクトルの格納
                        KrdLab.clapack.Complex complex_k0_eigen_ans = KrdLab.clapack.Complex.Sqrt(evals[tagtModeIndex]);
                        complexNormalizedFreq_ans = latticeA * (complex_k0_eigen_ans / (2.0 * pi));
                        KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIndex);
                        System.Diagnostics.Debug.WriteLine("a/λ  ( " + tagtModeIndex + " ) = " + complexNormalizedFreq_ans.Real + " + " + complexNormalizedFreq_ans.Imaginary + " i ");
                        for (int ino = 0; ino < evec.Length; ino++)
                        {
                            //System.Diagnostics.Debug.WriteLine("    ( " + imode + ", " + ino + " ) = " + evec[ino].Real + " + " + evec[ino].Imaginary + " i ");
                            uint nodeNumber = sortedNodes[ino];
                            resVec[nodeNumber] = evec[ino];
                        }
                    }
                }

                // ポート境界1の節点の値を境界2にも格納する
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1];

                    // 境界2の節点
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[no_c_all_fieldPortBcId2.Length - 1 - i];
                    //resVec[nodeNumberPortBc2] = cvalue; // v = v(x, y)exp(-jβx)と置いた場合
                    resVec[nodeNumberPortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合
                }

                // 位相調整
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    /*
                    for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++)
                    {
                        uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                        KrdLab.clapack.Complex cvalue = resVec[ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                     */
                    for (int ino = 0; ino < resVec.Length; ino++)
                    {
                        KrdLab.clapack.Complex cvalue = resVec[ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                }
                if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    phaseShift = fValueAtMaxAbs / maxAbs;
                }
                System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi);
                for (int i = 0; i < resVec.Length; i++)
                {
                    resVec[i] /= phaseShift;
                }

                // 前回の固有ベクトルを更新
                if (isModeTrace && complexNormalizedFreq_ans.Real != 0.0 && Math.Abs(complexNormalizedFreq_ans.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    //PrevModalVec = resVec;
                    PrevModalVec = new KrdLab.clapack.Complex[node_cnt];
                    resVec.CopyTo(PrevModalVec, 0);
                }
                else
                {
                    // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように)
                    //PrevModalVec = null;
                }

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 固有ベクトルの計算結果をワールド座標系にセットする
                WgUtilForPeriodicEigenBetaSpecified.SetFieldValueForDisplay(World, FieldValId, resVec);

                // 表示用にデータを格納する
                if (betaIndex == 0)
                {
                    EigenValueList.Clear();
                }

                // 表示用加工
                Complex evalueToShow = new Complex(complexNormalizedFreq_ans.Real, complexNormalizedFreq_ans.Imaginary);
                EigenValueList.Add(evalueToShow);

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                if (showException)
                {
                    Console.WriteLine(exception.Message + " " + exception.StackTrace);
                }
                // 表示用にデータを格納する
                if (betaIndex == 0)
                {
                    EigenValueList.Clear();
                }
                EigenValueList.Add(new Complex(0.0, 0.0));

                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }
コード例 #3
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="timeIndex">時刻のインデックス</param>
        /// <param name="timeLoopCnt">時間計算回数</param>
        /// <param name="newmarkBeta">Newmarkβ法のβ</param>
        /// <param name="timeDelta">時刻刻み</param>
        /// <param name="gaussianT0">ガウシアンパルスの遅延時間</param>
        /// <param name="gaussianTp">ガウシアンパルスの時間幅</param>
        /// <param name="NormalizedFreqSrc">励振するモードの規格化周波数</param>
        /// <param name="VIdRefList">観測点の頂点ID(= 節点番号 + 1)</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">導波路幅</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループのフィールドID</param>
        /// <param name="FieldForceBcId">強制境界のフィールドID</param>
        /// <param name="FieldPortBcIdList">ポート1、ポート2、励振面の境界のフィールドID</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="node_cnt">節点数(強制境界を含む)</param>
        /// <param name="sortedNodes">ソート済み節点番号リスト</param>
        /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param>
        /// <param name="sortedNodes_Port_List">境界のソート済み節点番号リスト(ポート1,ポート2,励振面)</param>
        /// <param name="toSorted_Port_List">境界の節点番号→ソート済み節点インデックスマップ(ポート1,ポート2,励振面)</param>
        /// <param name="KMat">剛性行列</param>
        /// <param name="MMat">質量行列</param>
        /// <param name="QbMatSrc">境界質量行列(励振面)</param>
        /// <param name="betaXSrc">境界の伝搬定数(励振面)</param>
        /// <param name="profileSrc">境界のモード分布(励振面)</param>
        /// <param name="AMat">係数行列(逆行列)</param>
        /// <param name="Ez">電界分布(現在)</param>
        /// <param name="Ez_Prev">電界分布(1つ前)</param>
        /// <param name="Ez_Prev2">電界分布(2つ前)</param>
        /// <param name="EzTimeAryPort1">ポート1観測点の電界リスト(時間変化)</param>
        /// <param name="EzTimeAryPort2">ポート2観測点の電界リスト(時間変化)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            bool IsSolveStraightWg,
            ref int timeIndex,
            int timeLoopCnt,
            double newmarkBeta,
            double timeDelta,
            double gaussianT0,
            double gaussianTp,
            double NormalizedFreqSrc,
            double NormalizedFreq1,
            double NormalizedFreq2,
            bool initFlg,
            double WaveguideWidth,
            bool isPCWaveguide,
            double latticeA,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            IList<uint> FieldPmlLoopIdList,
            IList<bool> IsPmlYDirectionList,
            IList<double> PmlStPosXList,
            IList<double> PmlLengthList,
            uint FieldPortSrcBcId,
            IList<uint> VIdRefList,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            bool IsShowAbsField,
            int node_cnt,
            IList<uint> sortedNodes,
            Dictionary<uint, uint> toSorted,
            IList<uint> sortedNodes_PortSrc,
            Dictionary<uint, uint> toSorted_PortSrc,
            MyDoubleBandMatrix KMat,
            MyDoubleBandMatrix MMat,
            double[] QbMatSrc,
            double betaXSrc,
            double[] profileSrc,
            double[] AMat,
            ref double[] Ez,
            ref double[] Ez_Prev,
            ref double[] Ez_Prev2,
            ref double[][][][] W2_F_e_List,
            ref double[][][][] W2_G_e_List,
            ref IList<double> EzTimeAryPort1,
            ref IList<double> EzTimeAryPort2,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;

            // ポート数
            int portCnt = FieldPmlLoopIdList.Count;

            // 時刻の取得
            if (timeIndex == -1)
            {
                return success;
            }
            if (timeIndex >= timeLoopCnt)
            {
                timeIndex = -1;
                return success;
            }
            // 以下curTimeIndexに対する計算
            double curTime = timeIndex * timeDelta;

            double dt = timeDelta;

            try
            {
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);

                // 励振源のパラメータ
                // 波数
                double k0Src = NormalizedFreqSrc * pi / WaveguideWidth;
                // 波長
                double waveLengthSrc = 2.0 * pi / k0Src;
                // 周波数
                double freqSrc = c0 / waveLengthSrc;
                // 角周波数
                double omegaSrc = 2.0 * pi * freqSrc;

                //--------------------------------------------------------------
                // 電界
                //--------------------------------------------------------------
                uint free_node_cnt = (uint)sortedNodes.Count;
                uint free_node_cnt_all = free_node_cnt;
                System.Diagnostics.Debug.Assert(Ez.Length == free_node_cnt_all);

                Ez_Prev.CopyTo(Ez_Prev2, 0);
                Ez.CopyTo(Ez_Prev, 0);
                for (int ino = 0; ino < free_node_cnt_all; ino++)
                {
                    Ez[ino] = 0.0;
                }

                //--------------------------------------------------------------
                // 残差
                //--------------------------------------------------------------
                double[] vec_MMat = new double[free_node_cnt];
                double[] vec_KMat = new double[free_node_cnt];
                for (int ino = 0; ino < free_node_cnt; ino++)
                {
                    vec_MMat[ino] = (2.0 / (dt * dt)) * Ez_Prev[ino] - (1.0 / (dt * dt)) * Ez_Prev2[ino];
                    vec_KMat[ino] = -(1.0 - 2.0 * newmarkBeta) * Ez_Prev[ino] - newmarkBeta * Ez_Prev2[ino];
                }
                vec_MMat = MyMatrixUtil.product(
                    MMat,
                    vec_MMat, (int)free_node_cnt);
                vec_KMat = MyMatrixUtil.product(
                    KMat,
                    vec_KMat, (int)free_node_cnt);

                double[] resVec = MyMatrixUtil.plus(vec_MMat, vec_KMat);
                System.Diagnostics.Debug.Assert(resVec.Length == free_node_cnt_all);

                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    uint workFieldPmlLoopId =FieldPmlLoopIdList[portIndex];
                    bool workIsPmlYDirection = IsPmlYDirectionList[portIndex];
                    double workPmlPosX = PmlStPosXList[portIndex];
                    double workPmlLength = PmlLengthList[portIndex];
                    double[][][] work_w2_F_e_list = W2_F_e_List[portIndex];
                    double[][][] work_w2_G_e_list = W2_G_e_List[portIndex];
                    WgUtilForTDPml.AddPmlResVec(
                        timeIndex,
                        World,
                        workFieldPmlLoopId,
                        workIsPmlYDirection,
                        workPmlPosX,
                        workPmlLength,
                        dt,
                        newmarkBeta,
                        Medias,
                        LoopDic,
                        (uint)node_cnt,
                        free_node_cnt,
                        toSorted,
                        Ez_Prev,
                        Ez_Prev2,
                        ref work_w2_F_e_list,
                        ref work_w2_G_e_list,
                        ref resVec
                        );
                    // 再格納
                    W2_F_e_List[portIndex] = work_w2_F_e_list;
                    W2_G_e_List[portIndex] = work_w2_G_e_list;
                }

                //--------------------------------------------------------------
                // 励振源
                //--------------------------------------------------------------
                {
                    int portIndex = portCnt; // ポートリストの最後の要素が励振境界
                    // 境界の節点番号リスト
                    IList<uint> sortedNodes_Port = sortedNodes_PortSrc;
                    // 境界の節点数(強制境界を含まない)
                    int nodeCntB_f = sortedNodes_Port.Count;
                    double[] QbMat = QbMatSrc;

                    if (isPCWaveguide)
                    {

                        //////////
                        //TEST 中央に点波源を置く
                        profileSrc = new double[profileSrc.Length];
                        profileSrc[profileSrc.Length / 2] = 1.0;

                        /*
                        ///////////
                        // TEST: 欠陥部を平面波励振する
                        //betaXSrc = k0Src;
                        profileSrc = new double[profileSrc.Length];
                        for (int i = 0; i < 5; i++)
                        {
                            profileSrc[profileSrc.Length / 2 - 2 + i] = 1.0;
                        }
                         */
                    }

                    double srcF1 = 0.0;
                    double srcF2 = 0.0;
                    double srcF0 = 0.0;

                    int n = timeIndex;
                    // ガウシアンパルス
                    if ((n * dt) <= (2.0 * gaussianT0 + dt))
                    {
                        /*
                        // ガウシアンパルス
                        srcF1 = Math.Exp(-1.0 * ((n + 1) * dt - gaussianT0) * ((n + 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF2 = Math.Exp(-1.0 * ((n - 1) * dt - gaussianT0) * ((n - 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF0 = Math.Exp(-1.0 * ((n) * dt - gaussianT0) * ((n) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                         */

                        // 正弦波変調ガウシアンパルス
                        srcF1 = Math.Cos(omegaSrc * ((n + 1) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n + 1) * dt - gaussianT0) * ((n + 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF2 = Math.Cos(omegaSrc * ((n - 1) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n - 1) * dt - gaussianT0) * ((n - 1) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));
                        srcF0 = Math.Cos(omegaSrc * ((n) * dt - gaussianT0))
                                * Math.Exp(-1.0 * ((n) * dt - gaussianT0) * ((n) * dt - gaussianT0) / (2.0 * gaussianTp * gaussianTp));

                    }

                    /*
                    // 正弦波
                    srcF1 = Math.Sin(omegaSrc * (n + 1) * dt);
                    srcF2 = Math.Sin(omegaSrc * (n - 1) * dt);
                    srcF0 = Math.Sin(omegaSrc * (n) * dt);
                     */

                    // 境界積分
                    double[] srcdFdt = new double[nodeCntB_f];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        double normalizeFactor = -1.0;
                        srcdFdt[ino] = normalizeFactor * profileSrc[ino] * (srcF1 - srcF2) / (2.0 * dt);
                    }
                    double vpx = omegaSrc / betaXSrc;
                    double[] vec_QbMat = MyMatrixUtil.product((-2.0 / vpx), srcdFdt);
                    vec_QbMat = MyMatrixUtil.product_native(
                        QbMat, nodeCntB_f, nodeCntB_f,
                        vec_QbMat, nodeCntB_f);
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            // 強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        resVec[ino_f] += vec_QbMat[ino];
                    }

                    /*
                    // 領域積分
                    double[] srcdFdt2_f = new double[free_node_cnt];
                    double[] srcF_f = new double[free_node_cnt];
                    for (int ino = 0; ino < nodeCntB_f; ino++)
                    {
                        uint ino_global = sortedNodes_Port[ino];
                        if (!toSorted.ContainsKey(ino_global))
                        {
                            // 強制境界は除外済み
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int ino_f = (int)toSorted[ino_global];
                        double normalizeFactor = -1.0;
                        //double normalizeFactor = -omegaSrc * myu0 / betaXSrc;
                        srcF_f[ino_f] = normalizeFactor * profileSrc[ino] * srcF0;
                        srcdFdt2_f[ino_f] = normalizeFactor * profileSrc[ino] * (srcF1 - 2.0 * srcF0 + srcF2) / (dt * dt);
                    }
                    double[] vec_MMatSrc = MyMatrixUtil.product_native(
                        MMat, (int)free_node_cnt, (int)free_node_cnt,
                        srcdFdt2_f, (int)free_node_cnt
                        );
                    double[] vec_KMatSrc = MyMatrixUtil.product_native(
                        KMat, (int)free_node_cnt, (int)free_node_cnt,
                        srcF_f, (int)free_node_cnt
                        );
                    for (int ino = 0; ino < free_node_cnt; ino++)
                    {
                        resVec[ino] += vec_MMatSrc[ino] + vec_KMatSrc[ino];
                    }
                     */
                }

                //------------------------------------------------------------------
                // Ezを求める
                //------------------------------------------------------------------
                /*
                // 連立方程式を解く
                {
                    int matLen = (int)free_node_cnt_all;
                    double[] A = new double[matLen * matLen];
                    AMat.CopyTo(A, 0); // コピーを取る
                    double[] B = resVec;

                    double[] X = null;
                    int x_row = matLen;
                    int x_col = 1;
                    int a_row = matLen;
                    int a_col = matLen;
                    int b_row = matLen;
                    int b_col = 1;
                    KrdLab.clapack.Function.dgesv(ref X, ref x_row, ref x_col, A, a_row, a_col, B, b_row, b_col);

                    X.CopyTo(Ez, 0);
                }
                 */

                // 逆行列を用いる
                Ez = MyMatrixUtil.product_native(
                    AMat, (int)free_node_cnt_all, (int)free_node_cnt_all,
                    resVec, (int)free_node_cnt_all
                    );

                // 観測点
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    // 頂点IDから1を引いたものが節点番号
                    uint nodeNumber = VIdRefList[portIndex] - 1;
                    int ino_f = (int)toSorted[nodeNumber];
                    double fVal = Ez[ino_f];
                    if (portIndex == 0)
                    {
                        if (EzTimeAryPort1 != null)
                        {
                            EzTimeAryPort1.Add(fVal);
                        }
                    }
                    else if (portIndex == 1)
                    {
                        if (EzTimeAryPort2 != null)
                        {
                            EzTimeAryPort2.Add(fVal);
                        }
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                    }
                }

                // 解ベクトルをワールド座標系にセット
                WgUtil.SetFieldValueForDisplay(World, FieldValId, Ez, toSorted);

                if ((timeIndex + 1) % 50 == 0)
                {
                    Console.WriteLine("{0}", (timeIndex + 1));
                }

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, IsSolveStraightWg, Camera);
                }
                success = true;

            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
            }
            return success;
        }
コード例 #4
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="freqIndex">計算する周波数のインデックス</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="FreqDelta">計算刻み幅</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">波長</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループの値のフィールドID</param>
        /// <param name="FieldForceBcId">強制境界の値のフィールドID</param>
        /// <param name="WgPortInfoList">入出力導波路情報リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsInoutWgSame">同じ入出力導波路?</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="Ls">リニアシステム</param>
        /// <param name="Prec">プリコンディショナ―</param>
        /// <param name="ScatterVecList">散乱係数リスト(ポート毎のモード散乱係数リストのリスト)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int freqIndex,
            double NormalizedFreq1,
            double NormalizedFreq2,
            double FreqDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            IList<WgUtilForPeriodicEigenExt.WgPortInfo> WgPortInfoList,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            bool IsInoutWgSame,
            bool IsShowAbsField,
            ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec,
            ref IList<IList<Complex[]>> ScatterVecList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            // ポート数
            int portCnt = WgPortInfoList.Count;
            // モード電力の合計を出力として表示する
            //bool isShowTotalPortPower = true;
            bool isShowTotalPortPower = false;
            // PC導波路?
            bool isPCWaveguide = false;
            foreach (WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo in WgPortInfoList)
            {
                if (workWgPortInfo.IsPCWaveguide)
                {
                    isPCWaveguide = true;
                    break;
                }
            }
            //// モード追跡する?
            //bool isModeTrace = true;
            //if (!isPCWaveguide)
            //{
            //    isModeTrace = false;
            //}

            // モード追跡用の固有ベクトル格納先の初期化
            if (freqIndex == 0)
            {
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    WgPortInfoList[portIndex].PrevModalVecList = null;
                }
            }
            try
            {

                // 規格化周波数
                double normalizedFreq = getNormalizedFreq(
                    ref freqIndex,
                    NormalizedFreq1,
                    NormalizedFreq2,
                    FreqDelta);
                if (freqIndex == -1)
                {
                    return success;
                }
                // 格子定数
                double latticeA = 0.0;
                double periodicDistance = 0.0;
                if (portCnt > 0)
                {
                    latticeA = WgPortInfoList[0].LatticeA;
                    periodicDistance = WgPortInfoList[0].PeriodicDistance;
                }
                // 波数
                double k0 = 0;
                if (isPCWaveguide)
                {
                    k0 = normalizedFreq * 2.0 * pi / latticeA;
                    System.Diagnostics.Debug.WriteLine("a/λ:{0}", normalizedFreq);
                }
                else
                {
                    k0 = normalizedFreq * pi / WaveguideWidth;
                    System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq);
                }
                // 波長
                double waveLength = 2.0 * pi / k0;

                //------------------------------------------------------------------
                // リニアシステム
                //------------------------------------------------------------------
                Ls.Clear();
                Prec.Clear();
                WgUtil.GC_Collect();

                //------------------------------------------------------------------
                // 界パターン追加
                //------------------------------------------------------------------
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);
                // 領域全体の界パターンを追加
                Ls.AddPattern_Field(FieldValId, World);

                // 上記界パターンでは、隣接する要素以外の剛性行列の値は追加できないようです。境界用に追加パターンを作成
                foreach (WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo in WgPortInfoList)
                {
                    WgUtil.MakeWaveguidePortBCPattern(Ls, World, workWgPortInfo.FieldPortBcId);
                }

                //------------------------------------------------------------------
                // 固定境界条件を設定
                //------------------------------------------------------------------
                if (FieldForceBcId != 0)
                {
                    Ls.SetFixedBoundaryCondition_Field(FieldForceBcId, 0, World); // 固定境界条件を設定
                }
                uint[] fixedBcNodes = null;
                // 強制境界条件を課す節点を取得する
                // 境界の固有モード解析で強制境界を指定する際に使用する(CZLinearSystemのBCFlagを参照できないので)
                Dictionary<uint, uint> tmp_to_no_boundary = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out fixedBcNodes, out tmp_to_no_boundary);
                }

                //------------------------------------------------------------------
                // 剛性行列、残差ベクトルのマージ
                //------------------------------------------------------------------
                Ls.InitializeMarge();

                IList<double[,]> ryy_1d_port_list = new List<double[,]>();
                IList<Complex[]> eigen_values_port_list = new List<Complex[]>();
                IList<Complex[,]> eigen_vecs_port_list = new List<Complex[,]>();
                IList<Complex[,]> eigen_dFdXs_port_list = new List<Complex[,]>();

                // 境界の界に導波路開口条件を追加
                bool retAddPort = false;

                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo = WgPortInfoList[portIndex];

                    if (!IsInoutWgSame || (IsInoutWgSame && portIndex == 0))
                    {
                        // 導波路開口1
                        double[,] ryy_1d_port1 = null;
                        Complex[] eigen_values_port1 = null;
                        Complex[,] eigen_vecs_port1 = null;
                        Complex[,] eigen_dFdXs_port1 = null;
                        bool isModeTrace = workWgPortInfo.IsModeTrace;
                        if (!workWgPortInfo.IsPCWaveguide)
                        {
                            isModeTrace = false;
                        }
                        retAddPort = WgUtilForPeriodicEigenExt.GetPortPeriodicWaveguideFemMatAndEigenVec(
                            Ls,
                            waveLength,
                            WaveModeDv,
                            World,
                            workWgPortInfo.FieldInputWgLoopId,
                            workWgPortInfo.FieldPortBcId,
                            workWgPortInfo.FieldInputWgBcId,
                            fixedBcNodes,
                            workWgPortInfo.IsPCWaveguide,
                            workWgPortInfo.LatticeA,
                            workWgPortInfo.PeriodicDistance,
                            workWgPortInfo.PCWaveguidePorts,
                            workWgPortInfo.IncidentModeIndex,
                            workWgPortInfo.IsSolveEigenItr,
                            workWgPortInfo.PropModeCntToSolve,
                            workWgPortInfo.IsSVEA,
                            isModeTrace,
                            ref workWgPortInfo.PrevModalVecList,
                            workWgPortInfo.MinEffN,
                            workWgPortInfo.MaxEffN,
                            workWgPortInfo.MinWaveNum,
                            workWgPortInfo.MaxWaveNum,
                            Medias,
                            workWgPortInfo.InputWgLoopDic,
                            workWgPortInfo.InputWgEdgeDic,
                            (portIndex == 0) ? true : false, // isPortBc2Reverse : 周期構造導波路の外部境界と内部境界の辺の方向が逆かどうかを指定する。
                                                             //                    図面の作成手順より、ポート1の場合true ポート2の場合false
                            out ryy_1d_port1,
                            out eigen_values_port1,
                            out eigen_vecs_port1,
                            out eigen_dFdXs_port1);
                        /*
                        // DEBUG モード確認
                        {
                            //暫定描画処理
                            DrawerAry.Clear();
                            DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                            DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                            // カメラの変換行列初期化
                            DrawerAry.InitTrans(Camera);
                            return true;
                        }
                         */
                        // 格納する
                        ryy_1d_port_list.Add(ryy_1d_port1);
                        eigen_values_port_list.Add(eigen_values_port1);
                        eigen_vecs_port_list.Add(eigen_vecs_port1);
                        eigen_dFdXs_port_list.Add(eigen_dFdXs_port1);

                        // 入射モードチェック
                        if (retAddPort)
                        {
                            if ((workWgPortInfo.IncidentModeIndex >= eigen_values_port_list[portIndex].Length)
                                || (Math.Abs(eigen_values_port_list[portIndex][workWgPortInfo.IncidentModeIndex].Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 入射モードが伝搬モードでない
                                )
                            {
                                retAddPort = false;
                            }
                        }
                    }
                    else if (IsInoutWgSame && portIndex != 0)
                    {
                        double[,] ryy_1d_port2 = null;
                        Complex[] eigen_values_port2 = null;
                        Complex[,] eigen_vecs_port2 = null;
                        Complex[,] eigen_dFdXs_port2 = null;

                        //  出力側は入力側と同じ導波路とする
                        double[,] ryy_1d_port1 = ryy_1d_port_list[0];
                        Complex[] eigen_values_port1 = eigen_values_port_list[0];
                        Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[0];
                        Complex[,] eigen_dFdXs_port1 = eigen_dFdXs_port_list[0];
                        ryy_1d_port2 = new double[ryy_1d_port1.GetLength(0), ryy_1d_port1.GetLength(1)];
                        for (int i = 0; i < ryy_1d_port2.GetLength(0); i++)
                        {
                            // 位置を反転
                            for (int j = 0; j < ryy_1d_port2.GetLength(1); j++)
                            {
                                double value = ryy_1d_port1[ryy_1d_port2.GetLength(0) - 1 - i, ryy_1d_port2.GetLength(1) - 1 - j];
                                ryy_1d_port2[i, j] = value;
                            }
                        }
                        eigen_values_port2 = new Complex[eigen_values_port1.Length];
                        eigen_vecs_port2 = new Complex[eigen_vecs_port1.GetLength(0), eigen_vecs_port1.GetLength(1)];
                        eigen_dFdXs_port2 = new Complex[eigen_dFdXs_port1.GetLength(0), eigen_dFdXs_port1.GetLength(1)];
                        for (int i = 0; i < eigen_vecs_port2.GetLength(0); i++)
                        {
                            Complex betam = eigen_values_port1[i];
                            eigen_values_port2[i] = betam;
                            // 位置を反転
                            for (int j = 0; j < eigen_vecs_port2.GetLength(1); j++)
                            {
                                eigen_vecs_port2[i, j] = eigen_vecs_port1[i, eigen_vecs_port2.GetLength(1) - 1 - j];
                                eigen_dFdXs_port2[i, j] = eigen_dFdXs_port1[i, eigen_dFdXs_port2.GetLength(1) - 1 - j];
                            }
                        }

                        // 格納する
                        ryy_1d_port_list.Add(ryy_1d_port2);
                        eigen_values_port_list.Add(eigen_values_port2);
                        eigen_vecs_port_list.Add(eigen_vecs_port2);
                        eigen_dFdXs_port_list.Add(eigen_dFdXs_port2);
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                        retAddPort = false;
                    }
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                                int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                                if (isShowTotalPortPower)
                                {
                                    propModeCnt = 1;
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        {
                            DrawerAry.Clear();
                            Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                            DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                            DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                            // カメラの変換行列初期化
                            DrawerAry.InitTrans(Camera);
                            // 表示位置調整
                            setupPanAndScale(probNo, Camera);
                        }
                        return false;
                    }

                    // 入射振幅を指定する(全モード入射)
                    Complex[] work_amps = null;
                    if (probNo == 13)
                    {
                        if (workWgPortInfo.IsIncidentPort)
                        {
                            /*
                            work_amps = Problem13_2.GetIncidentAmplitude(
                                World,
                                workWgPortInfo.FieldPortBcId,
                                workWgPortInfo.PCWaveguidePorts,
                                eigen_values_port_list[portIndex],
                                eigen_vecs_port_list[portIndex]);
                             */
                            /*
                            work_amps = Problem13_3.GetIncidentAmplitude(
                                World,
                                workWgPortInfo.FieldPortBcId,
                                workWgPortInfo.PCWaveguidePorts,
                                eigen_values_port_list[portIndex],
                                eigen_vecs_port_list[portIndex]);
                             */
                        }
                    }
                    workWgPortInfo.Amps = work_amps;

                    retAddPort = WgUtilForPeriodicEigenExt.AddLinSys_PeriodicWaveguidePortBC(
                        Ls,
                        waveLength,
                        WaveModeDv,
                        workWgPortInfo.PeriodicDistance,
                        World,
                        workWgPortInfo.FieldInputWgLoopId,
                        workWgPortInfo.FieldPortBcId,
                        fixedBcNodes,
                        workWgPortInfo.IsIncidentPort, // isInputPort : true
                        workWgPortInfo.IncidentModeIndex,
                        workWgPortInfo.Amps,
                        false, // isFreeBc: false:モード展開  true:PMLを装荷する場合、Sommerfeld境界条件を適用する場合
                        ryy_1d_port_list[portIndex],
                        eigen_values_port_list[portIndex],
                        eigen_vecs_port_list[portIndex],
                        eigen_dFdXs_port_list[portIndex]);
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                                int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                                if (isShowTotalPortPower)
                                {
                                    propModeCnt = 1;
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        return false;
                    }
                    System.Diagnostics.Debug.WriteLine("port{0} node_cnt: {1}", (portIndex + 1), eigen_vecs_port_list[portIndex].GetLength(1));
                }
                /*
                // TEST Sommerfelt
                CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(Ls, waveLength, World, FieldPortBcId1);
                CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(Ls, waveLength, World, FieldPortBcId2);
                 */
                /*
                //  散乱係数計算用に1のモード分布をセット
                ryy_1d_port2 = ryy_1d_port1;
                eigen_values_port2 = eigen_values_port1;
                eigen_vecs_port2 = eigen_vecs_port1;
                eigen_dFdXs_port2 = eigen_dFdXs_port1;
                */

                // 領域
                WgUtil.AddLinSysHelmholtz(Ls, waveLength, World, FieldLoopId
                    , Medias, LoopDic);

                double res = Ls.FinalizeMarge();
                //System.Diagnostics.Debug.WriteLine("Residual : " + res);

                //------------------------------------------------------------------
                // プリコンディショナ―
                //------------------------------------------------------------------
                // set Preconditioner
                //Prec.SetFillInLevel(1);
                //Prec.SetFillInLevel(int.MaxValue);  // 対称でなくても解けてしまう
                // ILU(0)のパターン初期化
                //Prec.SetLinearSystem(Ls);

                //------------------------------------------------------------------
                // リニアシステムを解く
                //------------------------------------------------------------------
                // メモリを解放する
                WgUtil.GC_Collect();
                /*
                // プリコンディショナに値を設定してILU分解を行う
                Prec.SetValue(Ls);
                double tol = 1.0e-6;
                uint maxIter = 2000;
                uint iter = maxIter;
                CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
                if (iter == maxIter)
                {
                    Console.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                    System.Diagnostics.Debug.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                }
                //System.Diagnostics.Debug.WriteLine("Solved!");

                // 計算結果をワールド座標系に反映する
                Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                 */

                //// 非対称複素行列の連立方程式をclapackで解く
                //solveAsymmetricCompplexMatEqn(Ls, World, FieldValId);

                // 非対称複素帯行列の連立方程式をclapackで解く
                solveAsymmetricComplexBandMatEqn(Ls, World, FieldValId);

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 反射、透過係数
                double totalPower = 0.0;
                int incidentPortNo = getIncidentPortNo(WgPortInfoList);
                IList<Complex[]> portScatterVecList = new List<Complex[]>();
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    Complex[] eigen_values_port1 = eigen_values_port_list[portIndex];
                    double[,] ryy_1d_port1 = ryy_1d_port_list[portIndex];
                    Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[portIndex];
                    Complex[,] eigen_dFdXs_port1 = eigen_dFdXs_port_list[portIndex];
                    WgUtilForPeriodicEigenExt.WgPortInfo wgPortInfo1 = WgPortInfoList[portIndex];
                    int propModeCntToShow = wgPortInfo1.PropModeCntToSolve;
                    if (isShowTotalPortPower)
                    {
                        propModeCntToShow = 1;
                    }
                    Complex[] scatterVec = new Complex[propModeCntToShow];
                    for (int m = 0; m < propModeCntToShow; m++)
                    {
                        scatterVec[m] = 0.0;
                    }

                    for (uint imode = 0; imode < eigen_values_port1.Length; imode++)
                    {
                        if (Math.Abs(eigen_values_port1[imode].Real) >= 1.0e-12 && Math.Abs(eigen_values_port1[imode].Imag) < 1.0e-12)
                        {
                            Complex s11 = 0.0;
                            bool isIncidentMode = (wgPortInfo1.IsIncidentPort && imode == wgPortInfo1.IncidentModeIndex);
                            if (wgPortInfo1.Amps != null)
                            {
                                // 全モード入射の時
                                isIncidentMode = wgPortInfo1.IsIncidentPort;
                            }
                            s11 = WgUtilForPeriodicEigenExt.GetPeriodicWaveguidePortReflectionCoef(
                                Ls,
                                waveLength,
                                WaveModeDv,
                                wgPortInfo1.PeriodicDistance,
                                World,
                                wgPortInfo1.FieldPortBcId,
                                imode,
                                isIncidentMode,
                                wgPortInfo1.Amps,
                                ryy_1d_port1,
                                eigen_values_port1,
                                eigen_vecs_port1,
                                eigen_dFdXs_port1);
                            System.Diagnostics.Debug.WriteLine("    s" + (portIndex + 1) + incidentPortNo + " = (" + s11.Real + "," + s11.Imag + ")" + " |s" + (portIndex + 1) + incidentPortNo + "|^2 = " + Complex.SquaredNorm(s11) + ((imode == wgPortInfo1.IncidentModeIndex) ? "  incident" : ""));
                            if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                            {
                                totalPower += Complex.SquaredNorm(s11);
                            }
                            if (isShowTotalPortPower)
                            {
                                // ポート電力を計算
                                scatterVec[0] += Complex.Norm(s11) * Complex.Norm(s11);
                            }
                            else
                            {
                                if (imode < propModeCntToShow)
                                {
                                    scatterVec[imode] = s11;
                                }
                            }
                        }
                    }
                    portScatterVecList.Add(scatterVec);
                }
                System.Diagnostics.Debug.WriteLine("    totalPower = {0}", totalPower);
                if (isShowTotalPortPower)
                {
                    for (int p = 0; p < portCnt; p++)
                    {
                        // ルート電力に変換
                        Complex[] scatterVec = portScatterVecList[p];
                        double sqrtPower = Math.Sqrt(Complex.Norm(scatterVec[0]));
                        scatterVec[0] = sqrtPower;
                        //portScatterVecList[p] = scatterVec;
                        System.Diagnostics.Debug.WriteLine("port total sqrt power s{0}{1} : {2}", (p + 1), incidentPortNo, sqrtPower);
                    }
                }

                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    ScatterVecList.Add(portScatterVecList);
                }

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                    for (int p = 0; p < portCnt; p++)
                    {
                        WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                        int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                        if (isShowTotalPortPower)
                        {
                            propModeCnt = 1;
                        }
                        Complex[] work_scatterVec = new Complex[propModeCnt];
                        for (int imode = 0; imode < propModeCnt; imode++)
                        {
                            work_scatterVec[imode] = 0;
                        }
                        work_portScatterVecList.Add(work_scatterVec);
                    }
                    ScatterVecList.Add(work_portScatterVecList);
                }
                {
                    DrawerAry.Clear();
                    Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                    DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                    DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);
                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }
コード例 #5
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="freqIndex">周波数のインデックス</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="FreqDelta">計算刻み幅</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">導波路幅</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループのフィールドID</param>
        /// <param name="FieldForceBcId">強制境界のフィールドID</param>
        /// <param name="FieldPortBcId1">ポート1境界のフィールドID</param>
        /// <param name="FieldPortBcId2">ポート2境界のフィールドID</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="Ls">リニアシステム</param>
        /// <param name="Prec">プリコンディショナ―</param>
        /// <param name="ScatterVecList">散乱係数リスト(ポート毎のモード散乱係数リストのリスト)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int freqIndex,
            double NormalizedFreq1,
            double NormalizedFreq2,
            double FreqDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            IList<MediaInfo> Medias,
            Dictionary<uint, World.Loop> LoopDic,
            Dictionary<uint, World.Edge> EdgeDic,
            bool IsShowAbsField,
            ref CZLinearSystem Ls,
            ref CZPreconditioner_ILU Prec,
            ref IList<IList<Complex[]>> ScatterVecList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            // 入射モードインデックス
            int incidentModeIndex = 0;
            // ポート数
            int portCnt = 2;
            int incidentPortNo = getIncidentPortNo();
            int propModeCnt_port1 = 1;
            int propModeCnt_port2 = 1;
            // モード電力の合計を出力として表示する
            bool isShowTotalPortPower = false;
            if (probNo == 3)
            {
                /*
                // 入力5モード表示
                //propModeCnt_port1 = 5;
                //propModeCnt_port2 = 1;
                // 出力5モード表示
                //propModeCnt_port1 = 1;
                //propModeCnt_port2 = 5;
                propModeCnt_port1 = 3;
                propModeCnt_port2 = 3;
                 */
                //isShowTotalPortPower = true; // モード電力の合計を出力として表示する
            }
            try
            {

                // 規格化周波数
                double normalizedFreq = getNormalizedFreq(
                    ref freqIndex,
                    NormalizedFreq1,
                    NormalizedFreq2,
                    FreqDelta);
                if (freqIndex == -1)
                {
                    return success;
                }
                // 波数
                double k0 = normalizedFreq * pi / WaveguideWidth;
                // 波長
                double waveLength = 2.0 * pi / k0;
                System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq);

                //------------------------------------------------------------------
                // リニアシステム
                //------------------------------------------------------------------
                Ls.Clear();
                Prec.Clear();
                WgUtil.GC_Collect();

                //------------------------------------------------------------------
                // 界パターン追加
                //------------------------------------------------------------------
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);
                // 領域全体の界パターンを追加
                Ls.AddPattern_Field(FieldValId, World);

                // 上記界パターンでは、隣接する要素以外の剛性行列の値は追加できないようです。境界用に追加パターンを作成
                uint[] fieldPortBcId_list = {FieldPortBcId1, FieldPortBcId2};
                System.Diagnostics.Debug.Assert(fieldPortBcId_list.Length == portCnt);
                foreach (uint workFieldPortBcId in fieldPortBcId_list)
                {
                    WgUtil.MakeWaveguidePortBCPattern(Ls, World, workFieldPortBcId);
                }

                //------------------------------------------------------------------
                // 固定境界条件を設定
                //------------------------------------------------------------------
                if (FieldForceBcId != 0)
                {
                    Ls.SetFixedBoundaryCondition_Field(FieldForceBcId, 0, World); // 固定境界条件を設定
                }
                uint[] fixedBcNodes = null;
                // 強制境界条件を課す節点を取得する
                // 境界の固有モード解析で強制境界を指定する際に使用する(CZLinearSystemのBCFlagを参照できないので)
                Dictionary<uint, uint> tmp_to_no_boundary = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out fixedBcNodes, out tmp_to_no_boundary);
                }
                //------------------------------------------------------------------
                // プリコンディショナ―
                //------------------------------------------------------------------
                // set Preconditioner
                //Prec.SetFillInLevel(1);
                uint fillInLevel = 1;
                if (probNo == 3)
                {
                    // 誘電体スラブ導波路ではILU(1)では収束しないので、フィルインレベルを大きくとる
                    fillInLevel = 15;
                }
                System.Diagnostics.Debug.WriteLine("fillInLevel: {0}", fillInLevel);
                Prec.SetFillInLevel(fillInLevel);

                // ILU(0)のパターン初期化
                Prec.SetLinearSystem(Ls);

                //------------------------------------------------------------------
                // 剛性行列、残差ベクトルのマージ
                //------------------------------------------------------------------
                Ls.InitializeMarge();

                IList<double[,]> ryy_1d_port_list = new List<double[,]>();
                IList<Complex[]> eigen_values_port_list = new List<Complex[]>();
                IList<Complex[,]> eigen_vecs_port_list = new List<Complex[,]>();
                System.Diagnostics.Debug.Assert(incidentPortNo == 1);

                // 境界の界に導波路開口条件を追加
                bool retAddPort = false;

                // 境界の界に導波路開口条件を追加
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    uint workFieldPortBcId = fieldPortBcId_list[portIndex];
                    double[,] ryy_1d_port1 = null;
                    Complex[] eigen_values_port1 = null;
                    Complex[,] eigen_vecs_port1 = null;
                    retAddPort = WgUtil.AddLinSys_WaveguidePortBC(
                        Ls,
                        waveLength,
                        WaveModeDv,
                        World,
                        workFieldPortBcId,
                        fixedBcNodes,
                        (portIndex == (incidentPortNo - 1)),
                        incidentModeIndex,
                        Medias,
                        EdgeDic,
                        out ryy_1d_port1,
                        out eigen_values_port1,
                        out eigen_vecs_port1);
                    // 格納する
                    ryy_1d_port_list.Add(ryy_1d_port1);
                    eigen_values_port_list.Add(eigen_values_port1);
                    eigen_vecs_port_list.Add(eigen_vecs_port1);
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                int propModeCnt = 0;
                                if (p == 0)
                                {
                                    propModeCnt = propModeCnt_port1;
                                }
                                else if (p == 1)
                                {
                                    propModeCnt = propModeCnt_port2;
                                }
                                else
                                {
                                    System.Diagnostics.Debug.Assert(false);
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        return false;
                    }
                    System.Diagnostics.Debug.WriteLine("port{0} node_cnt: {1}", (portIndex + 1), eigen_vecs_port_list[portIndex].GetLength(1));
                }

                // 領域
                WgUtil.AddLinSysHelmholtz(Ls, waveLength, World, FieldLoopId, Medias, LoopDic);

                double res = Ls.FinalizeMarge();
                //System.Diagnostics.Debug.WriteLine("Residual : " + res);

                //------------------------------------------------------------------
                // リニアシステムを解く
                //------------------------------------------------------------------
                // プリコンディショナに値を設定してILU分解を行う
                Prec.SetValue(Ls);
                double tol = 1.0e-6;
                uint maxIter = 2000;
                uint iter = maxIter;
                CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
                if (iter == maxIter)
                {
                    Console.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                    System.Diagnostics.Debug.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                }
                //System.Diagnostics.Debug.WriteLine("Solved!");

                // 計算結果をワールド座標系に反映する
                Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 反射、透過係数
                double totalPower = 0.0;
                IList<Complex[]> portScatterVecList = new List<Complex[]>();
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    Complex[] eigen_values_port1 = eigen_values_port_list[portIndex];
                    double[,] ryy_1d_port1 = ryy_1d_port_list[portIndex];
                    Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[portIndex];
                    int propModeCnt = 0;
                    if (portIndex == 0)
                    {
                        propModeCnt = propModeCnt_port1;
                    }
                    else if (portIndex == 1)
                    {
                        propModeCnt = propModeCnt_port2;
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                    }
                    Complex[] scatterVec = new Complex[propModeCnt];
                    for (int m = 0; m < propModeCnt; m++)
                    {
                        scatterVec[m] = 0.0;
                    }

                    uint workFieldPortBcId = fieldPortBcId_list[portIndex];
                    for (uint imode = 0; imode < eigen_values_port1.Length; imode++)
                    {
                        Complex s11 = WgUtil.GetWaveguidePortReflectionCoef(
                            Ls,
                            waveLength,
                            WaveModeDv,
                            World,
                            workFieldPortBcId,
                            imode,
                            ((portIndex == (incidentPortNo - 1)) && imode == incidentModeIndex),
                            ryy_1d_port1,
                            eigen_values_port1,
                            eigen_vecs_port1);
                        if (imode < propModeCnt || Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                        {
                            System.Diagnostics.Debug.WriteLine("    s" + (portIndex + 1) + incidentPortNo + " = (" + s11.Real + "," + s11.Imag + ")" + " |s" + (portIndex + 1) + incidentPortNo + "|^2 = " + Complex.SquaredNorm(s11) + ((imode == 0) ? "  incident" : ""));
                        }
                        if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                            && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                        {
                            totalPower += Complex.SquaredNorm(s11);
                        }
                        if (isShowTotalPortPower)
                        {
                            if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                            {
                                // ポート電力を計算
                                scatterVec[0] += Complex.Norm(s11) * Complex.Norm(s11);
                            }
                        }
                        else
                        {
                            if (imode < propModeCnt)
                            {
                                scatterVec[imode] = s11;
                            }
                        }
                    }
                    portScatterVecList.Add(scatterVec);
                }
                System.Diagnostics.Debug.WriteLine("    totalPower = {0}", totalPower);
                if (isShowTotalPortPower)
                {
                    for (int p = 0; p < portCnt; p++)
                    {
                        // ルート電力に変換
                        Complex[] scatterVec = portScatterVecList[p];
                        double sqrtPower = Math.Sqrt(Complex.Norm(scatterVec[0]));
                        scatterVec[0] = sqrtPower;
                        //portScatterVecList[p] = scatterVec;
                        System.Diagnostics.Debug.WriteLine("port total sqrt power s{0}{1} : {2}", (p + 1), incidentPortNo, sqrtPower);
                    }
                }

                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    ScatterVecList.Add(portScatterVecList);
                }

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                    for (int p = 0; p < portCnt; p++)
                    {
                        int propModeCnt = 0;
                        if (p == 0)
                        {
                            propModeCnt = propModeCnt_port1;
                        }
                        else if (p == 1)
                        {
                            propModeCnt = propModeCnt_port2;
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false);
                        }
                        Complex[] work_scatterVec = new Complex[propModeCnt];
                        for (int imode = 0; imode < propModeCnt; imode++)
                        {
                            work_scatterVec[imode] = 0;
                        }
                        work_portScatterVecList.Add(work_scatterVec);
                    }
                    ScatterVecList.Add(work_portScatterVecList);
                }
            }
            return success;
        }
コード例 #6
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="betaIndex"></param>
        /// <param name="isTriLattice"></param>
        /// <param name="calcBetaCnt"></param>
        /// <param name="initFlg"></param>
        /// <param name="periodicDistanceY"></param>
        /// <param name="WaveModeDv"></param>
        /// <param name="latticeA"></param>
        /// <param name="periodicDistanceX"></param>
        /// <param name="IsShowAbsField"></param>
        /// <param name="MinNormalizedFreq"></param>
        /// <param name="MaxNormalizedFreq"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="FieldLoopId"></param>
        /// <param name="FieldForceBcId"></param>
        /// <param name="FieldPortBcIds"></param>
        /// <param name="Medias"></param>
        /// <param name="LoopDic"></param>
        /// <param name="EdgeDic"></param>
        /// <param name="EigenValueList"></param>
        /// <param name="DrawerAry"></param>
        /// <param name="Camera"></param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int betaIndex,
            bool isTriLattice,
            int calcBetaCnt,
            bool initFlg,
            double periodicDistanceY,
            WgUtil.WaveModeDV WaveModeDv,
            double latticeA,
            double periodicDistanceX,
            bool IsShowAbsField,
            double MinNormalizedFreq,
            double MaxNormalizedFreq,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            IList<uint> FieldPortBcIds,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            ref IList<Complex[]> EigenValueList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            bool showException = true;
            try
            {
                // 規格化伝搬定数
                double beta = 0.0;
                double betaX = 0.0;
                double betaY = 0.0;
                getBeta(
                    ref betaIndex,
                    isTriLattice,
                    calcBetaCnt,
                    latticeA,
                    periodicDistanceX,
                    periodicDistanceY,
                    ref betaX,
                    ref betaY);
                if (betaIndex == -1)
                {
                    return success;
                }
                System.Diagnostics.Debug.WriteLine("beta: {0}    beta*d/(2.0 * pi): {1}",
                    beta,
                    beta * latticeA / (2.0 * pi));

                // 全節点数を取得する
                uint node_cnt = 0;
                //node_cnt = WgUtilForPeriodicEigenBetaSpecified.GetNodeCnt(World, FieldLoopId);
                double[][] coord_c_all = null;
                {
                    uint[] no_c_all_tmp = null;
                    Dictionary<uint, uint> to_no_all_tmp = null;
                    double[][] coord_c_all_tmp = null;
                    WgUtilForPeriodicEigenBetaSpecified.GetLoopCoordList(World, FieldLoopId, out no_c_all_tmp, out to_no_all_tmp, out coord_c_all_tmp);
                    node_cnt = (uint)no_c_all_tmp.Length;

                    // 座標リストを節点番号順に並び替えて格納
                    coord_c_all = new double[node_cnt][];
                    for (int ino = 0; ino < node_cnt; ino++)
                    {
                        uint nodeNumber = no_c_all_tmp[ino];
                        double[] coord = coord_c_all_tmp[ino];
                        coord_c_all[nodeNumber] = coord;
                    }
                }

                System.Diagnostics.Debug.WriteLine("node_cnt: {0}", node_cnt);

                // 境界の節点リストを取得する
                uint[] no_c_all_fieldForceBcId = null;
                Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out no_c_all_fieldForceBcId, out to_no_boundary_fieldForceBcId);
                }
                int boundaryCnt = FieldPortBcIds.Count;
                IList<uint[]> no_c_all_fieldPortBcId_list = new List<uint[]>();
                IList<Dictionary<uint, uint>> to_no_boundary_fieldPortBcId_list = new List<Dictionary<uint, uint>>();
                for (int i = 0; i < boundaryCnt; i++)
                {
                    uint[] work_no_c_all_fieldPortBcId = null;
                    Dictionary<uint, uint> work_to_no_boundary_fieldPortBcId = null;
                    uint work_fieldPortBcId = FieldPortBcIds[i];
                    WgUtil.GetBoundaryNodeList(World, work_fieldPortBcId, out work_no_c_all_fieldPortBcId, out work_to_no_boundary_fieldPortBcId);
                    no_c_all_fieldPortBcId_list.Add(work_no_c_all_fieldPortBcId);
                    to_no_boundary_fieldPortBcId_list.Add(work_to_no_boundary_fieldPortBcId);
                }

                uint[] no_c_all_fieldPortBcId1 = no_c_all_fieldPortBcId_list[0];
                uint[] no_c_all_fieldPortBcId2 = no_c_all_fieldPortBcId_list[1];
                uint[] no_c_all_fieldPortBcId3 = no_c_all_fieldPortBcId_list[2];
                uint[] no_c_all_fieldPortBcId4 = no_c_all_fieldPortBcId_list[3];
                uint[] no_c_all_fieldPortBcId5 = null;
                uint[] no_c_all_fieldPortBcId6 = null;
                if (boundaryCnt == 6)
                {
                    no_c_all_fieldPortBcId5 = no_c_all_fieldPortBcId_list[4];
                    no_c_all_fieldPortBcId6 = no_c_all_fieldPortBcId_list[5];
                }
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = to_no_boundary_fieldPortBcId_list[0];
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = to_no_boundary_fieldPortBcId_list[1];
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId3 = to_no_boundary_fieldPortBcId_list[2];
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId4 = to_no_boundary_fieldPortBcId_list[3];
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId5 = null;
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId6 = null;
                if (boundaryCnt == 6)
                {
                    to_no_boundary_fieldPortBcId5 = to_no_boundary_fieldPortBcId_list[4];
                    to_no_boundary_fieldPortBcId6 = to_no_boundary_fieldPortBcId_list[5];
                }
                /////////////////////////////////////////////////////////////////
                // コーナーの節点
                uint[] sharedNodes = new uint[boundaryCnt];
                if (boundaryCnt == 6)
                {
                    // 六角形領域の場合
                    // 境界の始点
                    for (int boundaryIndex = 0; boundaryIndex < boundaryCnt; boundaryIndex++)
                    {
                        uint[] work_no_c_all_fieldPortBcId = no_c_all_fieldPortBcId_list[boundaryIndex];
                        Dictionary<uint, uint> work_to_no_boundary_fieldPortBcId_prev = to_no_boundary_fieldPortBcId_list[(boundaryIndex - 1 + boundaryCnt) % boundaryCnt];
                        for (int i = 0; i < work_no_c_all_fieldPortBcId.Length; i++)
                        {
                            uint work_nodeNumberPortBc = work_no_c_all_fieldPortBcId[i];
                            if (work_to_no_boundary_fieldPortBcId_prev.ContainsKey(work_nodeNumberPortBc))
                            {
                                // 前の境界との共有頂点
                                sharedNodes[boundaryIndex] = work_nodeNumberPortBc;
                                break;
                            }
                        }
                    }
                }
                else
                {
                    // 四角形領域の場合
                    System.Diagnostics.Debug.Assert(boundaryCnt == 4);
                    // 境界1の両端
                    for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                    {
                        uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                        if (to_no_boundary_fieldPortBcId4.ContainsKey(nodeNumberPortBc1))
                        {
                            // 境界1と境界4の共有の頂点
                            // 左上頂点
                            sharedNodes[0] = nodeNumberPortBc1;
                        }
                        // 境界1と境界3の共有の頂点
                        if (to_no_boundary_fieldPortBcId3.ContainsKey(nodeNumberPortBc1))
                        {
                            // 左下頂点
                            sharedNodes[1] = nodeNumberPortBc1;
                        }
                    }
                    // 境界2の両端
                    for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
                    {
                        // 境界2の節点を追加
                        uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i];
                        // 境界2と境界4の共有の頂点
                        if (to_no_boundary_fieldPortBcId4.ContainsKey(nodeNumberPortBc2))
                        {
                            // 右上頂点
                            sharedNodes[2] = nodeNumberPortBc2;
                        }
                        // 境界2と境界3の共有の頂点
                        if (to_no_boundary_fieldPortBcId3.ContainsKey(nodeNumberPortBc2))
                        {
                            // 右下頂点
                            sharedNodes[3] = nodeNumberPortBc2;
                        }
                    }
                }
                // 共有境界の節点座標
                double[][] sharedNodeCoords = new double[sharedNodes.Length][];
                for (int i = 0; i < sharedNodes.Length; i++)
                {
                    sharedNodeCoords[i] = coord_c_all[sharedNodes[i]];
                }

                /////////////////////////////////////////////////////////////////////////////////
                // 節点のソート
                IList<uint> sortedNodes = new List<uint>();
                Dictionary<uint, int> toSorted = new Dictionary<uint, int>();

                // 四角形領域の場合
                uint boundary_node_cnt_B1 = 0; // 境界1
                uint boundary_node_cnt_B3 = 0; // 境界3
                uint boundary_node_cnt = 0; // 境界1 + 3
                // 六角形領域の場合
                uint boundary_node_cnt_each = 0;
                uint free_node_cnt = 0;
                uint free_node_cnt0 = 0;

                // ソートされた節点を取得する
                if (boundaryCnt == 6)
                {
                    // 六角形領域の場合
                    uint work_boundary_node_cnt_B1 = 0;
                    uint work_boundary_node_cnt_B2 = 0;
                    uint work_boundary_node_cnt_B3 = 0;
                    uint work_boundary_node_cnt_B4 = 0;
                    uint work_boundary_node_cnt_B5 = 0;
                    uint work_boundary_node_cnt_B6 = 0;
                    getSortedNodes_Hex(
                        probNo,
                        node_cnt,
                        FieldForceBcId,
                        to_no_boundary_fieldForceBcId,
                        no_c_all_fieldPortBcId_list,
                        to_no_boundary_fieldPortBcId_list,
                        sharedNodes,
                        ref sortedNodes,
                        ref toSorted,
                        ref work_boundary_node_cnt_B1,
                        ref work_boundary_node_cnt_B2,
                        ref work_boundary_node_cnt_B3,
                        ref work_boundary_node_cnt_B4,
                        ref work_boundary_node_cnt_B5,
                        ref work_boundary_node_cnt_B6,
                        ref boundary_node_cnt,
                        ref free_node_cnt,
                        ref free_node_cnt0
                        );
                    boundary_node_cnt_each = work_boundary_node_cnt_B1;
                    System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B2 == (boundary_node_cnt_each - 2));
                    System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B3 == (boundary_node_cnt_each - 2));
                    System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B4 == (boundary_node_cnt_each - 2));
                    System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B5 == (boundary_node_cnt_each - 2));
                    System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B6 == (boundary_node_cnt_each - 2));
                }
                else
                {
                    // 四角形領域の場合
                    getSortedNodes_Rect(
                        probNo,
                        node_cnt,
                        FieldForceBcId,
                        to_no_boundary_fieldForceBcId,
                        no_c_all_fieldPortBcId1,
                        no_c_all_fieldPortBcId2,
                        no_c_all_fieldPortBcId3,
                        no_c_all_fieldPortBcId4,
                        to_no_boundary_fieldPortBcId1,
                        to_no_boundary_fieldPortBcId2,
                        to_no_boundary_fieldPortBcId3,
                        to_no_boundary_fieldPortBcId4,
                        sharedNodes,
                        ref sortedNodes,
                        ref toSorted,
                        ref boundary_node_cnt_B1,
                        ref boundary_node_cnt_B3,
                        ref boundary_node_cnt,
                        ref free_node_cnt,
                        ref free_node_cnt0
                        );
                }

                // バンド構造計算時は、強制境界なし
                System.Diagnostics.Debug.Assert(FieldForceBcId == 0);
                System.Diagnostics.Debug.Assert(free_node_cnt0 == node_cnt);

                // 剛性行列、質量行列を作成
                KrdLab.clapack.Complex[] KMat0 = null;
                KrdLab.clapack.Complex[] MMat0 = null;
                {
                    KrdLab.clapack.Complex betaForMakingMat = 0.0;
                    betaForMakingMat = 0.0; // 直接Bloch境界条件を指定する場合
                    WgUtilForPeriodicEigenBetaSpecified.MkPeriodicHelmholtzMat(
                        betaForMakingMat,
                        false, // isYDirectionPeriodic: false
                        World,
                        FieldLoopId,
                        Medias,
                        LoopDic,
                        node_cnt,
                        free_node_cnt0,
                        toSorted,
                        out KMat0,
                        out MMat0);
                }

                // ソートされた行列を取得する
                KrdLab.clapack.Complex[] KMat = null;
                KrdLab.clapack.Complex[] MMat = null;
                // 四角形領域
                KrdLab.clapack.Complex expAX = 0.0;
                KrdLab.clapack.Complex expAY = 0.0;
                // 四角形領域 問題3
                KrdLab.clapack.Complex expAY1 = 0.0;
                KrdLab.clapack.Complex expAY2 = 0.0;
                // 六角形領域
                KrdLab.clapack.Complex expA1 = 0.0;
                KrdLab.clapack.Complex expA2 = 0.0;
                KrdLab.clapack.Complex expA3 = 0.0;
                if (boundaryCnt == 6)
                {
                    getSortedMatrix_Hex(
                        probNo,
                        periodicDistanceX,
                        periodicDistanceY,
                        betaX,
                        betaY,
                        coord_c_all,
                        sharedNodes,
                        sharedNodeCoords,
                        sortedNodes, toSorted,
                        boundary_node_cnt_each,
                        boundary_node_cnt,
                        free_node_cnt,
                        free_node_cnt0,
                        KMat0,
                        MMat0,
                        out expA1,
                        out expA2,
                        out expA3,
                        out KMat,
                        out MMat
                        );
                }
                else
                {
                    getSortedMatrix_Rect(
                        probNo,
                        periodicDistanceX,
                        periodicDistanceY,
                        betaX,
                        betaY,
                        no_c_all_fieldPortBcId1,
                        no_c_all_fieldPortBcId3,
                        coord_c_all,
                        sharedNodes,
                        sharedNodeCoords,
                        sortedNodes, toSorted,
                        boundary_node_cnt_B1,
                        boundary_node_cnt_B3,
                        boundary_node_cnt,
                        free_node_cnt,
                        free_node_cnt0,
                        KMat0,
                        MMat0,
                        out expAX,
                        out expAY,
                        out expAY1,
                        out expAY2,
                        out KMat,
                        out MMat
                        );
                }

                // 規格化周波数
                KrdLab.clapack.Complex complexNormalizedFreq_ans = 0.0;
                // 界ベクトルは全節点分作成
                KrdLab.clapack.Complex[] resVec = null;
                resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点

                {
                    int matLen = (int)free_node_cnt;
                    KrdLab.clapack.Complex[] evals = null;
                    KrdLab.clapack.Complex[,] evecs = null;
                    KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[KMat.Length];
                    KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[MMat.Length];
                    for (int i = 0; i < matLen * matLen; i++)
                    {
                        A[i] = KMat[i];
                        B[i] = MMat[i];
                    }

                    /*
                    // 一般化複素固有値解析
                    //   [A],[B]は内部で書き換えられるので注意
                    KrdLab.clapack.Complex[] ret_evals = null;
                    KrdLab.clapack.Complex[][] ret_evecs = null;
                    System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev");
                    KrdLab.clapack.FunctionExt.zggev(A, matLen, matLen, B, matLen, matLen, ref ret_evals, ref ret_evecs);

                    evals = ret_evals;
                    System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length);
                    // 2次元配列に格納する
                    evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen];
                    for (int i = 0; i < ret_evecs.Length; i++)
                    {
                        KrdLab.clapack.Complex[] ret_evec = ret_evecs[i];
                        for (int j = 0; j < ret_evec.Length; j++)
                        {
                            evecs[i, j] = ret_evec[j];
                        }
                    }
                     */

                    // エルミートバンド行列の固有値解析
                    {
                        KrdLab.clapack.Complex[] ret_evals = null;
                        KrdLab.clapack.Complex[,] ret_evecs = null;
                        solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref ret_evals, ref ret_evecs);
                        evals = ret_evals;
                        evecs = ret_evecs;
                    }

                    // 固有値のソート
                    WgUtilForPeriodicEigenBetaSpecified.Sort1DEigenMode(evals, evecs);

                    // 表示用にデータを格納する
                    if (betaIndex == 0)
                    {
                        EigenValueList.Clear();
                    }
                    Complex[] complexNormalizedFreqList = new Complex[MaxModeCnt];
                    for (int imode = 0; imode < evals.Length; imode++)
                    {
                        // 固有周波数
                        KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]);
                        // 規格化周波数
                        KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi));
                        if (imode < MaxModeCnt)
                        {
                            System.Diagnostics.Debug.WriteLine("a/λ  ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i ");
                            complexNormalizedFreqList[imode] = new Complex(complexNormalizedFreq.Real, complexNormalizedFreq.Imaginary);
                        }
                    }
                    EigenValueList.Add(complexNormalizedFreqList);

                    // 固有ベクトルの格納(1つだけ格納)
                    int tagtModeIndex = 0;
                    KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIndex);
                    for (int ino = 0; ino < evec.Length; ino++)
                    {
                        uint nodeNumber = sortedNodes[ino];
                        resVec[nodeNumber] = evec[ino];
                    }
                }

                // 従属な節点の界をセットする
                if (boundaryCnt == 6)
                {
                    // 六角形
                    setDependentFieldVal_Hex(
                        probNo,
                        no_c_all_fieldPortBcId1,
                        no_c_all_fieldPortBcId2,
                        no_c_all_fieldPortBcId3,
                        no_c_all_fieldPortBcId4,
                        no_c_all_fieldPortBcId5,
                        no_c_all_fieldPortBcId6,
                        sharedNodes,
                        expA1,
                        expA2,
                        expA3,
                        ref resVec);
                }
                else
                {
                    // 四角形
                    setDependentFieldVal_Rect(
                        probNo,
                        no_c_all_fieldPortBcId1,
                        no_c_all_fieldPortBcId2,
                        no_c_all_fieldPortBcId3,
                        no_c_all_fieldPortBcId4,
                        sharedNodes,
                        expAX,
                        expAY,
                        expAY1,
                        expAY2,
                        ref resVec);
                }

                // 位相調整
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    for (int ino = 0; ino < resVec.Length; ino++)
                    {
                        KrdLab.clapack.Complex cvalue = resVec[ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                }
                if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    phaseShift = fValueAtMaxAbs / maxAbs;
                }
                for (int i = 0; i < resVec.Length; i++)
                {
                    resVec[i] /= phaseShift;
                }
                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 固有ベクトルの計算結果をワールド座標系にセットする
                WgUtilForPeriodicEigenBetaSpecified.SetFieldValueForDisplay(World, FieldValId, resVec);
                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                if (showException)
                {
                    Console.WriteLine(exception.Message + " " + exception.StackTrace);
                }
                // 表示用にデータを格納する
                if (betaIndex == 0)
                {
                    EigenValueList.Clear();
                }
                Complex[] work_complexNormalizedFreqList = new Complex[MaxModeCnt];
                for (int imode = 0; imode < MaxModeCnt; imode++)
                {
                    work_complexNormalizedFreqList[imode] = new Complex(0.0, 0.0);
                }
                EigenValueList.Add(work_complexNormalizedFreqList);

                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }
コード例 #7
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="freqIndex"></param>
        /// <param name="NormalizedFreq1"></param>
        /// <param name="NormalizedFreq2"></param>
        /// <param name="FreqDelta"></param>
        /// <param name="initFlg"></param>
        /// <param name="WaveguideWidth"></param>
        /// <param name="WaveModeDv"></param>
        /// <param name="IsPCWaveguide"></param>
        /// <param name="latticeA"></param>
        /// <param name="periodicDistance"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="IsSolveEigenItr"></param>
        /// <param name="CalcModeIndex"></param>
        /// <param name="isSVEA"></param>
        /// <param name="PrevModalVec"></param>
        /// <param name="IsShowAbsField"></param>
        /// <param name="minEffN"></param>
        /// <param name="maxEffN"></param>
        /// <param name="minWaveNum"></param>
        /// <param name="maxWaveNum"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="FieldLoopId"></param>
        /// <param name="FieldForceBcId"></param>
        /// <param name="FieldPortBcId1"></param>
        /// <param name="FieldPortBcId2"></param>
        /// <param name="Medias"></param>
        /// <param name="LoopDic"></param>
        /// <param name="EdgeDic"></param>
        /// <param name="EigenValueList"></param>
        /// <param name="DrawerAry"></param>
        /// <param name="Camera"></param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int freqIndex,
            double NormalizedFreq1,
            double NormalizedFreq2,
            double FreqDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            bool IsPCWaveguide,
            double latticeA,
            double periodicDistance,
            IList<IList<uint>> PCWaveguidePorts,
            bool IsSolveEigenItr,
            int CalcModeIndex,
            bool isSVEA,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            bool IsShowAbsField,
            double minEffN,
            double maxEffN,
            double minWaveNum,
            double maxWaveNum,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            ref bool isCalcCouplingLength,
            ref IList<Complex> EigenValueList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            // 結合長を求める?
            double betaDiffForCoupler = 0.0;
            isCalcCouplingLength = false; // 求めない
            if (!isSVEA)
            {
                if (probNo == 2 || probNo == 5)
                {
                    //isCalcCouplingLength = false; // 求めない
                    isCalcCouplingLength = true; // 求める
                }
            }

            double minBeta = minEffN;
            double maxBeta = maxEffN;
            bool success = false;
            bool showException = true;
            try
            {
                // モード追跡する?
                //bool isModeTrace = true;
                if (!IsPCWaveguide)
                {
                    isModeTrace = false;
                }

                if (freqIndex == 0)
                {
                    PrevModalVec = null;
                }

                // 規格化周波数
                double normalizedFreq = getNormalizedFreq(
                    ref freqIndex,
                    NormalizedFreq1,
                    NormalizedFreq2,
                    FreqDelta);
                if (freqIndex == -1)
                {
                    return success;
                }
                // 波数
                double k0 = 0.0;
                if (IsPCWaveguide)
                {
                    k0 = normalizedFreq * 2.0 * pi / latticeA;
                    System.Diagnostics.Debug.WriteLine("a/λ:{0}", normalizedFreq);
                }
                else
                {
                    k0 = normalizedFreq * pi / WaveguideWidth;
                    System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq);
                }
                // 波長
                double waveLength = 2.0 * pi / k0;
                // 反復計算の初期値
                double initialBeta = 0.0;
                /*
                if (freqIndex != 0)
                {
                    int workFreqIndex = freqIndex - 1;
                    double prevNormalizedFreq = getNormalizedFreq(
                        ref workFreqIndex,
                        NormalizedFreq1,
                        NormalizedFreq2,
                        FreqDelta);
                    double prev_k0 = 0.0;
                    if (IsPCWaveguide)
                    {
                        prev_k0 = prevNormalizedFreq * 2.0 * pi / latticeA;
                    }
                    else
                    {
                        prev_k0 = prevNormalizedFreq * pi / WaveguideWidth;
                    }
                    initialBeta = EigenValueList[EigenValueList.Count - 1].Real * prev_k0;
                }
                 */

                // 全節点数を取得する
                uint node_cnt = 0;
                //node_cnt = WgUtilForPeriodicEigen.GetNodeCnt(World, FieldLoopId);
                double[][] coord_c_all = null;
                {
                    uint[] no_c_all_tmp = null;
                    Dictionary<uint, uint> to_no_all_tmp = null;
                    double[][] coord_c_all_tmp = null;
                    WgUtilForPeriodicEigen.GetLoopCoordList(World, FieldLoopId, out no_c_all_tmp, out to_no_all_tmp, out coord_c_all_tmp);
                    node_cnt = (uint)no_c_all_tmp.Length;

                    // 座標リストを節点番号順に並び替えて格納
                    coord_c_all = new double[node_cnt][];
                    for (int ino = 0; ino < node_cnt; ino++)
                    {
                        uint nodeNumber = no_c_all_tmp[ino];
                        double[] coord = coord_c_all_tmp[ino];
                        coord_c_all[nodeNumber] = coord;
                    }
                }

                System.Diagnostics.Debug.WriteLine("node_cnt: {0}", node_cnt);

                // 境界の節点リストを取得する
                uint[] no_c_all_fieldForceBcId = null;
                Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out no_c_all_fieldForceBcId, out to_no_boundary_fieldForceBcId);
                }
                uint[] no_c_all_fieldPortBcId1 = null;
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = null;
                WgUtil.GetBoundaryNodeList(World, FieldPortBcId1, out no_c_all_fieldPortBcId1, out to_no_boundary_fieldPortBcId1);
                uint[] no_c_all_fieldPortBcId2 = null;
                Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = null;
                WgUtil.GetBoundaryNodeList(World, FieldPortBcId2, out no_c_all_fieldPortBcId2, out to_no_boundary_fieldPortBcId2);

                // 節点のソート
                IList<uint> sortedNodes = new List<uint>();
                Dictionary<uint, int> toSorted = new Dictionary<uint, int>();
                //   境界1と境界2は周期構造条件より同じ界の値をとる
                // ポート境界1
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点を追加
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc1)) continue;
                    }
                    sortedNodes.Add(nodeNumberPortBc1);
                    int nodeIndex = sortedNodes.Count - 1;
                    toSorted.Add(nodeNumberPortBc1, nodeIndex);
                }
                uint boundary_node_cnt = (uint)sortedNodes.Count; // 境界1
                // 内部領域
                for (uint nodeNumber = 0; nodeNumber < node_cnt; nodeNumber++)
                {
                    // 追加済み節点はスキップ
                    //if (toSorted.ContainsKey(nodeNumber)) continue;
                    // 境界1は除く
                    if (to_no_boundary_fieldPortBcId1.ContainsKey(nodeNumber)) continue;
                    // 境界2は除く
                    if (to_no_boundary_fieldPortBcId2.ContainsKey(nodeNumber)) continue;
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumber)) continue;
                    }
                    sortedNodes.Add(nodeNumber);
                    toSorted.Add(nodeNumber, sortedNodes.Count - 1);
                }
                uint free_node_cnt = (uint)sortedNodes.Count;  // 境界1 + 内部領域
                for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
                {
                    // 境界2の節点を追加
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i];
                    if (FieldForceBcId != 0)
                    {
                        // 強制境界を除く
                        if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc2)) continue;
                    }
                    sortedNodes.Add(nodeNumberPortBc2);
                    int nodeIndex = sortedNodes.Count - 1;
                    toSorted.Add(nodeNumberPortBc2, nodeIndex);
                }
                uint free_node_cnt0 = (uint)sortedNodes.Count;  // 境界1 + 内部領域 + 境界2

                // 剛性行列、質量行列を作成
                double[] KMat0 = null;
                double[] CMat0 = null;
                double[] MMat0 = null;
                WgUtilForPeriodicEigen.MkPeriodicHelmholtzMat(
                    waveLength,
                    false, // isYDirectionPeriodic: false
                    0.0, // rotAngle
                    null, // rotOrigin
                    World,
                    FieldLoopId,
                    Medias,
                    LoopDic,
                    node_cnt,
                    free_node_cnt0,
                    toSorted,
                    out KMat0,
                    out CMat0,
                    out MMat0);

                // 緩慢変化包絡線近似?
                //bool isSVEA = true;  // 緩慢変化包絡線近似 Φ = φ(x, y) exp(-jβx) と置く方法
                //bool isSVEA = false; // Φを直接解く方法(exp(-jβd)を固有値として扱う)
                System.Diagnostics.Debug.WriteLine("isSVEA: {0}", isSVEA);
                System.Diagnostics.Debug.WriteLine("isModeTrace: {0}, CalcModeIndex: {1}, IsSolveEigenItr: {2}", isModeTrace, CalcModeIndex, IsSolveEigenItr);
                // 逆行列を使う?
                //bool isUseInvMat = false; // 逆行列を使用しない
                bool isUseInvMat = true; // 逆行列を使用する
                System.Diagnostics.Debug.WriteLine("isUseInvMat: {0}", isUseInvMat);

                /*
                // 反復計算のときはモード追跡をOFFにする(うまくいかないときがあるので)
                if (IsSolveEigenItr && isModeTrace)
                {
                    isModeTrace = false;
                    System.Diagnostics.Debug.WriteLine("isModeTrace force to false.(isSolveEigenItr == true)");
                }
                 */

                // 境界2の節点は境界1の節点と同一とみなす
                //   境界上の分割が同じであることが前提条件
                double[] KMat = null;
                double[] CMat = null;
                double[] MMat = null;
                if (isSVEA)
                {
                    KMat = new double[free_node_cnt * free_node_cnt];
                    CMat = new double[free_node_cnt * free_node_cnt];
                    MMat = new double[free_node_cnt * free_node_cnt];
                    for (int i = 0; i < free_node_cnt; i++)
                    {
                        for (int j = 0; j < free_node_cnt; j++)
                        {
                            KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                            CMat[i + free_node_cnt * j] = CMat0[i + free_node_cnt0 * j];
                            MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                        }
                    }
                    for (int i = 0; i < free_node_cnt; i++)
                    {
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            KMat[i + free_node_cnt * j] += KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                            CMat[i + free_node_cnt * j] += CMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                            MMat[i + free_node_cnt * j] += MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        }
                    }
                    for (int i = 0; i < boundary_node_cnt; i++)
                    {
                        for (int j = 0; j < free_node_cnt; j++)
                        {
                            KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                            CMat[i + free_node_cnt * j] += CMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                            MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                        }
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                            CMat[i + free_node_cnt * j] += CMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                            MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        }
                    }
                    // 行列要素check
                    {
                        for (int i = 0; i < free_node_cnt; i++)
                        {
                            for (int j = i; j < free_node_cnt; j++)
                            {
                                // [K]は対称行列
                                System.Diagnostics.Debug.Assert(Math.Abs(KMat[i + free_node_cnt * j] - KMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                                // [M]は対称行列
                                System.Diagnostics.Debug.Assert(Math.Abs(MMat[i + free_node_cnt * j] - MMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                                // [C]は反対称行列
                                System.Diagnostics.Debug.Assert(Math.Abs((-CMat[i + free_node_cnt * j]) - CMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                            }
                        }
                    }
                }
                else
                {
                    if (!isUseInvMat)
                    {
                    KMat = new double[free_node_cnt * free_node_cnt];
                    CMat = new double[free_node_cnt * free_node_cnt];
                    MMat = new double[free_node_cnt * free_node_cnt];

                    CMat0 = null;
                    MMat0 = null;
                    uint inner_node_cnt = free_node_cnt - boundary_node_cnt;
                    for (int i = 0; i < boundary_node_cnt; i++)
                    {
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            // [K21]
                            KMat[i + free_node_cnt * j] = KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j];
                            // [K11] + [K22]
                            CMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]
                                + KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                            // [K12]
                            MMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        }
                        for (int j = 0; j < inner_node_cnt; j++)
                        {
                            // [K20]
                            KMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [K10]
                            CMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[i + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [0]
                            MMat[i + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                        }
                    }
                    for (int i = 0; i < inner_node_cnt; i++)
                    {
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            // [0]
                            KMat[(i + boundary_node_cnt) + free_node_cnt * j] = 0.0;
                            // [K01]
                            CMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * j];
                            // [K02]
                            MMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)];
                        }
                        for (int j = 0; j < inner_node_cnt; j++)
                        {
                            // [0]
                            KMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                            // [K00]
                            CMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [0]
                            MMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                        }
                    }
                    }
                    else
                    {
                        KMat = null;
                        CMat = null;
                        MMat = null;
                    }
                }

                // 伝搬定数
                KrdLab.clapack.Complex betamToSolve = 0.0;
                // 界ベクトルは全節点分作成
                KrdLab.clapack.Complex[] resVec = null;
                // PC導波路の場合は、波数が[0, π]の領域から探索する
                if (IsPCWaveguide)
                {
                    //minBeta = 0.0;
                    //maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0;
                    //minBeta = minWaveNum * (2.0 * pi / periodicDistance) / k0;
                    //maxBeta = maxWaveNum * (2.0 * pi / periodicDistance) / k0;
                    double minBeta_BZ = minWaveNum * (2.0 * pi / periodicDistance) / k0;
                    double maxBeta_BZ = maxWaveNum * (2.0 * pi / periodicDistance) / k0;
                    if (minBeta_BZ > minBeta)
                    {
                        minBeta = minBeta_BZ;
                    }
                    if (maxBeta_BZ < maxBeta)
                    {
                        maxBeta = maxBeta_BZ;
                    }
                    System.Diagnostics.Debug.WriteLine("minWaveNum:{0}, maxWaveNum: {1}", minWaveNum, maxWaveNum);
                    System.Diagnostics.Debug.WriteLine("minBeta: {0}, maxBeta: {1}", minBeta, maxBeta);
                }

                // 緩慢変化包絡線近似は反復計算の時だけしか対応できていない
                // 緩慢変化包絡線近似でない場合は、マルチモードと同じく2次一般化固有値問題を解く
                if (!IsSolveEigenItr || CalcModeIndex >= 2 || !isSVEA)
                {
                    /*
                    // マルチモードの場合
                    // 周期構造導波路固有値問題を2次一般化固有値問題として解く
                    solveAsQuadraticGeneralizedEigen(
                        CalcModeIndex,
                        k0,
                        KMat,
                        CMat,
                        MMat,
                        node_cnt,
                        free_node_cnt,
                        boundary_node_cnt,
                        sortedNodes,
                        toSorted,
                        to_no_boundary_fieldPortBcId1,
                        isModeTrace,
                        ref PrevModalVec,
                        IsPCWaveguide,
                        PCWaveguidePorts,
                        minBeta,
                        maxBeta,
                        out betamToSolve,
                        out resVec);
                     */

                    if (!isUseInvMat)
                    {
                        // マルチモードの場合
                        // 周期構造導波路固有値問題を2次一般化固有値問題として解く(実行列として解く)
                        solveAsQuadraticGeneralizedEigenWithRealMat(
                            CalcModeIndex,
                            isSVEA,
                            periodicDistance,
                            k0,
                            KMat,
                            CMat,
                            MMat,
                            node_cnt,
                            free_node_cnt,
                            boundary_node_cnt,
                            sortedNodes,
                            toSorted,
                            to_no_boundary_fieldPortBcId1,
                            false, // isYDirectionPeriodic : false
                            coord_c_all,
                            IsPCWaveguide,
                            PCWaveguidePorts,
                            isModeTrace,
                            ref PrevModalVec,
                            minBeta,
                            maxBeta,
                            (2.0 * pi / periodicDistance), //k0, //1.0,
                            out betamToSolve,
                            out resVec);
                    }
                    else
                    {
                        // 逆行列を使用する方法
                        if (isSVEA)
                        {
                            System.Diagnostics.Debug.Assert(isSVEA == true);
                            // 周期構造導波路固有値問題を2次一般化固有値問題→標準固有値問題として解く(実行列として解く)
                            solveAsQuadraticGeneralizedEigenToStandardWithRealMat(
                                CalcModeIndex,
                                k0,
                                KMat,
                                CMat,
                                MMat,
                                node_cnt,
                                free_node_cnt,
                                boundary_node_cnt,
                                sortedNodes,
                                toSorted,
                                to_no_boundary_fieldPortBcId1,
                                IsPCWaveguide,
                                PCWaveguidePorts,
                                isModeTrace,
                                ref PrevModalVec,
                                minBeta,
                                maxBeta,
                                k0, //(2.0 * pi / periodicDistance), //k0, //1.0,
                                out betamToSolve,
                                out resVec);
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(isSVEA == false);
                            solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat(
                                CalcModeIndex,
                                periodicDistance,
                                k0,
                                KMat0,
                                true, // isPortBc2Reverse : true
                                node_cnt,
                                free_node_cnt0,
                                free_node_cnt,
                                boundary_node_cnt,
                                sortedNodes,
                                toSorted,
                                to_no_boundary_fieldPortBcId1,
                                false, // isYDirectionPeriodic : false
                                coord_c_all,
                                IsPCWaveguide,
                                PCWaveguidePorts,
                                isModeTrace,
                                ref PrevModalVec,
                                minBeta,
                                maxBeta,
                                (2.0 * pi / periodicDistance), //k0, //1.0,
                                isCalcCouplingLength,
                                out betamToSolve,
                                out resVec,
                                out betaDiffForCoupler);
                        }
                    }
                    if (betamToSolve.Real == 0.0 && betamToSolve.Imaginary == 0.0)
                    {
                        //Console.WriteLine("skipped calculation. No propagation mode exists At 2W /λ = {0}", normalizedFreq);
                        System.Diagnostics.Debug.WriteLine("skipped calculation. No propagation mode exists At 2W /λ = {0}", normalizedFreq);
                    }
                }
                else
                {
                    // 反復計算の初期値
                    betamToSolve = initialBeta;
                    // 高次モード?
                    bool isCalcSecondMode = (CalcModeIndex == 1) ? true : false;
                    // 周期構造導波路固有値問題を一般化固有値問題として解く(反復計算)
                    System.Diagnostics.Debug.Assert(isSVEA == true);
                    solveItrAsLinearGeneralizedEigen(
                        k0,
                        KMat,
                        CMat,
                        MMat,
                        node_cnt,
                        free_node_cnt,
                        boundary_node_cnt,
                        sortedNodes,
                        toSorted,
                        to_no_boundary_fieldPortBcId1,
                        IsPCWaveguide,
                        PCWaveguidePorts,
                        isCalcSecondMode,
                        isModeTrace,
                        ref PrevModalVec,
                        minBeta,
                        maxBeta,
                        ref betamToSolve,
                        out resVec);
                    if (betamToSolve.Real == 0.0 && betamToSolve.Imaginary == 0.0)
                    {
                        //Console.WriteLine("skipped calculation. No propagation mode exists At 2W /λ = {0}", normalizedFreq);
                        System.Diagnostics.Debug.WriteLine("skipped calculation. No propagation mode exists At 2W /λ = {0}", normalizedFreq);
                    }
                }

                // ポート境界1の節点の値を境界2にも格納する
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1];

                    // 境界2の節点
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[no_c_all_fieldPortBcId2.Length - 1 - i];
                    if (isSVEA)
                    {
                        // 緩慢変化包絡線近似の場合は、Φ2 = Φ1
                        resVec[nodeNumberPortBc2] = cvalue;
                    }
                    else
                    {
                        // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1
                        KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betamToSolve * periodicDistance);
                        resVec[nodeNumberPortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合
                    }
                }

                // 位相調整
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    /*
                    for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++)
                    {
                        uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                        KrdLab.clapack.Complex cvalue = resVec[ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                     */
                    for (int ino = 0; ino < resVec.Length; ino++)
                    {
                        KrdLab.clapack.Complex cvalue = resVec[ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                }
                if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    phaseShift = fValueAtMaxAbs / maxAbs;
                }
                System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi);
                for (int i = 0; i < resVec.Length; i++)
                {
                    resVec[i] /= phaseShift;
                }

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 固有ベクトルの計算結果をワールド座標系にセットする
                WgUtilForPeriodicEigen.SetFieldValueForDisplay(World, FieldValId, resVec);

                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    EigenValueList.Clear();
                }

                // 表示用加工
                if (isCalcCouplingLength)
                {
                    // 結合長(位相差)を格納する
                    EigenValueList.Add(betaDiffForCoupler / k0);
                    System.Diagnostics.Debug.WriteLine("betaDiffForCoupler: {0}  {1}  Lc: {2}",
                        betaDiffForCoupler / k0,
                        betaDiffForCoupler / k0 * (periodicDistance / latticeA) * normalizedFreq,
                        0.5 / (betaDiffForCoupler / k0 * (periodicDistance / latticeA) * normalizedFreq)
                        );
                }
                else
                {
                    // 伝搬定数をk0で規格化する
                    KrdLab.clapack.Complex normalizedBetam = betamToSolve / k0;
                    Complex evalueToShow = new Complex(normalizedBetam.Real, normalizedBetam.Imaginary);
                    EigenValueList.Add(evalueToShow);
                }

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                if (showException)
                {
                    Console.WriteLine(exception.Message + " " + exception.StackTrace);
                }
                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    EigenValueList.Clear();
                }
                EigenValueList.Add(new Complex(0.0, 0.0));

                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }