Ejemplo n.º 1
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">マージされる全体行列</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)
        {
            // 定数
            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;
            // ヘルムホルツ方程式のパラメータ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]);

            // 形状関数の微分の係数を求める
            //    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];
                }
            }

            // 要素剛性行列にマージする
            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];
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// フィールドの回転を取得する
        /// </summary>
        /// <param name="rotXFValues"></param>
        /// <param name="rotYFValues"></param>
        protected override void calcRotField(out Complex[] rotXFValues, out Complex[] rotYFValues)
        {
            base.calcRotField(out rotXFValues, out rotYFValues);

            rotXFValues = new Complex[NodeNumbers.Length];
            rotYFValues = new Complex[NodeNumbers.Length];

            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[vertexCnt][];
            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];
                pp[ino][1] = node.Coord[1];
            }
            // 面積座標の微分を求める
            //   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 = null;
            if (nodeCnt == Constants.TriNodeCnt_FirstOrder)
            {
                dndxC = new double[Constants.TriNodeCnt_FirstOrder, ndim, vertexCnt + 1]
                {
                    {
                        { 0.0, 0.0, 0.0, dldx[0, 0] },
                        { 0.0, 0.0, 0.0, dldx[0, 1] },
                    },
                    {
                        { 0.0, 0.0, 0.0, dldx[1, 0] },
                        { 0.0, 0.0, 0.0, dldx[1, 1] },
                    },
                    {
                        { 0.0, 0.0, 0.0, dldx[2, 0] },
                        { 0.0, 0.0, 0.0, dldx[2, 1] },
                    },
                };
            }
            else
            {
                dndxC = new double[Constants.TriNodeCnt_SecondOrder, 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 },
                    },
                };
            }
            // 節点の面積座標
            double[][] n_pts = null;
            if (nodeCnt == Constants.TriNodeCnt_FirstOrder)
            {
                n_pts = new double[Constants.TriNodeCnt_FirstOrder][]
                {
                    new double[vertexCnt] {
                        1.0, 0.0, 0.0
                    },
                    new double[vertexCnt] {
                        0.0, 1.0, 0.0
                    },
                    new double[vertexCnt] {
                        0.0, 0.0, 1.0
                    },
                };
            }
            else
            {
                n_pts = new double[Constants.TriNodeCnt_SecondOrder][]
                {
                    new double[vertexCnt] {
                        1.0, 0.0, 0.0
                    },
                    new double[vertexCnt] {
                        0.0, 1.0, 0.0
                    },
                    new double[vertexCnt] {
                        0.0, 0.0, 1.0
                    },
                    new double[vertexCnt] {
                        0.5, 0.5, 0.0
                    },
                    new double[vertexCnt] {
                        0.0, 0.5, 0.5
                    },
                    new double[vertexCnt] {
                        0.5, 0.0, 0.5
                    },
                };
            }
            for (int ino = 0; ino < nodeCnt; ino++)
            {
                double[] L    = n_pts[ino];
                double[] dNdx = new double[nodeCnt];
                double[] dNdy = new double[nodeCnt];
                for (int k = 0; k < nodeCnt; k++)
                {
                    int direction;
                    direction = 0;
                    dNdx[k]   = dndxC[k, direction, 0] * L[0] + dndxC[k, direction, 1] * L[1] + dndxC[k, direction, 2] * L[2] + dndxC[k, direction, 3];
                    direction = 1;
                    dNdy[k]   = dndxC[k, direction, 0] * L[0] + dndxC[k, direction, 1] * L[1] + dndxC[k, direction, 2] * L[2] + dndxC[k, direction, 3];
                }
                rotXFValues[ino] = new Complex();
                rotYFValues[ino] = new Complex();
                for (int k = 0; k < nodeCnt; k++)
                {
                    // (rot(Ez)x = dEz/dy
                    rotXFValues[ino] += _FValues[k] * dNdy[k];
                    // (rot(Ez)y = - dEz/dx
                    rotYFValues[ino] += -1.0 * _FValues[k] * dNdx[k];
                }
                // rot(Ez)を磁界の値に変換する
                rotXFValues[ino] *= _FactorForRot / _media_Q[0, 0];
                rotYFValues[ino] *= _FactorForRot / _media_Q[1, 1];
            }
        }