/// <summary>
        /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する
        /// </summary>
        /// <param name="waveLength">波長(E面の場合のみ使用する)</param>
        /// <param name="element">線要素</param>
        /// <param name="coords">座標リスト</param>
        /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param>
        /// <param name="Medias">媒質情報リスト</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="txx_1d">txx行列</param>
        /// <param name="ryy_1d">ryy行列</param>
        /// <param name="uzz_1d">uzz行列</param>
        public static void AddElementMatOf1dEigenValueProblem(
            double waveLength,
            FemLineElement element,
            IList <double> coords,
            Dictionary <int, int> toSorted,
            MediaInfo[] Medias,
            FemSolver.WGStructureDV WGStructureDv,
            FemSolver.WaveModeDV WaveModeDv,
            double waveguideWidthForEPlane,
            ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 2次線要素
            const int nno = Constants.LineNodeCnt_SecondOrder; // 3;

            int[] nodeNumbers = element.NodeNumbers;
            System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length);

            // 座標の取得
            double[] elementCoords = new double[nno];
            for (int n = 0; n < nno; n++)
            {
                int nodeIndex = nodeNumbers[n] - 1;
                elementCoords[n] = coords[nodeIndex];
            }
            // 線要素の長さ
            double elen = Math.Abs(elementCoords[1] - elementCoords[0]);
            // 媒質インデックス
            int mediaIndex = element.MediaIndex;
            // 媒質
            MediaInfo media = Medias[mediaIndex];

            double[,] media_P = null;
            double[,] media_Q = null;
            // ヘルムホルツ方程式のパラメータP,Qを取得する
            FemSolver.GetHelmholtzMediaPQ(
                k0,
                media,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                out media_P,
                out media_Q);

            double[,] integralN = new double[nno, nno]
            {
                { 4.0 / 30.0 * elen, -1.0 / 30.0 * elen, 2.0 / 30.0 * elen },
                { -1.0 / 30.0 * elen, 4.0 / 30.0 * elen, 2.0 / 30.0 * elen },
                { 2.0 / 30.0 * elen, 2.0 / 30.0 * elen, 16.0 / 30.0 * elen },
            };
            double[,] integralDNDY = new double[nno, nno]
            {
                { 7.0 / (3.0 * elen), 1.0 / (3.0 * elen), -8.0 / (3.0 * elen) },
                { 1.0 / (3.0 * elen), 7.0 / (3.0 * elen), -8.0 / (3.0 * elen) },
                { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) },
            };

            for (int ino = 0; ino < nno; ino++)
            {
                int inoBoundary = nodeNumbers[ino];
                int inoSorted;
                if (!toSorted.ContainsKey(inoBoundary))
                {
                    continue;
                }
                inoSorted = toSorted[inoBoundary];
                for (int jno = 0; jno < nno; jno++)
                {
                    int jnoBoundary = nodeNumbers[jno];
                    int jnoSorted;
                    if (!toSorted.ContainsKey(jnoBoundary))
                    {
                        continue;
                    }
                    jnoSorted = toSorted[jnoBoundary];
                    // 対称バンド行列対応
                    if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted)
                    {
                        continue;
                    }

                    double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno];
                    double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno];
                    double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno];
                    //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno;
                    //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno;
                    //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno;
                    txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno;
                    ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno;
                    uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno;
                }
            }
        }
예제 #2
0
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
                                         Dictionary <int, int> toSorted,
                                         FemElement element,
                                         IList <FemNode> Nodes,
                                         MediaInfo[] Medias,
                                         Dictionary <int, bool> ForceNodeNumberH,
                                         FemSolver.WGStructureDV WGStructureDv,
                                         FemSolver.WaveModeDV WaveModeDv,
                                         double waveguideWidthForEPlane,
                                         ref MyComplexMatrix mat,
                                         ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
                                         ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
                                         ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.QuadVertexCnt; //4;
            // 要素内節点数
            const int nno = Constants.QuadNodeCnt_FirstOrder; //4;  // 1次セレンディピティ
            // 座標次元数
            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,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                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];
                }
            }

            // 四角形の辺の長さを求める
            double[] le = new double[4];
            le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
            le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
            le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
            le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);
            System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit);
            System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit);
            double lx = le[0];
            double ly = le[1];

            // 要素節点座標( 局所r,s成分 )
            //        s
            //        |
            //    3+  +  +2
            //    |   |   |
            // ---+---+---+-->r
            //    |   |   |
            //    0+  +  +1
            //        |
            //
            double[][] n_pts =
            {
                // r, s
                new double[] { -1.0, -1.0 },    //0
                new double[] {  1.0, -1.0 },    //1
                new double[] {  1.0,  1.0 },    //2
                new double[] { -1.0,  1.0 },    //3
            };

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno]
            {
                {
                    { 2.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx) },
                    { -2.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx) },
                    { -1.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx) },
                    { 1.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx) },
                },
                {
                    { 2.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly) },
                    { 1.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly) },
                    { -1.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly) },
                    { -2.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly) },
                }
            };
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno]
            {
                { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 },
                { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 },
                { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 },
                { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0 },
            };

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                     - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int    jno   = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber))
                        {
                            continue;
                        }
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
예제 #3
0
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
                                         Dictionary <int, int> toSorted,
                                         FemElement element,
                                         IList <FemNode> Nodes,
                                         MediaInfo[] Medias,
                                         Dictionary <int, bool> ForceNodeNumberH,
                                         FemSolver.WGStructureDV WGStructureDv,
                                         FemSolver.WaveModeDV WaveModeDv,
                                         double waveguideWidthForEPlane,
                                         ref MyComplexMatrix mat,
                                         ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
                                         ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
                                         ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.TriVertexCnt; //3;
            // 要素内節点数
            const int nno = Constants.TriNodeCnt_FirstOrder; //3;  // 1次三角形要素
            // 座標次元数
            const int ndim = Constants.CoordDim2D;           //2;

            int[]     nodeNumbers = element.NodeNumbers;
            int[]     no_c        = new int[nno];
            MediaInfo media       = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得

            double[,] media_P = null;
            double[,] media_Q = null;
            // ヘルムホルツ方程式のパラメータP,Qを取得する
            FemSolver.GetHelmholtzMediaPQ(
                k0,
                media,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                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];
                }
            }
            // 面積を求める
            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]);

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    integralDNDX[0, ino, jno] = area * dldx[ino, 0] * dldx[jno, 0];
                    integralDNDX[1, ino, jno] = area * dldx[ino, 1] * dldx[jno, 1];
                }
            }
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno]
            {
                { area / 6.0, area / 12.0, area / 12.0 },
                { area / 12.0, area / 6.0, area / 12.0 },
                { area / 12.0, area / 12.0, area / 6.0 },
            };

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                     - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int    jno   = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber))
                        {
                            continue;
                        }
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
        /// <summary>
        /// 図面情報を読み込む
        /// </summary>
        /// <returns></returns>
        public static bool LoadFromFile(
            string filename,
            out string appVersion,
            out string useUtility,
            ref CCadObj2D editCad2D,
            ref IList<CadLogic.Loop> loopList,
            ref IList<EdgeCollection> edgeCollectionList,
            out int incidentPortNo,
            ref MediaInfo[] medias
            )
        {
            bool success = false;

            ////////////////////////////////////////////////////////
            // 出力データの初期化

            // アプリケーションのバージョン番号
            appVersion = "";
            // ユーティリティ名
            useUtility = "";

            // 図面のクリア
            editCad2D.Clear();
            //// ベースループIDを初期化
            //baseLoopId = 0;
            // ループ情報リストの初期化
            loopList.Clear();
            // 入射ポートの初期化
            incidentPortNo = 1;
            // ポートのエッジコレクションのリストを初期化
            edgeCollectionList.Clear();
            // 媒質の比誘電率、比透磁率の逆数の初期化
            foreach (MediaInfo media in medias)
            {
                // 比透磁率の逆数
                media.SetP(new double[,]
                    {
                        {1.0, 0.0, 0.0},
                        {0.0, 1.0, 0.0},
                        {0.0, 0.0, 1.0}
                    });
                // 比誘電率
                media.SetQ(new double[,]
                    {
                        {1.0, 0.0, 0.0},
                        {0.0, 1.0, 0.0},
                        {0.0, 0.0, 1.0}
                    });
            }

            try
            {
                // Cadオブジェクトデータファイル
                string basename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename);
                string cadObjFilename = basename + Constants.CadObjExt;

                if (File.Exists(cadObjFilename))
                {
                    // Cadオブジェクトデータを外部ファイルから読み込む
                    using (CSerializer fin = new CSerializer(cadObjFilename, true))
                    {
                        editCad2D.Serialize(fin);
                    }
                }
                else
                {
                    MessageBox.Show("CadObjデータファイルがありません");
                    return success;
                }

                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    string[] tokens;
                    const char delimiter = ',';
                    int cnt = 0;

                    // アプリケーションのバージョン番号
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("アプリケーションのバージョン情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "AppVersion")
                    {
                        MessageBox.Show("アプリケーションのバージョン情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    appVersion = tokens[1];

                    // ユーティリティ名
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("ユーティリティ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "UseUtility")
                    {
                        MessageBox.Show("ユーティリティ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    useUtility = tokens[1];
                    if (useUtility != CadLogic.UseUtility)
                    {
                        MessageBox.Show("ユーティリティ情報が本アプリケーションのバージョンのものと一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }

                    // ベースループID
                    //line = sr.ReadLine();
                    //if (line == null)
                    //{
                    //    MessageBox.Show("ベースループIDがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //    return success;
                    //}
                    //tokens = line.Split(delimiter);
                    //if (tokens.Length != 2 || tokens[0] != "BaseLoopId")
                    //{
                    //    MessageBox.Show("ベースループIDがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    //    return success;
                    //}
                    //baseLoopId = uint.Parse(tokens[1]);

                    // ループのリスト
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("ループ一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "LoopList")
                    {
                        MessageBox.Show("ループ一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    cnt = int.Parse(tokens[1]);
                    for (int i = 0; i < cnt; i++)
                    {
                        line = sr.ReadLine();
                        if (line == null)
                        {
                            MessageBox.Show("ループ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 4 || tokens[0] != "Loop")
                        {
                            MessageBox.Show("ループ情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        int countNo = int.Parse(tokens[1]);
                        uint loopId = uint.Parse(tokens[2]);
                        int mediaIndex = int.Parse(tokens[3]);
                        System.Diagnostics.Debug.Assert(countNo == i + 1);

                        CadLogic.Loop loop = new CadLogicBase.Loop(loopId, mediaIndex);
                        loopList.Add(loop);
                    }

                    // ポートのエッジコレクションのリスト
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("ポート一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "EdgeCollectionList")
                    {
                        MessageBox.Show("ポート一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    cnt = int.Parse(tokens[1]);
                    for (int i = 0; i < cnt; i++)
                    {
                        line = sr.ReadLine();
                        if (line == null)
                        {
                            MessageBox.Show("ポート情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        tokens = line.Split(delimiter);
                        if (tokens.Length < (4 + 1) || tokens[0] != "EdgeCollection")
                        {
                            MessageBox.Show("ポート情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        int countNo = int.Parse(tokens[1]);
                        int portNo = int.Parse(tokens[2]);
                        int eIdCnt = int.Parse(tokens[3]);
                        System.Diagnostics.Debug.Assert(countNo == i + 1);
                        System.Diagnostics.Debug.Assert(eIdCnt != 0 && eIdCnt == (tokens.Length - 4));

                        EdgeCollection edgeCollection = new EdgeCollection();
                        edgeCollection.No = portNo;
                        for (int tokenIndex = 4; tokenIndex < tokens.Length; tokenIndex++)
                        {
                            uint eId = uint.Parse(tokens[tokenIndex]);
                            if (!edgeCollection.ContainsEdgeId(eId))
                            {
                                bool ret = edgeCollection.AddEdgeId(eId, editCad2D);
                            }
                        }
                        edgeCollectionList.Add(edgeCollection);
                    }

                    // 入射ポート番号
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("入射ポート番号がありません");
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "IncidentPortNo")
                    {
                        MessageBox.Show("入射ポート番号がありません");
                        return success;
                    }
                    incidentPortNo = int.Parse(tokens[1]);

                    // 媒質情報
                    line = sr.ReadLine();
                    if (line == null)
                    {
                        MessageBox.Show("媒質情報がありません");
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Medias")
                    {
                        MessageBox.Show("媒質情報がありません");
                        return success;
                    }
                    cnt = int.Parse(tokens[1]);
                    for (int i = 0; i < cnt; i++)
                    {
                        line = sr.ReadLine();
                        if (line == null)
                        {
                            MessageBox.Show("媒質情報が不正です");
                            return success;
                        }
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 1 + 9 + 9)
                        {
                            MessageBox.Show("媒質情報が不正です");
                            return success;
                        }
                        int mediaIndex = int.Parse(tokens[0]);
                        System.Diagnostics.Debug.Assert(mediaIndex == i);
                        if (i >= medias.Length)
                        {
                            //読み飛ばす
                            continue;
                        }
                        double[,] p = new double[3, 3];
                        for (int m = 0; m < p.GetLength(0); m++)
                        {
                            for (int n = 0; n < p.GetLength(1); n++)
                            {
                                p[m, n] = double.Parse(tokens[1 + m * p.GetLength(1) + n]);
                            }
                        }
                            medias[i].SetP(p);

                        double[,] q = new double[3, 3];
                        for (int m = 0; m < q.GetLength(0); m++)
                        {
                            for (int n = 0; n < q.GetLength(1); n++)
                            {
                                q[m, n] = double.Parse(tokens[1 + 9 + m * q.GetLength(1) + n]);
                            }
                        }
                        medias[i].SetQ(q);
                    }
                }

                // 番号順に並び替え
                ((List<EdgeCollection>)edgeCollectionList).Sort();

                ////////////////////////////////////////////////////////////////////////
                // Cadオブジェクトの色をセットする
                // ループとその辺、頂点の色をセット
                foreach (CadLogic.Loop loop in loopList)
                {
                    uint id_l = loop.LoopId;
                    int mediaIndex = loop.MediaIndex;
                    MediaInfo media = medias[mediaIndex];
                    Color backColor = media.BackColor;
                    CadLogic.SetupColorOfCadObjectsForOneLoop(editCad2D, id_l, backColor);
                }
                // ポートの色をセットする
                CadLogic.SetupColorOfPortEdgeCollection(editCad2D, edgeCollectionList, incidentPortNo);

                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }

            return success;
        }
예제 #5
0
        /// <summary>
        /// Fem入力データファイルへ保存
        ///   I/FがCadの内部データ寄りになっているので、変更したいが後回し
        /// </summary>
        /// <param name="filename">ファイル名(*.fem)</param>
        /// <param name="nodeCnt">節点数</param>
        /// <param name="doubleCoords">節点座標リスト</param>
        /// <param name="elementCnt">要素数</param>
        /// <param name="elements">要素リスト</param>
        /// <param name="portCnt">ポート数</param>
        /// <param name="portList">ポートの節点番号リストのリスト</param>
        /// <param name="forceBCNodeNumbers">強制境界節点番号のリスト</param>
        /// <param name="incidentPortNo">入射ポート番号</param>
        /// <param name="medias">媒質情報リスト</param>
        /// <param name="firstWaveLength">計算開始波長</param>
        /// <param name="lastWaveLength">計算終了波長</param>
        /// <param name="calcCnt">計算周波数件数</param>
        /// <param name="wgStructureDv">導波路構造区分</param>
        /// <param name="waveModeDv">波のモード区分</param>
        /// <param name="lsEqnSolverDv">線形方程式解法区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        public static void SaveToFileFromCad
            (string filename,
            int nodeCnt, IList <double[]> doubleCoords,
            int elementCnt, IList <int[]> elements,
            int portCnt, IList <IList <int> > portList,
            int[] forceBCNodeNumbers,
            int incidentPortNo,
            MediaInfo[] medias,
            double firstWaveLength,
            double lastWaveLength,
            int calcCnt,
            FemSolver.WGStructureDV wgStructureDv,
            FemSolver.WaveModeDV waveModeDv,
            FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv,
            double waveguideWidthForEPlane)
        {
            //////////////////////////////////////////
            // ファイル出力
            //////////////////////////////////////////
            try
            {
                using (StreamWriter sw = new StreamWriter(filename))
                {
                    string line;

                    // 節点番号と座標の出力
                    line = string.Format("Nodes,{0}", nodeCnt);
                    sw.WriteLine(line);
                    for (int i = 0; i < doubleCoords.Count; i++)
                    {
                        double[] doubleCoord = doubleCoords[i];
                        int      nodeNumber  = i + 1;
                        line = string.Format("{0},{1},{2}", nodeNumber, doubleCoord[0], doubleCoord[1]);
                        sw.WriteLine(line);
                    }
                    // 要素番号と要素を構成する節点の全体節点番号の出力
                    line = string.Format("Elements,{0}", elementCnt);
                    sw.WriteLine(line);
                    foreach (int[] element in elements)
                    {
                        line = "";
                        foreach (int k in element)
                        {
                            line += string.Format("{0},", k);
                        }
                        line = line.Substring(0, line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                    // ポート境界条件節点
                    int portCounter = 0;
                    line = string.Format("Ports,{0}", portList.Count);
                    sw.WriteLine(line);
                    foreach (IList <int> nodes in portList)
                    {
                        line = string.Format("{0},{1}", ++portCounter, nodes.Count);
                        sw.WriteLine(line);
                        int portNodeNumber = 0;
                        foreach (int nodeNumber in nodes)
                        {
                            line = string.Format("{0},{1}", ++portNodeNumber, nodeNumber);
                            sw.WriteLine(line);
                        }
                    }
                    // 強制境界節点
                    line = string.Format("Force,{0}", forceBCNodeNumbers.Length);
                    sw.WriteLine(line);
                    foreach (int nodeNumber in forceBCNodeNumbers)
                    {
                        line = string.Format("{0}", nodeNumber);
                        sw.WriteLine(line);
                    }
                    // 入射ポート番号
                    line = string.Format("IncidentPortNo,{0}", incidentPortNo);
                    sw.WriteLine(line);
                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    // 媒質情報の個数
                    sw.WriteLine("Medias,{0}", medias.Length);
                    // 媒質情報の書き込み
                    for (int i = 0; i < medias.Length; i++)
                    {
                        MediaInfo media = medias[i];
                        line        = string.Format("{0},", i);
                        double[,] p = media.P;
                        for (int m = 0; m < p.GetLength(0); m++)
                        {
                            for (int n = 0; n < p.GetLength(1); n++)
                            {
                                line += string.Format("{0},", p[m, n]);
                            }
                        }
                        double[,] q = media.Q;
                        for (int m = 0; m < q.GetLength(0); m++)
                        {
                            for (int n = 0; n < q.GetLength(1); n++)
                            {
                                line += string.Format("{0},", q[m, n]);
                            }
                        }
                        line = line.Remove(line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                    // 計算対象周波数
                    sw.WriteLine("WaveLengthRange,{0},{1},{2}", firstWaveLength, lastWaveLength, calcCnt);
                    // 線形方程式解法区分
                    sw.WriteLine("LsEqnSolverDv,{0}", FemSolver.LinearSystemEqnSolverDVToStr(lsEqnSolverDv));
                    // 計算対象モード区分
                    sw.WriteLine("WaveModeDv,{0}", ((waveModeDv == FemSolver.WaveModeDV.TM) ? "TM" : "TE"));
                    // 導波路構造区分
                    sw.WriteLine("WGStructureDv,{0}", FemSolver.WGStructureDVToStr(wgStructureDv));
                    // 導波路幅(E面解析用)
                    sw.WriteLine("WaveguideWidthForEPlane,{0}", waveguideWidthForEPlane);
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }
        }
        /* 数値積分版
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="mat">マージされる全体行列</param>
        public static  void AddElementMat(double waveLength,
            Dictionary<int, int> toSorted,
            FemElement element,
            IList<FemNode> Nodes,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            FemSolver.WaveModeDv WaveModeDv,
            ref MyComplexMatrix mat)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            const int vertexCnt = Constants.QuadVertexCnt; //4;
            // 要素内節点数
            const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 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;
            if (WaveModeDv == FemSolver.WaveModeDv.TE)
            {
                media_P = media.P;
                media_Q = media.Q;
            }
            else if (WaveModeDv == FemSolver.WaveModeDv.TM)
            {
                media_P = media.Q;
                media_Q = media.P;
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
            // [p]は逆数をとる
            media_P = MyMatrixUtil.matrix_Inverse(media_P);

            // 節点座標(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];
                }
            }

            //// 四角形の辺の長さを求める
            //double[] le = new double[4];
            //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
            //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
            //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
            //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);

            // 要素節点座標( 局所r,s成分 )
            //        s
            //        |
            //    3+  6  +2
            //    |   |   |
            // ---7---+---5-->r
            //    |   |   |
            //    0+  4  +1
            //        |
            //
            double[][] n_pts =
                {
                    // r, s
                    new double[] {-1.0, -1.0},  //0
                    new double[] { 1.0, -1.0},  //1
                    new double[] { 1.0,  1.0},  //2
                    new double[] {-1.0,  1.0},  //3
                    new double[] {   0, -1.0},  //4
                    new double[] { 1.0,    0},  //5
                    new double[] {   0,  1.0},  //6
                    new double[] {-1.0,    0},  //7
                };

            // ガウスルジャンドルの積分公式
            double[][] g_pts = new double[5][]
                {
                    // ポイント(ξ: [-1 +1]区間)、重み
                    new double[] { -0.90617985, 0.23692689},
                    new double[] { -0.53846931, 0.47862867},
                    new double[] {0.0, 0.56888889},
                    new double[] {0.53846931, 0.47862867},
                    new double[] {0.90617985, 0.23692689}
                };

            // 要素剛性行列を作る
            double[,] emat = new Complex[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = 0.0;
                    double detjsum = 0; //check
                    foreach (double[] s_g_pt in g_pts)
                    {
                        foreach (double[] r_g_pt in g_pts)
                        {
                            // 積分点
                            double r = r_g_pt[0];
                            double s = s_g_pt[0];
                            // 重み(2次元)
                            double weight = r_g_pt[1] * s_g_pt[1];
                            // 形状関数
                            double[] N = new double[nno];
                            // 形状関数のr, s方向微分
                            double[] dNdr = new double[nno];
                            double[] dNds = new double[nno];
                            // 節点0~3 : 四角形の頂点
                            for (int i = 0; i < 4; i++)
                            {
                                // 節点の局所座標
                                double ri = n_pts[i][0];
                                double si = n_pts[i][1];
                                // 形状関数N
                                N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0);
                                // 形状関数のr方向微分
                                dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s);
                                // 形状関数のs方向微分
                                dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s);
                            }
                            // 節点4,6 : r方向辺上中点
                            foreach (int i in new int[]{ 4, 6})
                            {
                                // 節点の局所座標
                                double ri = n_pts[i][0];
                                double si = n_pts[i][1];
                                // 形状関数N
                                N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s);
                                // 形状関数のr方向微分
                                dNdr[i] = -1.0 * r * (1.0 + si * s);
                                // 形状関数のs方向微分
                                dNds[i] = 0.5 * si * (1.0 - r * r);
                            }
                            // 節点5,7 : s方向辺上中点
                            foreach (int i in new int[] { 5, 7 })
                            {
                                // 節点の局所座標
                                double ri = n_pts[i][0];
                                double si = n_pts[i][1];
                                // 形状関数N
                                N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s);
                                // 形状関数のr方向微分
                                dNdr[i] = 0.5 * ri * (1.0 - s * s);
                                // 形状関数のs方向微分
                                dNds[i] = -1.0 * s * (1.0 + ri * r);
                            }

                            // ヤコビアン行列
                            double j11;
                            double j12;
                            double j21;
                            double j22;
                            j11 = 0;
                            j12 = 0;
                            j21 = 0;
                            j22 = 0;

                            //for (int i = 0; i < vertexCnt; i++)
                            //{
                            //    // 頂点の座標の微分
                            //    // 座標の形状関数は一次四角形のものを使用する
                            //    // 節点の局所座標
                            //    double ri = n_pts[i][0];
                            //    double si = n_pts[i][1];
                            //    double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s);
                            //    double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si;
                            //    j11 += dNdr_1stOrder * pp[i][0];
                            //    j12 += dNdr_1stOrder * pp[i][1];
                            //    j21 += dNds_1stOrder * pp[i][0];
                            //    j22 += dNds_1stOrder * pp[i][1];
                            //}

                            for (int i = 0; i < nno; i++)
                            {
                                j11 += dNdr[i] * pp[i][0];
                                j12 += dNdr[i] * pp[i][1];
                                j21 += dNds[i] * pp[i][0];
                                j22 += dNds[i] * pp[i][1];
                            }
                            // ヤコビアン
                            double detj = j11 * j22 - j12 * j21;
                            detjsum += detj * weight;
                            //System.Diagnostics.Debug.WriteLine("det:{0}", detj);

                            // gradr[0] : gradrのx成分 grad[1] : gradrのy成分
                            // grads[0] : gradsのx成分 grads[1] : gradsのy成分
                            double[] gradr = new double[2];
                            double[] grads = new double[2];
                            gradr[0] =   j22 / detj;
                            gradr[1] = - j21 / detj;
                            grads[0] = - j12 / detj;
                            grads[1] =   j11 / detj;

                            // 形状関数のx, y方向微分
                            double[,] dNdX = new double[ndim, nno];
                            for (int i = 0; i < nno; i++)
                            {
                                for (int direction = 0; direction < ndim; direction++)
                                {
                                    dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction];
                                }
                            }

                            // 汎関数
                            double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno]
                                             - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno];
                            emat[ino, jno] += detj * weight * functional;
                        }
                    }
                    //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum);
                }
            }

            // 要素剛性行列にマージする
            for (int ino = 0; ino < nno; ino++)
            {
                int iNodeNumber = no_c[ino];
                if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                int inoGlobal = toSorted[iNodeNumber];
                for (int jno = 0; jno < nno; jno++)
                {
                    int jNodeNumber = no_c[jno];
                    if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
                    int jnoGlobal = toSorted[jNodeNumber];

                    mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                }
            }
        }
         */
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
            Dictionary<int, int> toSorted,
            FemElement element,
            IList<FemNode> Nodes,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            FemSolver.WGStructureDV WGStructureDv,
            FemSolver.WaveModeDV WaveModeDv,
            double waveguideWidthForEPlane,
            ref MyComplexMatrix mat,
            ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
            ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
            ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.QuadVertexCnt; //4;
            // 要素内節点数
            const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 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,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                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];
                }
            }

            // 四角形の辺の長さを求める
            double[] le = new double[4];
            le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
            le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
            le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
            le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);
            System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit);
            System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit);
            double lx = le[0];
            double ly = le[1];

            // 要素節点座標( 局所r,s成分 )
            //        s
            //        |
            //    3+  6  +2
            //    |   |   |
            // ---7---+---5-->r
            //    |   |   |
            //    0+  4  +1
            //        |
            //
            double[][] n_pts =
                {
                    // r, s
                    new double[] {-1.0, -1.0},  //0
                    new double[] { 1.0, -1.0},  //1
                    new double[] { 1.0,  1.0},  //2
                    new double[] {-1.0,  1.0},  //3
                    new double[] {   0, -1.0},  //4
                    new double[] { 1.0,    0},  //5
                    new double[] {   0,  1.0},  //6
                    new double[] {-1.0,    0},  //7
                };

            // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] Ni_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = 0.25 * ri * ri * si;
                Ni_a[i, 1] = 0.25 * ri * ri;
                Ni_a[i, 2] = 0.0;
                Ni_a[i, 3] = 0.25 * ri * si;
                Ni_a[i, 4] = 0.25 * ri * si * si;
                Ni_a[i, 5] = 0.25 * si * si;
                Ni_a[i, 6] = 0.0;
                Ni_a[i, 7] = -0.25;
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = -0.5 * si;
                Ni_a[i, 1] = -0.5;
                Ni_a[i, 2] = 0.0;
                Ni_a[i, 3] = 0.0;
                Ni_a[i, 4] = 0.0;
                Ni_a[i, 5] = 0.0;
                Ni_a[i, 6] = 0.5 * si;
                Ni_a[i, 7] = 0.5;
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = 0.0;
                Ni_a[i, 1] = 0.0;
                Ni_a[i, 2] = 0.5 * ri;
                Ni_a[i, 3] = 0.0;
                Ni_a[i, 4] = -0.5 * ri;
                Ni_a[i, 5] = -0.5;
                Ni_a[i, 6] = 0.0;
                Ni_a[i, 7] = 0.5;
            }

            // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] dNidr_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;  // r^2
                dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri;  // r
                dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si;  // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = 0.25 * ri * si * si;  // s^2
                dNidr_a[i, 6] = 0.25 * ri * si;  // s
                dNidr_a[i, 7] = 0.0;  //1
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;  // r^2
                dNidr_a[i, 2] = -1.0;  // r
                dNidr_a[i, 3] = -si;  // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = 0.0;  // s^2
                dNidr_a[i, 6] = 0.0;  // s
                dNidr_a[i, 7] = 0.0;  // 1
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;  // r^2
                dNidr_a[i, 2] = 0.0;  // r
                dNidr_a[i, 3] = 0.0;  // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = -0.5 * ri;  // s^2
                dNidr_a[i, 6] = 0.0;  // s
                dNidr_a[i, 7] = 0.5 * ri;  // 1
            }

            // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] dNids_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = 0.25 * ri * ri * si;  // r^2
                dNids_a[i, 2] = 0.25 * ri * si;  // r
                dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si;  // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;  // s^2
                dNids_a[i, 6] = 0.25 * 2.0 * si * si;  // s
                dNids_a[i, 7] = 0.0;  //1
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = -0.5 * si;  // r^2
                dNids_a[i, 2] = 0.0;  // r
                dNids_a[i, 3] = 0.0;  // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;  // s^2
                dNids_a[i, 6] = 0.0;  // s
                dNids_a[i, 7] = 0.5 * si;  //1
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = 0.0;  // r^2
                dNids_a[i, 2] = 0.0;  // r
                dNids_a[i, 3] = -ri;  // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;  // s^2
                dNids_a[i, 6] = -1.0;  // s
                dNids_a[i, 7] = 0.0;  //1
            }

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno];
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    integralN[ino, jno] = lx * ly / 4.0 *
                        (
                        // r^4s^2
                        4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3]
                                     + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7])
                        // 1
                        + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7]
                        );
                    integralDNDX[0, ino, jno] = ly / lx *
                        (
                        // r^4s^2
                        4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2]
                                     + dNidr_a[ino, 3] * dNidr_a[jno, 3]
                                     + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7])
                        // 1
                        + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7]
                        );
                    integralDNDX[1, ino, jno] = lx / ly *
                        (
                        // r^4s^2
                        4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2]
                                     + dNids_a[ino, 3] * dNids_a[jno, 3]
                                     + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7])
                        // 1
                        + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7]
                        );
                }
            }

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                         - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int jno = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
            Dictionary<int, int> toSorted,
            FemElement element,
            IList<FemNode> Nodes,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            FemSolver.WaveModeDV WaveModeDv,
            ref MyComplexMatrix mat,
            ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
            ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
            ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.QuadVertexCnt; //4;
            // 要素内節点数
            const int nno = Constants.QuadNodeCnt_FirstOrder; //4;  // 1次セレンディピティ
            // 座標次元数
            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;
            if (WaveModeDv == FemSolver.WaveModeDV.TE)
            {
                media_P = media.P;
                media_Q = media.Q;
            }
            else if (WaveModeDv == FemSolver.WaveModeDV.TM)
            {
                media_P = media.Q;
                media_Q = media.P;
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
            // [p]は逆数をとる
            media_P = MyMatrixUtil.matrix_Inverse(media_P);

            // 節点座標(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];
                }
            }

            // 四角形の辺の長さを求める
            double[] le = new double[4];
            le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
            le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
            le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
            le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);
            System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit);
            System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit);
            double lx = le[0];
            double ly = le[1];

            // 要素節点座標( 局所r,s成分 )
            //        s
            //        |
            //    3+  +  +2
            //    |   |   |
            // ---+---+---+-->r
            //    |   |   |
            //    0+  +  +1
            //        |
            //
            double[][] n_pts =
                {
                    // r, s
                    new double[] {-1.0, -1.0},  //0
                    new double[] { 1.0, -1.0},  //1
                    new double[] { 1.0,  1.0},  //2
                    new double[] {-1.0,  1.0},  //3
                };

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno]
                {
                    {
                        {  2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx),  -1.0 * ly /(6.0 * lx),  1.0 * ly /(6.0 * lx) },
                        { -2.0 * ly /(6.0 * lx),  2.0 * ly /(6.0 * lx),   1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx) },
                        { -1.0 * ly /(6.0 * lx),  1.0 * ly /(6.0 * lx),   2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx) },
                        {  1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx),  -2.0 * ly /(6.0 * lx),  2.0 * ly /(6.0 * lx) },
                    },
                    {
                        {  2.0 * lx /(6.0 * ly),  1.0 * lx /(6.0 * ly),  -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly) },
                        {  1.0 * lx /(6.0 * ly),  2.0 * lx /(6.0 * ly),  -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly) },
                        { -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly),   2.0 * lx /(6.0 * ly),  1.0 * lx /(6.0 * ly) },
                        { -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly),   1.0 * lx /(6.0 * ly),  2.0 * lx /(6.0 * ly) },
                    }
                };
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno]
                {
                    { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 },
                    { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 },
                    { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 },
                    { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0 },
                };

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                         - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int jno = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
        /// <summary>
        /// Ver1.2.0.0形式の図面ファイルから読み込み(Ver1.2.0.0→Ver1.3.0.0の変換あり)
        /// </summary>
        /// <param name="in_filename"></param>
        /// <param name="isBackupFile">バックアップファイル?</param>
        /// <param name="out_cad2d">格納先Cadオブジェクトのリファレンス</param>
        /// <param name="out_LoopList">ループ情報のリスト</param>
        /// <param name="out_edgeCollectionList">ポートのエッジコレクションのリスト</param>
        /// <param name="out_incidentPortNo">入射ポート番号</param>
        /// <param name="out_medias">媒質情報リストのリファレンス(比誘電率、比透磁率だけセットされる)</param>
        /// <returns></returns>
        public static bool LoadFromFile_Ver_1_2(
            string in_filename,
            out bool isBackupFile,
            ref CCadObj2D out_cad2d,
            ref IList<CadLogic.Loop> out_LoopList,
            ref IList<EdgeCollection> out_edgeCollectionList,
            out int out_incidentPortNo,
            ref MediaInfo[] out_medias
            )
        {
            bool success = false;

            ////////////////////////////////////////////////////////
            // 出力データの初期化

            // バックアップファイル?
            isBackupFile = false;
            // 図面のクリア
            out_cad2d.Clear();
            // ループ情報リストの初期化
            out_LoopList.Clear();
            // 入射ポートの初期化
            out_incidentPortNo = 1;
            // ポートのエッジコレクションのリストを初期化
            out_edgeCollectionList.Clear();
            // 媒質の比誘電率、比透磁率の逆数の初期化
            foreach (MediaInfo media in out_medias)
            {
                // 比透磁率の逆数
                media.SetP(new double[,]
                    {
                        {1.0, 0.0, 0.0},
                        {0.0, 1.0, 0.0},
                        {0.0, 0.0, 1.0}
                    });
                // 比誘電率
                media.SetQ(new double[,]
                    {
                        {1.0, 0.0, 0.0},
                        {0.0, 1.0, 0.0},
                        {0.0, 0.0, 1.0}
                    });
            }

            ////////////////////////////////////////////////////////
            // バックアップファイルの作成
            string filename = "";
            if (in_filename.IndexOf(Ver1_2_Backup_Suffix) >= 0)
            {
                isBackupFile = true;
                MessageBox.Show("このファイルはバックアップファイルです。このファイルを上書き保存しないようご注意ください。",
                    "旧データ形式からの変換", MessageBoxButtons.OK, MessageBoxIcon.Information);

                // 入力ファイル名をそのまま利用
                filename = in_filename;
            }
            else
            {
                // 指定されたCadファイルとその入出力データをリネームする
                string basename = Path.GetDirectoryName(in_filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(in_filename);
                string inputfilename = basename + Constants.FemInputExt;
                string outputfilename = basename + Constants.FemOutputExt;
                string indexfilename = outputfilename + Constants.FemOutputIndexExt;
                //ReadOnlyにするのを止める
                ////FEM入出力データは移動しない(Ver1.2のアプリで再計算すると落ちるので止めます:データ削除でtry catchしていないのが原因だと思われる)
                //string[] tagtfilenames = { in_filename };
                // 全ファイルを移動する
                string[] tagtfilenames = { in_filename, inputfilename, outputfilename, indexfilename };
                foreach (string tagtfilename in tagtfilenames)
                {
                    string fname = Path.GetFileNameWithoutExtension(tagtfilename);
                    string ext = Path.GetExtension(tagtfilename);
                    if (fname != Path.GetFileNameWithoutExtension(fname)) // .out.idxの場合、ファイル名に.outまで入るので小細工する
                    {
                        string ext2 = Path.GetExtension(fname);
                        string fname2 = Path.GetFileNameWithoutExtension(fname);
                        ext = ext2 + ext;
                        fname = fname2;
                    }
                    string tagtbasename = Path.GetDirectoryName(tagtfilename) + Path.DirectorySeparatorChar + fname;
                    string backupFilename = tagtbasename + Ver1_2_Backup_Suffix + ext;
                    if (File.Exists(tagtfilename))
                    {
                        if (!File.Exists(backupFilename))
                        {
                            // 対象ファイルが存在し、かつバックアップファイルが存在しないとき
                            //バックアップファイルの作成
                            //MyUtilLib.MyUtil.MoveFileWithReadOnly(tagtfilename, backupFilename);
                            try
                            {
                                // そのまま移動(更新時刻等の再設定が面倒なのでコピーでなく移動する)
                                File.Move(tagtfilename, backupFilename);

                                // コピーとして戻す
                                File.Copy(backupFilename, tagtfilename);
                            }
                            catch (Exception exception)
                            {
                                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                                MessageBox.Show(exception.Message);
                            }
                        }
                        else
                        {
                            // 対象ファイルは存在し、バックアップが存在するとき
                            // バックアップを作成できない
                            MessageBox.Show("すでに別のバックアップファイルがあるので、バックアップを作成できません。このファイルを上書き保存しないようご注意ください。",
                                "旧データ形式からの変換", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        }
                    }
                }

                // バックアップファイルに移動したので、バックアップファイルから読み込む
                filename = basename + Ver1_2_Backup_Suffix + Constants.CadExt;
            }

            // Ver1.2.0.0形式のファイルの読み込み
            Size maxDiv;
            bool[,] areaSelection;
            int[,] areaToMediaIndex;
            IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList_Ver_1_2;
            bool[,] yBoundarySelection;
            bool[,] xBoundarySelection;
            int incidentPortNo_Ver_1_2;
            MediaInfo[] medias_Ver_1_2;

            bool loadSuccess = false;
            loadSuccess = CadDatFile_Ver_1_2.LoadFromFile_Ver_1_2(
                filename, out maxDiv, out areaSelection, out areaToMediaIndex,
                out edgeList_Ver_1_2, out yBoundarySelection, out xBoundarySelection,
                out incidentPortNo_Ver_1_2, out medias_Ver_1_2
                );
            if (!loadSuccess)
            {
                return success;
            }

            /////////////////////////////////////////////////////////////////////////////////
            // 本バージョンへのデータ変換
            /////////////////////////////////////////////////////////////////////////////////

            /////////////////////////////////////////////////////////////////////////////////
            // そのまま使用できる情報
            out_incidentPortNo = incidentPortNo_Ver_1_2;

            /////////////////////////////////////////////////////////////////////////////////
            // 変換が必要な情報
            // Medias --> インデックスを1加算
            // AreaToMediaIndex --> インデックスを1加算
            // AreaSelection, AreaToMediaIndex  --> loop
            // EdgeVer1_2 --> EdgeCollection

            //////////////////////////
            // 媒質情報は、Ver1.2→Ver1.3で媒質インデックスが1つずれる(導体が追加されたため)
            for (int oldMediaIndex = 0; oldMediaIndex < medias_Ver_1_2.Length; oldMediaIndex++)
            {
                if (oldMediaIndex + 1 < out_medias.Length)
                {
                    int mediaIndex = oldMediaIndex + 1;  //インデックスを1加算
                    out_medias[mediaIndex].SetP(medias_Ver_1_2[oldMediaIndex].P);
                    out_medias[mediaIndex].SetQ(medias_Ver_1_2[oldMediaIndex].Q);
                }
            }
            for (int y = 0; y < maxDiv.Height; y++)
            {
                for (int x = 0; x < maxDiv.Width; x++)
                {
                    areaToMediaIndex[y, x]++; //インデックスを1加算
                }
            }

            ///////////////////////////
            // 変換準備
            /*
            // 領域選択情報を媒質情報にマージする(非選択の場合もインデックスは0が設定されているがこれを-1に変更)
            for (int y = 0; y < maxDiv.Height; y++)
            {
                for (int x = 0; x < maxDiv.Width; x++)
                {
                    if (!areaSelection[y, x])
                    {
                        // エリアが選択されていない
                        areaToMediaIndex[y, x] = -1; // 未指定に設定する
                    }
                }
            }
             */
            // 非選択部分は導体媒質を設定する
            for (int y = 0; y < maxDiv.Height; y++)
            {
                for (int x = 0; x < maxDiv.Width; x++)
                {
                    if (!areaSelection[y, x])
                    {
                        // エリアが選択されていない
                        areaToMediaIndex[y, x] = CadLogic.MetalMediaIndex; // 導体を指定する
                    }
                }
            }

            // ループの取得
            IList<DelFEM4NetCom.Pair<int, IList<Point>>> loopList = getLoopList(maxDiv, areaToMediaIndex);

            // ループをエッジに変換
            IList<IList<CadDatFile_Ver_1_2.Edge_Ver_1_2>> loopEdgeListList = getLoopEdgeList(loopList);

            // ポート境界のエッジリスト分、エッジコレクションを先に作成する(複数のループにまたがる場合があるため)
            foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 portEdge in edgeList_Ver_1_2)
            {
                EdgeCollection edgeCollection = new EdgeCollection();
                edgeCollection.No = portEdge.No;
                out_edgeCollectionList.Add(edgeCollection);
            }

            var newLoopEdgeListList = new List<IList<CadDatFile_Ver_1_2.Edge_Ver_1_2>>();
            // ループ数分チェック
            foreach (IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> loopEdgeList in loopEdgeListList)
            {
                // 1つのループ
                var newLoopEdgeList = new List<CadDatFile_Ver_1_2.Edge_Ver_1_2>();
                foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 loopEdge in loopEdgeList)
                {
                    // 1つのエッジ

                    // ポート境界を含んでいれば分解する
                    // 頂点リスト
                    IList<Point> vertexPts = new List<Point>();
                    // 頂点にポートが対応していれば、ポート番号を格納
                    // 既定値は -1
                    IList<int> toPortNo = new List<int>();

                    // エッジの最初の頂点を追加
                    vertexPts.Add(loopEdge.Points[0]);
                    toPortNo.Add(-1);

                    // ポート境界のエッジリストを走査
                    foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 portEdge in edgeList_Ver_1_2)
                    {
                        // contains?
                        Point minPt;
                        Point maxPt;
                        if (loopEdge.Contains(portEdge, out minPt, out maxPt))
                        {
                            // ポート境界が含まれていた
                            // ポート境界の頂点を追加
                            //vertexPts.Add(portEdge.Points[0]); // 始点
                            //vertexPts.Add(portEdge.Points[1]); // 終点
                            vertexPts.Add(minPt); // 始点
                            vertexPts.Add(maxPt); // 終点
                            // ポート番号を頂点にあわせて追加
                            toPortNo.Add(portEdge.No);
                            toPortNo.Add(portEdge.No);
                        }
                        else if (loopEdge.GetSimpleSwap().Contains(portEdge, out minPt, out maxPt))
                        {
                            // ポート境界の頂点を追加
                            //vertexPts.Add(portEdge.Points[1]);  // swap 終点
                            //vertexPts.Add(portEdge.Points[0]);  // swap 始点
                            vertexPts.Add(maxPt);  // swap 終点
                            vertexPts.Add(minPt);  // swap 始点
                            // ポート番号を頂点にあわせて追加
                            toPortNo.Add(portEdge.No);
                            toPortNo.Add(portEdge.No);
                        }
                    }
                    // 最後の頂点を追加
                    vertexPts.Add(loopEdge.Points[1]);
                    toPortNo.Add(-1);

                    // 頂点を元にしてエッジを再構築
                    for (int ino = 0; ino < vertexPts.Count - 1; ino++)
                    {
                        CadDatFile_Ver_1_2.Edge_Ver_1_2 work = new CadDatFile_Ver_1_2.Edge_Ver_1_2();
                        // ポート番号があれば格納
                        if (toPortNo[ino] != -1)
                        {
                            work.No = toPortNo[ino];
                        }
                        else
                        {
                            work.No = 0;
                        }
                        // 辺の始点、終点
                        work.Points[0] = vertexPts[ino];
                        work.Points[1] = vertexPts[ino + 1];
                        // Deltaの計算&格納
                        Point p1 = work.Points[0];
                        Point p2 = work.Points[1];
                        work.Delta = CadDatFile_Ver_1_2.Edge_Ver_1_2.CalcDelta(p1, p2);

                        // 空チェック
                        if (work.IsEmpty())
                        {
                            // 空の場合追加しない
                        }
                        else
                        {
                            // 追加
                            newLoopEdgeList.Add(work);
                        }
                    }
                    // 1つのエッジ再構築終了

                } // エッジ

                // 1つのループのエッジリストをリストに追加
                newLoopEdgeListList.Add(newLoopEdgeList);
            } // ループ

            ///////////////////////////////////////////////////////////////////
            // version1.3.0.0のデータ構造に反映する
            bool errorCCadObj = false;

            // ループ領域を作成
            //uint baseLoopId = 0;
            for (int loopIndex = 0; loopIndex < loopList.Count; loopIndex++)
            {
                System.Diagnostics.Debug.WriteLine("loopIndex: {0}", loopIndex);
                DelFEM4NetCom.Pair<int, IList<Point>> loop = loopList[loopIndex];
                // 媒質インデックス
                int mediaIndex = loop.First;
                // ループを構成する頂点
                IList<Point> pts = loop.Second;

                IList<CVector2D> pps = new List<CVector2D>();
                /*
                foreach (Point pt in pts)
                {
                    double xx = pt.X - maxDiv.Width * 0.5;
                    double yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                    pps.Add(new CVector2D(xx, yy));
                }
                 */
                // このループのエッジリストを取得する
                IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> loopEdgeList = newLoopEdgeListList[loopIndex];

                // エッジのリストインデックス→エッジコレクションのリストのインデックス変換マップ
                IList<int> loopEdgeIndexToEdgeCollectionIndex = new List<int>();

                // OpenGlの頂点リストを作成
                for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++)
                {
                    // エッジ
                    CadDatFile_Ver_1_2.Edge_Ver_1_2 work = loopEdgeList[loopEdgeIndex];

                    ////////////////////////////////
                    // OpenGlの頂点作成
                    double xx;
                    double yy;
                    Point pt;
                    pt = work.Points[0]; //始点を追加していく
                    xx = pt.X - maxDiv.Width * 0.5;
                    yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                    pps.Add(new CVector2D(xx, yy));
                    System.Diagnostics.Debug.WriteLine("pps[{0}]: {1}, {2}", pps.Count - 1, pps[pps.Count - 1].x, pps[pps.Count - 1].y);

                    // check: 終点は次のエッジの始点のはず
                    if (loopEdgeIndex < loopEdgeList.Count - 1)
                    {
                        CadDatFile_Ver_1_2.Edge_Ver_1_2 next = loopEdgeList[loopEdgeIndex + 1];
                        System.Diagnostics.Debug.Assert(work.Points[1].Equals(next.Points[0]));
                    }

                    /* ループの最後の点は追加しない
                    if (loopEdgeIndex == loopEdgeList.Count - 1)
                    {
                        // 最後だけ終点を追加
                        pt = work.Points[1];
                        xx = pt.X - maxDiv.Width * 0.5;
                        yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                        pps.Add(new CVector2D(xx, yy));
                    }
                    */

                    int edgeCollectionIndex = -1;
                    if (work.No != 0)
                    {
                        ////////////////////////////////////////////////////////
                        // ポート情報がある場合
                        // check
                        {
                            EdgeCollection edgeCollection = out_edgeCollectionList[work.No - 1];
                            System.Diagnostics.Debug.Assert(work.No == edgeCollection.No);
                        }
                        // エッジコレクションリストのインデックスをセット
                        edgeCollectionIndex = work.No - 1;
                    }
                    // エッジのリストインデックス→エッジコレクションのリストのインデックス変換マップ(ポートがない場合も-1で追加する)
                    loopEdgeIndexToEdgeCollectionIndex.Add(edgeCollectionIndex);
                } // loopEdgeIndex

                uint id_l = 0;
                // 多角形でループを作成するのを止める
                //uint id_l = out_cad2d.AddPolygon(pps, baseLoopId).id_l_add;
                // 自力でループ作成
                System.Diagnostics.Debug.WriteLine("makeLoop: loopIndex: {0}", loopIndex);
                id_l = CadLogic.makeLoop(out_cad2d, pps, out_LoopList, false);
                if (id_l == 0)
                {
                    // 領域分割でできた領域は、現状取り込みを実装していません。
                    MessageBox.Show("領域の追加に失敗しました。");
                    errorCCadObj = true;
                }
                else
                {
                    //////////////////////////////////////////////////////////////////////
                    // 辺と頂点を取得
                    IList<uint> vIdList = null;
                    IList<uint> eIdList = null;
                    CadLogic.GetEdgeVertexListOfLoop(out_cad2d, id_l, out vIdList, out eIdList);
                    // 元々の辺のインデックスに対して生成された辺のIDのリストを要素とするリスト
                    IList<IList<uint>> generatedEIdsList = new List<IList<uint>>();
                    // ループ作成時に辺が分割された場合も考慮
                    int eIdIndexOfs = 0;
                    System.Diagnostics.Debug.WriteLine("pps[0]: {0},{1}", pps[0].x, pps[0].y);
                    {
                        Edge_Ver_1_2 loopEdge0 = loopEdgeList[0];
                        CVector2D loopEdge0_pp_v1;
                        CVector2D loopEdge0_pp_v2;
                        {
                            double xx;
                            double yy;
                            Point pt;
                            pt = loopEdge0.Points[0];
                            xx = pt.X - maxDiv.Width * 0.5;
                            yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                            loopEdge0_pp_v1 = new CVector2D(xx, yy);
                            pt = loopEdge0.Points[1];
                            xx = pt.X - maxDiv.Width * 0.5;
                            yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                            loopEdge0_pp_v2 = new CVector2D(xx, yy);
                        }
                        System.Diagnostics.Debug.WriteLine("loopEdge0_pp_v1: {0},{1} loopEdge0_pp_v2: {2},{3}", loopEdge0_pp_v1.x, loopEdge0_pp_v1.y, loopEdge0_pp_v2.x, loopEdge0_pp_v2.y);
                        for (int eIdIndexSearch = 0; eIdIndexSearch < eIdList.Count; eIdIndexSearch++)
                        {
                            uint id_e = eIdList[eIdIndexSearch];
                            bool isIncluding = CadLogic.isEdgeIncludingEdge(out_cad2d, loopEdge0_pp_v1, loopEdge0_pp_v2, id_e);
                            if (isIncluding)
                            {
                                eIdIndexOfs = eIdIndexSearch;
                                break;
                            }
                        }
                    }
                    System.Diagnostics.Debug.WriteLine("eIdIndexOfs:{0}", eIdIndexOfs);

                    for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++)
                    {
                        IList<uint> generatedEIds = new List<uint>();
                        Edge_Ver_1_2 loopEdge = loopEdgeList[loopEdgeIndex];
                        CVector2D loopEdge_pp_v1;
                        CVector2D loopEdge_pp_v2;
                        {
                            double xx;
                            double yy;
                            Point pt;
                            pt = loopEdge.Points[0];
                            xx = pt.X - maxDiv.Width * 0.5;
                            yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                            loopEdge_pp_v1 = new CVector2D(xx, yy);
                            pt = loopEdge.Points[1];
                            xx = pt.X - maxDiv.Width * 0.5;
                            yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5;
                            loopEdge_pp_v2 = new CVector2D(xx, yy);
                        }
                        System.Diagnostics.Debug.WriteLine("  loopEdgeIndex:{0}", loopEdgeIndex);
                        System.Diagnostics.Debug.WriteLine("    loopEdge_pp_v1: {0},{1} loopEdge0_pp_v2: {2},{3}", loopEdge_pp_v1.x, loopEdge_pp_v1.y, loopEdge_pp_v2.x, loopEdge_pp_v2.y);
                        for (int eIdIndex = 0; eIdIndex < eIdList.Count; eIdIndex++)
                        {
                            uint id_e = eIdList[(eIdIndex + eIdIndexOfs) % eIdList.Count]; // 1つずらして取得
                            //System.Diagnostics.Debug.WriteLine("            {0} id_e:{1}", (eIdIndex + eIdIndexOfs) % eIdList.Count, id_e);
                            bool isIncluding = CadLogic.isEdgeIncludingEdge(out_cad2d, loopEdge_pp_v1, loopEdge_pp_v2, id_e);
                            if (!isIncluding)
                            {
                                continue;
                            }
                            generatedEIds.Add(id_e);
                            // check
                            {
                                uint id_v1 = 0;
                                uint id_v2 = 0;
                                CadLogic.getVertexIdsOfEdgeId(out_cad2d, id_e, out id_v1, out id_v2);
                                CVector2D pp_v1 = out_cad2d.GetVertexCoord(id_v1);
                                CVector2D pp_v2 = out_cad2d.GetVertexCoord(id_v2);
                                System.Diagnostics.Debug.WriteLine("    eId: {0}, pp_v1: {1},{2} pp_v2: {3},{4}", id_e, pp_v1.x, pp_v1.y, pp_v2.x, pp_v2.y);
                            }
                        }
                        generatedEIdsList.Add(generatedEIds);
                    }

                    ///////////////////////////////////////////////////////////////////////
                    // エッジコレクションにポート境界に対応する辺のIDをセットする
                    //IList<EdgeCollection> workEdgeCollectionList = new List<EdgeCollection>();  // ここで辺のIDをセットしたコレクションを辺の色付けのために一時保管する
                    for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++)
                    {
                        int edgeCollectionIndex = loopEdgeIndexToEdgeCollectionIndex[loopEdgeIndex];
                        if (edgeCollectionIndex != -1)
                        {
                            //
                            EdgeCollection edgeCollection = out_edgeCollectionList[edgeCollectionIndex];
                            IList<uint> generatedEIds = generatedEIdsList[loopEdgeIndex];
                            foreach (uint id_e in generatedEIds)
                            {
                                // 辺のIDをエッジコレクションにセット
                                // 辺の連続性はここではチェックしない(ばらばらで追加されるので)
                                bool chkFlg = false;
                                if (!edgeCollection.ContainsEdgeId(id_e))
                                {
                                    bool ret = edgeCollection.AddEdgeId(id_e, out_cad2d, chkFlg);
                                }
                            }

                            // 一時保管
                            //workEdgeCollectionList.Add(edgeCollection);
                        }
                    }
                    ////////////////////////////////////////////////////////////////////////
                    // 最初のループならばそのIdを記録する
                    //if (baseLoopId == 0)
                    //{
                    //    baseLoopId = id_l;
                    //}
                    // ループの情報を追加する
                    out_LoopList.Add(new CadLogic.Loop(id_l, mediaIndex));

                    // まだ処理が完全でないので下記は処理しない
                    // ループの内側にあるループを子ループに設定する
                    //CadLogic.reconstructLoopsInsideLoopAsChild(out_cad2d, id_l, ref out_LoopList, ref out_edgeCollectionList, out_medias, ref out_incidentPortNo);

                    ////////////////////////////////////////////////////////////////////////
                    // Cadオブジェクトの色をセットする
                    // ループとその辺、頂点の色をセット
                    MediaInfo media = out_medias[mediaIndex];
                    Color backColor = media.BackColor;
                    CadLogic.SetupColorOfCadObjectsForOneLoop(out_cad2d, id_l, backColor);
                    // ポートの色をセットする
                    //CadLogic.SetupColorOfPortEdgeCollection(out_cad2d, workEdgeCollectionList, incidentPortNo_Ver_1_2);
                } // if id_l != 0
            } // loopIndex

            // 番号順に並び替え
            ((List<EdgeCollection>)out_edgeCollectionList).Sort();
            // エッジコレクションの辺IDリストをソートする
            foreach (EdgeCollection workEdgeCollection in out_edgeCollectionList)
            {
                bool ret = workEdgeCollection.SortEdgeIds(out_cad2d);
            }

            // ポートの色をセットする
            CadLogic.SetupColorOfPortEdgeCollection(out_cad2d, out_edgeCollectionList, out_incidentPortNo);

            /////////////////////////////////////////////
            // 外側の導体媒質ループ削除処理
            //
            // 外側の導体媒質ループを取得する
            IList<CadLogic.Loop> delLoopList = new List<CadLogic.Loop>();
            foreach (CadLogic.Loop loop in out_LoopList)
            {
                if (loop.MediaIndex == CadLogic.MetalMediaIndex) // 導体の場合のみ実行
                {
                    // 外側の判定 --->他のループと共有していない辺が存在する
                    IList<uint> vIdList = null;
                    IList<uint> eIdList = null;
                    CadLogic.GetEdgeVertexListOfLoop(out_cad2d, loop.LoopId, out vIdList, out eIdList);

                    bool notSharedEdgeExists = false;
                    foreach (uint eId in eIdList)
                    {
                        if (CadLogic.isEdgeSharedByLoops(out_cad2d, eId))
                        {
                            // 辺を2つのループで共有している
                        }
                        else
                        {
                            // 辺を共有していない
                            notSharedEdgeExists = true;
                            break;
                        }
                    }
                    if (notSharedEdgeExists)
                    {
                        delLoopList.Add(loop);
                    }
                }
            }
            // 外側の導体媒質ループを削除
            foreach (CadLogic.Loop deltarget in delLoopList)
            {
                CadLogic.delLoop(out_cad2d, deltarget.LoopId, ref out_LoopList, ref out_edgeCollectionList, out_medias, ref out_incidentPortNo);
            }

            if (errorCCadObj)
            {
                success = false;
            }
            else
            {
                success = true;
            }
            return success;
        }
        /// <summary>
        /// Ver1.2.0.0形式のCadファイルフォーマットで図面情報を読み込む
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="maxDiv"></param>
        /// <param name="areaSelection"></param>
        /// <param name="areaToMediaIndex"></param>
        /// <param name="edgeList"></param>
        /// <param name="yBoundarySelection">2次的な情報(edgeListから生成される)</param>
        /// <param name="xBoundarySelection">2次的な情報(edgeListから生成される)</param>
        /// <param name="incidentPortNo"></param>
        /// <param name="medias"></param>
        /// <returns></returns>
        public static bool LoadFromFile_Ver_1_2(
            string filename,
            out Size maxDiv, out bool[,] areaSelection, out int[,] areaToMediaIndex,
            out IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList, out bool[,] yBoundarySelection, out bool[,] xBoundarySelection,
            out int incidentPortNo,
            out MediaInfo[] medias
            )
        {
            bool success = false;

            // ver1.2.0.0の設定値
            int maxMediaCount = 3;
            maxDiv = new Size(30, 30);

            // 初期化
            areaSelection = new bool[maxDiv.Width, maxDiv.Height];
            areaToMediaIndex = new int[maxDiv.Width, maxDiv.Height];
            for (int y = 0; y < maxDiv.Height; y++)
            {
                for (int x = 0; x < maxDiv.Width; x++)
                {
                    areaSelection[y, x] = false;
                    areaToMediaIndex[y, x] = 0;
                }
            }
            edgeList = new List<CadDatFile_Ver_1_2.Edge_Ver_1_2>();
            yBoundarySelection = new bool[maxDiv.Height, maxDiv.Width + 1];
            xBoundarySelection = new bool[maxDiv.Height + 1, maxDiv.Width];
            for (int x = 0; x < maxDiv.Width + 1; x++)
            {
                for (int y = 0; y < maxDiv.Height; y++)
                {
                    yBoundarySelection[y, x] = false;
                }
            }
            for (int y = 0; y < maxDiv.Height + 1; y++)
            {
                for (int x = 0; x < maxDiv.Width; x++)
                {
                    xBoundarySelection[y, x] = false;
                }
            }
            incidentPortNo = 1;
            medias = new MediaInfo[maxMediaCount];
            for (int i = 0; i < medias.Length; i++)
            {
                MediaInfo media = new MediaInfo();
                media.BackColor = CadLogic.MediaBackColors[i];
                medias[i] = media;
            }

            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    string line;
                    string[] tokens;
                    const char delimiter = ',';
                    int cnt = 0;

                    // 領域選択
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens[0] != "AreaSelection")
                    {
                        MessageBox.Show("領域選択情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    cnt = int.Parse(tokens[1]);
                    for (int i = 0; i < cnt; i++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 && tokens.Length != 3)  // ver1.1.0.0で媒質インデックス追加
                        {
                            MessageBox.Show("領域選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        int x = int.Parse(tokens[0]);
                        int y = int.Parse(tokens[1]);
                        int mediaIndex = 0;//CadLogic.DefMediaIndex;
                        if (tokens.Length == 3)
                        {
                            mediaIndex = int.Parse(tokens[2]);
                        }
                        if ((x >= 0 && x < maxDiv.Width) && (y >= 0 && y < maxDiv.Height))
                        {
                            areaSelection[y, x] = true;
                        }
                        else
                        {
                            MessageBox.Show("領域選択座標値が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        // ver1.1.0.0で追加
                        areaToMediaIndex[y, x] = mediaIndex;
                    }

                    // ポート境界
                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens[0] != "EdgeList")
                    {
                        MessageBox.Show("境界選択情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return success;
                    }
                    cnt = int.Parse(tokens[1]);
                    for (int i = 0; i < cnt; i++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 5)
                        {
                            MessageBox.Show("境界選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        int edgeNo = int.Parse(tokens[0]);
                        Point[] p = new Point[2];
                        for (int k = 0; k < p.Length; k++)
                        {
                            p[k] = new Point();
                            p[k].X = int.Parse(tokens[1 + k * 2]);
                            p[k].Y = int.Parse(tokens[1 + k * 2 + 1]);

                        }
                        Size delta = new Size(0, 0);
                        if (p[0].X == p[1].X)
                        {
                            // Y方向境界
                            delta = new Size(0, 1);
                        }
                        else if (p[0].Y == p[1].Y)
                        {
                            // X方向境界
                            delta = new Size(1, 0);
                        }
                        else
                        {
                            MessageBox.Show("境界選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return success;
                        }
                        CadDatFile_Ver_1_2.Edge_Ver_1_2 edge = new CadDatFile_Ver_1_2.Edge_Ver_1_2();
                        edge.Delta = delta;
                        edge.No = edgeNo;
                        edge.Points[0] = p[0];
                        edge.Points[1] = p[1];
                        edgeList.Add(edge);
                    }
                    // 2次的な情報(edgeListから生成される)
                    foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 edge in edgeList)
                    {
                        if (edge.Delta.Width == 0)
                        {
                            // Y方向境界
                            int x = edge.Points[0].X;
                            int sty = edge.Points[0].Y;
                            int edy = edge.Points[1].Y;
                            for (int y = sty; y < edy; y++)
                            {
                                yBoundarySelection[y, x] = true;
                            }
                        }
                        else if (edge.Delta.Height == 0)
                        {
                            // X方向境界
                            int y = edge.Points[0].Y;
                            int stx = edge.Points[0].X;
                            int edx = edge.Points[1].X;
                            for (int x = stx; x < edx; x++)
                            {
                                xBoundarySelection[y, x] = true;
                            }
                        }
                        else
                        {
                            MessageBox.Show("Not implemented");
                        }
                    }

                    line = sr.ReadLine();
                    if (line.Length == 0)
                    {
                        MessageBox.Show("入射ポート番号がありません");
                        return success;
                    }
                    tokens = line.Split(delimiter);
                    if (tokens[0] != "IncidentPortNo")
                    {
                        MessageBox.Show("入射ポート番号がありません");
                        return success;
                    }
                    incidentPortNo = int.Parse(tokens[1]);

                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                        // 媒質情報なし
                        // ver1.0.0.0
                    }
                    else
                    {
                        // 媒質情報?
                        // ver1.1.0.0
                        tokens = line.Split(delimiter);
                        if (tokens[0] != "Medias")
                        {
                            MessageBox.Show("媒質情報がありません");
                            return success;
                        }
                        cnt = int.Parse(tokens[1]);
                        if (cnt > maxMediaCount)
                        {
                            MessageBox.Show("媒質情報の個数が不正です");
                            return success;
                        }
                        for (int i = 0; i < cnt; i++)
                        {
                            line = sr.ReadLine();
                            if (line.Length == 0)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return success;
                            }
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1 + 9 + 9)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return success;
                            }
                            int mediaIndex = int.Parse(tokens[0]);
                            System.Diagnostics.Debug.Assert(mediaIndex == i);

                            double[,] p = new double[3, 3];
                            for (int m = 0; m < p.GetLength(0); m++)
                            {
                                for (int n = 0; n < p.GetLength(1); n++)
                                {
                                    p[m, n] = double.Parse(tokens[1 + m * p.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetP(p);

                            double[,] q = new double[3, 3];
                            for (int m = 0; m < q.GetLength(0); m++)
                            {
                                for (int n = 0; n < q.GetLength(1); n++)
                                {
                                    q[m, n] = double.Parse(tokens[1 + 9 + m * q.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetQ(q);
                        }
                    }
                }
                success = true;
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }

            return success;
        }
        /// <summary>
        /// Fem入力データファイルへ保存
        ///   I/FがCadの内部データ寄りになっているので、変更したいが後回し
        /// </summary>
        /// <param name="filename">ファイル名(*.fem)</param>
        /// <param name="nodeCnt">節点数</param>
        /// <param name="doubleCoords">節点座標リスト</param>
        /// <param name="elementCnt">要素数</param>
        /// <param name="elements">要素リスト</param>
        /// <param name="portCnt">ポート数</param>
        /// <param name="portList">ポートの節点番号リストのリスト</param>
        /// <param name="forceBCNodeNumbers">強制境界節点番号のリスト</param>
        /// <param name="incidentPortNo">入射ポート番号</param>
        /// <param name="medias">媒質情報リスト</param>
        /// <param name="firstWaveLength">計算開始波長</param>
        /// <param name="lastWaveLength">計算終了波長</param>
        /// <param name="calcCnt">計算周波数件数</param>
        /// <param name="lsEqnSolverDv">線形方程式解法区分</param>
        public static void SaveToFileFromCad(string filename,
            int nodeCnt, IList<double[]> doubleCoords,
            int elementCnt, IList<int[]> elements,
            int portCnt, IList<IList<int>> portList,
            int[] forceBCNodeNumbers,
            int incidentPortNo,
            MediaInfo[] medias,
            double firstWaveLength,
            double lastWaveLength,
            int calcCnt,
            FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv)
        {
            //////////////////////////////////////////
            // ファイル出力
            //////////////////////////////////////////
            try
            {
                using (StreamWriter sw = new StreamWriter(filename))
                {
                    string line;

                    // 節点番号と座標の出力
                    line = string.Format("Nodes,{0}", nodeCnt);
                    sw.WriteLine(line);
                    for (int i = 0; i < doubleCoords.Count; i++)
                    {
                        double[] doubleCoord = doubleCoords[i];
                        int nodeNumber = i + 1;
                        line = string.Format("{0},{1},{2}", nodeNumber, doubleCoord[0], doubleCoord[1]);
                        sw.WriteLine(line);
                    }
                    // 要素番号と要素を構成する節点の全体節点番号の出力
                    line = string.Format("Elements,{0}", elementCnt);
                    sw.WriteLine(line);
                    foreach (int[] element in elements)
                    {
                        line = "";
                        foreach (int k in element)
                        {
                            line += string.Format("{0},", k);
                        }
                        line = line.Substring(0, line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                    // ポート境界条件節点
                    int portCounter = 0;
                    line = string.Format("Ports,{0}", portList.Count);
                    sw.WriteLine(line);
                    foreach (IList<int> nodes in portList)
                    {
                        line = string.Format("{0},{1}", ++portCounter, nodes.Count);
                        sw.WriteLine(line);
                        int portNodeNumber = 0;
                        foreach (int nodeNumber in nodes)
                        {
                            line = string.Format("{0},{1}", ++portNodeNumber, nodeNumber);
                            sw.WriteLine(line);
                        }
                    }
                    // 強制境界節点
                    line = string.Format("Force,{0}", forceBCNodeNumbers.Length);
                    sw.WriteLine(line);
                    foreach (int nodeNumber in forceBCNodeNumbers)
                    {
                        line = string.Format("{0}", nodeNumber);
                        sw.WriteLine(line);
                    }
                    // 入射ポート番号
                    line = string.Format("IncidentPortNo,{0}", incidentPortNo);
                    sw.WriteLine(line);
                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    // 媒質情報の個数
                    sw.WriteLine("Medias,{0}", medias.Length);
                    // 媒質情報の書き込み
                    for (int i = 0; i < medias.Length; i++)
                    {
                        MediaInfo media = medias[i];
                        line = string.Format("{0},", i);
                        double[,] p = media.P;
                        for (int m = 0; m < p.GetLength(0); m++)
                        {
                            for (int n = 0; n < p.GetLength(1); n++)
                            {
                                line += string.Format("{0},", p[m, n]);
                            }
                        }
                        double[,] q = media.Q;
                        for (int m = 0; m < q.GetLength(0); m++)
                        {
                            for (int n = 0; n < q.GetLength(1); n++)
                            {
                                line += string.Format("{0},", q[m, n]);
                            }
                        }
                        line = line.Remove(line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                    // 計算対象周波数
                    sw.WriteLine("WaveLengthRange,{0},{1},{2}", firstWaveLength, lastWaveLength, calcCnt);
                    // 線形方程式解法区分
                    sw.WriteLine("LsEqnSolverDv,{0}", FemSolver.LinearSystemEqnSolverDVToStr(lsEqnSolverDv));
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }
        }
        /// <summary>
        /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する
        /// </summary>
        /// <param name="element">線要素</param>
        /// <param name="coords">座標リスト</param>
        /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param>
        /// <param name="Medias">媒質情報リスト</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="txx_1d">txx行列</param>
        /// <param name="ryy_1d">ryy行列</param>
        /// <param name="uzz_1d">uzz行列</param>
        public static void AddElementMatOf1dEigenValueProblem(
            FemLineElement element,
            IList<double> coords,
            Dictionary<int, int> toSorted,
            MediaInfo[] Medias,
            FemSolver.WaveModeDV WaveModeDv,
            ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d)
        {
            // 1次線要素
            const int nno = Constants.LineNodeCnt_FirstOrder; // 2;

            int[] nodeNumbers = element.NodeNumbers;
            System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length);

            // 座標の取得
            double[] elementCoords = new double[nno];
            for (int n = 0; n < nno; n++)
            {
                int nodeIndex = nodeNumbers[n] - 1;
                elementCoords[n] = coords[nodeIndex];
            }
            // 線要素の長さ
            double elen = Math.Abs(elementCoords[1] - elementCoords[0]);
            // 媒質インデックス
            int mediaIndex = element.MediaIndex;
            // 媒質
            MediaInfo media = Medias[mediaIndex];
            double[,] media_P = null;
            double[,] media_Q = null;
            if (WaveModeDv == FemSolver.WaveModeDV.TE)
            {
                media_P = media.P;
                media_Q = media.Q;
            }
            else if (WaveModeDv == FemSolver.WaveModeDV.TM)
            {
                media_P = media.Q;
                media_Q = media.P;
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
            media_P = MyMatrixUtil.matrix_Inverse(media_P);

            double[,] integralN = new double[nno, nno]
                {
                    { elen / 3.0, elen / 6.0 },
                    { elen / 6.0, elen / 3.0 },
                };
            double[,] integralDNDY = new double[nno, nno]
                {
                    {  1.0 / elen, -1.0 / elen },
                    { -1.0 / elen,  1.0 / elen },
                };
            for (int ino = 0; ino < nno; ino++)
            {
                int inoBoundary = nodeNumbers[ino];
                int inoSorted;
                if (!toSorted.ContainsKey(inoBoundary)) continue;
                inoSorted = toSorted[inoBoundary];
                for (int jno = 0; jno < nno; jno++)
                {
                    int jnoBoundary = nodeNumbers[jno];
                    int jnoSorted;
                    if (!toSorted.ContainsKey(jnoBoundary)) continue;
                    jnoSorted = toSorted[jnoBoundary];
                    // 対称バンド行列対応
                    if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted)
                    {
                        continue;
                    }

                    double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno];
                    double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno];
                    double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno];
                    //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno;
                    //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno;
                    //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno;
                    txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno;
                    ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno;
                    uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno;
                }
            }
        }
        /// <summary>
        ///  Fem入力データをファイルへ書き込み
        /// </summary>
        /// <param name="filename">ファイル名(*.fem)</param>
        /// <param name="nodes">節点リスト</param>
        /// <param name="elements">要素リスト</param>
        /// <param name="ports">ポートの節点番号リストのリスト</param>
        /// <param name="forceBCNodes">強制境界節点番号リスト</param>
        /// <param name="incidentPortNo">入射ポート番号</param>
        /// <param name="medias">媒質情報リスト</param>
        /// <param name="firstWaveLength">計算開始波長</param>
        /// <param name="lastWaveLength">計算終了波長</param>
        /// <param name="calcCnt">計算件数</param>
        /// <param name="lsEqnSolverDv">線形方程式解法区分</param>
        /// <returns></returns>
        public static void SaveToFile(string filename,
            IList<FemNode> nodes,
            IList<FemElement> elements,
            IList<IList<int>> ports,
            IList<int> forceBCNodes,
            int incidentPortNo,
            MediaInfo[] medias,
            double firstWaveLength,
            double lastWaveLength,
            int calcCnt,
            FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv
            )
        {
            int nodeCnt = nodes.Count;
            IList<double[]> doubleCoords = new List<double[]>();
            foreach (FemNode femNode in nodes)
            {
                doubleCoords.Add(femNode.Coord);
            }
            int elementCnt = elements.Count;
            IList<int[]> in_elements = new List<int[]>();
            foreach (FemElement femElement in elements)
            {
                int cnt = 2 + femElement.NodeNumbers.Length;
                int[] in_element = new int[cnt];
                in_element[0] = femElement.No;
                in_element[1] = femElement.MediaIndex;
                for (int ino = 0; ino < femElement.NodeNumbers.Length; ino++)
                {
                    in_element[2 + ino] = femElement.NodeNumbers[ino];
                }
                in_elements.Add(in_element);
            }
            int portCnt = ports.Count;
            int[] forceBCNodeNumbers = forceBCNodes.ToArray();

            SaveToFileFromCad(
                filename,
                nodeCnt, doubleCoords,
                elementCnt, in_elements,
                portCnt, ports,
                forceBCNodeNumbers,
                incidentPortNo,
                medias,
                firstWaveLength,
                lastWaveLength,
                calcCnt,
                lsEqnSolverDv);
        }
        /// <summary>
        ///  Fem入力データをファイルから読み込み
        /// </summary>
        /// <param name="filename">ファイル名(*.fem)</param>
        /// <param name="nodes">節点リスト</param>
        /// <param name="elements">要素リスト</param>
        /// <param name="ports">ポートの節点番号リストのリスト</param>
        /// <param name="forceBCNodes">強制境界節点番号リスト</param>
        /// <param name="incidentPortNo">入射ポート番号</param>
        /// <param name="medias">媒質情報リスト</param>
        /// <param name="firstWaveLength">計算開始波長</param>
        /// <param name="lastWaveLength">計算終了波長</param>
        /// <param name="calcCnt">計算件数</param>
        /// <returns></returns>
        public static bool LoadFromFile(
            string filename,
            out IList<FemNode> nodes,
            out IList<FemElement> elements,
            out IList<IList<int>> ports,
            out IList<int> forceBCNodes,
            out int incidentPortNo,
            out MediaInfo[] medias,
            out double firstWaveLength,
            out double lastWaveLength,
            out int calcCnt,
            out FemSolver.LinearSystemEqnSoverDV lsEqnSoverDv
            )
        {
            int eNodeCnt = 0;

            nodes = new List<FemNode>();
            elements = new List<FemElement>();
            ports = new List<IList<int>>();
            forceBCNodes = new List<int>();
            incidentPortNo = 1;
            medias = new MediaInfo[Constants.MaxMediaCount];
            for (int i = 0; i < medias.Length; i++)
            {
                MediaInfo media = new MediaInfo();
                media.BackColor = CadLogic.MediaBackColors[i];
                medias[i] = media;
            }
            firstWaveLength = 0.0;
            lastWaveLength = 0.0;
            calcCnt = 0;
            lsEqnSoverDv = Constants.DefLsEqnSolverDv;

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

            // 入力データ読み込み
            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    const char delimiter = ',';
                    string line;
                    string[] tokens;

                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Nodes")
                    {
                        MessageBox.Show("節点情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int nodeCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < nodeCnt; i++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 3)
                        {
                            MessageBox.Show("節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        int no = int.Parse(tokens[0]);
                        if (no != i + 1)
                        {
                            MessageBox.Show("節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        FemNode femNode = new FemNode();
                        femNode.No = no;
                        femNode.Coord = new double[2];
                        femNode.Coord[0] = double.Parse(tokens[1]);
                        femNode.Coord[1] = double.Parse(tokens[2]);
                        nodes.Add(femNode);
                    }

                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Elements")
                    {
                        MessageBox.Show("要素情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int elementCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < elementCnt; i++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if ((tokens.Length != 1 + Constants.TriNodeCnt_SecondOrder)
                            && (tokens.Length != 2 + Constants.TriNodeCnt_SecondOrder)  // ver1.1.0.0で媒質インデックスを番号の後に挿入
                            && (tokens.Length != 2 + Constants.QuadNodeCnt_SecondOrder_Type2)
                            && (tokens.Length != 2 + Constants.TriNodeCnt_FirstOrder)
                            && (tokens.Length != 2 + Constants.QuadNodeCnt_FirstOrder)
                            )
                        {
                            MessageBox.Show("要素情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        int elemNo = int.Parse(tokens[0]);
                        int mediaIndex = 0;
                        int indexOffset = 1; // ver1.0.0.0
                        int workENodeCnt = Constants.TriNodeCnt_SecondOrder;
                        if (tokens.Length == 1 + Constants.TriNodeCnt_SecondOrder)
                        {
                            // 媒質インデックスのない古い形式(ver1.0.0.0)
                        }
                        else
                        {
                            // ver1.1.0.0で媒質インデックスを追加
                            mediaIndex = int.Parse(tokens[1]);
                            indexOffset = 2;

                            workENodeCnt = tokens.Length - 2;
                        }
                        if (workENodeCnt <= 0)
                        {
                            MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        if (eNodeCnt == 0)
                        {
                            // 最初の要素の節点数を格納(チェックに利用)
                            eNodeCnt = workENodeCnt;
                        }
                        else
                        {
                            // 要素の節点数が変わった?
                            if (workENodeCnt != eNodeCnt)
                            {
                                MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                        }
                        //FemElement femElement = new FemElement();
                        FemElement femElement = FemMeshLogic.CreateFemElementByElementNodeCnt(eNodeCnt);
                        femElement.No = elemNo;
                        femElement.MediaIndex = mediaIndex;
                        femElement.NodeNumbers = new int[eNodeCnt];
                        for (int n = 0; n < femElement.NodeNumbers.Length; n++)
                        {
                            femElement.NodeNumbers[n] = int.Parse(tokens[n + indexOffset]);
                        }
                        elements.Add(femElement);
                    }

                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Ports")
                    {
                        MessageBox.Show("入出力ポート情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int portCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < portCnt; i++)
                    {
                        line = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2)
                        {
                            MessageBox.Show("入出力ポート情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        int portNo = int.Parse(tokens[0]);
                        int portNodeCnt = int.Parse(tokens[1]);
                        if (portNo != i + 1)
                        {
                            MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return false;
                        }
                        IList<int> portNodes = new List<int>();
                        for (int n = 0; n < portNodeCnt; n++)
                        {
                            line = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 2)
                            {
                                MessageBox.Show("ポートの節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                            int portNodeNumber = int.Parse(tokens[0]);
                            int nodeNumber = int.Parse(tokens[1]);
                            if (portNodeNumber != n + 1)
                            {
                                MessageBox.Show("ポートの節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return false;
                            }
                            portNodes.Add(nodeNumber);
                        }
                        ports.Add(portNodes);
                    }

                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Force")
                    {
                        MessageBox.Show("強制境界情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    int forceNodeCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < forceNodeCnt; i++)
                    {
                        line = sr.ReadLine();
                        int nodeNumber = int.Parse(line);
                        forceBCNodes.Add(nodeNumber);
                    }

                    line = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "IncidentPortNo")
                    {
                        MessageBox.Show("入射ポート番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return false;
                    }
                    incidentPortNo = int.Parse(tokens[1]);

                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                        // 媒質情報なし
                        // ver1.0.0.0
                    }
                    else
                    {
                        // 媒質情報?
                        // ver1.1.0.0
                        tokens = line.Split(delimiter);
                        if (tokens[0] != "Medias")
                        {
                            MessageBox.Show("媒質情報がありません");
                            return false;
                        }
                        int cnt = int.Parse(tokens[1]);
                        if (cnt > Constants.MaxMediaCount)
                        {
                            MessageBox.Show("媒質情報の個数が不正です");
                            return false;
                        }
                        for (int i = 0; i < cnt; i++)
                        {
                            line = sr.ReadLine();
                            if (line.Length == 0)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return false;
                            }
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1 + 9 + 9)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return false;
                            }
                            int mediaIndex = int.Parse(tokens[0]);
                            System.Diagnostics.Debug.Assert(mediaIndex == i);

                            double[,] p = new double[3, 3];
                            for (int m = 0; m < p.GetLength(0); m++)
                            {
                                for (int n = 0; n < p.GetLength(1); n++)
                                {
                                    p[m, n] = double.Parse(tokens[1 + m * p.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetP(p);

                            double[,] q = new double[3, 3];
                            for (int m = 0; m < q.GetLength(0); m++)
                            {
                                for (int n = 0; n < q.GetLength(1); n++)
                                {
                                    q[m, n] = double.Parse(tokens[1 + 9 + m * q.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetQ(q);
                        }
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 4 || tokens[0] != "WaveLengthRange")
                        {
                            MessageBox.Show("計算対象周波数情報がありません");
                            return false;
                        }
                        firstWaveLength = double.Parse(tokens[1]);
                        lastWaveLength = double.Parse(tokens[2]);
                        calcCnt = int.Parse(tokens[3]);
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "LsEqnSolverDv")
                        {
                            MessageBox.Show("線形方程式解法区分情報がありません");
                            return false;
                        }
                        string value  = tokens[1];
                        lsEqnSoverDv = FemSolver.StrToLinearSystemEqnSolverDV(value);
                    }

                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }

            return true;
        }
        /* 数値積分版
         * /// <summary>
         * /// ヘルムホルツ方程式に対する有限要素マトリクス作成
         * /// </summary>
         * /// <param name="waveLength">波長</param>
         * /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
         * /// <param name="element">有限要素</param>
         * /// <param name="Nodes">節点リスト</param>
         * /// <param name="Medias">媒質リスト</param>
         * /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
         * /// <param name="WaveModeDv">計算する波のモード区分</param>
         * /// <param name="mat">マージされる全体行列</param>
         * public static  void AddElementMat(double waveLength,
         *  Dictionary<int, int> toSorted,
         *  FemElement element,
         *  IList<FemNode> Nodes,
         *  MediaInfo[] Medias,
         *  Dictionary<int, bool> ForceNodeNumberH,
         *  FemSolver.WaveModeDv WaveModeDv,
         *  ref MyComplexMatrix mat)
         * {
         *  // 定数
         *  const double pi = Constants.pi;
         *  const double c0 = Constants.c0;
         *  // 波数
         *  double k0 = 2.0 * pi / waveLength;
         *  // 角周波数
         *  double omega = k0 * c0;
         *
         *  // 要素頂点数
         *  const int vertexCnt = Constants.QuadVertexCnt; //4;
         *  // 要素内節点数
         *  const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 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;
         *  if (WaveModeDv == FemSolver.WaveModeDv.TE)
         *  {
         *      media_P = media.P;
         *      media_Q = media.Q;
         *  }
         *  else if (WaveModeDv == FemSolver.WaveModeDv.TM)
         *  {
         *      media_P = media.Q;
         *      media_Q = media.P;
         *  }
         *  else
         *  {
         *      System.Diagnostics.Debug.Assert(false);
         *  }
         *  // [p]は逆数をとる
         *  media_P = MyMatrixUtil.matrix_Inverse(media_P);
         *
         *  // 節点座標(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];
         *      }
         *  }
         *
         *  //// 四角形の辺の長さを求める
         *  //double[] le = new double[4];
         *  //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
         *  //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
         *  //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
         *  //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);
         *
         *  // 要素節点座標( 局所r,s成分 )
         *  //        s
         *  //        |
         *  //    3+  6  +2
         *  //    |   |   |
         *  // ---7---+---5-->r
         *  //    |   |   |
         *  //    0+  4  +1
         *  //        |
         *  //
         *  double[][] n_pts =
         *      {
         *          // r, s
         *          new double[] {-1.0, -1.0},  //0
         *          new double[] { 1.0, -1.0},  //1
         *          new double[] { 1.0,  1.0},  //2
         *          new double[] {-1.0,  1.0},  //3
         *          new double[] {   0, -1.0},  //4
         *          new double[] { 1.0,    0},  //5
         *          new double[] {   0,  1.0},  //6
         *          new double[] {-1.0,    0},  //7
         *      };
         *
         *
         *  // ガウスルジャンドルの積分公式
         *  double[][] g_pts = new double[5][]
         *      {
         *          // ポイント(ξ: [-1 +1]区間)、重み
         *          new double[] { -0.90617985, 0.23692689},
         *          new double[] { -0.53846931, 0.47862867},
         *          new double[] {0.0, 0.56888889},
         *          new double[] {0.53846931, 0.47862867},
         *          new double[] {0.90617985, 0.23692689}
         *      };
         *
         *  // 要素剛性行列を作る
         *  double[,] emat = new Complex[nno, nno];
         *  for (int ino = 0; ino < nno; ino++)
         *  {
         *      for (int jno = 0; jno < nno; jno++)
         *      {
         *          emat[ino, jno] = 0.0;
         *          double detjsum = 0; //check
         *          foreach (double[] s_g_pt in g_pts)
         *          {
         *              foreach (double[] r_g_pt in g_pts)
         *              {
         *                  // 積分点
         *                  double r = r_g_pt[0];
         *                  double s = s_g_pt[0];
         *                  // 重み(2次元)
         *                  double weight = r_g_pt[1] * s_g_pt[1];
         *                  // 形状関数
         *                  double[] N = new double[nno];
         *                  // 形状関数のr, s方向微分
         *                  double[] dNdr = new double[nno];
         *                  double[] dNds = new double[nno];
         *                  // 節点0~3 : 四角形の頂点
         *                  for (int i = 0; i < 4; i++)
         *                  {
         *                      // 節点の局所座標
         *                      double ri = n_pts[i][0];
         *                      double si = n_pts[i][1];
         *                      // 形状関数N
         *                      N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0);
         *                      // 形状関数のr方向微分
         *                      dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s);
         *                      // 形状関数のs方向微分
         *                      dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s);
         *                  }
         *                  // 節点4,6 : r方向辺上中点
         *                  foreach (int i in new int[]{ 4, 6})
         *                  {
         *                      // 節点の局所座標
         *                      double ri = n_pts[i][0];
         *                      double si = n_pts[i][1];
         *                      // 形状関数N
         *                      N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s);
         *                      // 形状関数のr方向微分
         *                      dNdr[i] = -1.0 * r * (1.0 + si * s);
         *                      // 形状関数のs方向微分
         *                      dNds[i] = 0.5 * si * (1.0 - r * r);
         *                  }
         *                  // 節点5,7 : s方向辺上中点
         *                  foreach (int i in new int[] { 5, 7 })
         *                  {
         *                      // 節点の局所座標
         *                      double ri = n_pts[i][0];
         *                      double si = n_pts[i][1];
         *                      // 形状関数N
         *                      N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s);
         *                      // 形状関数のr方向微分
         *                      dNdr[i] = 0.5 * ri * (1.0 - s * s);
         *                      // 形状関数のs方向微分
         *                      dNds[i] = -1.0 * s * (1.0 + ri * r);
         *                  }
         *
         *                  // ヤコビアン行列
         *                  double j11;
         *                  double j12;
         *                  double j21;
         *                  double j22;
         *                  j11 = 0;
         *                  j12 = 0;
         *                  j21 = 0;
         *                  j22 = 0;
         *
         *                  //for (int i = 0; i < vertexCnt; i++)
         *                  //{
         *                  //    // 頂点の座標の微分
         *                  //    // 座標の形状関数は一次四角形のものを使用する
         *                  //    // 節点の局所座標
         *                  //    double ri = n_pts[i][0];
         *                  //    double si = n_pts[i][1];
         *                  //    double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s);
         *                  //    double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si;
         *                  //    j11 += dNdr_1stOrder * pp[i][0];
         *                  //    j12 += dNdr_1stOrder * pp[i][1];
         *                  //    j21 += dNds_1stOrder * pp[i][0];
         *                  //    j22 += dNds_1stOrder * pp[i][1];
         *                  //}
         *
         *                  for (int i = 0; i < nno; i++)
         *                  {
         *                      j11 += dNdr[i] * pp[i][0];
         *                      j12 += dNdr[i] * pp[i][1];
         *                      j21 += dNds[i] * pp[i][0];
         *                      j22 += dNds[i] * pp[i][1];
         *                  }
         *                  // ヤコビアン
         *                  double detj = j11 * j22 - j12 * j21;
         *                  detjsum += detj * weight;
         *                  //System.Diagnostics.Debug.WriteLine("det:{0}", detj);
         *
         *                  // gradr[0] : gradrのx成分 grad[1] : gradrのy成分
         *                  // grads[0] : gradsのx成分 grads[1] : gradsのy成分
         *                  double[] gradr = new double[2];
         *                  double[] grads = new double[2];
         *                  gradr[0] =   j22 / detj;
         *                  gradr[1] = - j21 / detj;
         *                  grads[0] = - j12 / detj;
         *                  grads[1] =   j11 / detj;
         *
         *                  // 形状関数のx, y方向微分
         *                  double[,] dNdX = new double[ndim, nno];
         *                  for (int i = 0; i < nno; i++)
         *                  {
         *                      for (int direction = 0; direction < ndim; direction++)
         *                      {
         *                          dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction];
         *                      }
         *                  }
         *
         *                  // 汎関数
         *                  double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno]
         *                                   - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno];
         *                  emat[ino, jno] += detj * weight * functional;
         *              }
         *          }
         *          //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum);
         *      }
         *  }
         *
         *  // 要素剛性行列にマージする
         *  for (int ino = 0; ino < nno; ino++)
         *  {
         *      int iNodeNumber = no_c[ino];
         *      if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
         *      int inoGlobal = toSorted[iNodeNumber];
         *      for (int jno = 0; jno < nno; jno++)
         *      {
         *          int jNodeNumber = no_c[jno];
         *          if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
         *          int jnoGlobal = toSorted[jNodeNumber];
         *
         *          mat[inoGlobal, jnoGlobal] += emat[ino, jno];
         *      }
         *  }
         * }
         */
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
                                         Dictionary <int, int> toSorted,
                                         FemElement element,
                                         IList <FemNode> Nodes,
                                         MediaInfo[] Medias,
                                         Dictionary <int, bool> ForceNodeNumberH,
                                         FemSolver.WGStructureDV WGStructureDv,
                                         FemSolver.WaveModeDV WaveModeDv,
                                         double waveguideWidthForEPlane,
                                         ref MyComplexMatrix mat,
                                         ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
                                         ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
                                         ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.QuadVertexCnt; //4;
            // 要素内節点数
            const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 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,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                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];
                }
            }

            // 四角形の辺の長さを求める
            double[] le = new double[4];
            le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]);
            le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]);
            le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]);
            le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]);
            System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit);
            System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit);
            double lx = le[0];
            double ly = le[1];

            // 要素節点座標( 局所r,s成分 )
            //        s
            //        |
            //    3+  6  +2
            //    |   |   |
            // ---7---+---5-->r
            //    |   |   |
            //    0+  4  +1
            //        |
            //
            double[][] n_pts =
            {
                // r, s
                new double[] { -1.0, -1.0 },    //0
                new double[] {  1.0, -1.0 },    //1
                new double[] {  1.0,  1.0 },    //2
                new double[] { -1.0,  1.0 },    //3
                new double[] {    0, -1.0 },    //4
                new double[] {  1.0,    0 },    //5
                new double[] {    0,  1.0 },    //6
                new double[] { -1.0,    0 },    //7
            };

            // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] Ni_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = 0.25 * ri * ri * si;
                Ni_a[i, 1] = 0.25 * ri * ri;
                Ni_a[i, 2] = 0.0;
                Ni_a[i, 3] = 0.25 * ri * si;
                Ni_a[i, 4] = 0.25 * ri * si * si;
                Ni_a[i, 5] = 0.25 * si * si;
                Ni_a[i, 6] = 0.0;
                Ni_a[i, 7] = -0.25;
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = -0.5 * si;
                Ni_a[i, 1] = -0.5;
                Ni_a[i, 2] = 0.0;
                Ni_a[i, 3] = 0.0;
                Ni_a[i, 4] = 0.0;
                Ni_a[i, 5] = 0.0;
                Ni_a[i, 6] = 0.5 * si;
                Ni_a[i, 7] = 0.5;
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                Ni_a[i, 0] = 0.0;
                Ni_a[i, 1] = 0.0;
                Ni_a[i, 2] = 0.5 * ri;
                Ni_a[i, 3] = 0.0;
                Ni_a[i, 4] = -0.5 * ri;
                Ni_a[i, 5] = -0.5;
                Ni_a[i, 6] = 0.0;
                Ni_a[i, 7] = 0.5;
            }

            // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] dNidr_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;                       // r^2
                dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri;      // r
                dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si; // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = 0.25 * ri * si * si;       // s^2
                dNidr_a[i, 6] = 0.25 * ri * si;            // s
                dNidr_a[i, 7] = 0.0;                       //1
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;  // r^2
                dNidr_a[i, 2] = -1.0; // r
                dNidr_a[i, 3] = -si;  // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = 0.0;  // s^2
                dNidr_a[i, 6] = 0.0;  // s
                dNidr_a[i, 7] = 0.0;  // 1
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNidr_a[i, 0] = 0.0;
                dNidr_a[i, 1] = 0.0;       // r^2
                dNidr_a[i, 2] = 0.0;       // r
                dNidr_a[i, 3] = 0.0;       // rs
                dNidr_a[i, 4] = 0.0;
                dNidr_a[i, 5] = -0.5 * ri; // s^2
                dNidr_a[i, 6] = 0.0;       // s
                dNidr_a[i, 7] = 0.5 * ri;  // 1
            }

            // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7
            double[,] dNids_a = new double[nno, 8];
            for (int i = 0; i < 4; i++)
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = 0.25 * ri * ri * si;       // r^2
                dNids_a[i, 2] = 0.25 * ri * si;            // r
                dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si; // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;                       // s^2
                dNids_a[i, 6] = 0.25 * 2.0 * si * si;      // s
                dNids_a[i, 7] = 0.0;                       //1
            }
            foreach (int i in new int[] { 4, 6 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = -0.5 * si; // r^2
                dNids_a[i, 2] = 0.0;       // r
                dNids_a[i, 3] = 0.0;       // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;       // s^2
                dNids_a[i, 6] = 0.0;       // s
                dNids_a[i, 7] = 0.5 * si;  //1
            }
            foreach (int i in new int[] { 5, 7 })
            {
                // 節点の局所座標
                double ri = n_pts[i][0];
                double si = n_pts[i][1];
                dNids_a[i, 0] = 0.0;
                dNids_a[i, 1] = 0.0;  // r^2
                dNids_a[i, 2] = 0.0;  // r
                dNids_a[i, 3] = -ri;  // rs
                dNids_a[i, 4] = 0.0;
                dNids_a[i, 5] = 0.0;  // s^2
                dNids_a[i, 6] = -1.0; // s
                dNids_a[i, 7] = 0.0;  //1
            }

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno];
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    integralN[ino, jno] = lx * ly / 4.0 *
                                          (
                        // r^4s^2
                        4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3]
                                       + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7])
                        // 1
                        + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7]
                                          );
                    integralDNDX[0, ino, jno] = ly / lx *
                                                (
                        // r^4s^2
                        4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2]
                                       + dNidr_a[ino, 3] * dNidr_a[jno, 3]
                                       + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7])
                        // 1
                        + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7]
                                                );
                    integralDNDX[1, ino, jno] = lx / ly *
                                                (
                        // r^4s^2
                        4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0]
                        // r^2s^2
                        + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2]
                                       + dNids_a[ino, 3] * dNids_a[jno, 3]
                                       + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6])
                        // r^4
                        + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1]
                        // r^2
                        + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7])
                        // r^2s^4
                        + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4]
                        // s^4
                        + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5]
                        // s^2
                        + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7])
                        // 1
                        + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7]
                                                );
                }
            }

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                     - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int    jno   = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber))
                    {
                        continue;
                    }
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber))
                        {
                            continue;
                        }
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
            Dictionary<int, int> toSorted,
            FemElement element,
            IList<FemNode> Nodes,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            FemSolver.WGStructureDV WGStructureDv,
            FemSolver.WaveModeDV WaveModeDv,
            double waveguideWidthForEPlane,
            ref MyComplexMatrix mat,
            ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
            ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
            ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            //const int vertexCnt = Constants.TriVertexCnt; //3;
            // 要素内節点数
            const int nno = Constants.TriNodeCnt_FirstOrder; //3;  // 1次三角形要素
            // 座標次元数
            const int ndim = Constants.CoordDim2D; //2;

            int[] nodeNumbers = element.NodeNumbers;
            int[] no_c = new int[nno];
            MediaInfo media = Medias[element.MediaIndex];  // ver1.1.0.0 媒質情報の取得
            double[,] media_P = null;
            double[,] media_Q = null;
            // ヘルムホルツ方程式のパラメータP,Qを取得する
            FemSolver.GetHelmholtzMediaPQ(
                k0,
                media,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                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];
                }
            }
            // 面積を求める
            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]);

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    integralDNDX[0, ino, jno] = area * dldx[ino, 0] * dldx[jno, 0];
                    integralDNDX[1, ino, jno] = area * dldx[ino, 1] * dldx[jno, 1];
                }
            }
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno]
                {
                    { area / 6.0 , area / 12.0, area / 12.0 },
                    { area / 12.0, area /  6.0, area / 12.0 },
                    { area / 12.0, area / 12.0, area /  6.0 },
                };

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                         - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int jno = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
        /// <summary>
        /// Ver1.2.0.0形式のCadファイルフォーマットで図面情報を保存する
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="maxDiv"></param>
        /// <param name="areaSelection"></param>
        /// <param name="areaToMediaIndex"></param>
        /// <param name="edgeList"></param>
        /// <param name="incidentPortNo"></param>
        /// <param name="medias"></param>
        public static void SaveToFile_Ver_1_2(
            string filename,
            Size maxDiv, bool[,] areaSelection, int[,] areaToMediaIndex,
            IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList,
            int incidentPortNo,
            MediaInfo[] medias
            )
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(filename))
                {
                    int counter;
                    string line;

                    // 領域: 書き込む個数の計算
                    counter = 0;
                    for (int y = 0; y < maxDiv.Height; y++)
                    {
                        for (int x = 0; x < maxDiv.Width; x++)
                        {
                            if (areaSelection[y, x])
                            {
                                counter++;
                            }
                        }
                    }
                    // 領域: 書き込み
                    sw.WriteLine("AreaSelection,{0}", counter);
                    for (int y = 0; y < maxDiv.Height; y++)
                    {
                        for (int x = 0; x < maxDiv.Width; x++)
                        {
                            if (areaSelection[y, x])
                            {
                                // ver1.1.0.0から座標の後に媒質インデックスを追加
                                sw.WriteLine("{0},{1},{2}", x, y, areaToMediaIndex[y, x]);
                            }
                        }
                    }
                    // ポート境界: 書き込み個数の計算
                    sw.WriteLine("EdgeList,{0}", edgeList.Count);
                    // ポート境界: 書き込み
                    foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 edge in edgeList)
                    {
                        sw.WriteLine("{0},{1},{2},{3},{4}", edge.No, edge.Points[0].X, edge.Points[0].Y, edge.Points[1].X, edge.Points[1].Y);
                    }
                    // 入射ポート番号
                    sw.WriteLine("IncidentPortNo,{0}", incidentPortNo);
                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    // 媒質情報の個数
                    sw.WriteLine("Medias,{0}", medias.Length);
                    // 媒質情報の書き込み
                    for (int i = 0; i < medias.Length; i++)
                    {
                        MediaInfo media = medias[i];
                        line = string.Format("{0},", i);
                        double[,] p = media.P;
                        for (int m = 0; m < p.GetLength(0); m++)
                        {
                            for (int n = 0; n < p.GetLength(1); n++)
                            {
                                line += string.Format("{0},", p[m, n]);
                            }
                        }
                        double[,] q = media.Q;
                        for (int m = 0; m < q.GetLength(0); m++)
                        {
                            for (int n = 0; n < q.GetLength(1); n++)
                            {
                                line += string.Format("{0},", q[m, n]);
                            }
                        }
                        line = line.Remove(line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }
        }
        /// <summary>
        /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する
        /// </summary>
        /// <param name="waveLength">波長(E面の場合のみ使用する)</param>
        /// <param name="element">線要素</param>
        /// <param name="coords">座標リスト</param>
        /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param>
        /// <param name="Medias">媒質情報リスト</param>
        /// <param name="WGStructureDv">導波路構造区分</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param>
        /// <param name="txx_1d">txx行列</param>
        /// <param name="ryy_1d">ryy行列</param>
        /// <param name="uzz_1d">uzz行列</param>
        public static void AddElementMatOf1dEigenValueProblem(
            double waveLength,
            FemLineElement element,
            IList<double> coords,
            Dictionary<int, int> toSorted,
            MediaInfo[] Medias,
            FemSolver.WGStructureDV WGStructureDv,
            FemSolver.WaveModeDV WaveModeDv,
            double waveguideWidthForEPlane,
            ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 2次線要素
            const int nno = Constants.LineNodeCnt_SecondOrder; // 3;

            int[] nodeNumbers = element.NodeNumbers;
            System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length);

            // 座標の取得
            double[] elementCoords = new double[nno];
            for (int n = 0; n < nno; n++)
            {
                int nodeIndex = nodeNumbers[n] - 1;
                elementCoords[n] = coords[nodeIndex];
            }
            // 線要素の長さ
            double elen = Math.Abs(elementCoords[1] - elementCoords[0]);
            // 媒質インデックス
            int mediaIndex = element.MediaIndex;
            // 媒質
            MediaInfo media = Medias[mediaIndex];
            double[,] media_P = null;
            double[,] media_Q = null;
            // ヘルムホルツ方程式のパラメータP,Qを取得する
            FemSolver.GetHelmholtzMediaPQ(
                k0,
                media,
                WGStructureDv,
                WaveModeDv,
                waveguideWidthForEPlane,
                out media_P,
                out media_Q);

            double[,] integralN = new double[nno, nno]
                {
                    {  4.0 / 30.0 * elen, -1.0 / 30.0 * elen,  2.0 / 30.0 * elen },
                    { -1.0 / 30.0 * elen,  4.0 / 30.0 * elen,  2.0 / 30.0 * elen },
                    {  2.0 / 30.0 * elen,  2.0 / 30.0 * elen, 16.0 / 30.0 * elen },
                };
            double[,] integralDNDY = new double[nno, nno]
                {
                    {  7.0 / (3.0 * elen),  1.0 / (3.0 * elen), -8.0 / (3.0 * elen) },
                    {  1.0 / (3.0 * elen),  7.0 / (3.0 * elen), -8.0 / (3.0 * elen) },
                    { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) },
                };

            for (int ino = 0; ino < nno; ino++)
            {
                int inoBoundary = nodeNumbers[ino];
                int inoSorted;
                if (!toSorted.ContainsKey(inoBoundary)) continue;
                inoSorted = toSorted[inoBoundary];
                for (int jno = 0; jno < nno; jno++)
                {
                    int jnoBoundary = nodeNumbers[jno];
                    int jnoSorted;
                    if (!toSorted.ContainsKey(jnoBoundary)) continue;
                    jnoSorted = toSorted[jnoBoundary];
                    // 対称バンド行列対応
                    if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted)
                    {
                        continue;
                    }

                    double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno];
                    double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno];
                    double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno];
                    //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno;
                    //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno;
                    //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno;
                    txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno;
                    ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno;
                    uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno;
                }
            }
        }
        /// <summary>
        /// 初期化処理
        /// </summary>
        protected void init()
        {
            _CadMode = CadModeType.None;
            SerializedCadObjBuff = "";
            LoopList.Clear();
            EdgeCollectionList.Clear();

            //edit
            EditPts.Clear();
            EditVertexIds.Clear();
            EditEdgeIds.Clear();

            IncidentPortNo = 1;
            for (int i = 0; i < Medias.Length; i++)
            {
                MediaInfo media = new MediaInfo();
                media.BackColor = MediaBackColors[i];
                Medias[i] = media;
            }
        }
        /// <summary>
        /// ヘルムホルツ方程式に対する有限要素マトリクス作成
        /// </summary>
        /// <param name="waveLength">波長</param>
        /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param>
        /// <param name="element">有限要素</param>
        /// <param name="Nodes">節点リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param>
        /// <param name="WaveModeDv">計算する波のモード区分</param>
        /// <param name="mat">マージされる全体行列(clapack使用時)</param>
        /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param>
        /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param>
        /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param>
        public static void AddElementMat(double waveLength,
            Dictionary<int, int> toSorted,
            FemElement element,
            IList<FemNode> Nodes,
            MediaInfo[] Medias,
            Dictionary<int, bool> ForceNodeNumberH,
            FemSolver.WaveModeDV WaveModeDv,
            ref MyComplexMatrix mat,
            ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc,
            ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c,
            ref int[] tmpBuffer)
        {
            // 定数
            const double pi = Constants.pi;
            const double c0 = Constants.c0;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 要素頂点数
            const int vertexCnt = Constants.TriVertexCnt; //3;
            // 要素内節点数
            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];  // ver1.1.0.0 媒質情報の取得
            double[,] media_P = null;
            double[,] media_Q = null;
            if (WaveModeDv == FemSolver.WaveModeDV.TE)
            {
                media_P = media.P;
                media_Q = media.Q;
            }
            else if (WaveModeDv == FemSolver.WaveModeDV.TM)
            {
                media_P = media.Q;
                media_Q = media.P;
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
            // [p]は逆数をとる
            media_P = MyMatrixUtil.matrix_Inverse(media_P);

            // 節点座標(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];
                }
            }
            // 面積を求める
            double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]);
            //Console.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, vertexCnt + 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},
                    },
                };

            // ∫dN/dndN/dn dxdy
            //     integralDNDX[n, ino, jno]  n = 0 --> ∫dN/dxdN/dx dxdy
            //                                n = 1 --> ∫dN/dydN/dy dxdy
            double[, ,] integralDNDX = new double[ndim, nno, nno];
            for (int n = 0; n < ndim; n++)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    for (int jno = 0; jno < nno; jno++)
                    {
                        integralDNDX[n, ino, jno]
                            = area / 6.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 1] + dndxC[ino, n, 2] * dndxC[jno, n, 2])
                                  + area / 12.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 1] + dndxC[ino, n, 0] * dndxC[jno, n, 2]
                                                      + dndxC[ino, n, 1] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 2]
                                                      + dndxC[ino, n, 2] * dndxC[jno, n, 0] + dndxC[ino, n, 2] * dndxC[jno, n, 1])
                                  + area / 3.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 3] + dndxC[ino, n, 1] * dndxC[jno, n, 3]
                                                      + dndxC[ino, n, 2] * dndxC[jno, n, 3]
                                                      + dndxC[ino, n, 3] * dndxC[jno, n, 0] + dndxC[ino, n, 3] * dndxC[jno, n, 1]
                                                      + dndxC[ino, n, 3] * dndxC[jno, n, 2])
                                  + area * dndxC[ino, n, 3] * dndxC[jno, n, 3];
                    }
                }
            }
            // ∫N N dxdy
            double[,] integralN = new double[nno, nno]
                {
                    {  6.0 * area / 180.0, -1.0 * area / 180.0, -1.0 * area / 180.0,                 0.0, -4.0 * area / 180.0,                 0.0},
                    { -1.0 * area / 180.0,  6.0 * area / 180.0, -1.0 * area / 180.0,                 0.0,                 0.0, -4.0 * area / 180.0},
                    { -1.0 * area / 180.0, -1.0 * area / 180.0,  6.0 * area / 180.0, -4.0 * area / 180.0,                 0.0,                 0.0},
                    {                 0.0,                 0.0, -4.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0, 16.0 * area / 180.0},
                    { -4.0 * area / 180.0,                 0.0,                 0.0, 16.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0},
                    {                 0.0, -4.0 * area / 180.0,                 0.0, 16.0 * area / 180.0, 16.0 * area / 180.0, 32.0 * area / 180.0},
                };

            // 要素剛性行列を作る
            double[,] emat = new double[nno, nno];
            for (int ino = 0; ino < nno; ino++)
            {
                for (int jno = 0; jno < nno; jno++)
                {
                    emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno]
                                         - k0 * k0 * media_Q[2, 2] * integralN[ino, jno];
                }
            }

            // 要素剛性行列にマージする
            if (mat_cc != null)
            {
                // 全体節点番号→要素内節点インデックスマップ
                Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>();
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    uint inoGlobal = (uint)toSorted[iNodeNumber];
                    inoGlobalDic.Add(inoGlobal, ino);
                }
                // マージ用の節点番号リスト
                uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>();
                // マージする節点数("col"と"row"のサイズ)
                uint ncolrow_tmp = (uint)no_c_tmp.Length;
                // Note:
                //   要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0
                if (ncolrow_tmp > 0)
                {
                    // マージする要素行列
                    DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp];
                    for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++)
                    {
                        int ino = inoGlobalDic[no_c_tmp[ino_tmp]];
                        for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++)
                        {
                            int jno = inoGlobalDic[no_c_tmp[jno_tmp]];
                            double value = emat[ino, jno];
                            DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0);
                            // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意)
                            ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM;
                        }
                    }
                    // 全体行列に要素行列をマージする
                    mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer);
                }
            }
            else if (mat != null)
            {
                for (int ino = 0; ino < nno; ino++)
                {
                    int iNodeNumber = no_c[ino];
                    if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue;
                    int inoGlobal = toSorted[iNodeNumber];
                    for (int jno = 0; jno < nno; jno++)
                    {
                        int jNodeNumber = no_c[jno];
                        if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue;
                        int jnoGlobal = toSorted[jNodeNumber];

                        //mat[inoGlobal, jnoGlobal] += emat[ino, jno];
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno];
                        // 実数部に加算する
                        //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno];
                        // バンドマトリクス対応
                        mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno];
                    }
                }
            }
        }
예제 #20
0
        /// <summary>
        ///  Fem入力データをファイルから読み込み
        /// </summary>
        /// <param name="filename">ファイル名(*.fem)</param>
        /// <param name="nodes">節点リスト</param>
        /// <param name="elements">要素リスト</param>
        /// <param name="ports">ポートの節点番号リストのリスト</param>
        /// <param name="forceBCNodes">強制境界節点番号リスト</param>
        /// <param name="incidentPortNo">入射ポート番号</param>
        /// <param name="medias">媒質情報リスト</param>
        /// <param name="firstWaveLength">計算開始波長</param>
        /// <param name="lastWaveLength">計算終了波長</param>
        /// <param name="calcCnt">計算件数</param>
        /// <param name="wgStructureDv">導波路構造区分</param>
        /// <param name="waveModeDv">波のモード区分</param>
        /// <param name="lsEqnSoverDv">線形方程式解法区分</param>
        /// <param name="waveguideWidthForEPlane">導波管幅(E面解析用)</param>
        /// <returns></returns>
        public static bool LoadFromFile(
            string filename,
            out IList <FemNode> nodes,
            out IList <FemElement> elements,
            out IList <IList <int> > ports,
            out IList <int> forceBCNodes,
            out int incidentPortNo,
            out MediaInfo[] medias,
            out double firstWaveLength,
            out double lastWaveLength,
            out int calcCnt,
            out FemSolver.WGStructureDV wgStructureDv,
            out FemSolver.WaveModeDV waveModeDv,
            out FemSolver.LinearSystemEqnSoverDV lsEqnSoverDv,
            out double waveguideWidthForEPlane
            )
        {
            int eNodeCnt = 0;

            nodes          = new List <FemNode>();
            elements       = new List <FemElement>();
            ports          = new List <IList <int> >();
            forceBCNodes   = new List <int>();
            incidentPortNo = 1;
            medias         = new MediaInfo[Constants.MaxMediaCount];
            for (int i = 0; i < medias.Length; i++)
            {
                MediaInfo media = new MediaInfo();
                media.BackColor = CadLogic.MediaBackColors[i];
                medias[i]       = media;
            }
            firstWaveLength         = 0.0;
            lastWaveLength          = 0.0;
            calcCnt                 = 0;
            wgStructureDv           = Constants.DefWGStructureDv;
            waveModeDv              = Constants.DefWaveModeDv;
            lsEqnSoverDv            = Constants.DefLsEqnSolverDv;
            waveguideWidthForEPlane = 0;

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

            // 入力データ読み込み
            try
            {
                using (StreamReader sr = new StreamReader(filename))
                {
                    const char delimiter = ',';
                    string     line;
                    string[]   tokens;

                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Nodes")
                    {
                        MessageBox.Show("節点情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int nodeCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < nodeCnt; i++)
                    {
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 3)
                        {
                            MessageBox.Show("節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        int no = int.Parse(tokens[0]);
                        if (no != i + 1)
                        {
                            MessageBox.Show("節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        FemNode femNode = new FemNode();
                        femNode.No       = no;
                        femNode.Coord    = new double[2];
                        femNode.Coord[0] = double.Parse(tokens[1]);
                        femNode.Coord[1] = double.Parse(tokens[2]);
                        nodes.Add(femNode);
                    }

                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Elements")
                    {
                        MessageBox.Show("要素情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int elementCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < elementCnt; i++)
                    {
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if ((tokens.Length != 1 + Constants.TriNodeCnt_SecondOrder) &&
                            (tokens.Length != 2 + Constants.TriNodeCnt_SecondOrder) &&  // ver1.1.0.0で媒質インデックスを番号の後に挿入
                            (tokens.Length != 2 + Constants.QuadNodeCnt_SecondOrder_Type2) &&
                            (tokens.Length != 2 + Constants.TriNodeCnt_FirstOrder) &&
                            (tokens.Length != 2 + Constants.QuadNodeCnt_FirstOrder)
                            )
                        {
                            MessageBox.Show("要素情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        int elemNo       = int.Parse(tokens[0]);
                        int mediaIndex   = 0;
                        int indexOffset  = 1; // ver1.0.0.0
                        int workENodeCnt = Constants.TriNodeCnt_SecondOrder;
                        if (tokens.Length == 1 + Constants.TriNodeCnt_SecondOrder)
                        {
                            // 媒質インデックスのない古い形式(ver1.0.0.0)
                        }
                        else
                        {
                            // ver1.1.0.0で媒質インデックスを追加
                            mediaIndex  = int.Parse(tokens[1]);
                            indexOffset = 2;

                            workENodeCnt = tokens.Length - 2;
                        }
                        if (workENodeCnt <= 0)
                        {
                            MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        if (eNodeCnt == 0)
                        {
                            // 最初の要素の節点数を格納(チェックに利用)
                            eNodeCnt = workENodeCnt;
                        }
                        else
                        {
                            // 要素の節点数が変わった?
                            if (workENodeCnt != eNodeCnt)
                            {
                                MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                        }
                        //FemElement femElement = new FemElement();
                        FemElement femElement = FemMeshLogic.CreateFemElementByElementNodeCnt(eNodeCnt);
                        femElement.No          = elemNo;
                        femElement.MediaIndex  = mediaIndex;
                        femElement.NodeNumbers = new int[eNodeCnt];
                        for (int n = 0; n < femElement.NodeNumbers.Length; n++)
                        {
                            femElement.NodeNumbers[n] = int.Parse(tokens[n + indexOffset]);
                        }
                        elements.Add(femElement);
                    }

                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Ports")
                    {
                        MessageBox.Show("入出力ポート情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int portCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < portCnt; i++)
                    {
                        line   = sr.ReadLine();
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2)
                        {
                            MessageBox.Show("入出力ポート情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        int portNo      = int.Parse(tokens[0]);
                        int portNodeCnt = int.Parse(tokens[1]);
                        if (portNo != i + 1)
                        {
                            MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                            return(false);
                        }
                        IList <int> portNodes = new List <int>();
                        for (int n = 0; n < portNodeCnt; n++)
                        {
                            line   = sr.ReadLine();
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 2)
                            {
                                MessageBox.Show("ポートの節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                            int portNodeNumber = int.Parse(tokens[0]);
                            int nodeNumber     = int.Parse(tokens[1]);
                            if (portNodeNumber != n + 1)
                            {
                                MessageBox.Show("ポートの節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                return(false);
                            }
                            portNodes.Add(nodeNumber);
                        }
                        ports.Add(portNodes);
                    }

                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "Force")
                    {
                        MessageBox.Show("強制境界情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    int forceNodeCnt = int.Parse(tokens[1]);
                    for (int i = 0; i < forceNodeCnt; i++)
                    {
                        line = sr.ReadLine();
                        int nodeNumber = int.Parse(line);
                        forceBCNodes.Add(nodeNumber);
                    }

                    line   = sr.ReadLine();
                    tokens = line.Split(delimiter);
                    if (tokens.Length != 2 || tokens[0] != "IncidentPortNo")
                    {
                        MessageBox.Show("入射ポート番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        return(false);
                    }
                    incidentPortNo = int.Parse(tokens[1]);

                    //////////////////////////////////////////
                    //// Ver1.1.0.0からの追加情報
                    //////////////////////////////////////////
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                        // 媒質情報なし
                        // ver1.0.0.0
                    }
                    else
                    {
                        // 媒質情報?
                        // ver1.1.0.0
                        tokens = line.Split(delimiter);
                        if (tokens[0] != "Medias")
                        {
                            MessageBox.Show("媒質情報がありません");
                            return(false);
                        }
                        int cnt = int.Parse(tokens[1]);
                        if (cnt > Constants.MaxMediaCount)
                        {
                            MessageBox.Show("媒質情報の個数が不正です");
                            return(false);
                        }
                        for (int i = 0; i < cnt; i++)
                        {
                            line = sr.ReadLine();
                            if (line.Length == 0)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return(false);
                            }
                            tokens = line.Split(delimiter);
                            if (tokens.Length != 1 + 9 + 9)
                            {
                                MessageBox.Show("媒質情報が不正です");
                                return(false);
                            }
                            int mediaIndex = int.Parse(tokens[0]);
                            System.Diagnostics.Debug.Assert(mediaIndex == i);

                            double[,] p = new double[3, 3];
                            for (int m = 0; m < p.GetLength(0); m++)
                            {
                                for (int n = 0; n < p.GetLength(1); n++)
                                {
                                    p[m, n] = double.Parse(tokens[1 + m * p.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetP(p);

                            double[,] q = new double[3, 3];
                            for (int m = 0; m < q.GetLength(0); m++)
                            {
                                for (int n = 0; n < q.GetLength(1); n++)
                                {
                                    q[m, n] = double.Parse(tokens[1 + 9 + m * q.GetLength(1) + n]);
                                }
                            }
                            medias[i].SetQ(q);
                        }
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 4 || tokens[0] != "WaveLengthRange")
                        {
                            MessageBox.Show("計算対象周波数情報がありません");
                            return(false);
                        }
                        firstWaveLength = double.Parse(tokens[1]);
                        lastWaveLength  = double.Parse(tokens[2]);
                        calcCnt         = int.Parse(tokens[3]);
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "LsEqnSolverDv")
                        {
                            MessageBox.Show("線形方程式解法区分情報がありません");
                            return(false);
                        }
                        string value = tokens[1];
                        lsEqnSoverDv = FemSolver.StrToLinearSystemEqnSolverDV(value);
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "WaveModeDv")
                        {
                            MessageBox.Show("計算対象モード区分情報がありません");
                            return(false);
                        }
                        if (tokens[1] == "TE")
                        {
                            waveModeDv = FemSolver.WaveModeDV.TE;
                        }
                        else if (tokens[1] == "TM")
                        {
                            waveModeDv = FemSolver.WaveModeDV.TM;
                        }
                        else
                        {
                            MessageBox.Show("計算対象モード区分情報が不正です");
                            return(false);
                        }
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "WGStructureDv")
                        {
                            MessageBox.Show("計算対象導波路構造区分情報がありません");
                            return(false);
                        }
                        wgStructureDv = FemSolver.StrToWGStructureDV(tokens[1]);
                    }
                    line = sr.ReadLine();
                    if (line == null || line.Length == 0)
                    {
                    }
                    else
                    {
                        tokens = line.Split(delimiter);
                        if (tokens.Length != 2 || tokens[0] != "WaveguideWidthForEPlane")
                        {
                            MessageBox.Show("E面解析用導波路幅がありません");
                            return(false);
                        }
                        waveguideWidthForEPlane = double.Parse(tokens[1]);
                    }
                }
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return(false);
            }

            return(true);
        }
 public object Clone()
 {
     MediaInfo media = new MediaInfo(this.p, this.q);
     media.BackColor = this.BackColor;
     return (object)media;
 }
        /////////////////////////////////////////////////////////////////////////////
        // 定数
        /////////////////////////////////////////////////////////////////////////////
        /////////////////////////////////////////////////////////////////////////////
        // 型
        /////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// 図面情報を保存する
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="editCad2D"></param>
        /// <param name="loopList"></param>
        /// <param name="edgeCollectionList"></param>
        /// <param name="incidentPortNo"></param>
        /// <param name="medias"></param>
        public static void SaveToFile(
            string filename,
            CCadObj2D editCad2D,
            IList<CadLogic.Loop> loopList,
            IList<EdgeCollection> edgeCollectionList,
            int incidentPortNo,
            MediaInfo[] medias
            )
        {
            // 番号順に並び替え
            ((List<EdgeCollection>)edgeCollectionList).Sort();

            try
            {
                // Cadオブジェクトデータファイル
                string basename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename);
                string cadObjFilename = basename + Constants.CadObjExt;

                // Cadオブジェクトデータを外部ファイルに書き込み
                using (CSerializer fout = new CSerializer(cadObjFilename, false))
                {
                    editCad2D.Serialize(fout);
                }

                // Cadデータの書き込み
                using (StreamWriter sw = new StreamWriter(filename))
                {
                    int counter;
                    string line;

                    // アプリケーションのバージョン番号
                    sw.WriteLine("AppVersion,{0}", MyUtilLib.MyUtil.getAppVersion());
                    // CadLogicの使用ユーティリティ名
                    sw.WriteLine("UseUtility,{0}", CadLogic.UseUtility);
                    //// ベースループID
                    //sw.WriteLine("BaseLoopId,{0}", baseLoopId);
                    // ループのリスト
                    counter = 0;
                    sw.WriteLine("LoopList,{0}", loopList.Count);
                    foreach (CadLogic.Loop loop in loopList)
                    {
                        sw.WriteLine("Loop,{0},{1},{2}", ++counter, loop.LoopId, loop.MediaIndex);
                    }
                    // ポートのエッジコレクションのリスト
                    counter = 0;
                    sw.WriteLine("EdgeCollectionList,{0}", edgeCollectionList.Count);
                    foreach (EdgeCollection edgeCollection in edgeCollectionList)
                    {
                        line = string.Format("EdgeCollection,{0},{1},{2},", ++counter, edgeCollection.No, edgeCollection.EdgeIds.Count);
                        foreach (uint eId in edgeCollection.EdgeIds)
                        {
                            line += string.Format("{0},", eId);
                        }
                        line = line.Remove(line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                    // 入射ポート番号
                    sw.WriteLine("IncidentPortNo,{0}", incidentPortNo);
                    // 媒質情報の個数
                    sw.WriteLine("Medias,{0}", medias.Length);
                    // 媒質情報の書き込み
                    for (int i = 0; i < medias.Length; i++)
                    {
                        MediaInfo media = medias[i];
                        line = string.Format("{0},", i);
                        double[,] p = media.P;
                        for (int m = 0; m < p.GetLength(0); m++)
                        {
                            for (int n = 0; n < p.GetLength(1); n++)
                            {
                                line += string.Format("{0},", p[m, n]);
                            }
                        }
                        double[,] q = media.Q;
                        for (int m = 0; m < q.GetLength(0); m++)
                        {
                            for (int n = 0; n < q.GetLength(1); n++)
                            {
                                line += string.Format("{0},", q[m, n]);
                            }
                        }
                        line = line.Remove(line.Length - 1); // 最後の,を削除
                        sw.WriteLine(line);
                    }
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                MessageBox.Show(exception.Message);
            }
        }