Example #1
0
        // {x} = [A]{v}
        public static KrdLab.clapack.Complex[] product(double[] matA, int a_row, int a_col, KrdLab.clapack.Complex[] vec, int vec_row)
        {
            System.Diagnostics.Debug.Assert(a_col == vec_row);
            KrdLab.clapack.Complex[] retVec = new KrdLab.clapack.Complex[a_row];

            for (int i = 0; i < a_row; i++)
            {
                retVec[i] = new KrdLab.clapack.Complex(0.0, 0.0);
                for (int k = 0; k < a_col; k++)
                {
                    retVec[i] += matA[i + k * a_row] * vec[k];
                }
            }
            return(retVec);
        }
Example #2
0
        public static KrdLab.clapack.Complex[] product(
            KrdLab.clapack.Complex[] matA, int a_row, int a_col,
            KrdLab.clapack.Complex[] matB, int b_row, int b_col)
        {
            System.Diagnostics.Debug.Assert(a_col == b_row);
            int x_row = a_row;
            int x_col = b_col;

            KrdLab.clapack.Complex[] matX = new KrdLab.clapack.Complex[x_row * x_col];
            for (int i = 0; i < x_row; i++)
            {
                for (int j = 0; j < x_col; j++)
                {
                    matX[i + j * x_row] = 0.0;
                    for (int k = 0; k < a_col; k++)
                    {
                        matX[i + j * x_row] += matA[i + k * a_row] * matB[k + j * b_row];
                    }
                }
            }
            return(matX);
        }
Example #3
0
        // {x} = [A]{v}
        public static KrdLab.clapack.Complex[] product(double[] matA, int a_row, int a_col, KrdLab.clapack.Complex[] vec, int vec_row)
        {
            System.Diagnostics.Debug.Assert(a_col == vec_row);
            KrdLab.clapack.Complex[] retVec = new KrdLab.clapack.Complex[a_row];

            for (int i = 0; i < a_row; i++)
            {
                retVec[i] = new KrdLab.clapack.Complex(0.0, 0.0);
                for (int k = 0; k < a_col; k++)
                {
                    retVec[i] += matA[i + k * a_row] * vec[k];
                }
            }
            return retVec;
        }
Example #4
0
 public static KrdLab.clapack.Complex[] product(
     KrdLab.clapack.Complex[] matA, int a_row, int a_col,
     KrdLab.clapack.Complex[] matB, int b_row, int b_col)
 {
     System.Diagnostics.Debug.Assert(a_col == b_row);
     int x_row = a_row;
     int x_col = b_col;
     KrdLab.clapack.Complex[] matX = new KrdLab.clapack.Complex[x_row * x_col];
     for (int i = 0; i < x_row; i++)
     {
         for (int j = 0; j < x_col; j++)
         {
             matX[i + j * x_row] = 0.0;
             for (int k = 0; k < a_col; k++)
             {
                 matX[i + j * x_row] += matA[i + k * a_row] * matB[k + j * b_row];
             }
         }
     }
     return matX;
 }
        /// <summary>
        /// ポート固有値解析
        /// </summary>
        public static void SolvePortWaveguideEigen(
            FemSolver.WaveModeDV WaveModeDv,
            double waveLength,
            double latticeA,
            int maxModeSpecified,
            IList<FemNode> Nodes,
            Dictionary<string, IList<int>> EdgeToElementNoH,
            IList<FemElement> Elements,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            IList<int> portNodes,
            IList<uint> portElemNoPeriodic,
            IList<IList<int>> portNodePeriodicB,
            IList<int> defectNodePeriodic,
            out int[] nodesBoundary,
            out MyDoubleMatrix ryy_1d,
            out Complex[] eigenValues,
            out Complex[,] eigenVecsB1,
            out Complex[,] eigen_dFdXsB1,
            out IList<int> nodePeriodic,
            out Dictionary<int, int> toNodePeriodic,
            out IList<double[]> coordsPeriodic,
            out KrdLab.clapack.Complex[][] eigenVecsPeriodic
            )
        {
            // ポート境界上
            nodesBoundary = null;
            ryy_1d = null;
            eigenValues = null;
            eigenVecsB1 = null;
            eigen_dFdXsB1 = null;
            // ポート周期構造領域
            nodePeriodic = null;
            toNodePeriodic = null;
            coordsPeriodic = null;
            eigenVecsPeriodic = null;

            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            getPortFemMat1D(
                WaveModeDv,
                waveLength,
                latticeA,
                Nodes,
                EdgeToElementNoH,
                Elements,
                Medias,
                ForceNodeNumberH,
                portNodes,
                out nodesBoundary,
                out ryy_1d
                );
            Dictionary<int, int> toNodesB = new Dictionary<int, int>();
            for (int ino = 0; ino < nodesBoundary.Length; ino++)
            {
                int nodeNumber = nodesBoundary[ino];
                //System.Diagnostics.Debug.WriteLine("nodesBoundary[{0}] = {1}", ino, nodesBoundary[ino]);
                toNodesB.Add(nodeNumber, ino);
            }

            //////////////////////////////////////////////////////////////////////////////
            // 周期構造導波路
            /////////////////////////////////////////////////////////////////////////////
            int incidentModeIndex = 0;
            Constants.FemElementShapeDV elemShapeDv;
            FemElement workElement = Elements[0];
            int order;
            int vertexCnt;
            FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(workElement.NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt);

            // 領域の節点リスト、座標リストを取得する
            //IList<int> nodePeriodic = null;
            //Dictionary<int, int> toNodePeriodic = null;
            //IList<double[]> coordsPeriodic = null;
            getCoordListPeriodic(
                Nodes,
                Elements,
                portElemNoPeriodic,
                out nodePeriodic,
                out toNodePeriodic,
                out coordsPeriodic
                );
            // 全節点数
            int nodeCntPeriodic = nodePeriodic.Count;

            IList<IList<int>> nodePeriodicB = portNodePeriodicB;
            IList<int> nodePeriodicB1 = nodePeriodicB[0];
            IList<int> nodePeriodicB2 = nodePeriodicB[1];
            Dictionary<int, int> toNodePeriodicB1 = new Dictionary<int, int>();
            Dictionary<int, int> toNodePeriodicB2 = new Dictionary<int, int>();
            for (int ino = 0; ino < nodePeriodicB1.Count; ino++)
            {
                int nodeNumber = nodePeriodicB1[ino];
                toNodePeriodicB1.Add(nodeNumber, ino);
            }
            for (int ino = 0; ino < nodePeriodicB2.Count; ino++)
            {
                int nodeNumber = nodePeriodicB2[ino];
                toNodePeriodicB2.Add(nodeNumber, ino);
            }

            // Y方向に周期構造?
            bool isYDirectionPeriodic = false;
            {
                int nodeNumber_first = nodePeriodicB1[0];
                int nodeNumber_last = nodePeriodicB1[nodePeriodicB1.Count - 1];
                int noB_first = toNodePeriodic[nodeNumber_first];
                int noB_last = toNodePeriodic[nodeNumber_last];
                double[] coord_first = coordsPeriodic[noB_first];
                double[] coord_last = coordsPeriodic[noB_last];
                if (Math.Abs(coord_first[1] - coord_last[1]) < 1.0e-12)
                {
                    isYDirectionPeriodic = true;
                }
            }
            System.Diagnostics.Debug.WriteLine("isYDirectionPeriodic: {0}", isYDirectionPeriodic);

            // 節点の並び替え
            IList<int> sortedNodesPeriodic = new List<int>();
            Dictionary<int, int> toSortedPeriodic = new Dictionary<int, int>();
            // ポート境界1
            for (int ino = 0; ino < nodePeriodicB1.Count; ino++)
            {
                // 境界1の節点番号
                int nodeNumberB1 = nodePeriodicB1[ino];
                if (ForceNodeNumberH.ContainsKey(nodeNumberB1))
                {
                    // 強制境界は除外
                    continue;
                }
                sortedNodesPeriodic.Add(nodeNumberB1);
                int index = sortedNodesPeriodic.Count - 1;
                toSortedPeriodic.Add(nodeNumberB1, index);
            }
            int nodeCntBPeriodic = sortedNodesPeriodic.Count; // 境界1
            // 内部領域
            for (int ino = 0; ino < nodeCntPeriodic; ino++)
            {
                int nodeNumber = nodePeriodic[ino];
                if (ForceNodeNumberH.ContainsKey(nodeNumber))
                {
                    // 強制境界は除外
                    continue;
                }
                if (toNodePeriodicB1.ContainsKey(nodeNumber))
                {
                    // 境界1は除外
                    continue;
                }
                if (toNodePeriodicB2.ContainsKey(nodeNumber))
                {
                    // 境界2は除外
                    continue;
                }
                sortedNodesPeriodic.Add(nodeNumber);
                int index = sortedNodesPeriodic.Count - 1;
                toSortedPeriodic.Add(nodeNumber, index);
            }
            int freeNodeCntPeriodic = sortedNodesPeriodic.Count; // 境界1 + 内部領域
            // ポート境界2
            for (int ino = 0; ino < nodePeriodicB2.Count; ino++)
            {
                // 境界2の節点番号
                int nodeNumberB2 = nodePeriodicB2[ino];
                if (ForceNodeNumberH.ContainsKey(nodeNumberB2))
                {
                    // 強制境界は除外
                    continue;
                }
                sortedNodesPeriodic.Add(nodeNumberB2);
                int index = sortedNodesPeriodic.Count - 1;
                toSortedPeriodic.Add(nodeNumberB2, index);
            }
            int freeNodeCntPeriodic_0 = sortedNodesPeriodic.Count; // 境界1 + 内部領域 + 境界2

            // 周期構造導波路固有値問題用FEM行列の作成
            //bool isSVEA = false; // Φを直接解く方法
            bool isSVEA = true; // Φ= φexp(-jβx)と置く方法(SVEA)
            double[] KMat0 = null;
            double[] CMat0 = null;
            double[] MMat0 = null;
            if (isSVEA)
            {
                // Φ = φexp(-jβx)と置く方法
                KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0];
                CMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0];
                MMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0];
            }
            else
            {
                // Φを直接解く方法
                KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0];
                CMat0 = null;
                MMat0 = null;
            }
            IList<uint> elemNoPeriodic = portElemNoPeriodic;
            int elemCnt = elemNoPeriodic.Count;
            for (int ie = 0; ie < elemCnt; ie++)
            {
                int elemNo = (int)elemNoPeriodic[ie];
                FemElement femElement = Elements[elemNo - 1];
                System.Diagnostics.Debug.Assert(femElement.No == elemNo);

                if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder)
                {
                    // 2次三角形要素
                    FemMat_Tri_Second.AddElementMatPeriodic(
                        isYDirectionPeriodic,
                        isSVEA,
                        waveLength,
                        nodeCntPeriodic,
                        freeNodeCntPeriodic_0,
                        toSortedPeriodic,
                        femElement,
                        Nodes,
                        Medias,
                        ForceNodeNumberH,
                        WaveModeDv,
                        ref KMat0,
                        ref CMat0,
                        ref MMat0);
                }
                else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder)
                {
                    // 1次三角形要素
                    FemMat_Tri_First.AddElementMatPeriodic(
                        isYDirectionPeriodic,
                        isSVEA,
                        waveLength,
                        nodeCntPeriodic,
                        freeNodeCntPeriodic_0,
                        toSortedPeriodic,
                        femElement,
                        Nodes,
                        Medias,
                        ForceNodeNumberH,
                        WaveModeDv,
                        ref KMat0,
                        ref CMat0,
                        ref MMat0);
                }
                else
                {
                    System.Diagnostics.Debug.Assert(false);
                }
            }

            double periodicDistance = latticeA; // 正方格子誘電体ロッド限定
            bool isModeTrace = false;
            KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null;
            double minBeta = 0.00; // 正方格子誘電体ロッド限定
            //double maxBeta = 0.90; // 正方格子誘電体ロッド限定
            double maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0;
            bool isPortBc2Reverse = false;
            // 伝搬定数
            KrdLab.clapack.Complex[] betamToSolveList = null;
            // 界ベクトルは全節点分作成
            KrdLab.clapack.Complex[][] resVecList = null;
            if (isSVEA)
            {
                System.Diagnostics.Debug.Assert(isSVEA == true);
                solveSVEAAsQuadraticGeneralizedEigenToStandardWithRealMat(
                    incidentModeIndex,
                    k0,
                    KMat0,
                    CMat0,
                    MMat0,
                    isPortBc2Reverse,
                    nodeCntPeriodic,
                    freeNodeCntPeriodic_0,
                    freeNodeCntPeriodic,
                    nodeCntBPeriodic,
                    sortedNodesPeriodic,
                    toSortedPeriodic,
                    toNodePeriodic,
                    toNodePeriodicB1,
                    defectNodePeriodic,
                    isModeTrace,
                    ref tmpPrevModalVec_1stMode,
                    minBeta,
                    maxBeta,
                    k0, //(2.0 * pi / periodicDistance), //k0, //1.0,
                    out betamToSolveList,
                    out resVecList);
            }
            else
            {
                System.Diagnostics.Debug.Assert(isSVEA == false);
                solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat(
                    incidentModeIndex,
                    periodicDistance,
                    k0,
                    KMat0,
                    isPortBc2Reverse,
                    nodeCntPeriodic,
                    freeNodeCntPeriodic_0,
                    freeNodeCntPeriodic,
                    nodeCntBPeriodic,
                    sortedNodesPeriodic,
                    toSortedPeriodic,
                    toNodePeriodic,
                    toNodePeriodicB1,
                    coordsPeriodic,
                    defectNodePeriodic,
                    isModeTrace,
                    ref tmpPrevModalVec_1stMode,
                    minBeta,
                    maxBeta,
                    (2.0 * pi / periodicDistance), //k0, //1.0,
                    out betamToSolveList,
                    out resVecList);
            }

            // 固有値が1つでも取得できているかチェック
            if (betamToSolveList == null)
            {
                System.Diagnostics.Debug.WriteLine("betamToSolveList == null");
                //System.Diagnostics.Debug.Assert(false);
                return;
            }
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex betam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                // ポート境界1の節点の値を境界2にも格納する
                for (int ino = 0; ino < nodePeriodicB1.Count; ino++)
                {
                    // 境界1の節点
                    int nodeNumberPortBc1 = nodePeriodicB1[ino];
                    int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1];

                    // 境界2の節点
                    int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino;
                    int nodeNumberPortBc2 = nodePeriodicB2[ino_B2];

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

            /////////////////////////////////////////////////////////////////////////////////////
            // 位相調整

            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    /*
                    // 境界上で位相調整する
                    for (int ino = 0; ino < nodePeriodicB1.Count; ino++)
                    {
                        int nodeNumberPortBc1 = nodePeriodicB1[ino];
                        int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1];
                        KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                     */

                    // 領域全体で位相調整する
                    for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++)
                    {
                        KrdLab.clapack.Complex cvalue = resVec[ino_InLoop];
                        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;
                }
            }

            /////////////////////////////////////////////////////////////////////////////////////
            // X方向の微分値を取得する
            KrdLab.clapack.Complex[][] resDFDXVecList = new KrdLab.clapack.Complex[betamToSolveList.Length][];
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = null;
                KrdLab.clapack.Complex[] resDFDYVec = null;
                double rotAngle = 0.0; // 暫定
                double[] rotOrigin = null; // 暫定

                if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder)
                {
                    // 2次三角形要素
                    getDFDXValues_Tri_SecondOrder(
                        WaveModeDv,
                        k0,
                        rotAngle,
                        rotOrigin,
                        Nodes,
                        Elements,
                        Medias,
                        ForceNodeNumberH,
                        elemNoPeriodic,
                        nodePeriodicB,
                        toNodePeriodic,
                        resVec,
                        out resDFDXVec,
                        out resDFDYVec);
                }
                else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder)
                {
                    // 1次三角形要素
                    getDFDXValues_Tri_FirstOrder(
                        WaveModeDv,
                        k0,
                        rotAngle,
                        rotOrigin,
                        Nodes,
                        Elements,
                        Medias,
                        ForceNodeNumberH,
                        elemNoPeriodic,
                        nodePeriodicB,
                        toNodePeriodic,
                        resVec,
                        out resDFDXVec,
                        out resDFDYVec);
                }
                else
                {
                    System.Diagnostics.Debug.Assert(false);
                }
                if (isYDirectionPeriodic)
                {
                    // Y方向周期構造の場合
                    resDFDXVecList[imode] = resDFDYVec;
                }
                else
                {
                    // X方向周期構造の場合
                    resDFDXVecList[imode] = resDFDXVec;
                }
            }
            // 境界1と境界2の節点の微分値は同じという条件を弱形式で課している為、微分値は同じにならない。
            // 加えて、getDFDXValuesは内部節点からの寄与を片側のみしか計算していない。
            // →境界の両側からの寄与を考慮する為に境界1の微分値と境界2の微分値を平均してみる
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex betam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];
                // ポート境界1の節点の微分値、ポート境界2の微分値は、両者の平均をとる
                for (int ino = 0; ino < nodePeriodicB1.Count; ino++)
                {
                    // 境界1の節点
                    int nodeNumberPortBc1 = nodePeriodicB1[ino];
                    int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1];
                    // 境界1の節点の界の微分値値を取得
                    KrdLab.clapack.Complex cdFdXValue1 = resDFDXVec[ino_InLoop_PortBc1];

                    // 境界2の節点
                    int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino;
                    int nodeNumberPortBc2 = nodePeriodicB2[ino_B2];
                    int ino_InLoop_PortBc2 = toNodePeriodic[nodeNumberPortBc2];
                    // 境界2の節点の界の微分値値を取得
                    KrdLab.clapack.Complex cdFdXValue2 = resDFDXVec[ino_InLoop_PortBc2];

                    // 平均値を計算し、境界の微分値として再格納する
                    if (isSVEA)
                    {
                        KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2) * 0.5;
                        resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue;
                        resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue;
                    }
                    else
                    {
                        // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1
                        KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance);
                        // Φ2から逆算でΦ1を求め、平均をとる
                        KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2 / expA) * 0.5;
                        resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue;
                        resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue * expA;
                    }
                }
            }

            //////////////////////////////////////////////////////////////////////////////////////
            if (!isSVEA)
            {
                // 緩慢変化包絡線近似でない場合は、緩慢変化包絡線近似の分布に変換する
                for (int imode = 0; imode < betamToSolveList.Length; imode++)
                {
                    KrdLab.clapack.Complex betam = betamToSolveList[imode];
                    KrdLab.clapack.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                    KrdLab.clapack.Complex[] resVec = resVecList[imode];
                    KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];
                    System.Diagnostics.Debug.Assert(resVec.Length == coordsPeriodic.Count);
                    int nodeNumber1st = sortedNodesPeriodic[0];
                    int ino_InLoop_1st = toNodePeriodic[nodeNumber1st];
                    double[] coord1st = coordsPeriodic[ino_InLoop_1st];
                    for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++)
                    {
                        // 節点の界の値
                        KrdLab.clapack.Complex fieldVal = resVec[ino_InLoop];
                        // 節点の界の微分値
                        KrdLab.clapack.Complex dFdXVal = resDFDXVec[ino_InLoop];
                        // 節点の座標
                        double[] coord = coordsPeriodic[ino_InLoop];
                        double x_pt = 0.0;
                        if (isYDirectionPeriodic)
                        {
                            x_pt = (coord[1] - coord1st[1]);
                        }
                        else
                        {
                            x_pt = (coord[0] - coord1st[0]);
                        }
                        //KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * x_pt);
                        KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * x_pt);

                        // ΦのSVEA(φ)
                        KrdLab.clapack.Complex fieldVal_SVEA = fieldVal / expX;
                        resVec[ino_InLoop] = fieldVal_SVEA;

                        // SVEAの微分( exp(-jβx)dφ/dx = dΦ/dx + jβφexp(-jβx))
                        //resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam * fieldVal_SVEA;
                        resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * fieldVal_SVEA;
                    }
                }
            }

            System.Diagnostics.Debug.WriteLine("betamToSolveList.Length {0}", betamToSolveList.Length);

            //////////////////////////////////////////////////////////////////////////////////////
            // モード数の修正
            int maxMode = maxModeSpecified;
            if (maxMode > betamToSolveList.Length)
            {
                maxMode = betamToSolveList.Length;
            }

            //////////////////////////////////////////////////////////////////////////////////////
            // 表示用に周期構造領域の固有モード分布を格納する
            eigenVecsPeriodic = new KrdLab.clapack.Complex[maxMode][];
            for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++)
            {
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                System.Diagnostics.Debug.Assert(resVec.Length == nodePeriodic.Count);
                eigenVecsPeriodic[tagtModeIndex] = new KrdLab.clapack.Complex[nodePeriodic.Count];
                resVec.CopyTo(eigenVecsPeriodic[tagtModeIndex], 0);
            }

            //////////////////////////////////////////////////////////////////////////////////////
            // 固有値、固有ベクトル
            // 格納
            int nodeCntB1 = nodePeriodicB1.Count;
            eigenValues = new Complex[maxMode];
            //eigenVecsB1 = new Complex[maxMode, nodeCntB1];
            //eigen_dFdXsB1 = new Complex[maxMode, nodeCntB1];
            eigenVecsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く
            eigen_dFdXsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く
            for (int imode = 0; imode < maxMode; imode++)
            {
                eigenValues[imode] = new Complex(0, 0);
                for (int ino = 0; ino < eigenVecsB1.GetLength(1); ino++)
                {
                    eigenVecsB1[imode, ino] = new Complex(0, 0);
                    eigen_dFdXsB1[imode, ino] = new Complex(0, 0);
                }
            }
            for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++)
            {
                //System.Diagnostics.Debug.WriteLine("imode = {0}", imode);

                KrdLab.clapack.Complex workBetam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];

                Complex betam = new Complex(workBetam.Real, workBetam.Imaginary);
                bool isComplexConjugateMode = false;
                //   減衰定数は符号がマイナス(β = -jα)
                if (betam.Imaginary > 0.0 && Math.Abs(betam.Real) <= 1.0e-12)
                {
                    betam = new Complex(betam.Real, -betam.Imaginary);
                    isComplexConjugateMode = true;
                }
                //Complex[] evec = new Complex[nodeCntB1];
                //Complex[] evec_dFdX = new Complex[nodeCntB1];
                Complex[] evec = new Complex[nodesBoundary.Length]; // 強制境界を除く
                Complex[] evec_dFdX = new Complex[nodesBoundary.Length]; // 強制境界を除く
                for (int ino = 0; ino < nodeCntB1; ino++)
                {
                    int nodeNumberPortBc1 = nodePeriodicB1[ino];
                    //System.Diagnostics.Debug.WriteLine("ino = {0} nodeNumberPortBc1 = {1}", ino, nodeNumberPortBc1);
                    int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1];
                    Complex cvalue = new Complex(resVec[ino_InLoop_PortBc1].Real, resVec[ino_InLoop_PortBc1].Imaginary);
                    Complex dFdXValue = new Complex(resDFDXVec[ino_InLoop_PortBc1].Real, resDFDXVec[ino_InLoop_PortBc1].Imaginary);
                    if (isComplexConjugateMode)
                    {
                        cvalue = Complex.Conjugate(cvalue);
                        dFdXValue = Complex.Conjugate(dFdXValue);
                    }

                    //evec[ino] = cvalue;
                    //evec_dFdX[ino] = dFdXValue;
                    ///////////////////////////////////////////////////
                    // 強制境界を除く
                    if (!toNodesB.ContainsKey(nodeNumberPortBc1))
                    {
                        continue;
                    }
                    int ino_f = toNodesB[nodeNumberPortBc1];
                    //System.Diagnostics.Debug.WriteLine("ino_f = {0}", ino_f);

                    evec[ino_f] = cvalue;
                    evec_dFdX[ino_f] = dFdXValue;
                    ///////////////////////////////////////////////////

                    //if (tagtModeIndex == incidentModeIndex)
                    {
                        //System.Diagnostics.Debug.WriteLine("evec[{0}] = {1} + {2} i", ino_f, evec[ino_f].Real, evec[ino_f].Imaginary);
                    }
                }
                // 規格化定数を求める
                Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec);
                //Complex[] evec_Modify = new Complex[nodeCntB1];
                Complex[] evec_Modify = new Complex[nodesBoundary.Length];//強制境界を除く
                Complex imagOne = new Complex(0.0, 1.0);
                Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                for (int ino = 0; ino < nodeCntB1; ino++)
                {
                    //evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam_periodic);
                    ///////////////////////////////////////////////////
                    // 強制境界を除く
                    int nodeNumberPortBc1 = nodePeriodicB1[ino];
                    if (!toNodesB.ContainsKey(nodeNumberPortBc1))
                    {
                        continue;
                    }
                    int ino_f = toNodesB[nodeNumberPortBc1];
                    evec_Modify[ino_f] = evec[ino_f] - evec_dFdX[ino_f] / (imagOne * betam_periodic);
                    ///////////////////////////////////////////////////
                }
                //Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec);
                Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec_Modify), workVec);
                if (WaveModeDv == FemSolver.WaveModeDV.TM)
                {
                    // TMモード
                    dm = Complex.Sqrt(omega * eps0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm);
                }
                else
                {
                    // TEモード
                    dm = Complex.Sqrt(omega * mu0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm);
                }

                // 伝搬定数の格納
                eigenValues[tagtModeIndex] = betam;
                if (tagtModeIndex < 10)
                {
                    System.Diagnostics.Debug.WriteLine("β/k0  ( " + tagtModeIndex + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + ((incidentModeIndex == tagtModeIndex) ? " incident" : ""));
                }
                // 固有ベクトルの格納(規格化定数を掛ける)
                for (int ino = 0; ino < evec.Length; ino++)
                {
                    Complex fm = dm * evec[ino];
                    Complex dfmdx = dm * evec_dFdX[ino];
                    eigenVecsB1[tagtModeIndex, ino] = fm;
                    eigen_dFdXsB1[tagtModeIndex, ino] = dfmdx;
                    //System.Diagnostics.Debug.WriteLine("eigen_vecs_Bc1({0}, {1}) = {2} + {3} i", imode, ino, fm.Real, fm.Imag);
                }
            }
            System.Diagnostics.Debug.WriteLine("eigen end");
        }
        public static void GetSortedModes(
            int incidentModeIndex,
            double k0,
            int nodeCntPeriodic,
            int freeNodeCntPeriodic,
            int nodeCntBPeriodic,
            IList<int> sortedNodesPeriodic,
            Dictionary<int, int> toSortedPeriodic,
            Dictionary<int, int> toNodePeriodic,
            IList<int> defectNodePeriodic,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            double minBeta,
            double maxBeta,
            KrdLab.clapack.Complex[] evals,
            KrdLab.clapack.Complex[,] evecs,
            bool isDebugShow,
            out KrdLab.clapack.Complex[] betamToSolveList,
            out KrdLab.clapack.Complex[][] resVecList)
        {
            betamToSolveList = null;
            resVecList = null;

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

            // 欠陥モードを取得
            IList<int> defectModeIndexList = new List<int>();
            // 追跡するモードのインデックス退避
            int traceModeIndex = -1;
            // フォトニック結晶導波路解析用
            {
                double hitNorm = 0.0;
                for (int imode = 0; imode < evals.Length; imode++)
                {
                    // 伝搬定数
                    KrdLab.clapack.Complex betam = evals[imode];
                    // 界ベクトル
                    KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode);

                    // フォトニック結晶導波路の導波モードを判定する
                    //System.Diagnostics.Debug.Assert((free_node_cnt * 2) == fieldVec.Length);
                    bool isHitDefectMode = isDefectMode(
                        k0,
                        freeNodeCntPeriodic,
                        sortedNodesPeriodic,
                        toSortedPeriodic,
                        defectNodePeriodic,
                        minBeta,
                        maxBeta,
                        betam,
                        fieldVec);

                    // 入射モードを追跡する
                    if (isHitDefectMode
                        && isModeTrace && PrevModalVec != null)
                    {
                        // 同じ固有モード?
                        double ret_norm = 0.0;
                        bool isHitSameMode = isSameMode(
                            k0,
                            nodeCntPeriodic,
                            PrevModalVec,
                            freeNodeCntPeriodic,
                            toNodePeriodic,
                            sortedNodesPeriodic,
                            toSortedPeriodic,
                            betam,
                            fieldVec,
                            out ret_norm);
                        if (isHitSameMode)
                        {
                            // より分布の近いモードを採用する
                            if (Math.Abs(ret_norm - 1.0) < Math.Abs(hitNorm - 1.0))
                            {
                                // 追跡するモードのインデックス退避
                                traceModeIndex = imode;
                                hitNorm = ret_norm;
                                if (isDebugShow)
                                {
                                    System.Diagnostics.Debug.WriteLine("PCWaveguideMode(ModeTrace): imode = {0} β/k0 = {1} + {2} i", imode, betam.Real / k0, betam.Imaginary / k0);
                                }
                            }
                        }
                    }

                    if (isHitDefectMode)
                    {
                        if (isDebugShow)
                        {
                            System.Diagnostics.Debug.WriteLine("PCWaveguideMode: imode = {0} β/k0 = {1} + {2} i", imode, betam.Real / k0, betam.Imaginary / k0);
                        }
                        if (imode != traceModeIndex) // 追跡するモードは除外、あとで追加
                        {
                            defectModeIndexList.Add(imode);
                        }
                    }
                }
                if (isModeTrace && traceModeIndex != -1)
                {
                    if (isDebugShow)
                    {
                        System.Diagnostics.Debug.WriteLine("traceModeIndex:{0}", traceModeIndex);
                    }
                    // 追跡している入射モードがあれば最後に追加する
                    //defectModeIndexList.Add(traceModeIndex);
                    // 追跡している入射モードがあれば最後から入射モードインデックス分だけシフトした位置に挿入する
                    if (defectModeIndexList.Count >= (0 + incidentModeIndex))
                    {
                        defectModeIndexList.Insert(defectModeIndexList.Count - incidentModeIndex, traceModeIndex);
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("other modes dissappeared ! defectModeIndexList cleared.");
                        traceModeIndex = -1;
                        defectModeIndexList.Clear();
                    }
                }
            }
            IList<int> selectedModeList = new List<int>();
            // フォトニック結晶導波路解析用
            {
                // フォトニック結晶導波路
                if (defectModeIndexList.Count > 0)
                {
                    // フォトニック結晶欠陥部閉じ込めモード
                    for (int iDefectModeIndex = defectModeIndexList.Count - 1; iDefectModeIndex >= 0; iDefectModeIndex--)
                    {
                        int imode = defectModeIndexList[iDefectModeIndex];
                        // 伝搬定数
                        KrdLab.clapack.Complex betam = evals[imode];
                        // 界ベクトル
                        KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode);
                        if (Math.Abs(betam.Real) < 1.0e-12 && Math.Abs(betam.Imaginary) >= 1.0e-12)
                        {
                            // 減衰モード
                            // 正しく計算できていないように思われる
                            if (selectedModeList.Count > incidentModeIndex)
                            {
                                // 基本モード以外の減衰モードは除外する
                                //System.Diagnostics.Debug.WriteLine("skip evanesent mode:β/k0  ( " + imode + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i ");
                                continue;
                            }
                        }
                        selectedModeList.Add(imode);
                    }
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not converged photonic crystal waveguide mode");
                }
            }
            if (selectedModeList.Count > 0)
            {
                betamToSolveList = new KrdLab.clapack.Complex[selectedModeList.Count];
                resVecList = new KrdLab.clapack.Complex[selectedModeList.Count][];
                for (int imode = 0; imode < betamToSolveList.Length; imode++)
                {
                    resVecList[imode] = new KrdLab.clapack.Complex[nodeCntPeriodic]; // 全節点
                }
                for (int i = selectedModeList.Count - 1, selectedModeIndex = 0; i >= 0; i--, selectedModeIndex++)
                {
                    int imode = selectedModeList[i];
                    // 伝搬定数、固有ベクトルの格納
                    betamToSolveList[selectedModeIndex] = evals[imode];

                    KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode);
                    // 非線形固有値方程式の解は{Φ} {λΦ}の順になっている
                    //System.Diagnostics.Debug.Assert((evec.Length == free_node_cnt * 2));
                    // 前半の{Φ}のみ取得する
                    for (int ino = 0; ino < freeNodeCntPeriodic; ino++)
                    {
                        int nodeNumber = sortedNodesPeriodic[ino];
                        int ino_InLoop = toNodePeriodic[nodeNumber];
                        resVecList[selectedModeIndex][ino_InLoop] = evec[ino];
                    }
                    if (isDebugShow)
                    {
                        System.Diagnostics.Debug.WriteLine("mode({0}): index:{1} β/k0 = {2} + {3} i", selectedModeIndex, imode, (betamToSolveList[selectedModeIndex].Real / k0), (betamToSolveList[selectedModeIndex].Imaginary / k0));
                    }
                }
            }

            if (isModeTrace)
            {
                if (PrevModalVec != null && (traceModeIndex == -1))
                {
                    // モード追跡に失敗した場合
                    betamToSolveList = null;
                    resVecList = null;
                    System.Diagnostics.Debug.WriteLine("fail to trace mode at k0 = {0}", k0);
                    System.Diagnostics.Debug.WriteLine("fail to trace mode at k0 = {0}", k0);
                    return;
                }

                // 前回の固有ベクトルを更新
                if ((PrevModalVec == null || (PrevModalVec != null && traceModeIndex != -1)) // 初回格納、またはモード追跡に成功した場合だけ更新
                    && (betamToSolveList != null && betamToSolveList.Length >= (1 + incidentModeIndex))
                    )
                {
                    // 返却用リストでは伝搬定数の昇順に並んでいる→入射モードは最後
                    KrdLab.clapack.Complex betam = betamToSolveList[betamToSolveList.Length - 1 - incidentModeIndex];
                    KrdLab.clapack.Complex[] resVec = resVecList[betamToSolveList.Length - 1 - incidentModeIndex];
                    if (betam.Real != 0.0 && Math.Abs(betam.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                    {
                        //PrevModalVec = resVec;
                        PrevModalVec = new KrdLab.clapack.Complex[nodeCntPeriodic];
                        resVec.CopyTo(PrevModalVec, 0);
                    }
                    else
                    {
                        // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように)
                        //PrevModalVec = null;
                    }
                }
                else
                {
                    // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように)
                    //PrevModalVec = null;
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////
        // Φ = φexp(-jβx)と置く方法(SVEA)
        private static void solveSVEAAsQuadraticGeneralizedEigenToStandardWithRealMat(
            int incidentModeIndex,
            double k0,
            double[] KMat0,
            double[] CMat0,
            double[] MMat0,
            bool isPortBc2Reverse,
            int nodeCntPeriodic,
            int freeNodeCntPeriodic_0,
            int freeNodeCnt,
            int nodeCntBPeriodic,
            IList<int> sortedNodesPeriodic,
            Dictionary<int, int> toSortedPeriodic,
            Dictionary<int, int> toNodePeriodic,
            Dictionary<int, int> toNodePeriodicB1,
            IList<int> defectNodePeriodic,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            double minBeta,
            double maxBeta,
            double betaNormalizingFactor,
            out KrdLab.clapack.Complex[] betamToSolveList,
            out KrdLab.clapack.Complex[][] resVecList)
        {
            betamToSolveList = null;
            resVecList = null;

            double[] KMat = new double[freeNodeCnt * freeNodeCnt];
            double[] CMat = new double[freeNodeCnt * freeNodeCnt];
            double[] MMat = new double[freeNodeCnt * freeNodeCnt];
            for (int i = 0; i < freeNodeCnt; i++)
            {
                for (int j = 0; j < freeNodeCnt; j++)
                {
                    KMat[i + freeNodeCnt * j] = KMat0[i + freeNodeCntPeriodic_0 * j];
                    CMat[i + freeNodeCnt * j] = CMat0[i + freeNodeCntPeriodic_0 * j];
                    MMat[i + freeNodeCnt * j] = MMat0[i + freeNodeCntPeriodic_0 * j];
                }
            }
            for (int i = 0; i < freeNodeCnt; i++)
            {
                for (int j = 0; j < nodeCntBPeriodic; j++)
                {
                    int jno_B2 = isPortBc2Reverse ? (int)(freeNodeCnt + nodeCntBPeriodic - 1 - j) : (int)(freeNodeCnt + j);
                    KMat[i + freeNodeCnt * j] += KMat0[i + freeNodeCntPeriodic_0 * jno_B2];
                    CMat[i + freeNodeCnt * j] += CMat0[i + freeNodeCntPeriodic_0 * jno_B2];
                    MMat[i + freeNodeCnt * j] += MMat0[i + freeNodeCntPeriodic_0 * jno_B2];
                }
            }
            for (int i = 0; i < nodeCntBPeriodic; i++)
            {
                for (int j = 0; j < freeNodeCnt; j++)
                {
                    int ino_B2 = isPortBc2Reverse ? (int)(freeNodeCnt + nodeCntBPeriodic - 1 - i) : (int)(freeNodeCnt + i);
                    KMat[i + freeNodeCnt * j] += KMat0[ino_B2 + freeNodeCntPeriodic_0 * j];
                    CMat[i + freeNodeCnt * j] += CMat0[ino_B2 + freeNodeCntPeriodic_0 * j];
                    MMat[i + freeNodeCnt * j] += MMat0[ino_B2 + freeNodeCntPeriodic_0 * j];
                }
                for (int j = 0; j < nodeCntBPeriodic; j++)
                {
                    int ino_B2 = isPortBc2Reverse ? (int)(freeNodeCnt + nodeCntBPeriodic - 1 - i) : (int)(freeNodeCnt + i);
                    int jno_B2 = isPortBc2Reverse ? (int)(freeNodeCnt + nodeCntBPeriodic - 1 - j) : (int)(freeNodeCnt + j);
                    KMat[i + freeNodeCnt * j] += KMat0[ino_B2 + freeNodeCntPeriodic_0 * jno_B2];
                    CMat[i + freeNodeCnt * j] += CMat0[ino_B2 + freeNodeCntPeriodic_0 * jno_B2];
                    MMat[i + freeNodeCnt * j] += MMat0[ino_B2 + freeNodeCntPeriodic_0 * jno_B2];
                }
            }
            // 行列要素check
            {
                for (int i = 0; i < freeNodeCnt; i++)
                {
                    for (int j = i; j < freeNodeCnt; j++)
                    {
                        // [K]は対称行列
                        System.Diagnostics.Debug.Assert(Math.Abs(KMat[i + freeNodeCnt * j] - KMat[j + freeNodeCnt * i]) < Constants.PrecisionLowerLimit);
                        // [M]は対称行列
                        System.Diagnostics.Debug.Assert(Math.Abs(MMat[i + freeNodeCnt * j] - MMat[j + freeNodeCnt * i]) < Constants.PrecisionLowerLimit);
                        // [C]は反対称行列
                        System.Diagnostics.Debug.Assert(Math.Abs((-CMat[i + freeNodeCnt * j]) - CMat[j + freeNodeCnt * i]) < Constants.PrecisionLowerLimit);
                    }
                }
            }

            // 非線形固有値問題
            //  { [K] - jβ[C] - β^2[M] }{Φ}= {0}
            //  λ= - jβとおくと
            //  [K] + λ[C] + λ^2[M]{Φ}= {0}
            //
            // Lisys(Lapack)による固有値解析
            // マトリクスサイズは、強制境界及び境界3を除いたサイズ
            int matLen = (int)freeNodeCnt;
            KrdLab.clapack.Complex[] evals = null;
            KrdLab.clapack.Complex[,] evecs = null;

            // [M]の逆行列が存在する緩慢変化包絡線近似の場合のみ有効な方法
            //   Φを直接解く場合は使えない
            System.Diagnostics.Debug.WriteLine("calc [M]-1");
            // [M]の逆行列を求める
            double[] invMMat = MyUtilLib.Matrix.MyMatrixUtil.matrix_Inverse(MMat, matLen);
            System.Diagnostics.Debug.WriteLine("calc [M]-1[K]");
            // [M]-1[K]
            double[] invMKMat = MyUtilLib.Matrix.MyMatrixUtil.product(invMMat, matLen, matLen, KMat, matLen, matLen);
            System.Diagnostics.Debug.WriteLine("calc [M]-1[C]");
            // [M]-1[C]
            double[] invMCMat = MyUtilLib.Matrix.MyMatrixUtil.product(invMMat, matLen, matLen, CMat, matLen, matLen);

            // 標準固有値解析(実行列として解く)
            double[] A = new double[(matLen * 2) * (matLen * 2)];
            System.Diagnostics.Debug.WriteLine("set [A]");
            for (int i = 0; i < matLen; i++)
            {
                for (int j = 0; j < matLen; j++)
                {
                    A[i + j * (matLen * 2)] = 0.0;
                    A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0;
                    //  { [K] - jβ[C] - β^2[M] }{Φ}= {0}
                    // λ = -jβと置いた場合
                    //A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen];
                    //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen];
                    // λ = -j(β/k0)と置いた場合
                    //A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen] / (k0 * k0);
                    //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen] / (k0);
                    // λ = -j(β/betaNormalizingFactor)と置いた場合
                    A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen] / (betaNormalizingFactor * betaNormalizingFactor);
                    A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen] / (betaNormalizingFactor);
                }
            }
            double[] ret_r_evals = null;
            double[] ret_i_evals = null;
            double[][] ret_r_evecs = null;
            double[][] ret_i_evecs = null;
            System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.dgeev");
            KrdLab.clapack.FunctionExt.dgeev(A, (matLen * 2), (matLen * 2), ref ret_r_evals, ref ret_i_evals, ref ret_r_evecs, ref ret_i_evecs);

            evals = new KrdLab.clapack.Complex[ret_r_evals.Length];
            // βを格納
            for (int i = 0; i < ret_r_evals.Length; i++)
            {
                KrdLab.clapack.Complex eval = new KrdLab.clapack.Complex(ret_r_evals[i], ret_i_evals[i]);
                //  { [K] - jβ[C] - β^2[M] }{Φ}= {0}
                // λ = -jβと置いた場合(β = jλ)
                //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne;
                // λ = -j(β/k0)と置いた場合
                //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * k0;
                // λ = -j(β/betaNormalizingFactor)と置いた場合
                evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * betaNormalizingFactor;
            }

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

            // 固有値をソートする
            System.Diagnostics.Debug.Assert(evecs.GetLength(1) == freeNodeCnt * 2);
            GetSortedModes(
                incidentModeIndex,
                k0,
                nodeCntPeriodic,
                freeNodeCnt,
                nodeCntBPeriodic,
                sortedNodesPeriodic,
                toSortedPeriodic,
                toNodePeriodic,
                defectNodePeriodic,
                isModeTrace,
                ref PrevModalVec,
                minBeta,
                maxBeta,
                evals,
                evecs,
                true, // isDebugShow
                out betamToSolveList,
                out resVecList);
        }
        //////////////////////////////////////////////////////////////////////////////////////////////////
        // 周期構造導波路固有値問題:Φを直接解く方法
        private static void solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat(
            int incidentModeIndex,
            double periodicDistance,
            double k0,
            double[] KMat0,
            bool isPortBc2Reverse,
            int nodeCntPeriodic,
            int freeNodeCntPeriodic_0,
            int freeNodeCntPeriodic,
            int nodeCntBPeriodic,
            IList<int> sortedNodesPeriodic,
            Dictionary<int, int> toSortedPeriodic,
            Dictionary<int, int> toNodePeriodic,
            Dictionary<int, int> toNodePeriodicB1,
            IList<double[]> coordsPeriodic,
            IList<int> defectNodePeriodic,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            double minBeta,
            double maxBeta,
            double betaNormalizingFactor,
            out KrdLab.clapack.Complex[] betamToSolveList,
            out KrdLab.clapack.Complex[][] resVecList)
        {
            betamToSolveList = null;
            resVecList = null;

            // 複素モード、エバネセントモードの固有ベクトル計算をスキップする? (計算時間短縮するため)
            bool isSkipCalcComplexAndEvanescentModeVec = true;
            System.Diagnostics.Debug.WriteLine("isSkipCalcComplexAndEvanescentModeVec: {0}", isSkipCalcComplexAndEvanescentModeVec);
            // 緩慢変化包絡線近似? Φを直接解く方法なので常にfalse
            const bool isSVEA = false; // Φを直接解く方法
            // 境界1のみの式に変換
            int inner_node_cnt = freeNodeCntPeriodic - nodeCntBPeriodic;
            double[] P11 = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            double[] P10 = new double[nodeCntBPeriodic * inner_node_cnt];
            double[] P12 = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            double[] P01 = new double[inner_node_cnt * nodeCntBPeriodic];
            double[] P00 = new double[inner_node_cnt * inner_node_cnt];
            double[] P02 = new double[inner_node_cnt * nodeCntBPeriodic];
            double[] P21 = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            double[] P20 = new double[nodeCntBPeriodic * inner_node_cnt];
            double[] P22 = new double[nodeCntBPeriodic * nodeCntBPeriodic];

            for (int i = 0; i < nodeCntBPeriodic; i++)
            {
                int ino_B2 = isPortBc2Reverse ? (int)(freeNodeCntPeriodic + nodeCntBPeriodic - 1 - i) : (int)(freeNodeCntPeriodic + i);
                for (int j = 0; j < nodeCntBPeriodic; j++)
                {
                    int jno_B2 = isPortBc2Reverse ? (int)(freeNodeCntPeriodic + nodeCntBPeriodic - 1 - j) : (int)(freeNodeCntPeriodic + j);
                    // [K11]
                    P11[i + nodeCntBPeriodic * j] = KMat0[i + freeNodeCntPeriodic_0 * j];
                    // [K12]
                    P12[i + nodeCntBPeriodic * j] = KMat0[i + freeNodeCntPeriodic_0 * jno_B2];
                    // [K21]
                    P21[i + nodeCntBPeriodic * j] = KMat0[ino_B2 + freeNodeCntPeriodic_0 * j];
                    // [K22]
                    P22[i + nodeCntBPeriodic * j] = KMat0[ino_B2 + freeNodeCntPeriodic_0 * jno_B2];
                }
                for (int j = 0; j < inner_node_cnt; j++)
                {
                    // [K10]
                    P10[i + nodeCntBPeriodic * j] = KMat0[i + freeNodeCntPeriodic_0 * (j + nodeCntBPeriodic)];
                    // [K20]
                    P20[i + nodeCntBPeriodic * j] = KMat0[ino_B2 + freeNodeCntPeriodic_0 * (j + nodeCntBPeriodic)];
                }
            }
            for (int i = 0; i < inner_node_cnt; i++)
            {
                for (int j = 0; j < nodeCntBPeriodic; j++)
                {
                    int jno_B2 = isPortBc2Reverse ? (int)(freeNodeCntPeriodic + nodeCntBPeriodic - 1 - j) : (int)(freeNodeCntPeriodic + j);
                    // [K01]
                    P01[i + inner_node_cnt * j] = KMat0[(i + nodeCntBPeriodic) + freeNodeCntPeriodic_0 * j];
                    // [K02]
                    P02[i + inner_node_cnt * j] = KMat0[(i + nodeCntBPeriodic) + freeNodeCntPeriodic_0 * jno_B2];
                }
                for (int j = 0; j < inner_node_cnt; j++)
                {
                    // [K00]
                    P00[i + inner_node_cnt * j] = KMat0[(i + nodeCntBPeriodic) + freeNodeCntPeriodic_0 * (j + nodeCntBPeriodic)];
                }
            }

            System.Diagnostics.Debug.WriteLine("setup [K]B [C]B [M]B");
            double[] invP00 = MyMatrixUtil.matrix_Inverse(P00, (int)(freeNodeCntPeriodic - nodeCntBPeriodic));
            double[] P10_invP00 = MyMatrixUtil.product(
                P10, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                invP00, (int)inner_node_cnt, (int)inner_node_cnt);
            double[] P20_invP00 = MyMatrixUtil.product(
                P20, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                invP00, (int)inner_node_cnt, (int)inner_node_cnt);
            // for [C]B
            double[] P10_invP00_P01 = MyMatrixUtil.product(
                P10_invP00, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                P01, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            double[] P20_invP00_P02 = MyMatrixUtil.product(
                P20_invP00, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                P02, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            // for [M]B
            double[] P10_invP00_P02 = MyMatrixUtil.product(
                P10_invP00, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                P02, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            // for [K]B
            double[] P20_invP00_P01 = MyMatrixUtil.product(
                P20_invP00, (int)nodeCntBPeriodic, (int)inner_node_cnt,
                P01, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            // [C]B
            double[] CMatB = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            // [M]B
            double[] MMatB = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            // [K]B
            double[] KMatB = new double[nodeCntBPeriodic * nodeCntBPeriodic];
            for (int i = 0; i < nodeCntBPeriodic; i++)
            {
                for (int j = 0; j < nodeCntBPeriodic; j++)
                {
                    CMatB[i + nodeCntBPeriodic * j] =
                        - P10_invP00_P01[i + nodeCntBPeriodic * j]
                        + P11[i + nodeCntBPeriodic * j]
                        - P20_invP00_P02[i + nodeCntBPeriodic * j]
                        + P22[i + nodeCntBPeriodic * j];
                    MMatB[i + nodeCntBPeriodic * j] =
                        - P10_invP00_P02[i + nodeCntBPeriodic * j]
                        + P12[i + nodeCntBPeriodic * j];
                    KMatB[i + nodeCntBPeriodic * j] =
                        - P20_invP00_P01[i + nodeCntBPeriodic * j]
                        + P21[i + nodeCntBPeriodic * j];
                }
            }

            // 非線形固有値問題
            //  [K] + λ[C] + λ^2[M]{Φ}= {0}
            //
            // Lisys(Lapack)による固有値解析
            // マトリクスサイズは、強制境界及び境界3を除いたサイズ
            int matLen = (int)nodeCntBPeriodic;
            KrdLab.clapack.Complex[] evals = null;
            KrdLab.clapack.Complex[,] evecs = null;

            // 一般化固有値解析(実行列として解く)
            double[] A = new double[(matLen * 2) * (matLen * 2)];
            double[] B = new double[(matLen * 2) * (matLen * 2)];
            for (int i = 0; i < matLen; i++)
            {
                for (int j = 0; j < matLen; j++)
                {
                    A[i + j * (matLen * 2)] = 0.0;
                    A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0;
                    A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMatB[i + j * matLen];
                    A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * CMatB[i + j * matLen];
                }
            }
            for (int i = 0; i < matLen; i++)
            {
                for (int j = 0; j < matLen; j++)
                {
                    B[i + j * (matLen * 2)] = (i == j) ? 1.0 : 0.0;
                    B[i + (j + matLen) * (matLen * 2)] = 0.0;
                    B[(i + matLen) + j * (matLen * 2)] = 0.0;
                    B[(i + matLen) + (j + matLen) * (matLen * 2)] = MMatB[i + j * matLen];
                }
            }
            double[] ret_r_evals = null;
            double[] ret_i_evals = null;
            double[][] ret_r_evecs = null;
            double[][] ret_i_evecs = null;
            System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.dggev");
            KrdLab.clapack.FunctionExt.dggev(A, (matLen * 2), (matLen * 2), B, (matLen * 2), (matLen * 2), ref ret_r_evals, ref ret_i_evals, ref ret_r_evecs, ref ret_i_evecs);

            evals = new KrdLab.clapack.Complex[ret_r_evals.Length];
            // βを格納
            for (int i = 0; i < ret_r_evals.Length; i++)
            {
                KrdLab.clapack.Complex eval = new KrdLab.clapack.Complex(ret_r_evals[i], ret_i_evals[i]);
                //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary);
                if ((Math.Abs(eval.Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(eval.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                    || double.IsInfinity(eval.Real) || double.IsInfinity(eval.Imaginary)
                    || double.IsNaN(eval.Real) || double.IsNaN(eval.Imaginary)
                    )
                {
                    // 無効な固有値
                    //evals[i] = -1.0 * KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue;
                    evals[i] = KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue;
                }
                else
                {
                    //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary);
                    KrdLab.clapack.Complex betatmp = -1.0 * MyUtilLib.Matrix.MyMatrixUtil.complex_Log(eval) / (KrdLab.clapack.Complex.ImaginaryOne * periodicDistance);
                    evals[i] = new KrdLab.clapack.Complex(betatmp.Real, betatmp.Imaginary);
                }
            }
            System.Diagnostics.Debug.Assert(ret_r_evals.Length == ret_r_evecs.Length);
            // 2次元配列に格納する ({Φ}のみ格納)
            evecs = new KrdLab.clapack.Complex[ret_r_evecs.Length, freeNodeCntPeriodic];

            System.Diagnostics.Debug.WriteLine("calc {Φ}0");
            double[] invP00_P01 = MyMatrixUtil.product(
                invP00, (int)inner_node_cnt, (int)inner_node_cnt,
                P01, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            double[] invP00_P02 = MyMatrixUtil.product(
                invP00, (int)inner_node_cnt, (int)inner_node_cnt,
                P02, (int)inner_node_cnt, (int)nodeCntBPeriodic);
            KrdLab.clapack.Complex[] transMat = new KrdLab.clapack.Complex[inner_node_cnt * nodeCntBPeriodic];
            System.Diagnostics.Debug.Assert(evals.Length == ret_r_evecs.Length);
            System.Diagnostics.Debug.Assert(evals.Length == ret_i_evecs.Length);
            for (int imode = 0; imode < evals.Length; imode++)
            {
                KrdLab.clapack.Complex betam = evals[imode];
                // 複素モード、エバネセントモードの固有モード計算をスキップする?
                if (isSkipCalcComplexAndEvanescentModeVec)
                {
                    if (Math.Abs(betam.Imaginary) >= Constants.PrecisionLowerLimit)
                    {
                        // 複素モード、エバネセントモードの固有モード計算をスキップする
                        continue;
                    }
                }

                KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance);
                double[] ret_r_evec = ret_r_evecs[imode];
                double[] ret_i_evec = ret_i_evecs[imode];
                System.Diagnostics.Debug.Assert(ret_r_evec.Length == nodeCntBPeriodic * 2);
                KrdLab.clapack.Complex[] fVecB = new KrdLab.clapack.Complex[nodeCntBPeriodic];
                ///////////////////////////////
                // {Φ}Bのみ格納
                for (int ino = 0; ino < nodeCntBPeriodic; ino++)
                {
                    KrdLab.clapack.Complex cvalue = new KrdLab.clapack.Complex(ret_r_evec[ino], ret_i_evec[ino]);
                    evecs[imode, ino] = cvalue;
                    fVecB[ino] = cvalue;
                }

                ///////////////////////////////
                // {Φ}0を計算
                //   変換行列を計算
                for (int i = 0; i < inner_node_cnt; i++)
                {
                    for (int j = 0; j < nodeCntBPeriodic; j++)
                    {
                        transMat[i + inner_node_cnt * j] = -1.0 * (invP00_P01[i + inner_node_cnt * j] + expA * invP00_P02[i + inner_node_cnt * j]);
                    }
                }
                //   {Φ}0を計算
                KrdLab.clapack.Complex[] fVecInner = MyMatrixUtil.product(
                    transMat, (int)inner_node_cnt, (int)nodeCntBPeriodic,
                    fVecB, (int)nodeCntBPeriodic);
                //   {Φ}0を格納
                for (int ino = 0; ino < inner_node_cnt; ino++)
                {
                    evecs[imode, ino + nodeCntBPeriodic] = fVecInner[ino];
                }
            }

            ////////////////////////////////////////////////////////////////////

            if (!isSVEA)
            {
                System.Diagnostics.Debug.Assert(freeNodeCntPeriodic == (sortedNodesPeriodic.Count - nodeCntBPeriodic));
                for (int imode = 0; imode < evals.Length; imode++)
                {
                    // 伝搬定数
                    KrdLab.clapack.Complex betatmp = evals[imode];
                    // 界ベクトル
                    KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode);

                    KrdLab.clapack.Complex beta_d_tmp = betatmp * periodicDistance;
                    if (
                        // [-π, 0]の解を[π, 2π]に移動する
                        ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                             && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.0
                             && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                             && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                             && (beta_d_tmp.Real / (2.0 * pi)) >= (-0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                             && (beta_d_tmp.Real / (2.0 * pi)) < 0.0)
                        // [0, π]の解を[2π, 3π]に移動する
                        || ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (1.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                                && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.5
                                && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && (beta_d_tmp.Real / (2.0 * pi)) >= (0.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                                && (beta_d_tmp.Real / (2.0 * pi)) < 0.5)
                        )
                    {
                        // [0, π]の解を2πだけ移動する
                        double delta_phase = 2.0 * pi;
                        beta_d_tmp.Real += delta_phase;
                        betatmp = beta_d_tmp / periodicDistance;
                        //check
                        System.Diagnostics.Debug.WriteLine("shift beta * d / (2π): {0} + {1} i to {2} + {3} i",
                            evals[imode].Real * periodicDistance / (2.0 * pi),
                            evals[imode].Imaginary * periodicDistance / (2.0 * pi),
                            beta_d_tmp.Real / (2.0 * pi),
                            beta_d_tmp.Imaginary / (2.0 * pi));
                        // 再設定
                        evals[imode] = betatmp;
                    }
                }
            }

            // 固有値をソートする
            System.Diagnostics.Debug.Assert(evecs.GetLength(1) == freeNodeCntPeriodic);
            GetSortedModes(
                incidentModeIndex,
                k0,
                nodeCntPeriodic,
                freeNodeCntPeriodic,
                nodeCntBPeriodic,
                sortedNodesPeriodic,
                toSortedPeriodic,
                toNodePeriodic,
                defectNodePeriodic,
                isModeTrace,
                ref PrevModalVec,
                minBeta,
                maxBeta,
                evals,
                evecs,
                true, // isDebugShow
                out betamToSolveList,
                out resVecList);
        }
 /// <summary>
 /// 同じ固有モード?
 /// </summary>
 /// <param name="k0"></param>
 /// <param name="nodeCntPeriodic"></param>
 /// <param name="PrevModalVec"></param>
 /// <param name="freeNodeCntPeriodic"></param>
 /// <param name="sortedNodes"></param>
 /// <param name="toSorted"></param>
 /// <param name="betam"></param>
 /// <param name="fieldVec"></param>
 /// <returns></returns>
 private static bool isSameMode(
     double k0,
     int nodeCntPeriodic,
     KrdLab.clapack.Complex[] PrevModalVec,
     int freeNodeCntPeriodic,
     Dictionary<int, int> toNodePeriodic,
     IList<int> sortedNodesPeriodic,
     Dictionary<int, int> toSorted,
     KrdLab.clapack.Complex betam,
     KrdLab.clapack.Complex[] fieldVec,
     out double ret_norm)
 {
     bool isHit = false;
     ret_norm = 0.0;
     if (betam.Real > 0.0 && Math.Abs(betam.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
     {
         KrdLab.clapack.Complex[] workModalVec1 = new KrdLab.clapack.Complex[nodeCntPeriodic]; // 前回
         KrdLab.clapack.Complex[] workModalVec2 = new KrdLab.clapack.Complex[nodeCntPeriodic]; // 今回
         // 前半の{Φ}のみ取得する
         for (int ino = 0; ino < freeNodeCntPeriodic; ino++)
         {
             // 今回の固有ベクトル
             //System.Diagnostics.Debug.WriteLine("    ( " + imode + ", " + ino + " ) = " + evec[ino].Real + " + " + evec[ino].Imaginary + " i ");
             int nodeNumber = sortedNodesPeriodic[ino];
             int ino_InLoop = toNodePeriodic[nodeNumber];
             workModalVec2[ino_InLoop] = fieldVec[ino];
             // 対応する前回の固有ベクトル
             workModalVec1[ino_InLoop] = PrevModalVec[ino_InLoop];
         }
         KrdLab.clapack.Complex norm1 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec1), workModalVec1);
         KrdLab.clapack.Complex norm2 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec2), workModalVec2);
         for (int i = 0; i < nodeCntPeriodic; i++)
         {
             workModalVec1[i] /= Math.Sqrt(norm1.Magnitude);
             workModalVec2[i] /= Math.Sqrt(norm2.Magnitude);
         }
         KrdLab.clapack.Complex norm12 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec1), workModalVec2);
         double thLikeMin = 0.9;
         double thLikeMax = 1.1;
         if (norm12.Magnitude >= thLikeMin && norm12.Magnitude < thLikeMax)
         {
             isHit = true;
             ret_norm = norm12.Magnitude;
             System.Diagnostics.Debug.WriteLine("norm (prev * current): {0} + {1}i (Abs: {2})", norm12.Real, norm12.Imaginary, norm12.Magnitude);
         }
     }
     return isHit;
 }
Example #10
0
        /// <summary>
        /// 界のx方向微分値を取得する (2次三角形要素)
        /// </summary>
        /// <param name="world"></param>
        /// <param name="fieldValId"></param>
        private static void getDFDXValues_Tri_SecondOrder(
            FemSolver.WaveModeDV WaveModeDv,
            double k0,
            double rotAngle,
            double[] rotOrigin,
            IList<FemNode> Nodes,
            IList<FemElement> Elements,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            IList<uint> elemNoPeriodic,
            IList<IList<int>> nodePeriodicB,
            Dictionary<int, int> toNodePeriodic,
            KrdLab.clapack.Complex[] fVec,
            out KrdLab.clapack.Complex[] dFdXVec,
            out KrdLab.clapack.Complex[] dFdYVec)
        {
            dFdXVec = new KrdLab.clapack.Complex[fVec.Length];
            dFdYVec = new KrdLab.clapack.Complex[fVec.Length];

            Dictionary<int, int> nodeElemCntH = new Dictionary<int, int>();
            Dictionary<int, double> nodeAreaSum = new Dictionary<int, double>();

            int elemCnt = elemNoPeriodic.Count;
            for (int ie = 0; ie < elemCnt; ie++)
            {
                int elemNo = (int)elemNoPeriodic[ie];
                FemElement element = Elements[elemNo - 1];
                System.Diagnostics.Debug.Assert(element.No == elemNo);

                // 要素内節点数
                const int nno = Constants.TriNodeCnt_SecondOrder; //6;  // 2次三角形要素
                // 座標次元数
                const int ndim = Constants.CoordDim2D; //2;

                int[] nodeNumbers = element.NodeNumbers;
                int[] no_c = new int[nno];
                MediaInfo media = Medias[element.MediaIndex];
                double[,] media_P = null;
                double[,] media_Q = null;
                // ヘルムホルツ方程式のパラメータP,Qを取得する
                FemSolver.GetHelmholtzMediaPQ(
                    k0,
                    media,
                    WaveModeDv,
                    out media_P,
                    out media_Q);

                // 節点座標(IFの都合上配列の配列形式の2次元配列を作成)
                double[][] pp = new double[nno][];
                for (int ino = 0; ino < nno; ino++)
                {
                    int nodeNumber = nodeNumbers[ino];
                    int nodeIndex = nodeNumber - 1;
                    FemNode node = Nodes[nodeIndex];

                    no_c[ino] = nodeNumber;
                    pp[ino] = new double[ndim];
                    for (int n = 0; n < ndim; n++)
                    {
                        pp[ino][n] = node.Coord[n];
                    }
                }
                if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit)
                {
                    // 座標を回転移動する
                    for (uint inoes = 0; inoes < nno; inoes++)
                    {
                        double[] srcPt = new double[] { pp[inoes][0], pp[inoes][1] };
                        double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin);
                        for (int i = 0; i < ndim; i++)
                        {
                            pp[inoes][i] = destPt[i];
                        }
                    }
                }

                // 面積を求める
                double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]);
                //System.Diagnostics.Debug.WriteLine("Elem No {0} area:  {1}", element.No, area);
                System.Diagnostics.Debug.Assert(area >= 0.0);

                // 面積座標の微分を求める
                //   dldx[k, n] k面積座標Lkのn方向微分
                double[,] dldx = null;
                double[] const_term = null;
                KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]);

                // 形状関数の微分の係数を求める
                //    dndxC[ino,n,k]  ino節点のn方向微分のLk(k面積座標)の係数
                //       dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3]
                double[, ,] dndxC = new double[nno, ndim, Constants.TriVertexCnt + 1]
                {
                    {
                        {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]},
                        {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]},
                    },
                    {
                        {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]},
                        {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]},
                    },
                    {
                        {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]},
                        {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]},
                    },
                    {
                        {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0},
                        {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0},
                    },
                    {
                        {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0},
                        {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0},
                    },
                    {
                        {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0},
                        {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0},
                    },
                };

                // 界の微分値を計算
                KrdLab.clapack.Complex[] dFdXs = new KrdLab.clapack.Complex[nno];
                KrdLab.clapack.Complex[] dFdYs = new KrdLab.clapack.Complex[nno];
                // 節点の面積座標
                double[,] L_node = new double[Constants.TriNodeCnt_SecondOrder, 3]
                {
                    {1.0, 0.0, 0.0},
                    {0.0, 1.0, 0.0},
                    {0.0, 0.0, 1.0},
                    {0.5, 0.5, 0.0},
                    {0.0, 0.5, 0.5},
                    {0.5, 0.0, 0.5}
                };
                for (int inoes = 0; inoes < nno; inoes++)
                {
                    for (int jnoes = 0; jnoes < nno; jnoes++)
                    {
                        int jNodeNumber = no_c[jnoes];
                        if (!toNodePeriodic.ContainsKey(jNodeNumber))
                        {
                            System.Diagnostics.Debug.Assert(false);
                            continue;
                        }
                        int jnoGlobal = toNodePeriodic[jNodeNumber];
                        KrdLab.clapack.Complex fVal = fVec[jnoGlobal];
                        double[] dNdx_node = new double[ndim];
                        for (int n = 0; n < ndim; n++)
                        {
                            dNdx_node[n] = dndxC[jnoes, n, 0] * L_node[inoes, 0]
                                           + dndxC[jnoes, n, 1] * L_node[inoes, 1]
                                           + dndxC[jnoes, n, 2] * L_node[inoes, 2]
                                           + dndxC[jnoes, n, 3];
                        }
                        dFdXs[inoes] += dNdx_node[0] * fVal;
                        dFdYs[inoes] += dNdx_node[1] * fVal;
                    }
                }
                // 格納
                for (int inoes = 0; inoes < nno; inoes++)
                {
                    int iNodeNumber = no_c[inoes];
                    if (!toNodePeriodic.ContainsKey(iNodeNumber))
                    {
                        System.Diagnostics.Debug.Assert(false);
                        continue;
                    }
                    int inoGlobal = toNodePeriodic[iNodeNumber];

                    //dFdXVec[inoGlobal] += dFdXs[inoes];
                    //dFdYVec[inoGlobal] += dFdYs[inoes];
                    // Note:
                    //  TEzモードのとき -dHz/dx = jωDy
                    dFdXVec[inoGlobal] += dFdXs[inoes] * area;
                    dFdYVec[inoGlobal] += dFdYs[inoes] * area;

                    if (nodeElemCntH.ContainsKey(inoGlobal))
                    {
                        nodeElemCntH[inoGlobal]++;
                        // 面積を格納
                        nodeAreaSum[inoGlobal] += area;
                    }
                    else
                    {
                        nodeElemCntH.Add(inoGlobal, 1);
                        nodeAreaSum.Add(inoGlobal, area);
                    }
                }
            }
            for (int i = 0; i < dFdXVec.Length; i++)
            {
                //int cnt = nodeElemCntH[i];
                //dFdXVec[i] /= cnt;
                //dFdYVec[i] /= cnt;
                double areaSum = nodeAreaSum[i];
                dFdXVec[i] = (dFdXVec[i] / areaSum);
                dFdYVec[i] = (dFdYVec[i] / areaSum);
            }
        }
Example #11
0
 // x = Log(c)
 public static KrdLab.clapack.Complex complex_Log(KrdLab.clapack.Complex c)
 {
     System.Numerics.Complex work = new System.Numerics.Complex(c.Real, c.Imaginary);
     work = System.Numerics.Complex.Log(work);
     return(new KrdLab.clapack.Complex(work.Real, work.Imaginary));
 }
Example #12
0
        ///////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 周期構造導波路固有モードのデータを読み込む
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="freqNo"></param>
        /// <returns></returns>
        public bool LoadOutputPeriodic(string filename, int freqNo, int modeIndex)
        {
            // 界分布をクリアする
            clearEigenFieldValueOfElements();

            if (!isInputDataReady())
            {
                return false;
            }
            if (!isOutputDataReady())
            {
                return false;
            }
            int portCnt = Ports.Count;
            if (portCnt == 0)
            {
                return false;
            }

            // 最大モード数を取得する
            // 既にロード済みの伝搬定数リストからモードの数を取得する
            int modeCnt = GetMaxModeCnt();
            if (modeCnt <= modeIndex)
            {
                return false;
            }

            IList<Dictionary<int, int>> toNodePeriodicList = new List<Dictionary<int, int>>();
            KrdLab.clapack.Complex[][][] eigenVecsPeriodicList = new KrdLab.clapack.Complex[portCnt][][];
            for (int portIndex = 0; portIndex < portCnt; portIndex++)
            {
                // 周期構造導波路固有モード出力ファイルから読み込む
                double dummy_waveLength = 0.0;
                IList<int> nodePeriodic = null;
                Dictionary<int, int> toNodePeriodic = null;
                IList<double[]> coordsPeriodic = null;
                KrdLab.clapack.Complex[] dummy_eigenValues = null;
                KrdLab.clapack.Complex[][] eigenVecsPeriodic = null;
                bool ret = FemOutputPeriodicDatFile.LoadFromFile(
                    filename,
                    freqNo,
                    (portIndex + 1),
                    out dummy_waveLength,
                    out nodePeriodic,
                    out toNodePeriodic,
                    out coordsPeriodic,
                    out dummy_eigenValues,
                    out eigenVecsPeriodic
                    );
                if (!ret)
                {
                    return false;
                }

                if (Math.Abs(dummy_waveLength - WaveLength) >= Constants.PrecisionLowerLimit)
                {
                    return false;
                }
                System.Diagnostics.Debug.Assert(Math.Abs(dummy_waveLength - WaveLength) < Constants.PrecisionLowerLimit);

                // 格納
                toNodePeriodicList.Add(toNodePeriodic);
                eigenVecsPeriodicList[portIndex] = eigenVecsPeriodic;
            }

            // 要素にフィールド値をセットする
            setupEigenFieldValueToElements(toNodePeriodicList, eigenVecsPeriodicList, modeIndex);

            return true;
        }
Example #13
0
        /// <summary>
        /// ポート固有値解析
        /// </summary>
        public static void SolvePortWaveguideEigen(
            FemSolver.WaveModeDV WaveModeDv,
            double waveLength,
            int maxModeSpecified,
            IList <FemNode> Nodes,
            Dictionary <string, IList <int> > EdgeToElementNoH,
            IList <FemElement> Elements,
            MediaInfo[] Medias,
            Dictionary <int, bool> ForceNodeNumberH,
            IList <int> portNodes,
            out int[] nodesBoundary,
            out MyDoubleMatrix ryy_1d,
            out Complex[] eigenValues,
            out Complex[,] eigenVecs)
        {
            //System.Diagnostics.Debug.WriteLine("solvePortWaveguideEigen: {0},{1}", waveLength, portNo);
            nodesBoundary = null;
            ryy_1d        = null;
            eigenValues   = null;
            eigenVecs     = null;


            // 2D次元数
            const int ndim2d = Constants.CoordDim2D; //2;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 節点番号リスト(要素インデックス: 1D節点番号 - 1 要素:2D節点番号)
            IList <int> nodes = portNodes;
            // 2D→1D節点番号マップ
            Dictionary <int, int> to1dNodes = new Dictionary <int, int>();
            // 節点座標リスト
            IList <double> coords = new List <double>();
            // 要素リスト
            IList <FemLineElement> elements = new List <FemLineElement>();
            // 1D節点番号リスト(ソート済み)
            IList <int> sortedNodes = new List <int>();
            // 1D節点番号→ソート済みリストインデックスのマップ
            Dictionary <int, int> toSorted = new Dictionary <int, int>();

            // 2Dの要素から次数を取得する
            Constants.FemElementShapeDV elemShapeDv2d;
            int order;
            int vertexCnt2d;

            FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(Elements[0].NodeNumbers.Length, out elemShapeDv2d, out order, out vertexCnt2d);

            // 2D→1D節点番号マップ作成
            for (int i = 0; i < nodes.Count; i++)
            {
                int nodeNumber2d = nodes[i];
                if (!to1dNodes.ContainsKey(nodeNumber2d))
                {
                    to1dNodes.Add(nodeNumber2d, i + 1);
                }
            }
            // 原点
            int     nodeNumber0 = nodes[0];
            int     nodeIndex0  = nodeNumber0 - 1;
            FemNode node0       = Nodes[nodeIndex0];

            double[] coord0 = new double[ndim2d];
            coord0[0] = node0.Coord[0];
            coord0[1] = node0.Coord[1];
            // 座標リスト作成
            double[] coord = new double[ndim2d];
            foreach (int nodeNumber in nodes)
            {
                int     nodeIndex = nodeNumber - 1;
                FemNode node      = Nodes[nodeIndex];
                coord[0] = node.Coord[0];
                coord[1] = node.Coord[1];
                double x = FemMeshLogic.GetDistance(coord, coord0);
                //System.Diagnostics.Debug.WriteLine("{0},{1},{2},{3}", nodeIndex, coord[0], coord[1], x);
                coords.Add(x);
            }

            // 線要素を作成する
            if (order == Constants.FirstOrder)
            {
                // 1次線要素
                FemMat_Line_First.MkElements(
                    nodes,
                    EdgeToElementNoH,
                    Elements,
                    ref elements);
            }
            else
            {
                // 2次線要素
                FemMat_Line_Second.MkElements(
                    nodes,
                    EdgeToElementNoH,
                    Elements,
                    ref elements);
            }

            // 強制境界節点と内部領域節点を分離
            foreach (int nodeNumber2d in nodes)
            {
                int nodeNumber = to1dNodes[nodeNumber2d];
                if (ForceNodeNumberH.ContainsKey(nodeNumber2d))
                {
                    System.Diagnostics.Debug.WriteLine("{0}:    {1}    {2}", nodeNumber, Nodes[nodeNumber2d - 1].Coord[0], Nodes[nodeNumber2d - 1].Coord[1]);
                }
                else
                {
                    sortedNodes.Add(nodeNumber);
                    toSorted.Add(nodeNumber, sortedNodes.Count - 1);
                }
            }
            // 対称バンド行列のパラメータを取得する
            int rowcolSize   = 0;
            int subdiaSize   = 0;
            int superdiaSize = 0;

            {
                bool[,] matPattern = null;
                GetMatNonzeroPatternForEigen(elements, toSorted, out matPattern);
                GetBandMatrixSubDiaSizeAndSuperDiaSizeForEigen(matPattern, out rowcolSize, out subdiaSize, out superdiaSize);
            }
            // ソート済み1D節点インデックス→2D節点番号マップ
            nodesBoundary = new int[sortedNodes.Count];
            for (int i = 0; i < sortedNodes.Count; i++)
            {
                int nodeNumber   = sortedNodes[i];
                int nodeIndex    = nodeNumber - 1;
                int nodeNumber2d = nodes[nodeIndex];
                nodesBoundary[i] = nodeNumber2d;
            }

            // 節点数
            int nodeCnt = sortedNodes.Count;
            // 固有値、固有ベクトル
            int maxMode = maxModeSpecified;

            if (maxMode > nodeCnt)
            {
                maxMode = nodeCnt;
            }
            eigenValues = new Complex[maxMode];
            eigenVecs   = new Complex[maxMode, nodeCnt];
            // 固有モード解析でのみ使用するuzz_1d, txx_1d
            MyDoubleMatrix txx_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);
            MyDoubleMatrix uzz_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            // ryy_1dマトリクス (線要素)
            ryy_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            for (int elemIndex = 0; elemIndex < elements.Count; elemIndex++)
            {
                // 線要素
                FemLineElement element = elements[elemIndex];

                // 1Dヘルムホルツ方程式固有値問題の要素行列を加算する
                if (order == Constants.FirstOrder)
                {
                    // 1次線要素
                    FemMat_Line_First.AddElementMatOf1dEigenValueProblem(
                        waveLength, // E面の場合のみ使用
                        element,
                        coords,
                        toSorted,
                        Medias,
                        WaveModeDv,
                        ref txx_1d, ref ryy_1d, ref uzz_1d);
                }
                else
                {
                    // 2次線要素
                    FemMat_Line_Second.AddElementMatOf1dEigenValueProblem(
                        waveLength, // E面の場合のみ使用
                        element,
                        coords,
                        toSorted,
                        Medias,
                        WaveModeDv,
                        ref txx_1d, ref ryy_1d, ref uzz_1d);
                }
            }

            // [A] = [Txx] - k0 * k0 *[Uzz]
            //メモリ節約
            //MyDoubleMatrix matA = new MyDoubleMatrix(nodeCnt, nodeCnt);
            MyDoubleSymmetricBandMatrix matA = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            for (int ino = 0; ino < nodeCnt; ino++)
            {
                for (int jno = 0; jno < nodeCnt; jno++)
                {
                    // 対称バンド行列対応
                    if (matA is MyDoubleSymmetricBandMatrix && ino > jno)
                    {
                        continue;
                    }
                    // 剛性行列
                    //matA[ino, jno] = txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno];
                    //  質量行列matBが正定値行列となるように剛性行列matAの方の符号を反転する
                    matA[ino, jno] = -(txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno]);
                }
            }

            // ( [txx] - k0^2[uzz] + β^2[ryy]){Ez} = {0}より
            // [A]{x} = λ[B]{x}としたとき、λ = β^2 とすると[B] = -[ryy]
            //MyDoubleMatrix matB = MyMatrixUtil.product(-1.0, ryy_1d);
            // 質量行列が正定値となるようにするため、上記符号反転を剛性行列の方に反映し、質量行列はryy_1dをそのまま使用する
            //MyDoubleMatrix matB = new MyDoubleMatrix(ryy_1d);
            MyDoubleSymmetricBandMatrix matB = new MyDoubleSymmetricBandMatrix((MyDoubleSymmetricBandMatrix)ryy_1d);

            // 一般化固有値問題を解く
            Complex[] evals = null;
            Complex[,] evecs = null;
            try
            {
                // 固有値、固有ベクトルを求める
                solveEigen(matA, matB, out evals, out evecs);
                // 固有値のソート
                Sort1DEigenMode(k0, evals, evecs);
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.Assert(false);
            }
            for (int imode = 0; imode < evecs.GetLength(0); imode++)
            {
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    // 境界上で位相調整する
                    for (int ino = 0; ino < evecs.GetLength(1); ino++)
                    {
                        KrdLab.clapack.Complex cvalue = evecs[imode, 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 ino = 0; ino < evecs.GetLength(1); ino++)
                {
                    evecs[imode, ino] /= phaseShift;
                }
            }

            for (int imode = 0; imode < maxMode; imode++)
            {
                eigenValues[imode] = 0;
            }
            for (int tagtModeIdx = evals.Length - 1, imode = 0; tagtModeIdx >= 0 && imode < maxMode; tagtModeIdx--)
            {
                // 伝搬定数は固有値のsqrt
                Complex betam = Complex.Sqrt(evals[tagtModeIdx]);
                // 定式化BUGFIX
                //   減衰定数は符号がマイナス(β = -jα)
                bool isConjugateMode = false;
                if (betam.Imaginary >= 0.0)
                {
                    betam           = new Complex(betam.Real, -betam.Imaginary);
                    isConjugateMode = true;
                }
                // 固有ベクトル
                Complex[] evec = MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIdx);
                if (isConjugateMode)
                {
                    evec = MyMatrixUtil.vector_Conjugate(evec);
                }
                // 規格化定数を求める
                // 実数の場合 [ryy]*t = [ryy]t ryyは対称行列より[ryy]t = [ryy]
                Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec);
                Complex   dm      = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec);
                {
                    // H面、平行平板
                    if (WaveModeDv == FemSolver.WaveModeDV.TM)
                    {
                        dm = Complex.Sqrt(omega * eps0 / Complex.Abs(betam) / dm);
                    }
                    else
                    {
                        dm = Complex.Sqrt(omega * mu0 / Complex.Abs(betam) / dm);
                    }
                }
                //System.Diagnostics.Debug.WriteLine("dm = " + dm);

                // 伝搬定数の格納
                eigenValues[imode] = betam;
                // check
                if (imode < 5)
                {
                    //System.Diagnostics.Debug.WriteLine("eigenValues [ " + imode + "] = " + betam.Real + " + " + betam.Imaginary + " i " + " tagtModeIdx :" + tagtModeIdx + " " );
                    System.Diagnostics.Debug.WriteLine("β/k0 [ " + imode + "] = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + " tagtModeIdx :" + tagtModeIdx + " ");
                }
                // 固有ベクトルの格納(規格化定数を掛ける)
                for (int inoSorted = 0; inoSorted < nodeCnt; inoSorted++)
                {
                    Complex fm = dm * evec[inoSorted];
                    eigenVecs[imode, inoSorted] = fm;
                    //System.Diagnostics.Debug.WriteLine("eigenVecs [ " + imode + ", " + inoSorted + "] = " + fm.Real + " + " + fm.Imaginary + " i  Abs:" + Complex.Abs(fm));
                }
                imode++;
            }
        }
        /*
        /// <summary>
        /// 計算済み周波数の件数を取得
        /// </summary>
        /// <param name="filename"></param>
        /// <returns></returns>
        public static int GetCalculatedFreqCnt(string filename, out int firstFreq, out int lastFreq)
        {
            int freqCnt = 0;

            firstFreq = 1;
            lastFreq = 1;
            // ファイル本体の存在確認
            if (!File.Exists(filename))
            {
                return freqCnt;
            }
            // インデックスファイルから件数を取得する
            string indexfilename = filename + Constants.FemOutputIndexExt;
            // インデックスファイルの存在確認
            if (!File.Exists(indexfilename))
            {
                return freqCnt;
            }
            try
            {
                // 周波数が順番に並んでいない場合を考慮
                int minFreq = int.MaxValue;
                int maxFreq = int.MinValue;
                IList<int> freqNoList = new List<int>();
                using (StreamReader sr = new StreamReader(indexfilename))
                {
                    string line;
                    string[] tokens;
                    char delimiter = ',';

                    while (!sr.EndOfStream)
                    {
                        line = sr.ReadLine();
                        if (line.Length == 0) break;
                        tokens = line.Split(delimiter);
                        int tmpFreqNo = int.Parse(tokens[0]);
                        int tmpPortNo = int.Parse(tokens[1]);
                        long tmpFOfs = long.Parse(tokens[2]);
                        if (tmpFreqNo < 1)
                        {
                            MessageBox.Show("周波数インデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return freqCnt;
                        }
                        if (tmpPortNo < 1)
                        {
                            MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return freqCnt;
                        }
                        if (freqNoList.Contains(tmpFreqNo))
                        {
                            // ポート番号違いの同じ周波数
                            continue;
                        }
                        else
                        {
                            freqNoList.Add(tmpFreqNo);
                        }

                        // 周波数が順番に並んでいない場合を考慮
                        if (minFreq > tmpFreqNo)
                        {
                            minFreq = tmpFreqNo;
                        }
                        if (maxFreq < tmpFreqNo)
                        {
                            maxFreq = tmpFreqNo;
                        }

                        freqCnt++;
                    }
                }
                // 周波数が順番に並んでいない場合を考慮
                if (freqCnt > 0)
                {
                    firstFreq = minFreq;
                    lastFreq = maxFreq;
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return freqCnt;
            }

            return freqCnt;
        }
         */
        public static bool LoadFromFile(
            string filename,
            int freqNo,
            int portNo,
            out double waveLength,
            out IList<int> nodePeriodic,
            out Dictionary<int, int> toNodePeriodic,
            out IList<double[]> coordsPeriodic,
            out KrdLab.clapack.Complex[] eigenValues,
            out KrdLab.clapack.Complex[][] eigenVecsPeriodic
            )
        {
            const char delimiter = ',';

            waveLength = 0.0;
            nodePeriodic = null;
            toNodePeriodic = null;
            coordsPeriodic = null;
            eigenValues = null;
            eigenVecsPeriodic = null;

            if (!File.Exists(filename))
            {
                return false;
            }

            long readFileOfs = 0;
            bool findFlg = false;
            // 読み込み開始位置をインデックスファイルから読み出す
            string indexfilename = filename + Constants.FemOutputIndexExt;
            try
            {
                using (StreamReader sr = new StreamReader(indexfilename))
                {
                    string line;
                    string[] tokens;

                    while (!sr.EndOfStream)
                    {
                        line = sr.ReadLine();
                        if (line.Length == 0) break;
                        tokens = line.Split(delimiter);
                        int tmpFreqNo = int.Parse(tokens[0]);
                        int tmpPortNo = int.Parse(tokens[1]);
                        long tmpFOfs = long.Parse(tokens[2]);
                        if (tmpFreqNo < 1)
                        {
                            MessageBox.Show("周波数インデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        if (tmpPortNo < 1)
                        {
                            MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        if (freqNo == -1 && portNo == tmpPortNo)
                        {
                            // 最後の結果データの読み込み開始位置を更新
                            readFileOfs = tmpFOfs;
                            findFlg = true;
                        }
                        else if (freqNo == tmpFreqNo && portNo == tmpPortNo)
                        {
                            // 指定周波数、ポート番号の場合
                            readFileOfs = tmpFOfs;
                            findFlg = true;
                            break;
                        }
                        else
                        {
                            // 該当しない
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            if (!findFlg)
            {
                return false;
            }

            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    Stream stream = sr.BaseStream;
                    string line;
                    string[] tokens;

                    stream.Seek(readFileOfs, SeekOrigin.Begin);

                    line = sr.ReadLine();
                    if (line != "S")
                    {
                        MessageBox.Show("開始シーケンスがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }

                    /////////////////////////////////////
                    {
                        // 節点数
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "nodeCntB")
                        {
                            MessageBox.Show("節点数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        int nodeCntB = int.Parse(tokens[1]);
                        // 節点番号
                        line = sr.ReadLine();
                        if (line != "nodePeriodic")
                        {
                            MessageBox.Show("節点番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        nodePeriodic = new List<int>();
                        toNodePeriodic = new Dictionary<int, int>();
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1)
                            {
                                MessageBox.Show("節点番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                            int nodeNumber = int.Parse(tokens[0]);
                            nodePeriodic.Add(nodeNumber);
                            toNodePeriodic.Add(nodeNumber, ino);
                        }
                        // 座標
                        line = sr.ReadLine();
                        if (line != "coordsPeriodic")
                        {
                            MessageBox.Show("節点座標がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        coordsPeriodic = new List<double[]>();
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 2)
                            {
                                MessageBox.Show("節点座標がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                            double xx = double.Parse(tokens[0]);
                            double yy = double.Parse(tokens[1]);
                            double[] pp = new double[] { xx, yy };
                            coordsPeriodic.Add(pp);
                        }
                    }

                    /////////////////////////////////////

                    // 周波数番号
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "freqNo")
                    {
                        MessageBox.Show("周波数番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int tmpFreqNo = int.Parse(tokens[1]);
                    if (freqNo != -1 && tmpFreqNo != freqNo)
                    {
                        MessageBox.Show("周波数番号が一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    // ポート番号
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "portNo")
                    {
                        MessageBox.Show("ポート番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int tmpPortNo = int.Parse(tokens[1]);
                    if (tmpPortNo != portNo)
                    {
                        MessageBox.Show("ポート番号が一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }

                    // 波数
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "waveLength")
                    {
                        MessageBox.Show("波長がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    waveLength = double.Parse(tokens[1]);

                    // 伝搬モード数
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "modeCnt")
                    {
                        MessageBox.Show("モード数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int modeCnt = int.Parse(tokens[1]);
                    eigenValues = new KrdLab.clapack.Complex[modeCnt];
                    eigenVecsPeriodic = new KrdLab.clapack.Complex[modeCnt][];
                    for (int imode = 0; imode < modeCnt; imode++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "mode")
                        {
                            MessageBox.Show("モードがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        int tmpModeIndex = int.Parse(tokens[1]);
                        if (tmpModeIndex != imode)
                        {
                            MessageBox.Show("モードインデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }

                        // 伝搬定数
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "beta")
                        {
                            MessageBox.Show("伝搬定数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        KrdLab.clapack.Complex beta = MyUtilLib.MyUtil.ComplexParse(tokens[1]);

                        // 固有モード分布
                        int nodeCntB = nodePeriodic.Count;
                        eigenVecsPeriodic[imode] = new KrdLab.clapack.Complex[nodeCntB];
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1)
                            {
                                MessageBox.Show("固有モード分布がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                            KrdLab.clapack.Complex fVal = MyUtilLib.MyUtil.ComplexParse(tokens[0]);
                            eigenVecsPeriodic[imode][ino] = fVal;
                        }

                    }
                }

            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
            return true;
        }
Example #15
0
        /// <summary>
        /// 計算結果をファイルに出力(追記モード)
        /// 伝搬モードのみを出力
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="freqNo"></param>
        /// <param name="portNo"></param>
        /// <param name="waveLength"></param>
        /// <param name="nodePeriodic"></param>
        /// <param name="toNodePeriodic"></param>
        /// <param name="coordsPeriodic"></param>
        /// <param name="eigenValues"></param>
        /// <param name="eigenVecsPeriodic"></param>
        public static void AppendToFile(
            string filename,
            int freqNo,
            int portNo,
            double waveLength,
            IList <int> nodePeriodic,
            Dictionary <int, int> toNodePeriodic,
            IList <double[]> coordsPeriodic,
            KrdLab.clapack.Complex[] eigenValues,
            KrdLab.clapack.Complex[][] eigenVecsPeriodic
            )
        {
            // 波数
            double k0 = 2.0 * Constants.pi / waveLength;

            if (eigenValues == null)
            {
                return;
            }
            int modeCnt = 0; // 伝搬モードの数

            for (int imode = 0; imode < eigenValues.Length; imode++)
            {
                KrdLab.clapack.Complex beta = eigenValues[imode];
                if (Math.Abs(beta.Imaginary / k0) >= Constants.PrecisionLowerLimit)
                {
                    // 減衰モード
                    break;
                }
                modeCnt++;
            }
            if (modeCnt == 0)
            {
                return;
            }
            int nodeCntB = nodePeriodic.Count;

            long writeFileOfs = 0;  // 書き込み開始位置

            try
            {
                // 追記モードで書き込み
                using (StreamWriter sw = new StreamWriter(filename, true))
                {
                    Stream stream = sw.BaseStream;

                    // 書き込み開始位置を記憶
                    writeFileOfs = stream.Position;

                    // 開始シーケンスの書き込み
                    sw.WriteLine("S");

                    /////////////////////////////////////
                    {
                        // 節点数
                        sw.WriteLine("nodeCntB,{0}", nodeCntB);
                        // 節点番号
                        sw.WriteLine("nodePeriodic");
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            sw.WriteLine("{0}", nodePeriodic[ino]);
                        }
                        // 座標
                        sw.WriteLine("coordsPeriodic");
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            sw.WriteLine("{0},{1}", coordsPeriodic[ino][0], coordsPeriodic[ino][1]);
                        }
                    }
                    /////////////////////////////////////

                    // 周波数番号
                    sw.WriteLine("freqNo,{0}", freqNo);
                    // ポート番号
                    sw.WriteLine("portNo,{0}", portNo);
                    // 波数
                    sw.WriteLine("waveLength,{0}", waveLength);
                    // 伝搬モード数
                    sw.WriteLine("modeCnt,{0}", modeCnt);
                    for (int imode = 0; imode < modeCnt; imode++)
                    {
                        KrdLab.clapack.Complex   beta             = eigenValues[imode];
                        KrdLab.clapack.Complex[] eigenVecPeriodic = eigenVecsPeriodic[imode];
                        sw.WriteLine("mode,{0}", imode);
                        // 伝搬定数
                        sw.WriteLine("beta,{0}+{1}i", beta.Real, beta.Imaginary);
                        // 固有モード分布
                        System.Diagnostics.Debug.Assert(nodeCntB == eigenVecPeriodic.Length);
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            KrdLab.clapack.Complex fVal = eigenVecPeriodic[ino];
                            sw.WriteLine("{0}+{1}i", fVal.Real, fVal.Imaginary);
                        }
                    }
                    // 終了シーケンスの書き込み
                    sw.WriteLine("E");
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            // 書き込み開始位置をインデックスファイルに記録する
            string indexfilename = filename + Constants.FemOutputIndexExt;

            try
            {
                // 追記モードで書き込み
                using (StreamWriter sw = new StreamWriter(indexfilename, true))
                {
                    string line;
                    line = string.Format("{0},{1},{2}", freqNo, portNo, writeFileOfs);
                    sw.WriteLine(line);
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
Example #16
0
        /*
         * /// <summary>
         * /// 計算済み周波数の件数を取得
         * /// </summary>
         * /// <param name="filename"></param>
         * /// <returns></returns>
         * public static int GetCalculatedFreqCnt(string filename, out int firstFreq, out int lastFreq)
         * {
         *  int freqCnt = 0;
         *
         *  firstFreq = 1;
         *  lastFreq = 1;
         *  // ファイル本体の存在確認
         *  if (!File.Exists(filename))
         *  {
         *      return freqCnt;
         *  }
         *  // インデックスファイルから件数を取得する
         *  string indexfilename = filename + Constants.FemOutputIndexExt;
         *  // インデックスファイルの存在確認
         *  if (!File.Exists(indexfilename))
         *  {
         *      return freqCnt;
         *  }
         *  try
         *  {
         *      // 周波数が順番に並んでいない場合を考慮
         *      int minFreq = int.MaxValue;
         *      int maxFreq = int.MinValue;
         *      IList<int> freqNoList = new List<int>();
         *      using (StreamReader sr = new StreamReader(indexfilename))
         *      {
         *          string line;
         *          string[] tokens;
         *          char delimiter = ',';
         *
         *          while (!sr.EndOfStream)
         *          {
         *              line = sr.ReadLine();
         *              if (line.Length == 0) break;
         *              tokens = line.Split(delimiter);
         *              int tmpFreqNo = int.Parse(tokens[0]);
         *              int tmpPortNo = int.Parse(tokens[1]);
         *              long tmpFOfs = long.Parse(tokens[2]);
         *              if (tmpFreqNo < 1)
         *              {
         *                  MessageBox.Show("周波数インデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
         *                  return freqCnt;
         *              }
         *              if (tmpPortNo < 1)
         *              {
         *                  MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
         *                  return freqCnt;
         *              }
         *              if (freqNoList.Contains(tmpFreqNo))
         *              {
         *                  // ポート番号違いの同じ周波数
         *                  continue;
         *              }
         *              else
         *              {
         *                  freqNoList.Add(tmpFreqNo);
         *              }
         *
         *              // 周波数が順番に並んでいない場合を考慮
         *              if (minFreq > tmpFreqNo)
         *              {
         *                  minFreq = tmpFreqNo;
         *              }
         *              if (maxFreq < tmpFreqNo)
         *              {
         *                  maxFreq = tmpFreqNo;
         *              }
         *
         *              freqCnt++;
         *          }
         *      }
         *      // 周波数が順番に並んでいない場合を考慮
         *      if (freqCnt > 0)
         *      {
         *          firstFreq = minFreq;
         *          lastFreq = maxFreq;
         *      }
         *  }
         *  catch (Exception exception)
         *  {
         *      System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
         *      MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
         *      return freqCnt;
         *  }
         *
         *  return freqCnt;
         * }
         */

        public static bool LoadFromFile(
            string filename,
            int freqNo,
            int portNo,
            out double waveLength,
            out IList <int> nodePeriodic,
            out Dictionary <int, int> toNodePeriodic,
            out IList <double[]> coordsPeriodic,
            out KrdLab.clapack.Complex[] eigenValues,
            out KrdLab.clapack.Complex[][] eigenVecsPeriodic
            )
        {
            const char delimiter = ',';

            waveLength        = 0.0;
            nodePeriodic      = null;
            toNodePeriodic    = null;
            coordsPeriodic    = null;
            eigenValues       = null;
            eigenVecsPeriodic = null;

            if (!File.Exists(filename))
            {
                return(false);
            }

            long readFileOfs = 0;
            bool findFlg     = false;
            // 読み込み開始位置をインデックスファイルから読み出す
            string indexfilename = filename + Constants.FemOutputIndexExt;

            try
            {
                using (StreamReader sr = new StreamReader(indexfilename))
                {
                    string   line;
                    string[] tokens;

                    while (!sr.EndOfStream)
                    {
                        line = sr.ReadLine();
                        if (line.Length == 0)
                        {
                            break;
                        }
                        tokens = line.Split(delimiter);
                        int  tmpFreqNo = int.Parse(tokens[0]);
                        int  tmpPortNo = int.Parse(tokens[1]);
                        long tmpFOfs   = long.Parse(tokens[2]);
                        if (tmpFreqNo < 1)
                        {
                            MessageBox.Show("周波数インデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        if (tmpPortNo < 1)
                        {
                            MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        if (freqNo == -1 && portNo == tmpPortNo)
                        {
                            // 最後の結果データの読み込み開始位置を更新
                            readFileOfs = tmpFOfs;
                            findFlg     = true;
                        }
                        else if (freqNo == tmpFreqNo && portNo == tmpPortNo)
                        {
                            // 指定周波数、ポート番号の場合
                            readFileOfs = tmpFOfs;
                            findFlg     = true;
                            break;
                        }
                        else
                        {
                            // 該当しない
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }

            if (!findFlg)
            {
                return(false);
            }

            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    Stream   stream = sr.BaseStream;
                    string   line;
                    string[] tokens;

                    stream.Seek(readFileOfs, SeekOrigin.Begin);

                    line = sr.ReadLine();
                    if (line != "S")
                    {
                        MessageBox.Show("開始シーケンスがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }

                    /////////////////////////////////////
                    {
                        // 節点数
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "nodeCntB")
                        {
                            MessageBox.Show("節点数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        int nodeCntB = int.Parse(tokens[1]);
                        // 節点番号
                        line = sr.ReadLine();
                        if (line != "nodePeriodic")
                        {
                            MessageBox.Show("節点番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        nodePeriodic   = new List <int>();
                        toNodePeriodic = new Dictionary <int, int>();
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line   = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1)
                            {
                                MessageBox.Show("節点番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                            int nodeNumber = int.Parse(tokens[0]);
                            nodePeriodic.Add(nodeNumber);
                            toNodePeriodic.Add(nodeNumber, ino);
                        }
                        // 座標
                        line = sr.ReadLine();
                        if (line != "coordsPeriodic")
                        {
                            MessageBox.Show("節点座標がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        coordsPeriodic = new List <double[]>();
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line   = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 2)
                            {
                                MessageBox.Show("節点座標がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                            double   xx = double.Parse(tokens[0]);
                            double   yy = double.Parse(tokens[1]);
                            double[] pp = new double[] { xx, yy };
                            coordsPeriodic.Add(pp);
                        }
                    }

                    /////////////////////////////////////

                    // 周波数番号
                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "freqNo")
                    {
                        MessageBox.Show("周波数番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int tmpFreqNo = int.Parse(tokens[1]);
                    if (freqNo != -1 && tmpFreqNo != freqNo)
                    {
                        MessageBox.Show("周波数番号が一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    // ポート番号
                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "portNo")
                    {
                        MessageBox.Show("ポート番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int tmpPortNo = int.Parse(tokens[1]);
                    if (tmpPortNo != portNo)
                    {
                        MessageBox.Show("ポート番号が一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }

                    // 波数
                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "waveLength")
                    {
                        MessageBox.Show("波長がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    waveLength = double.Parse(tokens[1]);

                    // 伝搬モード数
                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "modeCnt")
                    {
                        MessageBox.Show("モード数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int modeCnt = int.Parse(tokens[1]);
                    eigenValues       = new KrdLab.clapack.Complex[modeCnt];
                    eigenVecsPeriodic = new KrdLab.clapack.Complex[modeCnt][];
                    for (int imode = 0; imode < modeCnt; imode++)
                    {
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "mode")
                        {
                            MessageBox.Show("モードがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        int tmpModeIndex = int.Parse(tokens[1]);
                        if (tmpModeIndex != imode)
                        {
                            MessageBox.Show("モードインデックスが不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }

                        // 伝搬定数
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "beta")
                        {
                            MessageBox.Show("伝搬定数がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        KrdLab.clapack.Complex beta = MyUtilLib.MyUtil.ComplexParse(tokens[1]);

                        // 固有モード分布
                        int nodeCntB = nodePeriodic.Count;
                        eigenVecsPeriodic[imode] = new KrdLab.clapack.Complex[nodeCntB];
                        for (int ino = 0; ino < nodeCntB; ino++)
                        {
                            line   = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1)
                            {
                                MessageBox.Show("固有モード分布がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                            KrdLab.clapack.Complex fVal = MyUtilLib.MyUtil.ComplexParse(tokens[0]);
                            eigenVecsPeriodic[imode][ino] = fVal;
                        }
                    }
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }
            return(true);
        }