/// <summary> /// ヘルムホルツの方程式 PML要素の全体行列の追加(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">値のフィールドID</param> /// <param name="pmlStPosX">PML媒質開始位置X座標</param> /// <param name="pmlLength">PML長さ</param> /// <param name="dt">時刻刻み幅</param> /// <param name="newmarkBeta">Newmark法β</param> /// <param name="media">媒質</param> /// <param name="eaId">要素アレイID</param> /// <param name="node_cnt">解析領域全体の節点数</param> /// <param name="free_node_cnt">解析領域全体の自由節点数(強制境界を除いた節点数)</param> /// <param name="toSorted">節点番号→ソート済み(強制境界を除いた)節点リストのインデックスマップ</param> /// <param name="AMat">全体行列</param> /// <returns></returns> private static bool addPmlMat_EachElementAry( CFieldWorld world, uint fieldValId, bool isPmlYDirection, double pmlStPosX, double pmlLength, double dt, double newmarkBeta, MediaInfo media, uint eaId, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, ref MyDoubleBandMatrix AMat) { System.Diagnostics.Debug.Assert(free_node_cnt == AMat.RowSize && free_node_cnt == AMat.ColumnSize); System.Diagnostics.Debug.Assert(world.IsIdEA(eaId)); // 要素アレイを取得 CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.TRI); if (!world.IsIdField(fieldValId)) { return false; } // 値のフィールドを取得 CField valField = world.GetField(fieldValId); // 値の要素セグメント(コーナー)を取得 CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world); // 座標の要素セグメント(コーナー)を取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); uint nno = 3; uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 要素節点の座標 double[,] coord_c = new double[nno, ndim]; // 要素行列 double[,] eMMat = new double[nno, nno]; double[,] eKXMat = new double[nno, nno]; double[,] eKYMat = new double[nno, nno]; CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, world); CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 座標を取得 for (uint inoes = 0; inoes < nno; inoes++) { double[] tmpval = null; ns_c_co.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == ndim); for (int i = 0; i < tmpval.Length; i++) { coord_c[inoes, i] = tmpval[i]; } } // 節点の値を取って来る es_c_va.GetNodes(ielem, no_c); for (uint inoes = 0; inoes < nno; inoes++) { Complex[] tmpval = null; ns_c_val.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == 1); value_c[inoes] = tmpval[0]; } // 節点座標 double[] p1 = new double[ndim]; double[] p2 = new double[ndim]; double[] p3 = new double[ndim]; for (int i = 0; i < ndim; i++) { p1[i] = coord_c[0, i]; p2[i] = coord_c[1, i]; p3[i] = coord_c[2, i]; } // 面積を求める double area = CKerEMatTri.TriArea(p1, p2, p3); // 形状関数の微分を求める double[,] dldx = null; double[] const_term = null; CKerEMatTri.TriDlDx(out dldx, out const_term, p1, p2, p3); // ∫(dLi/dx)(dLj/dx) dxdy double[,] integralDLDX = new double[3, 3]; // ∫(dLi/dy)(dLj/dy) dxdy double[,] integralDLDY = new double[3, 3]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDLDX[ino, jno] = area * dldx[ino, 0] * dldx[jno, 0]; } } for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDLDY[ino, jno] = area * dldx[ino, 1] * dldx[jno, 1]; } } /* // ∫(dLi/dx)Lj dxdy double[,] integralDLDXL = new double[3, 3]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDLDXL[ino, jno] = area * dldx[ino, 0] / 3.0; } } // ∫(dLi/dy)Lj dxdy double[,] integralDLDYL = new double[3, 3]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDLDYL[ino, jno] = area * dldx[ino, 1] / 3.0; } } */ // ∫LiLj dxdy double[,] integralL = new double[3, 3] { { 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 }, }; // 要素剛性行列、要素質量行列を作る for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { // 要素剛性行列 eKXMat[ino, jno] = media.P[1, 1] * integralDLDX[ino, jno]; eKYMat[ino, jno] = media.P[0, 0] * integralDLDY[ino, jno]; // 要素質量行列 eMMat[ino, jno] = eps0 * myu0 * media.Q[2, 2] * integralL[ino, jno]; } } // PML媒質パラメータ double posXG = (p1[0] + p2[0] + p3[0]) / 3.0; if (isPmlYDirection) { posXG = (p1[1] + p2[1] + p3[1]) / 3.0; } double sigmaX_e = 0.0; double c1_F_e = 0.0; double c1_G_e = 0.0; double c3_G_e = 0.0; GetPmlParameter( posXG, pmlStPosX, pmlLength, dt, out sigmaX_e, out c1_F_e, out c1_G_e, out c3_G_e); // 要素剛性行列にマージする double[,] work_eKXMat = eKXMat; double[,] work_eKYMat = eKYMat; if (isPmlYDirection) { work_eKXMat = eKYMat; work_eKYMat = eKXMat; } for (int ino = 0; ino < nno; ino++) { uint iNodeNumber = no_c[ino]; if (!toSorted.ContainsKey(iNodeNumber)) continue; int inoGlobal = (int)toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { uint jNodeNumber = no_c[jno]; if (!toSorted.ContainsKey(jNodeNumber)) continue; int jnoGlobal = (int)toSorted[jNodeNumber]; // clapack形式の行列格納方法で格納(バンド行列) AMat._body[AMat.GetBufferIndex(inoGlobal, jnoGlobal)] += (sigmaX_e / eps0) * (1.0 / (2.0 * dt)) * eMMat[ino, jno] + c1_F_e * newmarkBeta * work_eKYMat[ino, jno] + c1_G_e * newmarkBeta * work_eKXMat[ino, jno]; } } } return true; }
// {x} = [A]{v} public static double[] product(MyDoubleBandMatrix matAB, double[] vec, int vec_row) { int a_row = matAB.RowSize; int a_col = matAB.ColumnSize; int subdiaSize = matAB.SubdiaSize; int superdiaSize = matAB.SuperdiaSize; System.Diagnostics.Debug.Assert(a_col == vec_row); double[] retVec = new double[a_row]; /* for (int i = 0; i < a_row; i++) { retVec[i] = 0.0; for (int k = 0; k < a_col; k++) { if (Math.Max(0, k - superdiaSize) <= i && i <= Math.Min((a_row - 1), k + subdiaSize)) { retVec[i] += matAB._body[matAB.GetBufferIndex(i, k)] * vec[k]; } } } */ for (int k = 0; k < a_col; k++) { // 対角成分 retVec[k] += matAB._body[matAB.GetBufferIndex(k, k)] * vec[k]; // subdiagonal成分 if (k < a_col - 1) { for (int i = k + 1; i <= k + subdiaSize && i < a_row; i++) { retVec[i] += matAB._body[matAB.GetBufferIndex(i, k)] * vec[k]; } } if (k > 0) { for (int i = k - 1; i >= k - superdiaSize && i >= 0; i--) { retVec[i] += matAB._body[matAB.GetBufferIndex(i, k)] * vec[k]; } } } return retVec; }