/// <summary> /// 周期構造導波路固有値問題用FEM行列の追加 /// </summary> /// <param name="isYDirectionPeriodic"></param> /// <param name="waveLength"></param> /// <param name="nodeCntPeriodic"></param> /// <param name="freeNodeCntPeriodic_0"></param> /// <param name="toSortedPeriodic"></param> /// <param name="element"></param> /// <param name="Nodes"></param> /// <param name="Medias"></param> /// <param name="ForceNodeNumberH"></param> /// <param name="WaveModeDv"></param> /// <param name="KMat"></param> public static void AddElementMatPeriodic( bool isYDirectionPeriodic, bool isSVEA, double waveLength, int nodeCntPeriodic, int freeNodeCntPeriodic_0, Dictionary <int, int> toSortedPeriodic, FemElement element, IList <FemNode> Nodes, MediaInfo[] Medias, Dictionary <int, bool> ForceNodeNumberH, FemSolver.WaveModeDV WaveModeDv, ref double[] KMat, ref double[] CMat, ref double[] MMat) { // 定数 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, WaveModeDv, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める 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]; } } } // ∫(dNi/dx)Nj dxdy // ∫(dNi/dy)Nj dxdy double[, ,] integralDNDXL = new double[2, nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int n = 0; n < ndim; n++) { integralDNDXL[n, ino, 0] = (area / 30.0) * dndxC[ino, n, 0] - (area / 60.0) * (dndxC[ino, n, 1] + dndxC[ino, n, 2]); integralDNDXL[n, ino, 1] = (area / 30.0) * dndxC[ino, n, 1] - (area / 60.0) * (dndxC[ino, n, 0] + dndxC[ino, n, 2]); integralDNDXL[n, ino, 2] = (area / 30.0) * dndxC[ino, n, 2] - (area / 60.0) * (dndxC[ino, n, 0] + dndxC[ino, n, 1]); integralDNDXL[n, ino, 3] = (area / 15.0) * (2.0 * dndxC[ino, n, 0] + 2.0 * dndxC[ino, n, 1] + dndxC[ino, n, 2] + 5.0 * dndxC[ino, n, 3]); integralDNDXL[n, ino, 4] = (area / 15.0) * (dndxC[ino, n, 0] + 2.0 * dndxC[ino, n, 1] + 2.0 * dndxC[ino, n, 2] + 5.0 * dndxC[ino, n, 3]); integralDNDXL[n, ino, 5] = (area / 15.0) * (2.0 * dndxC[ino, n, 0] + dndxC[ino, n, 1] + 2.0 * dndxC[ino, n, 2] + 5.0 * dndxC[ino, 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[,] eKMat = new double[nno, nno]; double[,] eCMat = new double[nno, nno]; double[,] eMMat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { eKMat[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 (isSVEA) { if (isYDirectionPeriodic) { eCMat[ino, jno] = -media.P[1, 1] * (integralDNDXL[1, ino, jno] - integralDNDXL[1, jno, ino]); } else { eCMat[ino, jno] = -media.P[1, 1] * (integralDNDXL[0, ino, jno] - integralDNDXL[0, jno, ino]); } // 要素質量行列 eMMat[ino, jno] = media.P[1, 1] * integralN[ino, jno]; } } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) { continue; } int inoGlobal = toSortedPeriodic[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) { continue; } int jnoGlobal = toSortedPeriodic[jNodeNumber]; KMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eKMat[ino, jno]; if (isSVEA) { CMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eCMat[ino, jno]; MMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eMMat[ino, jno]; } } } }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列</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.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, WaveModeDv, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める 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]; } } }
/// <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]; } }