/// <summary>
        /// csv�`���̃f�[�^�I�u�W�F�N�g��ݒ肷��D
        /// </summary>
        /// <param name="data">ICsv�C���^�t�F�[�X����������I�u�W�F�N�g</param>
        public void SetCSV(KrdLab.Lisys.ICsv data)
        {
            this.DataGridView.Rows.Clear();
            this.DataGridView.Columns.Clear();

            if (data == null)
            {
                return;
            }

            string csv = data.ToCsv();
            string[] lines = csv.Split(new string[]{"\r\n"},StringSplitOptions.None);
            if (lines.Length < 1)
            {
                return;
            }

            String[] cols = lines[0].Split(',');
            for (int c = 0; c < cols.Length; ++c)
            {
                this.DataGridView.Columns.Add("c-" + c, c.ToString());
            }

            foreach (string line in lines)
            {
                this.DataGridView.Rows.Add(line.Split(','));
            }
        }
Пример #2
0
        /// <summary>
        /// �\���Ώۂ̍s���ݒ肷��D
        /// </summary>
        /// <param name="m"></param>
        public void SetMatrix(KrdLab.Lisys.Matrix m)
        {
            this.DataGridView.Rows.Clear();
            this.DataGridView.Columns.Clear();
            if (m == null)
            {
                return;
            }

            for (int c = 0; c < m.ColumnSize; ++c)
            {
                var gridCol = new DataGridViewColumn();
                gridCol.HeaderText = String.Format("[ , {0}]", c);
                gridCol.ReadOnly = true;
                gridCol.SortMode = DataGridViewColumnSortMode.NotSortable;
                this.DataGridView.Columns.Add(gridCol);
            }

            for (int r = 0; r < m.RowSize; ++r)
            {
                var gridRow = new DataGridViewRow();
                gridRow.HeaderCell.Value = String.Format("[{0}, ]", r);
                gridRow.ReadOnly = true;
                var row = m.Rows[r];
                foreach (var v in row)
                {
                    var cell = new DataGridViewTextBoxCell();
                    cell.Value = v.ToString();
                    gridRow.Cells.Add(cell);
                }
                this.DataGridView.Rows.Add(gridRow);
            }
            this.DataGridView.RowHeadersWidth = 100;
        }
Пример #3
0
        /// <summary>
        /// 四角形領域:ソートされた行列を取得する
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="periodicDistanceX"></param>
        /// <param name="periodicDistanceY"></param>
        /// <param name="betaX"></param>
        /// <param name="betaY"></param>
        /// <param name="no_c_all_fieldPortBcId1"></param>
        /// <param name="no_c_all_fieldPortBcId3"></param>
        /// <param name="coord_c_all"></param>
        /// <param name="sharedNodes"></param>
        /// <param name="sharedNodeCoords"></param>
        /// <param name="sortedNodes"></param>
        /// <param name="toSorted"></param>
        /// <param name="boundary_node_cnt_B1"></param>
        /// <param name="boundary_node_cnt_B3"></param>
        /// <param name="boundary_node_cnt"></param>
        /// <param name="free_node_cnt"></param>
        /// <param name="free_node_cnt0"></param>
        /// <param name="KMat0"></param>
        /// <param name="MMat0"></param>
        /// <param name="expAX"></param>
        /// <param name="expAY"></param>
        /// <param name="expAY1"></param>
        /// <param name="expAY2"></param>
        /// <param name="KMat"></param>
        /// <param name="MMat"></param>
        private static void getSortedMatrix_Rect(
            int probNo,
            double periodicDistanceX,
            double periodicDistanceY,
            KrdLab.clapack.Complex betaX,
            KrdLab.clapack.Complex betaY,
            uint[] no_c_all_fieldPortBcId1,
            uint[] no_c_all_fieldPortBcId3,
            double[][] coord_c_all,
            uint[] sharedNodes,
            double[][] sharedNodeCoords,
            IList<uint> sortedNodes,
            Dictionary<uint, int> toSorted,
            uint boundary_node_cnt_B1,
            uint boundary_node_cnt_B3,
            uint boundary_node_cnt,
            uint free_node_cnt,
            uint free_node_cnt0,
            KrdLab.clapack.Complex[] KMat0,
            KrdLab.clapack.Complex[] MMat0,
            out KrdLab.clapack.Complex expAX,
            out KrdLab.clapack.Complex expAY,
            out KrdLab.clapack.Complex expAY1,
            out KrdLab.clapack.Complex expAY2,
            out KrdLab.clapack.Complex[] KMat,
            out KrdLab.clapack.Complex[] MMat
            )
        {
            // 境界2の節点は境界1の節点と同一とみなす
            //   境界上の分割が同じであることが前提条件
            KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
            MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
            // 直接Bloch境界条件を指定する場合
            expAX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX);
            expAY = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY);
            // 左下と左上のX座標オフセット
            double ofsX = sharedNodeCoords[0][0] - sharedNodeCoords[1][0];
            if (Math.Abs(ofsX) >= Constants.PrecisionLowerLimit)
            {
                // 斜め領域の場合
                //  Y方向の周期境界条件にはオフセット分のX方向成分の因子が入る
                System.Diagnostics.Debug.WriteLine("ofsX: {0}", ofsX);
                expAY *= KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * ofsX);
            }
            expAY1 = 0.0;
            expAY2 = 0.0;
            if (probNo == 3)
            {
                expAY = 1.0;
                expAY1 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5)
                    * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY);
                expAY2 = KrdLab.clapack.Complex.Exp(1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5)
                    * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY);
            }
            int nodeIndexShared0 = toSorted[sharedNodes[0]]; // 左上頂点
            System.Diagnostics.Debug.Assert((free_node_cnt + boundary_node_cnt_B1 - 1 - nodeIndexShared0) == toSorted[sharedNodes[2]]);//左上と右上
            if (probNo == 3)
            {
                nodeIndexShared0 = -1;
            }
            uint boundary_node_cnt_Half_B3 = 0;
            if (probNo == 3)
            {
                System.Diagnostics.Debug.Assert(no_c_all_fieldPortBcId3.Length % 2 == 1);
                boundary_node_cnt_Half_B3 = ((uint)no_c_all_fieldPortBcId3.Length - 1) / 2;
                System.Diagnostics.Debug.Assert(boundary_node_cnt_B3 == (no_c_all_fieldPortBcId3.Length - 2));
                System.Diagnostics.Debug.Assert(boundary_node_cnt_B3 == (boundary_node_cnt_Half_B3 * 2 - 1));
            }

            /*
            if (probNo == 3)
            {
                ////////////////////////////////////////////////////////////////////////////////////
                // check
                {
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        int j_3_L = (int)(j + boundary_node_cnt_B1);
                        uint nodeNumber_3_L = sortedNodes[j_3_L];
                        double[] coord_3_L = coord_c_all[nodeNumber_3_L];
                        System.Diagnostics.Debug.WriteLine("3_L: {0}  {1}  {2} {3}", j_3_L, nodeNumber_3_L, coord_3_L[0], coord_3_L[1]);

                        int j_4_R = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j);
                        uint nodeNumber_4_R = sortedNodes[j_4_R];
                        double[] coord_4_R = coord_c_all[nodeNumber_4_R];
                        System.Diagnostics.Debug.WriteLine("4_R: {0}  {1}  {2} {3}", j_4_R, nodeNumber_4_R, coord_4_R[0], coord_4_R[1]);
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        uint nodeNumber_shared1 = sharedNodes[1];
                        int j_shared1 = toSorted[nodeNumber_shared1];
                        double[] coord_shared1 = coord_c_all[nodeNumber_shared1];
                        System.Diagnostics.Debug.WriteLine("shared1: {0}  {1}  {2} {3}", j_shared1, nodeNumber_shared1, coord_shared1[0], coord_shared1[1]);

                        // 境界4中点
                        int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                        uint nodeNumber_m_B4 = sortedNodes[jm_B4];
                        double[] coord_m_B4 = coord_c_all[nodeNumber_m_B4];
                        System.Diagnostics.Debug.WriteLine("m_B4: {0}  {1}  {2} {3}", jm_B4, nodeNumber_m_B4, coord_m_B4[0], coord_m_B4[1]);
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        int j_3_R = (int)(j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3);
                        uint nodeNumber_3_R = sortedNodes[j_3_R];
                        double[] coord_3_R = coord_c_all[nodeNumber_3_R];
                        System.Diagnostics.Debug.WriteLine("3_R: {0}  {1}  {2} {3}", j_3_R, nodeNumber_3_R, coord_3_R[0], coord_3_R[1]);

                        int j_4_L = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j);
                        uint nodeNumber_4_L = sortedNodes[j_4_L];
                        double[] coord_4_L = coord_c_all[nodeNumber_4_L];
                        System.Diagnostics.Debug.WriteLine("4_L: {0}  {1}  {2} {3}", j_4_L, nodeNumber_4_L, coord_4_L[0], coord_4_L[1]);
                    }
                }
                ////////////////////////////////////////////////////////////////////////////////////
            }
             */

            /////////////////////////////////////////////////////////////////
            // 境界1+3+内部
            for (int i = 0; i < free_node_cnt; i++)
            {
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                    MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 境界1+3+内部
            for (int i = 0; i < free_node_cnt; i++)
            {
                // 境界2
                for (int j = 0; j < boundary_node_cnt_B1; j++)
                {
                    if (probNo == 3)
                    {
                    }
                    else
                    {
                        if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理
                    }
                    KMat[i + free_node_cnt * j] += expAX * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    MMat[i + free_node_cnt * j] += expAX * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                }
                if (probNo == 3)
                {
                    ////////////////////////////////////////////////////////////////////////////////////
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            expAY1 * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            expAY1 * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        int j1 = toSorted[sharedNodes[1]];
                        // 境界4中点
                        int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                        KMat[i + free_node_cnt * j1] += expAY1 * KMat0[i + free_node_cnt0 * jm_B4];
                        MMat[i + free_node_cnt * j1] += expAY1 * MMat0[i + free_node_cnt0 * jm_B4];
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            expAY2 * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            expAY2 * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    ////////////////////////////////////////////////////////////////////////////////////
                }
                else
                {
                    // 通常の処理
                    // 境界4
                    for (int j = 0; j < boundary_node_cnt_B3; j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            expAY * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            expAY * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    // 左上頂点と左下頂点
                    {
                        int j0 = toSorted[sharedNodes[0]]; // 左上頂点
                        int j1 = toSorted[sharedNodes[1]]; // 左下頂点
                        int j2 = toSorted[sharedNodes[2]]; // 右上頂点
                        int j3 = toSorted[sharedNodes[3]]; // 右下頂点
                        KMat[i + free_node_cnt * j0] +=
                              (1.0 / expAY) * KMat0[i + free_node_cnt0 * j1]
                            + expAX * KMat0[i + free_node_cnt0 * j2]
                            + (expAX / expAY) * KMat0[i + free_node_cnt0 * j3];
                        MMat[i + free_node_cnt * j0] +=
                              (1.0 / expAY) * MMat0[i + free_node_cnt0 * j1]
                            + expAX * MMat0[i + free_node_cnt0 * j2]
                            + (expAX / expAY) * MMat0[i + free_node_cnt0 * j3];
                    }
                }
            }

            /////////////////////////////////////////////////////////////////
            // 境界2
            for (int i = 0; i < boundary_node_cnt_B1; i++)
            {
                if (probNo == 3)
                {
                }
                else
                {
                    if (i == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理
                }
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i + free_node_cnt * j] += (1.0 / expAX) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j];
                    MMat[i + free_node_cnt * j] += (1.0 / expAX) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j];
                }
                // 境界2
                for (int j = 0; j < boundary_node_cnt_B1; j++)
                {
                    if (probNo == 3)
                    {
                    }
                    else
                    {
                        if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理
                    }
                    KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                }
                if (probNo == 3)
                {
                    ////////////////////////////////////////////////////////////////////////////////////
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAX) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAX) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        int j1 = toSorted[sharedNodes[1]];
                        // 境界4中点
                        int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                        KMat[i + free_node_cnt * j1] += (1.0 / expAX) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * jm_B4];
                        MMat[i + free_node_cnt * j1] += (1.0 / expAX) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * jm_B4];
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAX) * expAY2 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAX) * expAY2 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    ////////////////////////////////////////////////////////////////////////////////////
                }
                else
                {
                    // 通常の処理
                    // 境界4
                    for (int j = 0; j < boundary_node_cnt_B3; j++)
                    {
                        KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAX) * expAY * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                          + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAX) * expAY * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i)
                                                          + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    {
                        int j0 = toSorted[sharedNodes[0]]; // 左上頂点
                        int j1 = toSorted[sharedNodes[1]]; // 左下頂点
                        int j2 = toSorted[sharedNodes[2]]; // 右上頂点
                        int j3 = toSorted[sharedNodes[3]]; // 右下頂点
                        KMat[i + free_node_cnt * j0] +=
                              (1.0 / expAX) * (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j1]
                            + (1.0 / expAX) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j2]
                            + (1.0 / expAX) * (expAX / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j3];
                        MMat[i + free_node_cnt * j0] +=
                              (1.0 / expAX) * (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j1]
                            + (1.0 / expAX) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j2]
                            + (1.0 / expAX) * (expAX / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j3];
                    }
                }
            }

            if (probNo == 3)
            {
                ////////////////////////////////////////////////////////////////////////////////////
                // 境界4右半分
                for (int i = 0; i < (boundary_node_cnt_Half_B3 - 1); i++)
                {
                    // 境界1+3+内部
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY1) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * j];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY1) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * j];
                    }
                    // 境界2
                    for (int j = 0; j < boundary_node_cnt_B1; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY1) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY1) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                                           + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    }
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        int j1 = toSorted[sharedNodes[1]];
                        // 境界4中点
                        int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j1] +=
                            (1.0 / expAY1) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * jm_B4];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j1] +=
                            (1.0 / expAY1) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * jm_B4];
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAY1) * expAY2 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAY1) * expAY2 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                }
                // 境界4中点
                {
                    // 左下頂点
                    int i1 = toSorted[sharedNodes[1]];
                    // 境界4中点
                    int im_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                    // 境界1+3+内部
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * KMat0[im_B4 + free_node_cnt0 * j];
                        MMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * MMat0[im_B4 + free_node_cnt0 * j];
                    }
                    // 境界2
                    for (int j = 0; j < boundary_node_cnt_B1; j++)
                    {
                        KMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                        MMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    }
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAY1) * expAY1 * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                        MMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAY1) * expAY1 * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        int j1 = i1;
                        // 境界4中点
                        int jm_B4 = im_B4;
                        KMat[i1 + free_node_cnt * j1] +=
                            KMat0[im_B4 + free_node_cnt0 * jm_B4];
                        MMat[i1 + free_node_cnt * j1] +=
                            MMat0[im_B4 + free_node_cnt0 * jm_B4];
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAY1) * expAY2 * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            (1.0 / expAY1) * expAY2 * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                }
                // 境界4左半分
                for (int i = 0; i < (boundary_node_cnt_Half_B3 - 1); i++)
                {
                    // 境界1+3+内部
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] +=
                            (1.0 / expAY2) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j];
                        MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] +=
                            (1.0 / expAY2) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j];
                    }
                    // 境界2
                    for (int j = 0; j < boundary_node_cnt_B1; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] +=
                            (1.0 / expAY2) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] +=
                            (1.0 / expAY2) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    }
                    // 境界4右半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAY2) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                        MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            (1.0 / expAY2) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                            + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)];
                    }
                    // 境界4中点
                    {
                        // 左下頂点
                        int j1 = toSorted[sharedNodes[1]];
                        // 境界4中点
                        int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1);
                        KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j1] +=
                            (1.0 / expAY2) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * jm_B4];
                        MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j1] +=
                            (1.0 / expAY2) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * jm_B4];
                    }
                    // 境界4左半分
                    for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] +=
                            MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                }
                ////////////////////////////////////////////////////////////////////////////////////
            }
            else
            {
                // 通常の処理
                // 境界4
                for (int i = 0; i < boundary_node_cnt_B3; i++)
                {
                    // 境界1+3+内部
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j];
                    }
                    // 境界2
                    for (int j = 0; j < boundary_node_cnt_B1; j++)
                    {
                        if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                          + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] +=
                            (1.0 / expAY) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                                          + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    }
                    // 境界4
                    for (int j = 0; j < boundary_node_cnt_B3; j++)
                    {
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                            MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i)
                                  + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    {
                        int j0 = toSorted[sharedNodes[0]]; // 左上頂点
                        int j1 = toSorted[sharedNodes[1]]; // 左下頂点
                        int j2 = toSorted[sharedNodes[2]]; // 右上頂点
                        int j3 = toSorted[sharedNodes[3]]; // 右下頂点
                        KMat[i + boundary_node_cnt_B1 + free_node_cnt * j0] +=
                              (1.0 / expAY) * (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j1]
                            + (1.0 / expAY) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j2]
                            + (1.0 / expAY) * (expAX / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j3];
                        MMat[i + boundary_node_cnt_B1 + free_node_cnt * j0] +=
                              (1.0 / expAY) * (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j1]
                            + (1.0 / expAY) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j2]
                            + (1.0 / expAY) * (expAX / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j3];
                    }
                }
                // 左下頂点、右上頂点、右下頂点
                {
                    int i0 = toSorted[sharedNodes[0]]; // 左上頂点
                    int i1 = toSorted[sharedNodes[1]]; // 左下頂点
                    int i2 = toSorted[sharedNodes[2]]; // 右上頂点
                    int i3 = toSorted[sharedNodes[3]]; // 右下頂点
                    // 境界1+3+内部
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i0 + free_node_cnt * j] += expAY * KMat0[i1 + free_node_cnt0 * j]
                            + (1.0 / expAX) * KMat0[i2 + free_node_cnt0 * j]
                            + (expAY / expAX) * KMat0[i3 + free_node_cnt0 * j];
                        MMat[i0 + free_node_cnt * j] += expAY * MMat0[i1 + free_node_cnt0 * j]
                            + (1.0 / expAX) * MMat0[i2 + free_node_cnt0 * j]
                            + (expAY / expAX) * MMat0[i3 + free_node_cnt0 * j];
                    }
                    // 境界2
                    for (int j = 0; j < boundary_node_cnt_B1; j++)
                    {
                        if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理
                        KMat[i0 + free_node_cnt * j] +=
                              expAY * expAX * KMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]
                            + (1.0 / expAX) * expAX * KMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]
                            + (expAY / expAX) * expAX * KMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                        MMat[i0 + free_node_cnt * j] +=
                              expAY * expAX * MMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]
                            + (1.0 / expAX) * expAX * MMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]
                            + (expAY / expAX) * expAX * MMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)];
                    }
                    // 境界4
                    for (int j = 0; j < boundary_node_cnt_B3; j++)
                    {
                        KMat[i0 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                              expAY * expAY * KMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]
                            + (1.0 / expAX) * expAY * KMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]
                            + (expAY / expAX) * expAY * KMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                        MMat[i0 + free_node_cnt * (j + boundary_node_cnt_B1)] +=
                              expAY * expAY * MMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]
                            + (1.0 / expAX) * expAY * MMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]
                            + (expAY / expAX) * expAY * MMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)];
                    }
                    {
                        int j0 = i0;
                        int j1 = i1;
                        int j2 = i2;
                        int j3 = i3;
                        KMat[i0 + free_node_cnt * j0] +=
                              expAY * (1.0 / expAY) * KMat0[i1 + free_node_cnt0 * j1]
                            + expAY * expAX * KMat0[i1 + free_node_cnt0 * j2]
                            + expAY * (expAX / expAY) * KMat0[i1 + free_node_cnt0 * j3]
                            + (1.0 / expAX) * (1.0 / expAY) * KMat0[i2 + free_node_cnt0 * j1]
                            + (1.0 / expAX) * expAX * KMat0[i2 + free_node_cnt0 * j2]
                            + (1.0 / expAX) * (expAX / expAY) * KMat0[i2 + free_node_cnt0 * j3]
                            + (expAY / expAX) * (1.0 / expAY) * KMat0[i3 + free_node_cnt0 * j1]
                            + (expAY / expAX) * expAX * KMat0[i3 + free_node_cnt0 * j2]
                            + (expAY / expAX) * (expAX / expAY) * KMat0[i3 + free_node_cnt0 * j3];
                        MMat[i0 + free_node_cnt * j0] +=
                              expAY * (1.0 / expAY) * MMat0[i1 + free_node_cnt0 * j1]
                            + expAY * expAX * MMat0[i1 + free_node_cnt0 * j2]
                            + expAY * (expAX / expAY) * MMat0[i1 + free_node_cnt0 * j3]
                            + (1.0 / expAX) * (1.0 / expAY) * MMat0[i2 + free_node_cnt0 * j1]
                            + (1.0 / expAX) * expAX * MMat0[i2 + free_node_cnt0 * j2]
                            + (1.0 / expAX) * (expAX / expAY) * MMat0[i2 + free_node_cnt0 * j3]
                            + (expAY / expAX) * (1.0 / expAY) * MMat0[i3 + free_node_cnt0 * j1]
                            + (expAY / expAX) * expAX * MMat0[i3 + free_node_cnt0 * j2]
                            + (expAY / expAX) * (expAX / expAY) * MMat0[i3 + free_node_cnt0 * j3];
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// エルミートバンド行列の一般化固有値問題を解く(clapack)
        /// </summary>
        /// <param name="matLen"></param>
        /// <param name="A"></param>
        /// <param name="B"></param>
        /// <param name="evals"></param>
        /// <param name="evecs"></param>
        private static void solveHermitianBandMatGeneralizedEigen(int matLen, KrdLab.clapack.Complex[] A, KrdLab.clapack.Complex[] B, ref KrdLab.clapack.Complex[] evals, ref KrdLab.clapack.Complex[,] evecs)
        {
            // エルミート行列、正定値行列チェック
            bool isHermitianA = true;
            bool isHermitianB = true;
            bool isPositiveDefiniteB = true;
            for (int i = 0; i < matLen; i++)
            {
                // [B]の正定値行列チェック
                if (B[i + matLen * i].Real <= 0)
                {
                    isPositiveDefiniteB = false;
                    break;
                }
                for (int j = i; j < matLen; j++)
                {
                    // [A]のエルミート行列チェック
                    if (KrdLab.clapack.Complex.Abs(KrdLab.clapack.Complex.Conjugate(A[i + matLen * j]) - A[j + matLen * i]) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                    {
                        isHermitianA = false;
                        break;
                    }
                    // [B]のエルミート行列チェック
                    if (KrdLab.clapack.Complex.Abs(KrdLab.clapack.Complex.Conjugate(B[i + matLen * j]) - B[j + matLen * i]) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                    {
                        isHermitianB = false;
                        break;
                    }
                }
                if (!isHermitianA || !isHermitianB)
                {
                    break;
                }
            }
            System.Diagnostics.Debug.Assert(isHermitianA);
            System.Diagnostics.Debug.Assert(isHermitianB);
            System.Diagnostics.Debug.Assert(isPositiveDefiniteB);

            // パターン取得
            bool[,] patternA = new bool[matLen, matLen];
            bool[,] patternB = new bool[matLen, matLen];
            for (int i = 0; i < matLen; i++)
            {
                for (int j = 0; j < matLen; j++)
                {
                    //patternA[i, j] = (A[i + matLen * j].Magnitude >= Constants.PrecisionLowerLimit);
                    //patternB[i, j] = (B[i + matLen * j].Magnitude >= Constants.PrecisionLowerLimit);
                    patternA[i, j] = (A[i + matLen * j].Real != 0 || A[i + matLen * j].Imaginary != 0);
                    patternB[i, j] = (B[i + matLen * j].Real != 0 || B[i + matLen * j].Imaginary != 0);
                }
            }
            // バンド行列のバンド幅を縮小する
            KrdLab.clapack.Complex[] optA = new KrdLab.clapack.Complex[matLen * matLen];
            bool[,] optPatternA = new bool[matLen, matLen];
            IList<int> optNodesA = null;
            Dictionary<int, int> toOptNodesA = null;
            KrdLab.clapack.Complex[] optB = new KrdLab.clapack.Complex[matLen * matLen];
            bool[,] optPatternB = new bool[matLen, matLen];
            IList<int> optNodesB = null;
            Dictionary<int, int> toOptNodesB = null;
            // [B]のバンド幅を縮小する
            {
                GetOptBandMatNodes(patternB, out optNodesB, out toOptNodesB);
                for (int i = 0; i < matLen; i++)
                {
                    int ino_optB = toOptNodesB[i];
                    for (int j = 0; j < matLen; j++)
                    {
                        int jno_optB = toOptNodesB[j];
                        optPatternB[ino_optB, jno_optB] = patternB[i, j];
                        optB[ino_optB + matLen * jno_optB] = B[i + matLen * j];
                    }
                }
            }
            // [A]は[B]の節点並び替えに合わせて変更する
            {
                optNodesA = optNodesB;
                toOptNodesA = toOptNodesB;
                for (int i = 0; i < matLen; i++)
                {
                    int ino_optA = toOptNodesA[i];
                    for (int j = 0; j < matLen; j++)
                    {
                        int jno_optA = toOptNodesA[j];
                        optPatternA[ino_optA, jno_optA] = patternA[i, j];
                        optA[ino_optA + matLen * jno_optA] = A[i + matLen * j];
                    }
                }
            }
            patternA = null;
            patternB = null;
            A = null;
            B = null;

            // バンド行列のサイズ取得
            int a_rowcolSize;
            int a_subdiaSize;
            int a_superdiaSize;
            GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternA, out a_rowcolSize, out a_subdiaSize, out a_superdiaSize);
            int b_rowcolSize;
            int b_subdiaSize;
            int b_superdiaSize;
            GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternB, out b_rowcolSize, out b_subdiaSize, out b_superdiaSize);

            // バンド行列作成
            int _a_rsize = a_superdiaSize + 1;
            int _a_csize = a_rowcolSize;
            int _b_rsize = b_superdiaSize + 1;
            int _b_csize = b_rowcolSize;
            KrdLab.clapack.Complex[] AB = new KrdLab.clapack.Complex[_a_rsize * _a_csize];
            KrdLab.clapack.Complex[] BB = new KrdLab.clapack.Complex[_b_rsize * _b_csize];
            // [A]の値を[AB]にコピーする
            for (int c = 0; c < a_rowcolSize; c++)
            {
                // 対角成分
                AB[a_superdiaSize + c * _a_rsize] = optA[c + c * a_rowcolSize];

                // superdiagonals成分
                if (c > 0)
                {
                    for (int r = c - 1; r >= c - a_superdiaSize && r >= 0; r--)
                    {
                        AB[(r - c) + a_superdiaSize + c * _a_rsize] = optA[r + c * a_rowcolSize];
                    }
                }
            }
            // [B]の値を[BB]にコピーする
            for (int c = 0; c < b_rowcolSize; c++)
            {
                // 対角成分
                BB[b_superdiaSize + c * _b_rsize] = optB[c + c * b_rowcolSize];

                // superdiagonals成分
                if (c > 0)
                {
                    for (int r = c - 1; r >= c - b_superdiaSize && r >= 0; r--)
                    {
                        BB[(r - c) + b_superdiaSize + c * _b_rsize] = optB[r + c * b_rowcolSize];
                    }
                }
            }
            optA = null;
            optB = null;

            double[] ret_evals = null;
            KrdLab.clapack.Complex[][] ret_evecs = null;
            System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zhbgv");
            KrdLab.clapack.FunctionExt.zhbgv(AB, matLen, matLen, a_superdiaSize, BB, matLen, matLen, b_superdiaSize, ref ret_evals, ref ret_evecs);

            // エルミート行列の固有値は実数なので複素数配列への移し替えを行う
            evals = new KrdLab.clapack.Complex[ret_evals.Length];
            for (int i = 0; i < ret_evals.Length; i++)
            {
                evals[i].Real = ret_evals[i];
                evals[i].Imaginary = 0;
            }
            System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length);
            // 2次元配列に格納する
            evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen];
            for (int i = 0; i < ret_evecs.Length; i++)
            {
                KrdLab.clapack.Complex[] ret_evec = ret_evecs[i];
                for (int j = 0; j < ret_evec.Length; j++)
                {
                    // バンド幅縮小で並び替えた節点→元の節点番号変換
                    int jnoGlobal = optNodesB[j];
                    evecs[i, jnoGlobal] = ret_evec[j];
                }
            }
        }
Пример #5
0
        /// <summary>
        /// 欠陥モード?
        /// </summary>
        /// <param name="free_node_cnt"></param>
        /// <param name="sortedNodes"></param>
        /// <param name="toSorted"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="minNormalizedFreq"></param>
        /// <param name="maxNormalizedFreq"></param>
        /// <param name="normalizedFreq"></param>
        /// <param name="fieldVec"></param>
        /// <returns></returns>
        private static bool isDefectModeBetaSpecified(
            uint free_node_cnt,
            IList<uint> sortedNodes,
            Dictionary<uint, int> toSorted,
            IList<IList<uint>> PCWaveguidePorts,
            double minNormalizedFreq,
            double maxNormalizedFreq,
            KrdLab.clapack.Complex normalizedFreq,
            KrdLab.clapack.Complex[] fieldVec)
        {
            bool isHit = false;
            if (Math.Abs(normalizedFreq.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(normalizedFreq.Imaginary) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                // 複素モードは除外する
                return isHit;
            }
            else if (Math.Abs(normalizedFreq.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(normalizedFreq.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                // 伝搬モード
                // 後進波は除外する
                if (normalizedFreq.Real < 0)
                {
                    return isHit;
                }
            }
            else if (Math.Abs(normalizedFreq.Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(normalizedFreq.Imaginary) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                // 減衰モード
                //  利得のある波は除外する
                if (normalizedFreq.Imaginary > 0)
                {
                    return isHit;
                }
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
                return isHit;
            }

            // フォトニック結晶導波路の導波モードを判定する
            //
            // 領域内の節点の界の絶対値の2乗の和を計算
            //   要素分割が均一であることが前提。面積を考慮しない。
            double totalPower = 0.0;
            //for (int ino = 0; ino < fieldVec.Length; ino++)
            for (int ino = 0; ino < free_node_cnt; ino++)
            {
                double fieldAbs = fieldVec[ino].Magnitude;
                double power = fieldAbs * fieldAbs;
                totalPower += power;
            }
            // チャンネル上の節点の界の絶対値の2乗の和を計算
            //   要素分割が均一であることが前提。面積を考慮しない。
            int channelNodeCnt = 0;
            double channelTotalPower = 0.0;
            for (int portIndex = 0; portIndex < PCWaveguidePorts.Count; portIndex++)
            {
                IList<uint> portNodes = PCWaveguidePorts[portIndex];

                foreach (uint portNodeNumber in portNodes)
                {
                    if (!toSorted.ContainsKey(portNodeNumber)) continue;
                    int noSorted = toSorted[portNodeNumber];
                    //if (noSorted >= fieldVec.Length) continue;
                    if (noSorted >= free_node_cnt) continue;
                    KrdLab.clapack.Complex cvalue = fieldVec[noSorted];
                    double valAbs = cvalue.Magnitude;
                    double channelPower = valAbs * valAbs;
                    channelTotalPower += channelPower;
                    channelNodeCnt++;
                }
            }
            // 密度で比較する
            //totalPower /= fieldVec.Length;
            //channelTotalPower /= channelNodeCnt;
            ////const double powerRatioLimit = 3.0;
            //const double powerRatioLimit = 2.0;
            ////System.Diagnostics.Debug.WriteLine("channelTotalPower = {0}", (channelTotalPower / totalPower));
            // 総和で比較する
            const double powerRatioLimit = 0.5;
            if (Math.Abs(totalPower) >= Constants.PrecisionLowerLimit && (channelTotalPower / totalPower) >= powerRatioLimit)
            {
                if (normalizedFreq.Real >= minNormalizedFreq && normalizedFreq.Real <= maxNormalizedFreq)
                {
                    isHit = true;
                }
                else
                {
                    //System.Diagnostics.Debug.WriteLine("skip: a/λ = {0} + {1} i", normalizedFreq.Real, normalizedFreq.Imaginary);
                }
            }
            return isHit;
        }
Пример #6
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;
 }
Пример #7
0
        /// <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");
        }
Пример #8
0
        ////////////////////////////////////////////////////////////////////////////////////////
        // Φ = φ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);
        }
Пример #9
0
 /// <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;
 }
Пример #10
0
        /// <summary>
        /// 表示用に界の値を置き換える(複素数を複素数絶対値にする)
        /// </summary>
        /// <param name="world"></param>
        /// <param name="fieldValId"></param>
        public static void SetFieldValueForDisplay(CFieldWorld world, uint fieldValId, KrdLab.clapack.Complex[] resVec)
        {
            CField valField_base = world.GetField(fieldValId);
            System.Diagnostics.Debug.Assert(valField_base.GetFieldType() == FIELD_TYPE.ZSCALAR);

            IList<uint> aIdEA = valField_base.GetAryIdEA();
            foreach (uint eaId in aIdEA)
            {
                CElemAry ea = world.GetEA(eaId);
                CField valField = world.GetField(fieldValId);
                if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11)
                {
                    // 要素セグメントコーナー値
                    //CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world);
                    // 要素セグメントコーナー座標
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world);
                    uint nno = 3;
                    //uint ndim = 2;
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    //Complex[] value_c = new Complex[nno];
                    // 要素節点の座標
                    //double[,] coord_c = new double[nno, ndim];
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, world);
                    //CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);
                        // 座標を取得
                        //for (uint inoes = 0; inoes < nno; inoes++)
                        //{
                        //    double[] tmpval = null;
                        //    ns_c_co.GetValue(no_c[inoes], out tmpval);
                        //    System.Diagnostics.Debug.Assert(tmpval.Length == ndim);
                        //    for (int i = 0; i < tmpval.Length; i++)
                        //    {
                        //        coord_c[inoes, i] = tmpval[i];
                        //    }
                        //}
                        // 節点の値を取って来る
                        //es_c_va.GetNodes(ielem, no_c);
                        //for (uint inoes = 0; inoes < nno; inoes++)
                        //{
                        //    Complex[] tmpval = null;
                        //    ns_c_val.GetValue(no_c[inoes], out tmpval);
                        //    System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                        //    value_c[inoes] = tmpval[0];
                        //}
                        // 節点の値を絶対値にする
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            uint inoGlobal = no_c[inoes];
                            KrdLab.clapack.Complex cvalue = resVec[inoGlobal];
                            ns_c_val.SetValue(no_c[inoes], 0, cvalue.Real);
                            ns_c_val.SetValue(no_c[inoes], 1, cvalue.Imaginary);
                        }
                    }
                }
            }
        }
        ////////////////////////////////////////////////////////////////////////////////////////////////
        // DekFEMの処理を隠ぺいした簡易版
        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// PCOCGで線形方程式を解く
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged)
        public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            int matLen = mat.RowSize;

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 1");
            //------------------------------------------------------------------
            // ワールド座標系を生成
            //------------------------------------------------------------------
            uint baseId = 0;
            CFieldWorld World = new CFieldWorld();
            setupWorld((uint)matLen, ref World, out baseId);

            // 界の値を扱うバッファ?を生成する。
            // フィールド値IDが返却される。
            //    要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点
            uint FieldValId = World.MakeField_FieldElemDim(baseId, 0,
                FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER);

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 2");
            //------------------------------------------------------------------
            // リニアシステム
            //------------------------------------------------------------------
            CZLinearSystem Ls = new CZLinearSystem();
            CZPreconditioner_ILU Prec = new CZPreconditioner_ILU();

            //------------------------------------------------------------------
            // 界パターン追加
            //------------------------------------------------------------------
            Ls.AddPattern_Field(FieldValId, World);
            //  POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない

            // 非対角要素のパターンの追加
            {
                uint node_cnt = (uint)matLen;
                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                // パターンを追加
                using (CIndexedArray crs = new CIndexedArray())
                {
                    crs.InitializeSize(mat_cc.NBlkMatCol());

                    //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow());
                    using (UIntVectorIndexer index = crs.index)
                    using (UIntVectorIndexer ary = crs.array)
                    {
                        for (int iblk = 0; iblk < (int)crs.Size(); iblk++)
                        {
                            index[iblk] = 0;
                        }
                        for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                        {
                            // 現在のマトリクスのインデックス設定をコピーする
                            uint npsup = 0;
                            ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                            foreach (uint row_index in cur_rows)
                            {
                                ary.Add(row_index);
                            }
                            index[iblk + 1] = (uint)ary.Count;
                            //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup);
                            // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0)

                            // すべての節点に関して列を追加
                            int ino_global = iblk;
                            int col = iblk;
                            if (col != -1 && ino_global != -1)
                            {
                                // 関連付けられていない節点をその行の列データの最後に追加
                                int last_index = (int)index[col + 1] - 1;
                                int add_cnt = 0;
                                for (int jno_global = 0; jno_global < node_cnt; jno_global++)
                                {
                                    // 行列の0要素を除く
                                    //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit)
                                    //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15)
                                    //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                                    KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                    if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                                    {
                                        continue;
                                    }
                                    uint row = (uint)jno_global;
                                    if (ino_global != jno_global)  // 対角要素は除く
                                    {
                                        if (!cur_rows.Contains(row))
                                        {
                                            ary.Insert(last_index + 1 + add_cnt, row);
                                            add_cnt++;
                                            //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row);
                                        }
                                    }
                                }
                                if (add_cnt > 0)
                                {
                                    index[col + 1] = (uint)ary.Count;
                                }
                            }
                        }
                    }
                    crs.Sort();
                    System.Diagnostics.Debug.Assert(crs.CheckValid());
                    // パターンを削除する
                    mat_cc.DeletePattern();
                    // パターンを追加する
                    mat_cc.AddPattern(crs);
                }
            }

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 3");
            //------------------------------------------------------------------
            // プリコンディショナ―
            //------------------------------------------------------------------
            // set Preconditioner
            //Prec.SetFillInLevel(1);
            // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した
            //Prec.SetFillInLevel(0);
            // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする
            //Prec.SetFillInLevel((uint)mat.RowSize);
            //   完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い
            //Prec.SetFillInLevel(3);
            //   誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある
            //以上から
            //メインの導波管の計算時間を短くしたいのでフィルインなしにする
            //Prec.SetFillInLevel(0);
            //    導波管だとこれで十分
            // フィルインレベルの設定(既定値)
            Prec.SetFillInLevel(DefFillInLevel);
            // ILU(0)のパターン初期化
            Prec.SetLinearSystem(Ls);
            System.Diagnostics.Debug.WriteLine("SolvePCOCG 4");

            //------------------------------------------------------------------
            // 剛性行列、残差ベクトルのマージ
            //------------------------------------------------------------------
            Ls.InitializeMarge();
            {
                uint ntmp = Ls.GetTmpBufferSize();
                int[] tmpBuffer = new int[ntmp];
                for (int i = 0; i < ntmp; i++)
                {
                    tmpBuffer[i] = -1;
                }

                uint node_cnt = (uint)matLen;

                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                bool[,] add_flg = new bool[node_cnt, node_cnt];
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        add_flg[i, j] = false;
                        // 0要素はマージ対象でないので最初から除外する
                        //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit)
                        //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                        KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize];
                        if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                        {
                            add_flg[i, j] = true;
                        }
                    }
                }
                for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                {
                    // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応)
                    uint npsup = 0;
                    ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                    uint colcnt = 1;
                    uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する
                    Complex[] emattmp = new Complex[colcnt * rowcnt];
                    uint[] no_c_tmp_col = new uint[colcnt];
                    uint[] no_c_tmp_row = new uint[rowcnt];
                    no_c_tmp_col[0] = (uint)iblk;
                    no_c_tmp_row[0] = (uint)iblk;
                    for (int irow = 0; irow < cur_rows.Count; irow++)
                    {
                        no_c_tmp_row[irow + 1] = cur_rows[irow];
                    }
                    {
                        uint ino = 0;
                        uint ino_global = no_c_tmp_col[ino];
                        for (int jno = 0; jno < rowcnt; jno++)
                        {
                            uint jno_global = no_c_tmp_row[jno];
                            //emat[ino, jno]
                            if (!add_flg[ino_global, jno_global])
                            {
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global];
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize];
                                KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary);
                                add_flg[ino_global, jno_global] = true;
                            }
                            else
                            {
                                // ここにはこない
                                System.Diagnostics.Debug.Assert(false);
                                emattmp[ino * rowcnt + jno] = new Complex(0, 0);
                            }
                        }
                    }
                    // マージ!
                    mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer);
                }
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] );
                        System.Diagnostics.Debug.Assert(add_flg[i, j]);
                    }
                }

                // 残差ベクトルにマージ
                for (uint ino_global = 0; ino_global < node_cnt; ino_global++)
                {
                    // 残差ベクトルにマージする
                    uint no_tmp = ino_global;
                    //System.Numerics.Complex cvalue = resVec[ino_global];
                    KrdLab.clapack.Complex cvalue = resVec[ino_global];
                    Complex val = new Complex(cvalue.Real, cvalue.Imaginary);
                    res_c.AddValue(no_tmp, 0, val);
                }
            }
            double res = Ls.FinalizeMarge();
            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList<uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry ea = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint ino_global = no_c[ino];
                            Complex cvalue = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Prec.Clear();
            Prec.Dispose();
            World.Clear();
            World.Dispose();
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return success;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="Ls"></param>
        /// <param name="Prec"></param>
        /// <param name="tmpBuffer"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        public static bool SolvePCOCG(
            ref CFieldWorld World, ref uint FieldValId,
            ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer,
            ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            //------------------------------------------------------------------
            // マージの終了
            //------------------------------------------------------------------
            double res = Ls.FinalizeMarge();
            tmpBuffer = null;

            // マトリクスサイズの取得
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            // マトリクスのサイズ
            int matLen = (int)mat_cc.NBlkMatCol();

            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList<uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry ea = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint ino_global = no_c[ino];
                            Complex cvalue = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Ls = null;
            Prec.Clear();
            Prec.Dispose();
            Prec = null;
            World.Clear();
            World.Dispose();
            World = null;
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return success;
        }
Пример #13
0
        /// <summary>
        /// 四角形領域:従属な節点の界をセットする
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="no_c_all_fieldPortBcId1"></param>
        /// <param name="no_c_all_fieldPortBcId2"></param>
        /// <param name="no_c_all_fieldPortBcId3"></param>
        /// <param name="no_c_all_fieldPortBcId4"></param>
        /// <param name="sharedNodes"></param>
        /// <param name="expAX"></param>
        /// <param name="expAY"></param>
        /// <param name="expAY1"></param>
        /// <param name="expAY2"></param>
        /// <param name="resVec"></param>
        private static void setDependentFieldVal_Rect(
            int probNo,
            uint[] no_c_all_fieldPortBcId1,
            uint[] no_c_all_fieldPortBcId2,
            uint[] no_c_all_fieldPortBcId3,
            uint[] no_c_all_fieldPortBcId4,
            uint[] sharedNodes,
            KrdLab.clapack.Complex expAX,
            KrdLab.clapack.Complex expAY,
            KrdLab.clapack.Complex expAY1,
            KrdLab.clapack.Complex expAY2,
            ref KrdLab.clapack.Complex[] resVec
            )
        {
            if (probNo == 3)
            {
                // ポート境界1の節点の値を境界2にも格納する
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1];

                    // 境界2の節点
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[no_c_all_fieldPortBcId2.Length - 1 - i];
                    resVec[nodeNumberPortBc2] = expAX * cvalue; // 直接Bloch境界条件を指定する場合
                }
                // ポート境界3の節点の値を境界4にも格納する
                for (int i = 0; i < (no_c_all_fieldPortBcId3.Length - 1) / 2; i++)
                {
                    // 境界3の節点
                    uint nodeNumberPortBc3 = no_c_all_fieldPortBcId3[i];
                    // 境界3の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc3];

                    // 境界4の節点
                    uint nodeNumberPortBc4 = no_c_all_fieldPortBcId4[(no_c_all_fieldPortBcId4.Length - 1) / 2 - 1 - i];
                    resVec[nodeNumberPortBc4] = expAY1 * cvalue; // 直接Bloch境界条件を指定する場合
                }
                for (int i = (no_c_all_fieldPortBcId3.Length - 1) / 2; i < no_c_all_fieldPortBcId3.Length; i++)
                {
                    // 境界3の節点
                    uint nodeNumberPortBc3 = no_c_all_fieldPortBcId3[i];
                    // 境界3の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc3];

                    // 境界4の節点
                    uint nodeNumberPortBc4 = no_c_all_fieldPortBcId4[no_c_all_fieldPortBcId4.Length - 1 - (i - ((no_c_all_fieldPortBcId3.Length - 1) / 2))];
                    resVec[nodeNumberPortBc4] = expAY2 * cvalue; // 直接Bloch境界条件を指定する場合
                }
            }
            else
            {
                // 共有頂点の値を格納
                {
                    // 左上
                    uint nodeNumberShared0 = sharedNodes[0];
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberShared0];
                    // 左下
                    uint nodeNumberShared1 = sharedNodes[1];
                    resVec[nodeNumberShared1] = (1.0 / expAY) * cvalue;
                    // 右上
                    uint nodeNumberShared2 = sharedNodes[2];
                    resVec[nodeNumberShared2] = expAX * cvalue;
                    // 右下
                    uint nodeNumberShared3 = sharedNodes[3];
                    resVec[nodeNumberShared3] = (expAX / expAY) * cvalue;
                }
                // ポート境界1の節点の値を境界2にも格納する
                for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1];

                    // 境界2の節点
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[no_c_all_fieldPortBcId2.Length - 1 - i];
                    resVec[nodeNumberPortBc2] = expAX * cvalue; // 直接Bloch境界条件を指定する場合
                }
                // ポート境界3の節点の値を境界4にも格納する
                for (int i = 0; i < no_c_all_fieldPortBcId3.Length; i++)
                {
                    // 境界3の節点
                    uint nodeNumberPortBc3 = no_c_all_fieldPortBcId3[i];
                    // 境界3の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc3];

                    // 境界4の節点
                    uint nodeNumberPortBc4 = no_c_all_fieldPortBcId4[no_c_all_fieldPortBcId4.Length - 1 - i];
                    resVec[nodeNumberPortBc4] = expAY * cvalue; // 直接Bloch境界条件を指定する場合
                }
            }
        }
Пример #14
0
        /// <summary>
        /// 六角形領域:従属な節点の界をセットする
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="no_c_all_fieldPortBcId1"></param>
        /// <param name="no_c_all_fieldPortBcId2"></param>
        /// <param name="no_c_all_fieldPortBcId3"></param>
        /// <param name="no_c_all_fieldPortBcId4"></param>
        /// <param name="sharedNodes"></param>
        /// <param name="expAX"></param>
        /// <param name="expAY"></param>
        /// <param name="expAY1"></param>
        /// <param name="expAY2"></param>
        /// <param name="resVec"></param>
        private static void setDependentFieldVal_Hex(
            int probNo,
            uint[] no_c_all_fieldPortBcId1,
            uint[] no_c_all_fieldPortBcId2,
            uint[] no_c_all_fieldPortBcId3,
            uint[] no_c_all_fieldPortBcId4,
            uint[] no_c_all_fieldPortBcId5,
            uint[] no_c_all_fieldPortBcId6,
            uint[] sharedNodes,
            KrdLab.clapack.Complex expA1,
            KrdLab.clapack.Complex expA2,
            KrdLab.clapack.Complex expA3,
            ref KrdLab.clapack.Complex[] resVec
            )
        {
            // 共有頂点の値を格納
            {
                // 上
                uint nodeNumberShared0 = sharedNodes[0];
                KrdLab.clapack.Complex cvalue = resVec[nodeNumberShared0];
                // 右下
                uint nodeNumberShared4 = sharedNodes[4];
                resVec[nodeNumberShared4] = expA1 * cvalue;
                // 左下
                uint nodeNumberShared2 = sharedNodes[2];
                resVec[nodeNumberShared2] = (1.0 / expA3) * cvalue;
            }
            {
                // 左上
                uint nodeNumberShared1 = sharedNodes[1];
                KrdLab.clapack.Complex cvalue = resVec[nodeNumberShared1];
                // 下
                uint nodeNumberShared3 = sharedNodes[3];
                resVec[nodeNumberShared3] = expA1 * cvalue;
                // 右上
                uint nodeNumberShared5 = sharedNodes[5];
                resVec[nodeNumberShared5] = expA2 * cvalue;
            }
            // ポート境界1の節点の値を境界4にも格納する
            for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
            {
                // 境界1の節点
                uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                if (nodeNumberPortBc1 == sharedNodes[0]) continue;
                if (nodeNumberPortBc1 == sharedNodes[1]) continue;
                // 境界1の節点の界の値を取得
                KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1];

                // 境界4の節点
                uint nodeNumberPortBc4 = no_c_all_fieldPortBcId4[no_c_all_fieldPortBcId4.Length - 1 - i];
                resVec[nodeNumberPortBc4] = expA1 * cvalue; // 直接Bloch境界条件を指定する場合
            }
            // ポート境界2の節点の値を境界5にも格納する
            for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
            {
                // 境界2の節点
                uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i];
                if (nodeNumberPortBc2 == sharedNodes[1]) continue;
                if (nodeNumberPortBc2 == sharedNodes[2]) continue;
                // 境界3の節点の界の値を取得
                KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc2];

                // 境界5の節点
                uint nodeNumberPortBc5 = no_c_all_fieldPortBcId5[no_c_all_fieldPortBcId5.Length - 1 - i];
                resVec[nodeNumberPortBc5] = expA2 * cvalue; // 直接Bloch境界条件を指定する場合
            }
            // ポート境界3の節点の値を境界6にも格納する
            for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
            {
                // 境界2の節点
                uint nodeNumberPortBc3 = no_c_all_fieldPortBcId3[i];
                if (nodeNumberPortBc3 == sharedNodes[2]) continue;
                if (nodeNumberPortBc3 == sharedNodes[3]) continue;
                // 境界3の節点の界の値を取得
                KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc3];

                // 境界6の節点
                uint nodeNumberPortBc6 = no_c_all_fieldPortBcId6[no_c_all_fieldPortBcId6.Length - 1 - i];
                resVec[nodeNumberPortBc6] = expA3 * cvalue; // 直接Bloch境界条件を指定する場合
            }
        }
Пример #15
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);
            }
        }
Пример #16
0
 public static Complex[,] matrix_FromBuffer(KrdLab.clapack.Complex[] mat_, int nRow, int nCol)
 {
     Complex[,] mat = new Complex[nRow, nCol];
     // rowから先に埋めていく
     for (int j = 0; j < mat.GetLength(1); j++) // col
     {
         for (int i = 0; i < mat.GetLength(0); i++)  // row
         {
             KrdLab.clapack.Complex cval = mat_[j * mat.GetLength(0) + i];
             mat[i, j] = new Complex(cval.Real, cval.Imaginary);
         }
     }
     return mat;
 }
Пример #17
0
        /// <summary>
        /// 欠陥モード?
        /// </summary>
        /// <param name="k0"></param>
        /// <param name="freeNodeCntPeriodic"></param>
        /// <param name="sortedNodesPeriodic"></param>
        /// <param name="toSortedPeriodic"></param>
        /// <param name="defectNodePeriodic"></param>
        /// <param name="minBeta"></param>
        /// <param name="maxBeta"></param>
        /// <param name="betam"></param>
        /// <param name="fieldVec"></param>
        /// <returns></returns>
        private static bool isDefectMode(
            double k0,
            int freeNodeCntPeriodic,
            IList<int> sortedNodesPeriodic,
            Dictionary<int, int> toSortedPeriodic,
            IList<int> defectNodePeriodic,
            double minBeta,
            double maxBeta,
            KrdLab.clapack.Complex betam,
            KrdLab.clapack.Complex[] fieldVec)
        {
            bool isHit = false;
            if (Math.Abs(betam.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betam.Imaginary) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                // 複素モードは除外する
                return isHit;
            }
            else if (Math.Abs(betam.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betam.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                // 伝搬モード
                // 後進波は除外する
                if (betam.Real < 0)
                {
                    return isHit;
                }
            }
            else if (Math.Abs(betam.Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betam.Imaginary) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {

                // 減衰モード
                //  利得のある波は除外する
                if (betam.Imaginary > 0)
                {
                    return isHit;
                }

                /*
                //除外する
                return isHit;
                 */
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
                return isHit;
            }

            // フォトニック結晶導波路の導波モードを判定する
            //
            // 領域内の節点の界の絶対値の2乗の和を計算
            //   要素分割が均一であることが前提。面積を考慮しない。
            double totalPower = 0.0;
            //for (int ino = 0; ino < fieldVec.Length; ino++)
            for (int ino = 0; ino < freeNodeCntPeriodic; ino++)
            {
                double fieldAbs = fieldVec[ino].Magnitude;
                double power = fieldAbs * fieldAbs;
                totalPower += power;
            }
            // チャンネル上の節点の界の絶対値の2乗の和を計算
            //   要素分割が均一であることが前提。面積を考慮しない。
            int channelNodeCnt = 0;
            double channelTotalPower = 0.0;

            foreach (int defectNodeNumber in defectNodePeriodic)
            {
                if (!toSortedPeriodic.ContainsKey(defectNodeNumber)) continue;
                int noSorted = toSortedPeriodic[defectNodeNumber];
                //if (noSorted >= fieldVec.Length) continue;
                if (noSorted >= freeNodeCntPeriodic) continue;
                KrdLab.clapack.Complex cvalue = fieldVec[noSorted];
                double valAbs = cvalue.Magnitude;
                double channelPower = valAbs * valAbs;
                channelTotalPower += channelPower;
                channelNodeCnt++;
            }
            // 密度で比較する
            //totalPower /= fieldVec.Length;
            //channelTotalPower /= channelNodeCnt;
            ////const double powerRatioLimit = 3.0;
            //const double powerRatioLimit = 2.0;
            ////System.Diagnostics.Debug.WriteLine("channelTotalPower = {0}", (channelTotalPower / totalPower));
            // 総和で比較する
            const double powerRatioLimit = 0.5;
            if (Math.Abs(totalPower) >= Constants.PrecisionLowerLimit && (channelTotalPower / totalPower) >= powerRatioLimit)
            {
                //if (((Math.Abs(betam.Real) / k0) > maxBeta))
                if (Math.Abs(betam.Real / k0) > maxBeta || Math.Abs(betam.Real / k0) < minBeta)
                {
                    //System.Diagnostics.Debug.WriteLine("PCWaveguideMode: beta is invalid skip: β/k0 = {0} at k0 = {1}", betam.Real / k0, k0);
                    System.Diagnostics.Debug.WriteLine("PCWaveguideMode: beta is invalid skip: β/k0 = {0} at k0 = {1}", betam.Real / k0, k0);
                }
                else
                {
                    isHit = true;
                }
            }

            /*
            ////////////////////////暫定
            if (Math.Abs(betam.Real / k0) > maxBeta || Math.Abs(betam.Real / k0) < minBeta)
            {
                //System.Diagnostics.Debug.WriteLine("PCWaveguideMode: beta is invalid skip: β/k0 = {0} at k0 = {1}", betam.Real / k0, k0);
                System.Diagnostics.Debug.WriteLine("PCWaveguideMode: beta is invalid skip: β/k0 = {0} at k0 = {1}", betam.Real / k0, k0);
            }
            else
            {
                isHit = true;
            }
             */
            return isHit;
        }
Пример #18
0
 // 行列の行ベクトルを抜き出す
 public static KrdLab.clapack.Complex[] matrix_GetRowVec(KrdLab.clapack.Complex[,] matA, int row)
 {
     KrdLab.clapack.Complex[] rowVec = new KrdLab.clapack.Complex[matA.GetLength(1)];
     for (int j = 0; j < matA.GetLength(1); j++)
     {
         rowVec[j] = matA[row, j];
     }
     return rowVec;
 }
Пример #19
0
        //////////////////////////////////////////////////////////////////////////////////////////////////
        // 周期構造導波路固有値問題:Φを直接解く方法
        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);
        }
Пример #20
0
        public static KrdLab.clapack.Complex[] matrix_Inverse(KrdLab.clapack.Complex[] matA, int n)
        {
            System.Diagnostics.Debug.Assert(matA.Length == (n * n));
            KrdLab.clapack.Complex[] matA_ = new KrdLab.clapack.Complex[n * n];
            matA.CopyTo(matA_, 0);
            KrdLab.clapack.Complex[] matB_ = new KrdLab.clapack.Complex[n * n];
            // 単位行列
            for (int i = 0; i < matB_.Length; i++)
            {
                matB_[i] = 0.0;
            }
            for (int i = 0; i < n; i++)
            {
                matB_[i + i * n] = 1.0;
            }
            // [A][X] = [B]
            //  [B]の内容が書き換えられるので、matXを新たに生成せず、matBを出力に指定している
            int x_row = 0;
            int x_col = 0;
            KrdLab.clapack.FunctionExt.zgesv(ref matB_, ref x_row, ref x_col, matA_, n, n, matB_, n, n);

            KrdLab.clapack.Complex[] matX = matB_;
            return matX;
        }
Пример #21
0
        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;
                }
            }
        }
Пример #22
0
 public static void matrix_setRowVec(KrdLab.clapack.Complex[,] matA, int row, KrdLab.clapack.Complex[] rowVec)
 {
     System.Diagnostics.Debug.Assert(matA.GetLength(1) == rowVec.Length);
     for (int j = 0; j < matA.GetLength(1); j++)
     {
         matA[row, j] = rowVec[j];
     }
 }
Пример #23
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);
 }
Пример #24
0
 // {x} = ({v})*
 public static KrdLab.clapack.Complex[] vector_Conjugate(KrdLab.clapack.Complex[] vec)
 {
     KrdLab.clapack.Complex[] retVec = new KrdLab.clapack.Complex[vec.Length];
     for (int i = 0; i < retVec.Length; i++)
     {
         retVec[i] = KrdLab.clapack.Complex.Conjugate(vec[i]);
     }
     return retVec;
 }
Пример #25
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;
        }
Пример #26
0
 // x = {v1}t{v2}
 public static KrdLab.clapack.Complex vector_Dot(KrdLab.clapack.Complex[] v1, KrdLab.clapack.Complex[] v2)
 {
     System.Diagnostics.Debug.Assert(v1.Length == v2.Length);
     int n = v1.Length;
     KrdLab.clapack.Complex sum = new KrdLab.clapack.Complex(0.0, 0.0);
     for (int i = 0; i < n; i++)
     {
         sum += v1[i] * v2[i];
     }
     return sum;
 }
Пример #27
0
        /// <summary>
        /// 同じ固有モード?
        /// </summary>
        /// <param name="k0"></param>
        /// <param name="node_cnt"></param>
        /// <param name="PrevModalVec"></param>
        /// <param name="free_node_cnt"></param>
        /// <param name="sortedNodes"></param>
        /// <param name="toSorted"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="minNormalizedFreq"></param>
        /// <param name="maxNormalizedFreq"></param>
        /// <param name="complexNormalizedFreq"></param>
        /// <param name="fieldVec"></param>
        /// <returns></returns>
        private static bool isSameModeBetaSpecified(
            uint node_cnt,
            KrdLab.clapack.Complex[] PrevModalVec,
            uint free_node_cnt,
            IList<uint> sortedNodes,
            Dictionary<uint, int> toSorted,
            IList<IList<uint>> PCWaveguidePorts,
            double minNormalizedFreq,
            double maxNormalizedFreq,
            KrdLab.clapack.Complex complexNormalizedFreq,
            KrdLab.clapack.Complex[] fieldVec,
            out double ret_norm)
        {
            bool isHit = false;
            ret_norm = 0.0;
            if (complexNormalizedFreq.Real > 0.0 && Math.Abs(complexNormalizedFreq.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
            {
                KrdLab.clapack.Complex[] workModalVec1 = new KrdLab.clapack.Complex[node_cnt]; // 前回
                KrdLab.clapack.Complex[] workModalVec2 = new KrdLab.clapack.Complex[node_cnt]; // 今回
                // 前半の{Φ}のみ取得する
                for (int ino = 0; ino < free_node_cnt; ino++)
                {
                    // 今回の固有ベクトル
                    //System.Diagnostics.Debug.WriteLine("    ( " + imode + ", " + ino + " ) = " + evec[ino].Real + " + " + evec[ino].Imaginary + " i ");
                    uint nodeNumber = sortedNodes[ino];
                    workModalVec2[nodeNumber] = fieldVec[ino];

                    // 対応する前回の固有ベクトル
                    workModalVec1[nodeNumber] = PrevModalVec[nodeNumber];
                }
                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 < node_cnt; 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)
                {
                    System.Diagnostics.Debug.WriteLine("norm (prev * current): {0} + {1}i (Abs: {2})", norm12.Real, norm12.Imaginary, norm12.Magnitude);
                    if (complexNormalizedFreq.Real >= minNormalizedFreq && complexNormalizedFreq.Real <= maxNormalizedFreq)
                    {
                        isHit = true;
                        ret_norm = norm12.Magnitude;
                    }
                    else
                    {
                        System.Diagnostics.Debug.WriteLine("skip: a/λ = {0} + {1} i", complexNormalizedFreq.Real, complexNormalizedFreq.Imaginary);
                    }
                }
            }
            return isHit;
        }
Пример #28
0
 /// <summary>
 /// 周期構造導波路の伝搬定数に変換する(βdが[-π, π]に収まるように変換)
 /// </summary>
 /// <param name="beta"></param>
 /// <param name="periodicDistance"></param>
 /// <returns></returns>
 public static KrdLab.clapack.Complex ToBetaPeriodic(KrdLab.clapack.Complex betam, double periodicDistance)
 {
     // βの再変換
     KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance);
     KrdLab.clapack.Complex betam_periodic = -1.0 * MyUtilLib.Matrix.MyMatrixUtil.complex_Log(expA) / (KrdLab.clapack.Complex.ImaginaryOne * periodicDistance);
     return betam_periodic;
 }
Пример #29
0
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="betaIndex"></param>
        /// <param name="Beta1"></param>
        /// <param name="Beta2"></param>
        /// <param name="BetaDelta"></param>
        /// <param name="initFlg"></param>
        /// <param name="WaveguideWidth"></param>
        /// <param name="WaveModeDv"></param>
        /// <param name="IsPCWaveguide"></param>
        /// <param name="latticeA"></param>
        /// <param name="periodicDistance"></param>
        /// <param name="PCWaveguidePorts"></param>
        /// <param name="CalcModeIndex"></param>
        /// <param name="isSVEA"></param>
        /// <param name="PrevModalVec"></param>
        /// <param name="IsShowAbsField"></param>
        /// <param name="MinNormalizedFreq"></param>
        /// <param name="MaxNormalizedFreq"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="FieldLoopId"></param>
        /// <param name="FieldForceBcId"></param>
        /// <param name="FieldPortBcId1"></param>
        /// <param name="FieldPortBcId2"></param>
        /// <param name="Medias"></param>
        /// <param name="LoopDic"></param>
        /// <param name="EdgeDic"></param>
        /// <param name="EigenValueList"></param>
        /// <param name="DrawerAry"></param>
        /// <param name="Camera"></param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int betaIndex,
            double Beta1,
            double Beta2,
            double BetaDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            bool IsPCWaveguide,
            double latticeA,
            double periodicDistance,
            IList<IList<uint>> PCWaveguidePorts,
            int CalcModeIndex,
            bool isSVEA,
            ref KrdLab.clapack.Complex[] PrevModalVec,
            bool IsShowAbsField,
            double MinNormalizedFreq,
            double MaxNormalizedFreq,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            ref IList<Complex> EigenValueList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

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

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

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

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

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

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

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

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

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

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

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

                }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }
Пример #30
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="probNo"></param>
        /// <param name="periodicDistanceX"></param>
        /// <param name="periodicDistanceY"></param>
        /// <param name="betaX"></param>
        /// <param name="betaY"></param>
        /// <param name="coord_c_all"></param>
        /// <param name="sharedNodes"></param>
        /// <param name="sharedNodeCoords"></param>
        /// <param name="sortedNodes"></param>
        /// <param name="toSorted"></param>
        /// <param name="boundary_node_cnt_each"></param>
        /// <param name="boundary_node_cnt"></param>
        /// <param name="free_node_cnt"></param>
        /// <param name="free_node_cnt0"></param>
        /// <param name="KMat0"></param>
        /// <param name="MMat0"></param>
        /// <param name="expA1"></param>
        /// <param name="expA2"></param>
        /// <param name="expA3"></param>
        /// <param name="KMat"></param>
        /// <param name="MMat"></param>
        private static void getSortedMatrix_Hex(
            int probNo,
            double periodicDistanceX,
            double periodicDistanceY,
            KrdLab.clapack.Complex betaX,
            KrdLab.clapack.Complex betaY,
            double[][] coord_c_all,
            uint[] sharedNodes,
            double[][] sharedNodeCoords,
            IList<uint> sortedNodes,
            Dictionary<uint, int> toSorted,
            uint boundary_node_cnt_each,
            uint boundary_node_cnt,
            uint free_node_cnt,
            uint free_node_cnt0,
            KrdLab.clapack.Complex[] KMat0,
            KrdLab.clapack.Complex[] MMat0,
            out KrdLab.clapack.Complex expA1,
            out KrdLab.clapack.Complex expA2,
            out KrdLab.clapack.Complex expA3,
            out KrdLab.clapack.Complex[] KMat,
            out KrdLab.clapack.Complex[] MMat
            )
        {
            KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
            MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt];
            expA1 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5)
                * KrdLab.clapack.Complex.Exp(1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY * 0.75);
            expA2 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX);
            expA3 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5)
                * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY * 0.75);
            /*
            // check
            {
                // 境界4→境界1
                for (int j = 0; j < (boundary_node_cnt_each - 1); j++)
                {
                    int j_B1 = j;
                    uint nodeNumber_B1 = sortedNodes[j_B1];
                    System.Diagnostics.Debug.WriteLine("B1 {0} {1} {2} {3}",
                        j_B1, nodeNumber_B1, coord_c_all[nodeNumber_B1][0], coord_c_all[nodeNumber_B1][1]);
                    int j_B4 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1));
                    uint nodeNumber_B4 = sortedNodes[j_B4];
                    System.Diagnostics.Debug.WriteLine("B4 {0} {1} {2} {3}",
                        j_B4, nodeNumber_B4, coord_c_all[nodeNumber_B4][0], coord_c_all[nodeNumber_B4][1]);
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    int j_B2 = (int)(j + boundary_node_cnt_each);
                    uint nodeNumber_B2 = sortedNodes[j_B2];
                    System.Diagnostics.Debug.WriteLine("B2 {0} {1} {2} {3}",
                        j_B2, nodeNumber_B2, coord_c_all[nodeNumber_B2][0], coord_c_all[nodeNumber_B2][1]);
                    int j_B5 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j);
                    uint nodeNumber_B5 = sortedNodes[j_B5];
                    System.Diagnostics.Debug.WriteLine("B5 {0} {1} {2} {3}",
                        j_B5, nodeNumber_B5, coord_c_all[nodeNumber_B5][0], coord_c_all[nodeNumber_B5][1]);
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    int j_B3 = (int)(j + boundary_node_cnt_each + (boundary_node_cnt_each - 2));
                    uint nodeNumber_B3 = sortedNodes[j_B3];
                    System.Diagnostics.Debug.WriteLine("B3 {0} {1} {2} {3}",
                        j_B3, nodeNumber_B3, coord_c_all[nodeNumber_B3][0], coord_c_all[nodeNumber_B3][1]);
                    int j_B6 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j);
                    uint nodeNumber_B6 = sortedNodes[j_B6];
                    System.Diagnostics.Debug.WriteLine("B6 {0} {1} {2} {3}",
                        j_B6, nodeNumber_B6, coord_c_all[nodeNumber_B6][0], coord_c_all[nodeNumber_B6][1]);
                }
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    uint nodeNumber_shared0 = sortedNodes[j0];
                    uint nodeNumber_shared4 = sortedNodes[j4];
                    uint nodeNumber_shared2 = sortedNodes[j2];
                    System.Diagnostics.Debug.WriteLine("shared0 {0} {1} {2} {3}",
                        j0, nodeNumber_shared0, coord_c_all[nodeNumber_shared0][0], coord_c_all[nodeNumber_shared0][1]);
                    System.Diagnostics.Debug.WriteLine("shared4 {0} {1} {2} {3}",
                        j4, nodeNumber_shared4, coord_c_all[nodeNumber_shared4][0], coord_c_all[nodeNumber_shared4][1]);
                    System.Diagnostics.Debug.WriteLine("shared2 {0} {1} {2} {3}",
                        j2, nodeNumber_shared2, coord_c_all[nodeNumber_shared2][0], coord_c_all[nodeNumber_shared2][1]);
                }
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    uint nodeNumber_shared1 = sortedNodes[j1];
                    uint nodeNumber_shared3 = sortedNodes[j3];
                    uint nodeNumber_shared5 = sortedNodes[j5];
                    System.Diagnostics.Debug.WriteLine("shared1 {0} {1} {2} {3}",
                        j1, nodeNumber_shared1, coord_c_all[nodeNumber_shared1][0], coord_c_all[nodeNumber_shared1][1]);
                    System.Diagnostics.Debug.WriteLine("shared3 {0} {1} {2} {3}",
                        j3, nodeNumber_shared3, coord_c_all[nodeNumber_shared3][0], coord_c_all[nodeNumber_shared3][1]);
                    System.Diagnostics.Debug.WriteLine("shared5 {0} {1} {2} {3}",
                        j5, nodeNumber_shared5, coord_c_all[nodeNumber_shared5][0], coord_c_all[nodeNumber_shared5][1]);
                }
            }
             */

            /////////////////////////////////////////////////////////////////
            // 境界1+2 + 3+内部
            for (int i = 0; i < free_node_cnt; i++)
            {
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                    MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 境界1+2+3+内部
            for (int i = 0; i < free_node_cnt; i++)
            {
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i + free_node_cnt * j] += expA1 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i + free_node_cnt * j] += expA1 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        expA2 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        expA2 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        expA3 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        expA3 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    KMat[i + free_node_cnt * j0] +=
                          expA1 * KMat0[i + free_node_cnt0 * j4]
                        + (1.0 / expA3) * KMat0[i + free_node_cnt0 * j2];
                    MMat[i + free_node_cnt * j0] +=
                          expA1 * MMat0[i + free_node_cnt0 * j4]
                        + (1.0 / expA3) * MMat0[i + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    KMat[i + free_node_cnt * j1] +=
                          expA1 * KMat0[i + free_node_cnt0 * j3]
                        + expA2 * KMat0[i + free_node_cnt0 * j5];
                    MMat[i + free_node_cnt * j1] +=
                          expA1 * MMat0[i + free_node_cnt0 * j3]
                        + expA2 * MMat0[i + free_node_cnt0 * j5];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 境界4
            for (int i = 1; i < (boundary_node_cnt_each - 1); i++)
            {
                int i_B1 = i; // 境界1
                int i_B4 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (i - 1)); // 境界4
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i_B1 + free_node_cnt * j] += (1.0 / expA1) * KMat0[i_B4 + free_node_cnt0 * j];
                    MMat[i_B1 + free_node_cnt * j] += (1.0 / expA1) * MMat0[i_B4 + free_node_cnt0 * j];
                }
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i_B1 + free_node_cnt * j] += KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i_B1 + free_node_cnt * j] += MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        (1.0 / expA1) * expA2 * KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        (1.0 / expA1) * expA2 * MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        (1.0 / expA1) * expA3 * KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        (1.0 / expA1) * expA3 * MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    KMat[i_B1 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * KMat0[i_B4 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * KMat0[i_B4 + free_node_cnt0 * j2];
                    MMat[i_B1 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * MMat0[i_B4 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * MMat0[i_B4 + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    KMat[i_B1 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * KMat0[i_B4 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * KMat0[i_B4 + free_node_cnt0 * j5];
                    MMat[i_B1 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * MMat0[i_B4 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * MMat0[i_B4 + free_node_cnt0 * j5];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 境界5
            for (int i = 0; i < (boundary_node_cnt_each - 2); i++)
            {
                int i_B2 = (int)(i + boundary_node_cnt_each); // 境界2
                int i_B5 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - i); // 境界5
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * KMat0[i_B5 + free_node_cnt0 * j];
                    MMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * MMat0[i_B5 + free_node_cnt0 * j];
                }
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        (1.0 / expA2) * expA3 * KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        (1.0 / expA2) * expA3 * MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    KMat[i_B2 + free_node_cnt * j0] +=
                          (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * j4]
                        + (1.0 / expA2) * (1.0 / expA3) * KMat0[i_B5 + free_node_cnt0 * j2];
                    MMat[i_B2 + free_node_cnt * j0] +=
                          (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * j4]
                        + (1.0 / expA2) * (1.0 / expA3) * MMat0[i_B5 + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    KMat[i_B2 + free_node_cnt * j1] +=
                          (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * j3]
                        + (1.0 / expA2) * expA2 * KMat0[i_B5 + free_node_cnt0 * j5];
                    MMat[i_B2 + free_node_cnt * j1] +=
                          (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * j3]
                        + (1.0 / expA2) * expA2 * MMat0[i_B5 + free_node_cnt0 * j5];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 境界6
            for (int i = 0; i < (boundary_node_cnt_each - 2); i++)
            {
                int i_B3 = (int)(i + boundary_node_cnt_each + (boundary_node_cnt_each - 2)); // 境界3
                int i_B6 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - i); // 境界6
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * KMat0[i_B6 + free_node_cnt0 * j];
                    MMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * MMat0[i_B6 + free_node_cnt0 * j];
                }
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        (1.0 / expA3) * expA2 * KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                        (1.0 / expA3) * expA2 * MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                        MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    KMat[i_B3 + free_node_cnt * j0] +=
                          (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * j4]
                        + (1.0 / expA3) * (1.0 / expA3) * KMat0[i_B6 + free_node_cnt0 * j2];
                    MMat[i_B3 + free_node_cnt * j0] +=
                          (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * j4]
                        + (1.0 / expA3) * (1.0 / expA3) * MMat0[i_B6 + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    KMat[i_B3 + free_node_cnt * j1] +=
                          (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * j3]
                        + (1.0 / expA3) * expA2 * KMat0[i_B6 + free_node_cnt0 * j5];
                    MMat[i_B3 + free_node_cnt * j1] +=
                          (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * j3]
                        + (1.0 / expA3) * expA2 * MMat0[i_B6 + free_node_cnt0 * j5];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 頂点4→0, 頂点2→0
            {
                int i0 = toSorted[sharedNodes[0]];
                int i4 = toSorted[sharedNodes[4]];
                int i2 = toSorted[sharedNodes[2]];
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i0 + free_node_cnt * j] +=
                          (1.0 / expA1) * KMat0[i4 + free_node_cnt0 * j]
                        + expA3 * KMat0[i2 + free_node_cnt0 * j];
                    MMat[i0 + free_node_cnt * j] +=
                          (1.0 / expA1) * MMat0[i4 + free_node_cnt0 * j]
                        + expA3 * MMat0[i2 + free_node_cnt0 * j];
                }
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i0 + free_node_cnt * j] +=
                          (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]
                        + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i0 + free_node_cnt * j] +=
                          (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]
                        + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i0 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                          (1.0 / expA1) * expA2 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]
                        + expA3 * expA2 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i0 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                          (1.0 / expA1) * expA2 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]
                        + expA3 * expA2 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i0 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                          (1.0 / expA1) * expA3 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]
                        + expA3 * expA3 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i0 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                          (1.0 / expA1) * expA3 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]
                        + expA3 * expA3 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = i0;
                    int j4 = i4;
                    int j2 = i2;
                    KMat[i0 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * KMat0[i4 + free_node_cnt0 * j2]
                        + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * j4]
                        + expA3 * (1.0 / expA3) * KMat0[i2 + free_node_cnt0 * j2];
                    MMat[i0 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * MMat0[i4 + free_node_cnt0 * j2]
                        + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * j4]
                        + expA3 * (1.0 / expA3) * MMat0[i2 + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = toSorted[sharedNodes[1]];
                    int j3 = toSorted[sharedNodes[3]];
                    int j5 = toSorted[sharedNodes[5]];
                    KMat[i0 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * KMat0[i4 + free_node_cnt0 * j5]
                        + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * j3]
                        + expA3 * expA2 * KMat0[i2 + free_node_cnt0 * j5];
                    MMat[i0 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * MMat0[i4 + free_node_cnt0 * j5]
                        + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * j3]
                        + expA3 * expA2 * MMat0[i2 + free_node_cnt0 * j5];
                }
            }
            /////////////////////////////////////////////////////////////////
            // 頂点3→1, 頂点5→1
            {
                int i1 = toSorted[sharedNodes[1]];
                int i3 = toSorted[sharedNodes[3]];
                int i5 = toSorted[sharedNodes[5]];
                // 境界1+3+内部
                for (int j = 0; j < free_node_cnt; j++)
                {
                    KMat[i1 + free_node_cnt * j] +=
                          (1.0 / expA1) * KMat0[i3 + free_node_cnt0 * j]
                        + (1.0 / expA2) * KMat0[i5 + free_node_cnt0 * j];
                    MMat[i1 + free_node_cnt * j] +=
                          (1.0 / expA1) * MMat0[i3 + free_node_cnt0 * j]
                        + (1.0 / expA2) * MMat0[i5 + free_node_cnt0 * j];
                }
                // 境界4→境界1
                for (int j = 1; j < (boundary_node_cnt_each - 1); j++)
                {
                    KMat[i1 + free_node_cnt * j] +=
                          (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]
                        + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                    MMat[i1 + free_node_cnt * j] +=
                          (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]
                        + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))];
                }
                // 境界5→境界2
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i1 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                          (1.0 / expA1) * expA2 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]
                        + (1.0 / expA2) * expA2 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                    MMat[i1 + free_node_cnt * (j + boundary_node_cnt_each)] +=
                          (1.0 / expA1) * expA2 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]
                        + (1.0 / expA2) * expA2 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)];
                }
                // 境界6→境界3
                for (int j = 0; j < (boundary_node_cnt_each - 2); j++)
                {
                    KMat[i1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                          (1.0 / expA1) * expA3 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]
                        + (1.0 / expA2) * expA3 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                    MMat[i1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] +=
                          (1.0 / expA1) * expA3 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]
                        + (1.0 / expA2) * expA3 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)];
                }
                // 頂点4→0, 頂点2→0
                {
                    int j0 = toSorted[sharedNodes[0]];
                    int j4 = toSorted[sharedNodes[4]];
                    int j2 = toSorted[sharedNodes[2]];
                    KMat[i1 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * KMat0[i3 + free_node_cnt0 * j2]
                        + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * j4]
                        + (1.0 / expA2) * (1.0 / expA3) * KMat0[i5 + free_node_cnt0 * j2];
                    MMat[i1 + free_node_cnt * j0] +=
                          (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * j4]
                        + (1.0 / expA1) * (1.0 / expA3) * MMat0[i3 + free_node_cnt0 * j2]
                        + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * j4]
                        + (1.0 / expA2) * (1.0 / expA3) * MMat0[i5 + free_node_cnt0 * j2];
                }
                // 頂点3→1, 頂点5→1
                {
                    int j1 = i1;
                    int j3 = i3;
                    int j5 = i5;
                    KMat[i1 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * KMat0[i3 + free_node_cnt0 * j5]
                        + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * j3]
                        + (1.0 / expA2) * expA2 * KMat0[i5 + free_node_cnt0 * j5];
                    MMat[i1 + free_node_cnt * j1] +=
                          (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * j3]
                        + (1.0 / expA1) * expA2 * MMat0[i3 + free_node_cnt0 * j5]
                        + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * j3]
                        + (1.0 / expA2) * expA2 * MMat0[i5 + free_node_cnt0 * j5];
                }
            }
        }