Пример #1
0
        /// <summary>
        /// 1次線要素を作成する(固有値問題用)
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="EdgeToElementNoH"></param>
        /// <param name="Elements"></param>
        /// <param name="elements"></param>
        public static void MkElements(
            IList <int> nodes,
            Dictionary <string, IList <int> > EdgeToElementNoH,
            IList <FemElement> Elements,
            ref IList <FemLineElement> elements)
        {
            // 要素内節点数
            const int nno = Constants.LineNodeCnt_FirstOrder; //2; // 1次線要素

            // 要素リスト作成
            int elemCnt = (nodes.Count - 1); // 1次線要素

            for (int elemIndex = 0; elemIndex < elemCnt; elemIndex++)
            {
                // 線要素の要素内節点
                // 節点番号はポート上の1D節点番号(1起点の番号)
                //  1   2
                //  +---+
                FemLineElement element = new FemLineElement();
                element.No             = elemIndex + 1;
                element.NodeNumbers    = new int[nno];
                element.NodeNumbers[0] = elemIndex + 1;
                element.NodeNumbers[1] = elemIndex + 1 + 1;
                element.MediaIndex     = 0;
                elements.Add(element);
            }

            // 要素を1辺とする2D領域の要素番号を取得
            for (int elemIndex = 0; elemIndex < elements.Count; elemIndex++)
            {
                FemElement element     = elements[elemIndex];
                int[]      nodeNumbers = element.NodeNumbers;

                // 1辺だけ調べればよい(1-2をチェック)
                int    stNodeNumber = nodes[nodeNumbers[0] - 1];
                int    edNodeNumber = nodes[nodeNumbers[1] - 1];
                string edgeKey      = "";
                if (stNodeNumber < edNodeNumber)
                {
                    edgeKey = string.Format("{0}_{1}", stNodeNumber, edNodeNumber);
                }
                else
                {
                    edgeKey = string.Format("{0}_{1}", edNodeNumber, stNodeNumber);
                }
                if (!EdgeToElementNoH.ContainsKey(edgeKey))
                {
                    System.Diagnostics.Debug.WriteLine("logical error: Not find edge {0}", edgeKey);
                }
                else
                {
                    // 隣接する2Dの要素を1つ取得する
                    int        elemNo2d  = EdgeToElementNoH[edgeKey][0];
                    FemElement element2d = Elements[elemNo2d - 1];

                    // 媒質インデックスをセット
                    element.MediaIndex = element2d.MediaIndex;
                }
            }
        }
 /// <summary>
 /// コピー
 /// </summary>
 /// <param name="src"></param>
 public override void CP(FemElement src)
 {
     if (src == this)
     {
         return;
     }
     // 基本クラスのコピー
     base.CP(src);
 }
 /// <summary>
 /// コピー
 /// </summary>
 /// <param name="src"></param>
 public override void CP(FemElement src)
 {
     if (src == this)
     {
         return;
     }
     // 基本クラスのコピー
     base.CP(src);
 }
        /// <summary>
        /// 要素の節点数から該当するFemElementインスタンスを作成する
        /// </summary>
        /// <param name="eNodeCnt"></param>
        /// <returns></returns>
        public static FemElement CreateFemElementByElementNodeCnt(int eNodeCnt)
        {
            FemElement femElement = null;
            Constants.FemElementShapeDV elemShapeDv;
            int order;
            int vertexCnt;
            GetElementShapeDvAndOrderByElemNodeCnt(eNodeCnt, out elemShapeDv, out order, out vertexCnt);

            if (vertexCnt == Constants.TriVertexCnt)
            {
                femElement = new FemTriElement();
            }
            else if (vertexCnt == Constants.QuadVertexCnt)
            {
                femElement = new FemQuadElement();
            }
            else
            {
                femElement = new FemElement();
            }
            return femElement;
        }
        /// <summary>
        /// コピー
        /// </summary>
        /// <param name="src"></param>
        public virtual void CP(FemElement src)
        {
            if (src == this)
            {
                return;
            }
            No          = src.No;
            NodeNumbers = null;
            if (src.NodeNumbers != null)
            {
                NodeNumbers = new int[src.NodeNumbers.Length];
                for (int i = 0; i < src.NodeNumbers.Length; i++)
                {
                    NodeNumbers[i] = src.NodeNumbers[i];
                }
            }
            MediaIndex = src.MediaIndex;
            LineColor  = src.LineColor;
            BackColor  = src.BackColor;

            // 内部使用のフィールドはコピーしない
            _Nodes            = null;
            _FValues          = null;
            _RotXFValues      = null;
            _RotYFValues      = null;
            _PoyntingXFValues = null;
            _PoyntingYFValues = null;
            _FactorForRot     = 1.0;
            _media_Q          = new double[, ]
            {
                { 1.0, 0.0, 0.0 },
                { 0.0, 1.0, 0.0 },
                { 0.0, 0.0, 1.0 },
            };
            _WaveModeDv       = FemSolver.WaveModeDV.TE;
            _WGStructureDv    = FemSolver.WGStructureDV.HPlane2D;
            IsCoarseFieldMesh = false;
        }
        /// <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];
                    }
                }
            }
        }
Пример #7
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>
 /// <param name="g"></param>
 /// <param name="ofs"></param>
 /// <param name="delta"></param>
 /// <param name="regionSize"></param>
 /// <param name="drawColor"></param>
 /// <param name="fieldDv"></param>
 /// <param name="minRotFValue"></param>
 /// <param name="maxRotFValue"></param>
 public virtual void DrawRotField(Graphics g, Size ofs, Size delta, Size regionSize, Color drawColor, FemElement.FieldDV fieldDv, double minRotFValue, double maxRotFValue)
 {
 }
 /// <summary>
 /// フィールド値を描画する
 /// </summary>
 /// <param name="g"></param>
 /// <param name="ofs"></param>
 /// <param name="delta"></param>
 /// <param name="regionSize"></param>
 /// <param name="fieldDv"></param>
 /// <param name="valueDv"></param>
 /// <param name="colorMap"></param>
 public virtual void DrawField(Graphics g, Size ofs, Size delta, Size regionSize, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv, ColorMap colorMap)
 {
 }
        /// <summary>
        /// フィールドの回転ベクトル描画
        /// </summary>
        /// <param name="g"></param>
        /// <param name="panel"></param>
        public void DrawRotFieldEx(Graphics g, Panel panel, Rectangle clientRectangle, FemElement.FieldDV fieldDv)
        {
            if (!isInputDataReady())
            {
                return;
            }
            if (!isOutputDataReady())
            {
                return;
            }
            Size delta;
            Size ofs;
            Size regionSize;
            //getFitDrawRegion(panel, out delta, out ofs, out regionSize);
            getFitDrawRegion(clientRectangle.Width, clientRectangle.Height, out delta, out ofs, out regionSize);
            ofs.Width += clientRectangle.Left;
            ofs.Height += clientRectangle.Top;

            Color drawColor = Color.Gray;
            double min = 0.0;
            double max = 1.0;
            if (fieldDv == FemElement.FieldDV.PoyntingXY)
            {
                drawColor = Color.Green;//Color.YellowGreen;
                min = -MaxPoyntingFValue;
                max = MaxPoyntingFValue;
            }
            else if (fieldDv == FemElement.FieldDV.RotXY)
            {
                drawColor = Color.Red;
                if (WGStructureDv == FemSolver.WGStructureDV.EPlane2D)
                {
                    drawColor = (WaveModeDv == FemSolver.WaveModeDV.TM) ? Color.Red : Color.Blue;
                }
                else
                {
                    drawColor = (WaveModeDv == FemSolver.WaveModeDV.TM) ? Color.Blue : Color.Red;
                }
                min = -MaxRotFValue;
                max = MaxRotFValue;
            }
            else
            {
                return;
            }
            foreach (FemElement element in Elements)
            {
                // 回転ベクトル描画
                element.DrawRotField(g, ofs, delta, regionSize, drawColor, fieldDv, min, max);
            }
        }
        /// <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>
        /// 三角形要素:点が要素内に含まれる?
        /// </summary>
        /// <param name="element">要素</param>
        /// <param name="test_pp">テストする点</param>
        /// <param name="Nodes">節点リスト(要素は座標を持たないので節点リストが必要)</param>
        /// <returns></returns>
        public static bool TriElement_IsPointInElement(FemElement element, double[] test_pp, IList<FemNode> nodes)
        {
            bool hit = false;

            // 三角形の頂点数
            const int vertexCnt = Constants.TriVertexCnt;
            double[][] pps = new double[vertexCnt][];
            // 2次三角形要素の最初の3点=頂点の座標を取得
            for (int ino = 0; ino < vertexCnt; ino++)
            {
                int nodeNumber = element.NodeNumbers[ino];
                FemNode node = nodes[nodeNumber - 1];
                System.Diagnostics.Debug.Assert(node.No == nodeNumber);
                pps[ino] = node.Coord;
            }
            // バウンディングボックス取得
            double minX = double.MaxValue;
            double maxX = double.MinValue;
            double minY = double.MaxValue;
            double maxY = double.MinValue;
            foreach (double[] pp in pps)
            {
                double xx = pp[0];
                double yy = pp[1];
                if (minX > xx)
                {
                    minX = xx;
                }
                if (maxX < xx)
                {
                    maxX = xx;
                }
                if (minY > yy)
                {
                    minY = yy;
                }
                if (maxY < yy)
                {
                    maxY = yy;
                }
            }
            // バウンディングボックスでチェック
            if (test_pp[0] < minX || test_pp[0] > maxX)
            {
                return hit;
            }
            if (test_pp[1] < minY || test_pp[1] > maxY)
            {
                return hit;
            }

            // 頂点?
            foreach (double[] pp in pps)
            {
                if (Math.Abs(pp[0] - test_pp[0]) < Constants.PrecisionLowerLimit && Math.Abs(pp[1] - test_pp[1]) < Constants.PrecisionLowerLimit)
                {
                    hit = true;
                    break;
                }
            }
            if (!hit)
            {
                // 面積から内部判定する
                double area = KerEMatTri.TriArea(pps[0], pps[1], pps[2]);
                double sumOfSubArea = 0.0;
                for (int ino = 0; ino < vertexCnt; ino++)
                {
                    double[][] subArea_pp = new double[vertexCnt][];
                    subArea_pp[0] = pps[ino];
                    subArea_pp[1] = pps[(ino + 1) % vertexCnt];
                    subArea_pp[2] = test_pp;
                    //foreach (double[] work_pp in subArea_pp)
                    //{
                    //    System.Diagnostics.Debug.Write("{0},{1}  ", work_pp[0], work_pp[1]);
                    //}
                    double subArea = KerEMatTri.TriArea(subArea_pp[0], subArea_pp[1], subArea_pp[2]);
                    //System.Diagnostics.Debug.Write("  subArea = {0}", subArea);
                    //System.Diagnostics.Debug.WriteLine();
                    //BUGFIX
                    //if (subArea <= 0.0)
                    // 丁度辺上の場合は、サブエリアの1つが0になるのでこれは許可しないといけない
                    if (subArea < -1.0 * Constants.PrecisionLowerLimit)  // 0未満
                    {
                        sumOfSubArea = 0.0;
                        break;
                        // 外側?
                    }
                    sumOfSubArea += Math.Abs(subArea);
                }
                if (Math.Abs(area - sumOfSubArea) < Constants.PrecisionLowerLimit)
                {
                    hit = true;
                }
            }
            return hit;
        }
        /// <summary>
        /// 点が要素内に含まれる?
        /// </summary>
        /// <param name="element">要素</param>
        /// <param name="test_pp">テストする点</param>
        /// <param name="Nodes">節点リスト(要素は座標を持たないので節点リストが必要)</param>
        /// <returns></returns>
        public static bool IsPointInElement(FemElement element, double[] test_pp, IList<FemNode> nodes)
        {
            bool hit = false;
            int eNodeCnt = element.NodeNumbers.Length;
            Constants.FemElementShapeDV elemShapeDv;
            int order;
            int vertexCnt;
            GetElementShapeDvAndOrderByElemNodeCnt(eNodeCnt, out elemShapeDv, out order, out vertexCnt);

            if (vertexCnt == Constants.TriVertexCnt)
            {
                // 2次/1次三角形要素
                hit = TriElement_IsPointInElement(element, test_pp, nodes);
            }
            else if (vertexCnt == Constants.QuadVertexCnt)
            {
                // 2次/1次四角形要素
                hit = QuadElement_IsPointInElement(element, test_pp, nodes);
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
            }
            return hit;
        }
Пример #14
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);
        }
        /// <summary>
        /// フィールド値の回転を描画する
        /// </summary>
        /// <param name="g"></param>
        /// <param name="ofs"></param>
        /// <param name="delta"></param>
        /// <param name="regionSize"></param>
        /// <param name="drawColor"></param>
        /// <param name="fieldDv"></param>
        /// <param name="minRotFValue"></param>
        /// <param name="maxRotFValue"></param>
        public override void DrawRotField(Graphics g, Size ofs, Size delta, Size regionSize, Color drawColor, FemElement.FieldDV fieldDv, double minRotFValue, double maxRotFValue)
        {
            if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null)
            {
                return;
            }
            Complex[] tagtXValues = null;
            Complex[] tagtYValues = null;
            if (fieldDv == FemElement.FieldDV.PoyntingXY)
            {
                tagtXValues = _PoyntingXFValues;
                tagtYValues = _PoyntingYFValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotXY)
            {
                tagtXValues = _RotXFValues;
                tagtYValues = _RotYFValues;
            }
            else
            {
                return;
            }

            const int ndim = Constants.CoordDim2D; //2;      // 座標の次元数
            const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ)
            //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6;  // 三角形2次要素
            int nodeCnt = NodeNumbers.Length;
            if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder)
            {
                return;
            }
            // 三角形の節点座標を取得
            double[][] pp = new double[nodeCnt][];
            for (int ino = 0; ino < pp.GetLength(0); ino++)
            {
                FemNode node = _Nodes[ino];
                System.Diagnostics.Debug.Assert(node.Coord.Length == ndim);
                pp[ino] = new double[ndim];
                pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width;
                pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height;
            }

            // 表示する位置の面積座標
            double[] Li = new double[vertexCnt]
                {
                    1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0
                };
            // 表示する位置の形状関数
            double[] vNi = null;
            if (nodeCnt == Constants.TriNodeCnt_FirstOrder)
            {
                vNi = new double[]
                            {
                                Li[0],
                                Li[1],
                                Li[2]
                            };
            }
            else
            {
                vNi = new double[]
                            {
                                Li[0] * (2.0 * Li[0] - 1.0),
                                Li[1] * (2.0 * Li[1] - 1.0),
                                Li[2] * (2.0 * Li[2] - 1.0),
                                4.0 * Li[0] * Li[1],
                                4.0 * Li[1] * Li[2],
                                4.0 * Li[2] * Li[0],
                            };
            }
            // 表示する位置
            double showPosX = 0;
            double showPosY = 0;
            for (int k = 0; k < nodeCnt; k++)
            {
                showPosX += pp[k][0] * vNi[k];
                showPosY += pp[k][1] * vNi[k];
            }
            Complex cvalueX = new Complex(0, 0);
            Complex cvalueY = new Complex(0, 0);
            for (int k = 0; k < nodeCnt; k++)
            {
                cvalueX += tagtXValues[k] * vNi[k];
                cvalueY += tagtYValues[k] * vNi[k];
            }
            try
            {
                double showScale = ((double)regionSize.Width / DefPanelWidth) * ArrowLength;
                // 実数部のベクトル表示
                int lenX = 0;
                int lenY = 0;
                if (Math.Abs(maxRotFValue) >= Constants.PrecisionLowerLimit)
                {
                    lenX = (int)((double)(cvalueX.Real / maxRotFValue) * showScale);
                    lenY = (int)((double)(cvalueY.Real / maxRotFValue) * showScale);
                }
                if (lenX != 0 || lenY != 0)
                {
                    // Y方向は表示上逆になる
                    lenY = -lenY;
                    using (Pen pen = new Pen(drawColor, 1))
                    {
                        //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                        //pen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
                        pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                        //pen.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(3, 3, false); // 重い
                        g.DrawLine(pen, (int)showPosX, (int)showPosY, (int)(showPosX + lenX), (int)(showPosY + lenY));
                    }
                }
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
            }
        }
        /// <summary>
        /// フィールド値を描画する
        /// </summary>
        /// <param name="g"></param>
        /// <param name="ofs"></param>
        /// <param name="delta"></param>
        /// <param name="regionSize"></param>
        /// <param name="fieldDv"></param>
        /// <param name="valueDv"></param>
        /// <param name="colorMap"></param>
        /*
        public override void DrawField(Graphics g, Size ofs, Size delta, Size regionSize, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv, ColorMap colorMap)
        {
            //base.DrawField(g, ofs, delta, regionSize, colorMap);
            if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null)
            {
                return;
            }
            Complex[] tagtValues = null;
            if (fieldDv == FemElement.FieldDV.Field)
            {
                tagtValues = _FValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotX)
            {
                tagtValues = _RotXFValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotY)
            {
                tagtValues = _RotYFValues;
            }
            else
            {
                return;
            }

            const int ndim = Constants.CoordDim2D; //2;      // 座標の次元数
            const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ)
            //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6;  // 三角形2次要素
            int nodeCnt = NodeNumbers.Length;
            if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder)
            {
                return;
            }
            // 三角形の節点座標を取得
            double[][] pp = new double[nodeCnt][];
            for (int ino = 0; ino < pp.GetLength(0); ino++)
            {
                FemNode node = _Nodes[ino];
                System.Diagnostics.Debug.Assert(node.Coord.Length == ndim);
                pp[ino] = new double[ndim];
                pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width;
                pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height;
            }

            // 下記分割ロジックの原点となる頂点
            //   頂点0固定で計算していたが、原点の内角が直角のとき長方形メッシュになるので原点を2(頂点を0,1,2としたとき)にする
            int orginVertexNo = 2;
            // 内角が最大の頂点を取得し、その頂点を原点とする(後のロジックは原点が頂点を0,1,2としたとき、2になっている
            {
                double minCosth = double.MaxValue;
                int minCosthVertexNo = 0;
                for (int ino = 0; ino < vertexCnt; ino++)
                {
                    const int vecCnt = 2;
                    double[][] vec = new double[vecCnt][] { new double[ndim]{0, 0}, new double[ndim]{0, 0} };
                    double[] len = new double[vecCnt];
                    double costh;
                    {
                        int n1 = ino;
                        int n2 = (ino + 1) % 3;
                        int n3 = (ino + 2) % 3;
                        vec[0][0] = pp[n2][0] - pp[n1][0];
                        vec[0][1] = pp[n2][1] - pp[n1][1];
                        vec[1][0] = pp[n3][0] - pp[n1][0];
                        vec[1][1] = pp[n3][1] - pp[n1][1];
                        len[0] = FemMeshLogic.GetDistance(pp[n1], pp[n2]);
                        len[1] = FemMeshLogic.GetDistance(pp[n1], pp[n3]);
                        costh = (vec[0][0] * vec[1][0] + vec[0][1] * vec[1][1]) / (len[0] * len[1]);
                        if (costh < minCosth)
                        {
                            minCosth = costh;
                            minCosthVertexNo = ino;
                        }
                    }
                }
                orginVertexNo = (minCosthVertexNo + 2) % 3;
            }
            // 三角形内部を四角形で分割
            // 面積座標L1方向分割数
            //int ndiv = 4;
            int ndiv = Constants.TriDrawFieldMshDivCnt;
            double defdL1 = 1.0 / (double)ndiv;
            double defdL2 = defdL1;
            for (int i1 = 0; i1 < ndiv; i1++)
            {
                double vL1 = i1 * defdL1;
                double vL1Next = (i1 + 1) * defdL1;
                if (i1 == ndiv - 1)
                {
                    vL1Next = 1.0;
                }
                double vL2max = 1.0 - vL1;
                if (vL2max < 0.0)
                {
                    // ERROR
                    Console.WriteLine("logic error vL2max = {0}", vL2max);
                    continue;
                }
                double fdiv2 = (double)ndiv * vL2max;
                int ndiv2 = (int)fdiv2;
                if (fdiv2 - (double)ndiv2 > Constants.PrecisionLowerLimit)
                {
                    ndiv2++;
                }
                for (int i2 = 0; i2 < ndiv2; i2++)
                {
                    double vL2 = i2 * defdL2;
                    double vL2Next = (i2 + 1) * defdL2;
                    if (i2 == ndiv2 - 1)
                    {
                        vL2Next = vL2max;
                    }
                    double vL3 = 1.0 - vL1 - vL2;
                    if (vL3 < 0.0)
                    {
                        // ERROR
                        Console.WriteLine("logic error vL3 = {0}", vL3);
                        continue;
                    }

                    // 四角形の頂点
                    const int rectVCnt = 4;
                    double[][] rectLi = new double[rectVCnt][]
                    {
                        new double[]{vL1    , vL2    , 0},
                        new double[]{vL1Next, vL2    , 0},
                        new double[]{vL1Next, vL2Next, 0},
                        new double[]{vL1    , vL2Next, 0}
                    };
                    if ((i1 == ndiv - 1) || (i2 == ndiv2 - 1))
                    {
                        for (int k = 0; k < 3; k++)
                        {
                            rectLi[2][k] = rectLi[3][k];
                        }
                    }
                    double[][] rectpp = new double[rectVCnt][];
                    for (int ino = 0; ino < rectVCnt; ino++)
                    {
                        if (rectLi[ino][0] < 0.0)
                        {
                            rectLi[ino][0] = 0.0;
                            Console.WriteLine("logical error rectLi[{0}][0] = {1}", ino, rectLi[ino][0]);
                        }
                        if (rectLi[ino][0] > 1.0)
                        {
                            rectLi[ino][0] = 1.0;
                            Console.WriteLine("logical error rectLi[{0}][0] = {1}", ino, rectLi[ino][0]);
                        }
                        if (rectLi[ino][1] < 0.0)
                        {
                            rectLi[ino][1] = 0.0;
                            Console.WriteLine("logical error rectLi[{0}][1] = {1}", ino, rectLi[ino][1]);
                        }
                        if (rectLi[ino][1] > (1.0 - rectLi[ino][0]))  // L2最大値(1 - L1)チェック
                        {
                            rectLi[ino][1] = 1.0 - rectLi[ino][0];
                        }
                        rectLi[ino][2] = 1.0 - rectLi[ino][0] - rectLi[ino][1];
                        if (rectLi[ino][2] < 0.0)
                        {
                            Console.WriteLine("logical error rectLi[{0}][2] = {1}", ino, rectLi[ino][2]);
                        }
                    }
                    for (int ino = 0; ino < rectVCnt; ino++)
                    {
                        double[] vLpp = rectLi[ino];
                        double xx = 0.0;
                        double yy = 0.0;
                        for (int k = 0; k < vertexCnt; k++)
                        {
                            xx += pp[k][0] * vLpp[(k + orginVertexNo) % vertexCnt];
                            yy += pp[k][1] * vLpp[(k + orginVertexNo) % vertexCnt];
                        }
                        rectpp[ino] = new double[] { xx, yy };
                    }
                    // 表示する位置
                    double[] vLi = new double[] { (rectLi[0][0] + rectLi[1][0]) * 0.5, (rectLi[0][1] + rectLi[3][1]) * 0.5, 0 };
                    if (vLi[0] < 0.0)
                    {
                        vLi[0] = 0.0;
                    }
                    if (vLi[0] > 1.0)
                    {
                        vLi[0] = 1.0;
                    }
                    if (vLi[1] < 0.0)
                    {
                        vLi[1] = 0.0;
                    }
                    if (vLi[1] > (1.0 - vLi[0]))
                    {
                        vLi[1] = (1.0 - vLi[0]);
                    }
                    vLi[2] = 1.0 - vLi[0] - vLi[1];
                    if (vLi[2] < 0.0)
                    {
                        Console.WriteLine("logic error vLi[2] = {0}", vLi[2]);
                    }

                    // 表示する値
                    Complex cvalue = new Complex(0.0, 0.0);
                    // 表示する位置の形状関数値
                    double[] vNi = null;
                    double[] shiftedLi = new double[vertexCnt];
                    for (int i = 0; i < vertexCnt; i++)
                    {
                        shiftedLi[i] = vLi[(i + orginVertexNo) % vertexCnt];
                    }
                    if (nodeCnt == Constants.TriNodeCnt_FirstOrder)
                    {
                        vNi = new double[]
                            {
                                shiftedLi[0],
                                shiftedLi[1],
                                shiftedLi[2]
                            };
                    }
                    else
                    {
                        vNi = new double[]
                            {
                                shiftedLi[0] * (2.0 * shiftedLi[0] - 1.0),
                                shiftedLi[1] * (2.0 * shiftedLi[1] - 1.0),
                                shiftedLi[2] * (2.0 * shiftedLi[2] - 1.0),
                                4.0 * shiftedLi[0] * shiftedLi[1],
                                4.0 * shiftedLi[1] * shiftedLi[2],
                                4.0 * shiftedLi[2] * shiftedLi[0],
                            };
                    }

                    for (int k = 0; k < nodeCnt; k++)
                    {
                        cvalue += tagtValues[k] * vNi[k];
                    }
                    // 四角形の頂点(描画用)
                    Point[] rectp = new Point[rectVCnt];
                    for (int ino = 0; ino < rectVCnt; ino++)
                    {
                        rectp[ino] = new Point((int)rectpp[ino][0], (int)rectpp[ino][1]);
                    }
                    try
                    {
                        // 表示する値
                        double showValue = 0.0;
                        if (valueDv == ValueDV.Real)
                        {
                            showValue = cvalue.Real;
                        }
                        else if (valueDv == ValueDV.Imaginary)
                        {
                            showValue = cvalue.Imaginary;
                        }
                        else
                        {
                            // 既定値は絶対値
                            showValue = Complex.Abs(cvalue);
                        }
                        // 塗りつぶし色の取得
                        Color fillColor = colorMap.GetColor(showValue);
                        // 塗りつぶし
                        using (Brush brush = new SolidBrush(fillColor))
                        {
                            g.FillPolygon(brush, rectp);
                        }
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception.Message + " " + exception.StackTrace);
                    }
                }
            }
        }
        */
        public override void DrawField(Graphics g, Size ofs, Size delta, Size regionSize, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv, ColorMap colorMap)
        {
            //base.DrawField(g, ofs, delta, regionSize, colorMap);
            if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null)
            {
                return;
            }
            Complex[] tagtValues = null;
            if (fieldDv == FemElement.FieldDV.Field)
            {
                tagtValues = _FValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotX)
            {
                tagtValues = _RotXFValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotY)
            {
                tagtValues = _RotYFValues;
            }
            else
            {
                return;
            }

            const int ndim = Constants.CoordDim2D; //2;      // 座標の次元数
            const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ)
            //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6;  // 三角形2次要素
            int nodeCnt = NodeNumbers.Length;
            if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder)
            {
                return;
            }
            // 三角形の節点座標を取得
            double[][] pp = new double[nodeCnt][];
            for (int ino = 0; ino < pp.GetLength(0); ino++)
            {
                FemNode node = _Nodes[ino];
                System.Diagnostics.Debug.Assert(node.Coord.Length == ndim);
                pp[ino] = new double[ndim];
                pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width;
                pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height;
            }

            // 長方形描画領域のリスト
            IList<double[][]> rectLiList = _RectLiList;
            // 描画ロジック上の原点となる頂点
            int orginVertexNo = _OrginVertexNo;

            // 四角形の頂点
            const int rectVCnt = 4;
            foreach (double[][] rectLi in rectLiList)
            {
                double[][] rectpp = new double[rectVCnt][];
                for (int ino = 0; ino < rectVCnt; ino++)
                {
                    double[] vLpp = rectLi[ino];
                    double xx = 0.0;
                    double yy = 0.0;
                    for (int k = 0; k < vertexCnt; k++)
                    {
                        xx += pp[k][0] * vLpp[(k + orginVertexNo) % vertexCnt];
                        yy += pp[k][1] * vLpp[(k + orginVertexNo) % vertexCnt];
                    }
                    rectpp[ino] = new double[] { xx, yy };
                }
                // 表示する位置
                double[] vLi = new double[] { (rectLi[0][0] + rectLi[1][0]) * 0.5, (rectLi[0][1] + rectLi[3][1]) * 0.5, 0 };
                if (vLi[0] < 0.0)
                {
                    vLi[0] = 0.0;
                }
                if (vLi[0] > 1.0)
                {
                    vLi[0] = 1.0;
                }
                if (vLi[1] < 0.0)
                {
                    vLi[1] = 0.0;
                }
                if (vLi[1] > (1.0 - vLi[0]))
                {
                    vLi[1] = (1.0 - vLi[0]);
                }
                vLi[2] = 1.0 - vLi[0] - vLi[1];
                if (vLi[2] < 0.0)
                {
                    Console.WriteLine("logic error vLi[2] = {0}", vLi[2]);
                }
                // 表示する値
                Complex cvalue = new Complex(0.0, 0.0);
                // 表示する位置の形状関数値
                double[] vNi = null;
                double[] shiftedLi = new double[vertexCnt];
                for (int i = 0; i < vertexCnt; i++)
                {
                    shiftedLi[i] = vLi[(i + orginVertexNo) % vertexCnt];
                }
                if (nodeCnt == Constants.TriNodeCnt_FirstOrder)
                {
                    vNi = new double[]
                            {
                                shiftedLi[0],
                                shiftedLi[1],
                                shiftedLi[2]
                            };
                }
                else
                {
                    vNi = new double[]
                            {
                                shiftedLi[0] * (2.0 * shiftedLi[0] - 1.0),
                                shiftedLi[1] * (2.0 * shiftedLi[1] - 1.0),
                                shiftedLi[2] * (2.0 * shiftedLi[2] - 1.0),
                                4.0 * shiftedLi[0] * shiftedLi[1],
                                4.0 * shiftedLi[1] * shiftedLi[2],
                                4.0 * shiftedLi[2] * shiftedLi[0],
                            };
                }
                for (int k = 0; k < nodeCnt; k++)
                {
                    cvalue += tagtValues[k] * vNi[k];
                }
                // 四角形の頂点(描画用)
                Point[] rectp = new Point[rectVCnt];
                for (int ino = 0; ino < rectVCnt; ino++)
                {
                    rectp[ino] = new Point((int)rectpp[ino][0], (int)rectpp[ino][1]);
                }
                try
                {
                    // 表示する値
                    double showValue = 0.0;
                    if (valueDv == ValueDV.Real)
                    {
                        showValue = cvalue.Real;
                    }
                    else if (valueDv == ValueDV.Imaginary)
                    {
                        showValue = cvalue.Imaginary;
                    }
                    else
                    {
                        // 既定値は絶対値
                        showValue = Complex.Abs(cvalue);
                    }
                    // 塗りつぶし色の取得
                    Color fillColor = colorMap.GetColor(showValue);
                    // 塗りつぶし
                    using (Brush brush = new SolidBrush(fillColor))
                    {
                        g.FillPolygon(brush, rectp);
                    }
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message + " " + exception.StackTrace);
                }
            }
        }
        /* 数値積分版
        /// <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="g"></param>
        private void drawFValueLegendColorScale(Graphics g, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv)
        {
            const int cnt = LegendColorCnt;
            const int ofsX = 22;
            const int ofsY = 0;
            const int height = 20; // 1目盛の高さ
            //double divValue = 1.0 / (double)cnt;
            double min = 0.0;
            double max = 1.0;
            if (fieldDv == FemElement.FieldDV.Field)
            {
                min = MinFValue;
                max = MaxFValue;
            }
            else if (fieldDv == FemElement.FieldDV.RotX || fieldDv == FemElement.FieldDV.RotY)
            {
                min = MinRotFValue;
                max = MaxRotFValue;
            }
            else
            {
                return;
            }
            if (valueDv == FemElement.ValueDV.Abs)
            {
            }
            else
            {
                min = -max;
            }
            double divValue = (max - min) / (double)cnt;

            using (Font font = new Font("MS UI Gothic", 9))
            using (Brush brush = new SolidBrush(FValueLegendColorPanel.ForeColor))
            {
                for (int i = 0; i < cnt + 1; i++)
                {
                    int y = i * height;
                    double value = min + (cnt - i) * divValue;
                    string text = string.Format("{0:E3}", value);
                    g.DrawString(text, font, brush, new Point(ofsX, y + ofsY));
                }
            }
        }
        /// <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];
                    }
                }
            }
        }
        /// <summary>
        /// フィールド値の回転を描画する
        /// </summary>
        /// <param name="g"></param>
        /// <param name="ofs"></param>
        /// <param name="delta"></param>
        /// <param name="regionSize"></param>
        /// <param name="drawColor"></param>
        /// <param name="fieldDv"></param>
        /// <param name="minRotFValue"></param>
        /// <param name="maxRotFValue"></param>
        public override void DrawRotField(Graphics g, Size ofs, Size delta, Size regionSize, Color drawColor, FemElement.FieldDV fieldDv, double minRotFValue, double maxRotFValue)
        {
            if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null)
            {
                return;
            }
            Complex[] tagtXValues = null;
            Complex[] tagtYValues = null;
            if (fieldDv == FemElement.FieldDV.PoyntingXY)
            {
                tagtXValues = _PoyntingXFValues;
                tagtYValues = _PoyntingYFValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotXY)
            {
                tagtXValues = _RotXFValues;
                tagtYValues = _RotYFValues;
            }
            else
            {
                return;
            }

            const int ndim = Constants.CoordDim2D; //2;      // 座標の次元数
            //const int vertexCnt = Constants.QuadVertexCnt; //4; // 四角形形の頂点の数(2次要素でも同じ)
            //const int nodeCnt = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 四角形形2次要素
            int nodeCnt = NodeNumbers.Length;
            if (nodeCnt != Constants.QuadNodeCnt_SecondOrder_Type2 && nodeCnt != Constants.QuadNodeCnt_FirstOrder)
            {
                return;
            }

            // 四角形の節点座標を取得
            double[][] pp = new double[nodeCnt][];
            for (int ino = 0; ino < pp.GetLength(0); ino++)
            {
                FemNode node = _Nodes[ino];
                System.Diagnostics.Debug.Assert(node.Coord.Length == ndim);
                pp[ino] = new double[ndim];
                pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width;
                pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height;
            }
            // 四角形内部を四角形で分割
            // 要素節点座標( 局所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
                };

            // 節点上のrot(Ez)を求める
            int nno = nodeCnt;
            {
                double r = 0;
                double s = 0;

                // 形状関数
                double[] N = new double[nno];
                if (nodeCnt == Constants.QuadNodeCnt_SecondOrder_Type2)
                {
                    // 節点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);
                    }
                    // 節点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);
                    }
                    // 節点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);
                    }
                }
                else if (nodeCnt == Constants.QuadNodeCnt_FirstOrder)
                {
                    // 節点0~3 : 四角形の頂点
                    for (int i = 0; i < nno; 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);
                    }
                }
                // 表示する位置
                double showPosX = 0;
                double showPosY = 0;
                for (int k = 0; k < nodeCnt; k++)
                {
                    showPosX += pp[k][0] * N[k];
                    showPosY += pp[k][1] * N[k];
                }
                Complex cvalueX = new Complex(0, 0);
                Complex cvalueY = new Complex(0, 0);
                for (int k = 0; k < nodeCnt; k++)
                {
                    cvalueX += tagtXValues[k] * N[k];
                    cvalueY += tagtYValues[k] * N[k];
                }
                try
                {
                    double showScale = ((double)regionSize.Width / DefPanelWidth) * ArrowLength;
                    // 実数部のベクトル表示
                    int lenX = (int)((double)(cvalueX.Real / maxRotFValue) * showScale);
                    int lenY = (int)((double)(cvalueY.Real / maxRotFValue) * showScale);
                    if (lenX != 0 || lenY != 0)
                    {
                        // Y方向は表示上逆になる
                        lenY = -lenY;
                        using (Pen pen = new Pen(drawColor, 1))
                        {
                            //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot;
                            //pen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
                            pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor;
                            //pen.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(3, 3, false); // 重い
                            g.DrawLine(pen, (int)showPosX, (int)showPosY, (int)(showPosX + lenX), (int)(showPosY + lenY));
                        }
                    }
                }
                catch (Exception exception)
                {
                    Console.WriteLine(exception.Message + " " + exception.StackTrace);
                }
            }
        }
        /// <summary>
        /// 四角形要素:点が要素内に含まれる?
        /// </summary>
        /// <param name="element">要素</param>
        /// <param name="test_pp">テストする点</param>
        /// <param name="Nodes">節点リスト(要素は座標を持たないので節点リストが必要)</param>
        /// <returns></returns>
        public static bool QuadElement_IsPointInElement(FemElement element, double[] test_pp, IList<FemNode> nodes)
        {
            bool hit = false;

            // 四角形の頂点数
            const int vertexCnt = Constants.QuadVertexCnt;
            double[][] pps = new double[vertexCnt][];
            int[] nodeNumbers = new int[vertexCnt];
            // 2次四角形要素の最初の4点=頂点の座標を取得
            for (int ino = 0; ino < vertexCnt; ino++)
            {
                int nodeNumber = element.NodeNumbers[ino];
                FemNode node = nodes[nodeNumber - 1];
                System.Diagnostics.Debug.Assert(node.No == nodeNumber);
                pps[ino] = node.Coord;
                nodeNumbers[ino] = nodeNumber;
            }
            // バウンディングボックス取得
            double minX = double.MaxValue;
            double maxX = double.MinValue;
            double minY = double.MaxValue;
            double maxY = double.MinValue;
            foreach (double[] pp in pps)
            {
                double xx = pp[0];
                double yy = pp[1];
                if (minX > xx)
                {
                    minX = xx;
                }
                if (maxX < xx)
                {
                    maxX = xx;
                }
                if (minY > yy)
                {
                    minY = yy;
                }
                if (maxY < yy)
                {
                    maxY = yy;
                }
            }
            // バウンディングボックスでチェック
            if (test_pp[0] < minX || test_pp[0] > maxX)
            {
                return hit;
            }
            if (test_pp[1] < minY || test_pp[1] > maxY)
            {
                return hit;
            }

            // 2つの三角形に分ける
            //        s
            //        |
            //    3+  +  +2
            //    |   |   |
            // ---|---+---|-->r
            //    |   |   |
            //    0+  +  +1
            //        |
            FemElement[] tris = new FemElement[2];
            tris[0] = new FemElement();
            tris[0].NodeNumbers = new int[] { nodeNumbers[0], nodeNumbers[1], nodeNumbers[3], 0, 0, 0 };
            tris[1] = new FemElement();
            tris[1].NodeNumbers = new int[] { nodeNumbers[2], nodeNumbers[3], nodeNumbers[1], 0, 0, 0 };
            foreach (FemElement tri in tris)
            {
                bool hitInsideTri = TriElement_IsPointInElement(tri, test_pp, nodes);
                if (hitInsideTri)
                {
                    hit = true;
                    break;
                }
            }
            return hit;
        }
        /// <summary>
        /// フィールド値等高線図描画
        /// </summary>
        /// <param name="g"></param>
        /// <param name="panel"></param>
        public void DrawFieldEx(Graphics g, Panel panel, Rectangle clientRectangle, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv)
        {
            if (!isInputDataReady())
            {
                return;
            }
            if (!isOutputDataReady())
            {
                return;
            }
            Size delta;
            Size ofs;
            Size regionSize;
            //getFitDrawRegion(panel, out delta, out ofs, out regionSize);
            getFitDrawRegion(clientRectangle.Width, clientRectangle.Height, out delta, out ofs, out regionSize);
            ofs.Width += clientRectangle.Left;
            ofs.Height += clientRectangle.Top;

            double min = 0.0;
            double max = 1.0;
            if (fieldDv == FemElement.FieldDV.Field)
            {
                min = MinFValue;
                max = MaxFValue;
            }
            else if (fieldDv == FemElement.FieldDV.RotX || fieldDv == FemElement.FieldDV.RotY)
            {
                min = MinRotFValue;
                max = MaxRotFValue;
            }
            else
            {
                return;
            }

            // カラーマップに最小、最大を設定
            if (valueDv == FemElement.ValueDV.Real || valueDv == FemElement.ValueDV.Imaginary)
            {
                FValueColorMap.Min = -max;
                FValueColorMap.Max = max;
            }
            else
            {
                // 既定値は絶対値で処理する
                //FValueColorMap.Min = min;
                FValueColorMap.Min = 0.0;
                FValueColorMap.Max = max;
            }

            foreach (FemElement element in Elements)
            {
                // 等高線描画
                element.DrawField(g, ofs, delta, regionSize, fieldDv, valueDv, FValueColorMap);
            }
        }
Пример #23
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];
                    }
                }
            }
        }
        /// <summary>
        /// コピー
        /// </summary>
        /// <param name="src"></param>
        public virtual void CP(FemElement src)
        {
            if (src == this)
            {
                return;
            }
            No = src.No;
            NodeNumbers = null;
            if (src.NodeNumbers != null)
            {
                NodeNumbers = new int[src.NodeNumbers.Length];
                for (int i = 0; i < src.NodeNumbers.Length; i++)
                {
                    NodeNumbers[i] = src.NodeNumbers[i];
                }
            }
            MediaIndex = src.MediaIndex;
            LineColor = src.LineColor;
            BackColor = src.BackColor;

            // 内部使用のフィールドはコピーしない
            _Nodes = null;
            _FValues = null;
            _RotXFValues = null;
            _RotYFValues = null;
            _PoyntingXFValues = null;
            _PoyntingYFValues = null;
            _FactorForRot = 1.0;
            _media_Q = new double[,]
                {
                    {1.0, 0.0, 0.0},
                    {0.0, 1.0, 0.0},
                    {0.0, 0.0, 1.0},
                };
            _WaveModeDv = FemSolver.WaveModeDV.TE;
            _WGStructureDv = FemSolver.WGStructureDV.HPlane2D;
            IsCoarseFieldMesh = false;
        }
        /// <summary>
        /// フィールド値を描画する
        /// </summary>
        /// <param name="g"></param>
        /// <param name="ofs"></param>
        /// <param name="delta"></param>
        /// <param name="regionSize"></param>
        /// <param name="colorMap"></param>
        /// <param name="valueDv"></param>
        public override void DrawField(Graphics g, Size ofs, Size delta, Size regionSize, FemElement.FieldDV fieldDv, FemElement.ValueDV valueDv, ColorMap colorMap)
        {
            //base.DrawField(g, ofs, delta, regionSize, colorMap);
            if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null)
            {
                return;
            }
            Complex[] tagtValues = null;
            if (fieldDv == FemElement.FieldDV.Field)
            {
                tagtValues = _FValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotX)
            {
                tagtValues = _RotXFValues;
            }
            else if (fieldDv == FemElement.FieldDV.RotY)
            {
                tagtValues = _RotYFValues;
            }
            else
            {
                return;
            }

            const int ndim = Constants.CoordDim2D; //2;      // 座標の次元数
            const int vertexCnt = Constants.QuadVertexCnt; //3; // 四角形形の頂点の数(2次要素でも同じ)
            //const int nodeCnt = Constants.QuadNodeCnt_SecondOrder_Type2; //8;  // 四角形2次要素
            int nodeCnt = NodeNumbers.Length;
            if (nodeCnt != Constants.QuadNodeCnt_SecondOrder_Type2 && nodeCnt != Constants.QuadNodeCnt_FirstOrder)
            {
                return;
            }
            // 四角形節点座標を取得
            double[][] pp = new double[nodeCnt][];
            for (int ino = 0; ino < pp.GetLength(0); ino++)
            {
                FemNode node = _Nodes[ino];
                System.Diagnostics.Debug.Assert(node.Coord.Length == ndim);
                pp[ino] = new double[ndim];
                pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width;
                pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height;
            }
            // 四角形内部を四角形で分割
            // 要素節点座標( 局所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
                };

            int ndiv = this.IsCoarseFieldMesh ? (Constants.TriDrawFieldMshDivCnt / 2) : Constants.TriDrawFieldMshDivCnt;
            double defdr = 2.0 / (double)ndiv;
            double defds = defdr;
            for (int i1 = 0; i1 < ndiv; i1++)
            {
                double r =  - 1.0 + i1 * defdr;
                double rNext = r + defdr;
                for (int i2 = 0; i2 < ndiv; i2++)
                {
                    double s = -1.0 + i2 * defds;
                    double sNext = s + defds;

                    // 四角形の頂点
                    const int rectVCnt = 4;
                    double[][] rect_local_p = new double[rectVCnt][]
                    {
                        new double[]{r    , s    },
                        new double[]{rNext, s    },
                        new double[]{rNext, sNext},
                        new double[]{r    , sNext}
                    };
                    double[][] rectpp = new double[rectVCnt][];
                    for (int ino = 0; ino < rectVCnt; ino++)
                    {
                        double work_r = rect_local_p[ino][0];
                        double work_s = rect_local_p[ino][1];
                        double xx = 0.0;
                        double yy = 0.0;
                        for (int k = 0; k < vertexCnt; k++)
                        {
                            double ri = n_pts[k][0];
                            double si = n_pts[k][1];
                            xx += pp[k][0] * 0.25 * (1 + ri * work_r) * (1 + si * work_s);
                            yy += pp[k][1] * 0.25 * (1 + ri * work_r) * (1 + si * work_s);
                        }
                        rectpp[ino] = new double[] { xx, yy };
                    }
                    // 表示する位置
                    double[] disp_p = new double[] { (rect_local_p[0][0] + rect_local_p[1][0]) * 0.5, (rect_local_p[0][1] + rect_local_p[3][1]) * 0.5 };

                    // 表示する値
                    Complex cvalue = new Complex(0.0, 0.0);
                    // 表示する位置の形状関数値
                    double[] workN = new double[nodeCnt];
                    if (nodeCnt == Constants.QuadNodeCnt_FirstOrder)
                    {
                        double work_r = disp_p[0];
                        double work_s = disp_p[1];
                        for (int i = 0; i < 4; i++)
                        {
                            // 節点の局所座標
                            double ri = n_pts[i][0];
                            double si = n_pts[i][1];
                            workN[i] = 0.25 * (1.0 + ri * work_r) * (1.0 + si * work_s);
                        }
                    }
                    else
                    {
                        double work_r = disp_p[0];
                        double work_s = disp_p[1];
                        // 節点0~3 : 四角形の頂点
                        for (int i = 0; i < 4; i++)
                        {
                            // 節点の局所座標
                            double ri = n_pts[i][0];
                            double si = n_pts[i][1];
                            // 形状関数N
                            workN[i] = 0.25 * (1.0 + ri * work_r) * (1.0 + si * work_s) * (ri * work_r + si * work_s - 1.0);
                        }
                        // 節点4,6 : r方向辺上中点
                        foreach (int i in new int[] { 4, 6 })
                        {
                            // 節点の局所座標
                            double ri = n_pts[i][0];
                            double si = n_pts[i][1];
                            // 形状関数N
                            workN[i] = 0.5 * (1.0 - work_r * work_r) * (1.0 + si * work_s);
                        }
                        // 節点5,7 : s方向辺上中点
                        foreach (int i in new int[] { 5, 7 })
                        {
                            // 節点の局所座標
                            double ri = n_pts[i][0];
                            double si = n_pts[i][1];
                            // 形状関数N
                            workN[i] = 0.5 * (1.0 + ri * work_r) * (1.0 - work_s * work_s);
                        }
                    }
                    for (int k = 0; k < nodeCnt; k++)
                    {
                        cvalue += tagtValues[k] * workN[k];
                    }
                    // 四角形の頂点(描画用)
                    Point[] rectp = new Point[rectVCnt];
                    for (int ino = 0; ino < rectVCnt; ino++)
                    {
                        rectp[ino] = new Point((int)rectpp[ino][0], (int)rectpp[ino][1]);
                    }
                    try
                    {
                        // 表示する値
                        double showValue = 0.0;
                        if (valueDv == ValueDV.Real)
                        {
                            showValue = cvalue.Real;
                        }
                        else if (valueDv == ValueDV.Imaginary)
                        {
                            showValue = cvalue.Imaginary;
                        }
                        else
                        {
                            // 既定値は絶対値
                            showValue = Complex.Abs(cvalue);
                        }
                        // 塗りつぶし色の取得
                        Color fillColor = colorMap.GetColor(showValue);
                        // 塗りつぶし
                        using (Brush brush = new SolidBrush(fillColor))
                        {
                            g.FillPolygon(brush, rectp);
                        }
                    }
                    catch (Exception exception)
                    {
                        Console.WriteLine(exception.Message + " " + exception.StackTrace);
                    }
                }
            }
        }
        /* 数値積分版
         * /// <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];
                    }
                }
            }
        }