Пример #1
0
        /// <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;
        }
Пример #2
0
        /// <summary>
        /// 周期構造導波路固有値問題を一般化固有値問題として解く(反復計算) (緩慢変化包絡線近似用)
        /// </summary>
        /// <param name="k0"></param>
        /// <param name="KMat"></param>
        /// <param name="CMat"></param>
        /// <param name="MMat"></param>
        /// <param name="node_cnt"></param>
        /// <param name="free_node_cnt"></param>
        /// <param name="boundary_node_cnt"></param>
        /// <param name="sortedNodes"></param>
        /// <param name="toSorted"></param>
        /// <param name="to_no_boundary_fieldPortBcId1"></param>
        /// <param name="IsPCWaveguide"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="IsCalcSecondMode"></param>
        /// <param name="betamToSolve"></param>
        /// <param name="resVec"></param>
        private static void solveItrAsLinearGeneralizedEigen(
            double k0,
            double[] KMat,
            double[] CMat,
            double[] MMat,
            uint node_cnt,
            uint free_node_cnt,
            uint boundary_node_cnt,
            IList<uint> sortedNodes,
            Dictionary<uint, int> toSorted,
            Dictionary<uint, uint> to_no_boundary_fieldPortBcId1,
            bool IsPCWaveguide,
            IList<IList<uint>> PCWaveguidePorts,
            bool IsCalcSecondMode,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            double minBeta,
            double maxBeta,
            ref KrdLab.clapack.Complex betamToSolve,
            out KrdLab.clapack.Complex[] resVec)
        {
            //初期値は引数で与える
            //betamToSolve = 0.0;
            resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点

            //const bool isSVEA = true;

            //int itrMax = 10;
            //int itrMax = 20;
            int itrMax = 400;
            //double resMin = 1.0e-4;
            //double resMin = 1.0e-12;
            double resMin = 1.0e-6;
            double prevRes = double.MaxValue;
            bool isModeTraceWithinItr = true;
            KrdLab.clapack.Complex[] prevResVecItr = PrevModalVec;
            int itr = 0;
            for (itr = 0; itr < itrMax; itr++)
            {
                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] - KrdLab.clapack.Complex.ImaginaryOne * betamToSolve * CMat[i];
                    B[i] = MMat[i];
                }
                // 複素エルミートバンド行列の一般化固有値問題
                if (Math.Abs(betamToSolve.Imaginary) >= Constants.PrecisionLowerLimit) // 伝搬定数が実数の時のみに限定
                {
                    //Console.WriteLine("!!!!!!!!Not propagation mode. Skip calculate: betamToSolve: {0} + {1}i", betamToSolve.Real, betamToSolve.Imaginary);
                    System.Diagnostics.Debug.WriteLine("!!!!!!!!Not propagation mode. Skip calculate: betamToSolve: {0} + {1}i", betamToSolve.Real, betamToSolve.Imaginary);
                    betamToSolve = 0.0;
                    break;
                }
                else
                {
                    // エルミートバンド行列の一般化固有値問題を解く
                    solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref evals, ref evecs);
                    /*
                    {
                        // 複素一般化固有値問題を解く
                        // 複素非対称行列の一般化固有値問題
                        // 一般化複素固有値解析
                        //   [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];
                            }
                        }
                    }
                     */
                }

                // βを格納
                for (int i = 0; i < evals.Length; i++)
                {
                    KrdLab.clapack.Complex eval = evals[i];
                    // 固有値がβ2の場合
                    // Note: 固有値は2乗で求まる
                    //   βを求める
                    KrdLab.clapack.Complex eval_sqrt = KrdLab.clapack.Complex.Sqrt(eval);
                    if (eval_sqrt.Real > 0 && eval_sqrt.Imaginary > 0)
                    {
                        eval_sqrt.Imaginary = -eval_sqrt.Imaginary;
                    }
                    evals[i] = eval_sqrt;
                }

                // 固有値をソートする
                KrdLab.clapack.Complex[] work_betamToSolveList = null;
                KrdLab.clapack.Complex[][] work_resVecList = null;
                int work_incidentModeIndex = (IsCalcSecondMode ? 1 : 0);
                bool work_isModeTrace = isModeTrace;
                KrdLab.clapack.Complex[] workPrevModalVec = null;
                if (!IsPCWaveguide)
                {
                    work_isModeTrace = false;
                    workPrevModalVec = isModeTraceWithinItr ? prevResVecItr : PrevModalVec;
                }
                System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt);
                GetSortedModes(
                    work_incidentModeIndex,
                    k0,
                    node_cnt,
                    free_node_cnt,
                    boundary_node_cnt,
                    sortedNodes,
                    toSorted,
                    IsPCWaveguide,
                    PCWaveguidePorts,
                    work_isModeTrace,
                    ref workPrevModalVec,
                    minBeta,
                    maxBeta,
                    evals,
                    evecs,
                    false, // isDebugShow
                    out work_betamToSolveList,
                    out work_resVecList);
                if (work_betamToSolveList == null || work_betamToSolveList.Length == 0)
                {
                    System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode");
                    betamToSolve = 0;
                    for (int i = 0; i < resVec.Length; i++)
                    {
                        resVec[i] = 0;
                    }
                    break;
                }
                if (IsCalcSecondMode && work_incidentModeIndex >= work_betamToSolveList.Length)
                {
                    // 高次モード反復計算時
                    // 反復によって固有値を取得する場合は、基本モードがなくなるときがある(特定固有モードに収束させているため)
                    // fail safe
                    if (itr != 0 && work_incidentModeIndex >= work_betamToSolveList.Length)
                    {
                        work_incidentModeIndex = 0;
                    }
                }
                int tagtModeIndex = work_betamToSolveList.Length - 1 - work_incidentModeIndex;
                if (tagtModeIndex < 0 || tagtModeIndex >= work_betamToSolveList.Length)
                {
                    System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode [Error] tagtModeIndex = {0}", tagtModeIndex);
                    betamToSolve = 0;
                    for (int i = 0; i < resVec.Length; i++)
                    {
                        resVec[i] = 0;
                    }
                    break;
                }

                // 伝搬定数、固有ベクトルの格納
                // 収束判定用に前の伝搬定数を退避
                KrdLab.clapack.Complex prevBetam = betamToSolve;
                // 伝搬定数
                betamToSolve = work_betamToSolveList[tagtModeIndex];
                // 固有ベクトル
                work_resVecList[tagtModeIndex].CopyTo(resVec, 0);

                // 収束判定
                double res = KrdLab.clapack.Complex.Abs(prevBetam - betamToSolve);
                if (res < resMin)
                {
                    System.Diagnostics.Debug.WriteLine("converged itr: {0} betam: {1} + {2} i", itr, betamToSolve.Real, betamToSolve.Imaginary);
                    break;
                }
                // 発散判定
                if (itr >= 20 && Math.Abs(res) > Math.Abs(prevRes))
                {
                    System.Diagnostics.Debug.WriteLine("!!!!!!!! Not converged : prevRes = {0} res = {1} at 2/λ = {2}", prevRes, res, 2.0 / (2.0 * pi / k0));
                    Console.WriteLine("!!!!!!!! Not converged : prevRes = {0} res = {1} at 2/λ = {2}", prevRes, res, 2.0 / (2.0 * pi / k0));
                    betamToSolve = 0.0;
                    break;
                }
                prevRes = res;
                if (isModeTraceWithinItr && resVec != null)
                {
                    if (prevResVecItr == null)
                    {
                        // 初回のみメモリ確保
                        prevResVecItr = new KrdLab.clapack.Complex[node_cnt]; //全節点
                    }
                    // resVecは同じバッファを使いまわすので、退避用のprevResVecItrへはコピーする必要がある
                    resVec.CopyTo(prevResVecItr, 0);
                }
                // check
                if (itr % 20 == 0 && itr >= 20)
                {
                    System.Diagnostics.Debug.WriteLine("itr: {0}", itr);
                    Console.WriteLine("itr: {0}", itr);
                }
            }
            if (itr == itrMax)
            {
                System.Diagnostics.Debug.WriteLine("!!!!!!!! Not converged itr:{0} betam:{1} + {2} i at 2/λ = {3}", itr, betamToSolve.Real, betamToSolve.Imaginary, 2.0 / (2.0 * pi / k0));
                Console.WriteLine("!!!!!!!! Not converged itr:{0} betam:{1} + {2} i at 2/λ = {3}", itr, betamToSolve.Real, betamToSolve.Imaginary, 2.0 / (2.0 * pi / k0));
            }
            else if (itr >= 20 && (Math.Abs(betamToSolve.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit || Math.Abs(betamToSolve.Imaginary) >=  MyUtilLib.Matrix.Constants.PrecisionLowerLimit))
            {
                System.Diagnostics.Debug.WriteLine("converged but too slow!!!: itr: {0} at 2/λ = {1}", itr, 2.0 / (2.0 * pi / k0));
                Console.WriteLine("converged but too slow!!!: itr: {0} at 2/λ = {1}", itr, 2.0 / (2.0 * pi / k0));
            }
            // 前回の固有ベクトルを更新
            if (isModeTrace && betamToSolve.Real != 0.0 && Math.Abs(betamToSolve.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                //PrevModalVec = resVec;
                PrevModalVec = new KrdLab.clapack.Complex[node_cnt];
                resVec.CopyTo(PrevModalVec, 0);
            }
            else
            {
                // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように)
                //PrevModalVec = null;
            }
        }