/// <summary> /// ヘルムホルツの方程式 Sommerfelt放射条件(要素アレイ単位) /// </summary> /// <param name="ls"></param> /// <param name="waveLength"></param> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <param name="eaId"></param> /// <param name="tmpBuffer"></param> /// <returns></returns> private static bool AddLinSys_SommerfeltRadiationBC_EachElementAry(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId, uint eaId, int[] tmpBuffer) { System.Diagnostics.Debug.Assert(world.IsIdEA(eaId)); CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE); 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 = 2; // 座標の次元 uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 要素節点の座標 double[][] coord_c = new double[nno][]; for (int inoes = 0; inoes < nno; inoes++) { coord_c[inoes] = new double[ndim]; } // 要素剛性行列 (i, j) --> (i * RowSize + j) Complex[] ematBuffer = new Complex[nno * nno]; // 要素節点等価内力、外力、残差ベクトル Complex[] eres_c = new Complex[nno]; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world); 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 elen = Math.Sqrt((coord_c[0][0] - coord_c[1][0]) * (coord_c[0][0] - coord_c[1][0]) + (coord_c[0][1] - coord_c[1][1]) * (coord_c[0][1] - coord_c[1][1])); double k = 2.0 * pi / waveLength; Complex tmp_val1 = (k / 6.0 * elen) * (new Complex(0, 1)); Complex tmp_val2 = -1 / (2.0 * elen * k) * (new Complex(0, 1)); //emat[0, 0] ematBuffer[0] = tmp_val1 * 2 + tmp_val2; //emat[0, 1] ematBuffer[1] = tmp_val1 - tmp_val2; //emat[1, 0] ematBuffer[nno] = tmp_val1 - tmp_val2; //emat[1, 1] ematBuffer[nno + 1] = tmp_val1 * 2 + tmp_val2; // 要素節点等価内力ベクトルを求める for (int ino = 0; ino < nno; ino++) { eres_c[ino] = new Complex(0.0); for (int jno = 0; jno < nno; jno++) { eres_c[ino] -= ematBuffer[ino * nno + jno] * value_c[jno]; } } // 要素剛性行列にマージする mat_cc.Mearge(nno, no_c, nno, no_c, 1, ematBuffer, ref tmpBuffer); // 残差ベクトルにマージする for (int inoes = 0; inoes < nno; inoes++) { res_c.AddValue(no_c[inoes], 0, eres_c[inoes]); } } return true; }
/// <summary> /// ヘルムホルツの方程式 剛性行列 残差ベクトルの追加(要素アレイ単位) /// </summary> /// <param name="ls"></param> /// <param name="waveLength"></param> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <param name="eaId"></param> /// <param name="tmpBuffer"></param> /// <returns></returns> private static bool AddLinSysHelmholtz_EachElementAry(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId, uint eaId, int[] tmpBuffer) { 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][]; for (int inoes = 0; inoes < nno; inoes++) { coord_c[inoes] = new double[ndim]; } // 要素剛性行列のバッファ (i, j) --> (i * rowSize + j) Complex[] ematBuffer = new Complex[nno * nno]; // 要素節点等価内力、外力、残差ベクトル Complex[] eres_c = new Complex[nno]; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world); 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]; } //Console.WriteLine("coord_c [" + no_c[inoes] + " ] = " + coord_c[inoes, 0] + " " + coord_c[inoes, 1]); } // 節点の値を取って来る 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]; //Console.WriteLine("value_c [" + no_c[inoes] + " ] = " + tmpval[0].Real + " " + tmpval[0].Imag); } // 節点座標 double[] p1 = coord_c[0]; double[] p2 = coord_c[1]; double[] p3 = coord_c[2]; // 面積を求める double area = CKerEMatTri.TriArea(p1, p2, p3); // 形状関数の微分を求める double[,] dldx = null; double[] const_term = null; CKerEMatTri.TriDlDx(out dldx, out const_term, p1, p2, p3); // 要素剛性行列を作る for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { //emat[ino, jno] ematBuffer[ino * nno + jno] = area * (dldx[ino, 0] * dldx[jno, 0] + dldx[ino, 1] * dldx[jno, 1]); } } double k0 = 2 * pi / waveLength; double tmp_val = k0 * k0 * area / 12.0; for (int ino = 0; ino < nno; ino++) { //emat[ino, ino] ematBuffer[ino * nno + ino] -= new Complex(tmp_val); for (int jno = 0; jno < nno; jno++) { //emat[ino, jno] ematBuffer[ino * nno + jno] -= new Complex(tmp_val); } } // 要素節点等価内力ベクトルを求める for (int ino = 0; ino < nno; ino++) { eres_c[ino] = new Complex(0.0); for (int jno = 0; jno < nno; jno++) { eres_c[ino] -= ematBuffer[ino * nno + jno] * value_c[jno]; } } // 要素剛性行列にマージする mat_cc.Mearge(nno, no_c, nno, no_c, 1, ematBuffer, ref tmpBuffer); // 残差ベクトルにマージする for (int inoes = 0; inoes < nno; inoes++) { res_c.AddValue(no_c[inoes], 0, eres_c[inoes]); } } return true; }
/// <summary> /// PML媒質内の要素の残差ベクトルを加算する(要素アレイ単位) /// </summary> /// <param name="timeIndex"></param> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <param name="pmlStPosX"></param> /// <param name="pmlLength"></param> /// <param name="dt"></param> /// <param name="newmarkBeta"></param> /// <param name="media"></param> /// <param name="eaId"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="toSorted"></param> /// <param name="Ez_Prev"></param> /// <param name="Ez_Prev2"></param> /// <param name="w2_F_e_EA"></param> /// <param name="w2_G_e_EA"></param> /// <param name="resVec"></param> /// <returns></returns> private static bool addPmlResVec_EachElementAry( int timeIndex, 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, double[] Ez_Prev, double[] Ez_Prev2, ref double[][] w2_F_e_EA, ref double[][] w2_G_e_EA, ref double[] resVec) { System.Diagnostics.Debug.Assert(free_node_cnt == resVec.Length); 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); // 初回ステップ if (timeIndex == 0) { w2_F_e_EA = new double[ea.Size()][]; w2_G_e_EA = new double[ea.Size()][]; for (int ielem = 0; ielem < ea.Size(); ielem++) { w2_F_e_EA[ielem] = new double[nno]; w2_G_e_EA[ielem] = new double[nno]; } } 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); // w2_F, w2_Gの更新 double[] w2_F_e = w2_F_e_EA[(int)ielem]; double[] w2_G_e = w2_G_e_EA[(int)ielem]; for (int ino = 0; ino < nno; ino++) { uint iNodeNumber = no_c[ino]; if (!toSorted.ContainsKey(iNodeNumber)) continue; int inoGlobal = (int)toSorted[iNodeNumber]; w2_F_e[ino] = c1_F_e * Ez_Prev2[inoGlobal] + w2_F_e[ino]; w2_G_e[ino] = c1_G_e * Ez_Prev2[inoGlobal] + c3_G_e * w2_G_e[ino]; } // 残差ベクトルにマージする 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]; double resVec_inoGlobal = 0.0; for (int jno = 0; jno < nno; jno++) { uint jNodeNumber = no_c[jno]; if (!toSorted.ContainsKey(jNodeNumber)) continue; int jnoGlobal = (int)toSorted[jNodeNumber]; resVec_inoGlobal += (sigmaX_e / eps0) * (1.0 / (2.0 * dt)) * eMMat[ino, jno] * Ez_Prev2[jnoGlobal] - 1.0 * work_eKYMat[ino, jno] * ( (1.0 - newmarkBeta) * c1_F_e * Ez_Prev[jnoGlobal] + w2_F_e[jno] ) - 1.0 * work_eKXMat[ino, jno] * ( (newmarkBeta * c3_G_e * c1_G_e + (1.0 - 2.0 * newmarkBeta) * c1_G_e) * Ez_Prev[jnoGlobal] + (newmarkBeta * c3_G_e * c3_G_e + (1.0 - 2.0 * newmarkBeta) * c3_G_e + newmarkBeta) * w2_G_e[jno] ); } resVec[inoGlobal] += resVec_inoGlobal; } } return true; }
/// <summary> /// 非0パターンを作成する(要素アレイ単位) /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <param name="media"></param> /// <param name="eaId"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="toSorted"></param> /// <param name="matPattern"></param> /// <returns></returns> private static bool MkMatPattern_EachElementAry( CFieldWorld world, uint fieldValId, MediaInfo media, uint eaId, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, ref bool[,] matPattern) { System.Diagnostics.Debug.Assert(free_node_cnt * free_node_cnt == matPattern.Length); 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]; for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 非0要素を設定する 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形式の行列格納方法で格納 matPattern[inoGlobal, jnoGlobal] = true; } } } return true; }
/// <summary> /// ヘルムホルツの方程式 剛性行列 残差ベクトルの追加(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">値のフィールドID</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="KMat">剛性行列</param> /// <param name="MMat">質量行列</param> /// <returns></returns> private static bool MkHelmholtzMat_EachElementAry( CFieldWorld world, uint fieldValId, MediaInfo media, uint eaId, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, ref MyDoubleBandMatrix KMat, ref MyDoubleBandMatrix MMat) { System.Diagnostics.Debug.Assert(free_node_cnt == KMat.RowSize && free_node_cnt == KMat.ColumnSize); System.Diagnostics.Debug.Assert(free_node_cnt == MMat.RowSize && free_node_cnt == MMat.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[,] eKMat = new double[nno, nno]; // 要素結合行列 double[,] eCMat = new double[nno, nno]; // 要素質量行列 double[,] eMMat = 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++) { // 要素剛性行列 eKMat[ino, jno] = media.P[0, 0] * integralDLDY[ino, jno] + media.P[1, 1] * integralDLDX[ino, jno]; // 要素質量行列 eMMat[ino, jno] = eps0 * myu0 * media.Q[2, 2] * integralL[ino, jno]; } } // 要素剛性行列にマージする 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形式の行列格納方法で格納(バンド行列) KMat._body[KMat.GetBufferIndex(inoGlobal,jnoGlobal)] += eKMat[ino, jno]; MMat._body[KMat.GetBufferIndex(inoGlobal, jnoGlobal)] += eMMat[ino, jno]; } } } return true; }
/// <summary> /// 領域の界の値を取得する(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_area">節点番号配列</param> /// <param name="to_no_area">節点番号→境界上節点番号マップ</param> /// <param name="eaId">要素アレイID</param> /// <param name="value_c_all">フィールド値配列</param> /// <returns></returns> private static bool getAreaFieldValueList_EachElementAry(CFieldWorld world, uint fieldValId, uint[] no_c_area, Dictionary<uint, uint> to_no_area, uint eaId, Complex[] value_c_all) { uint node_cnt = (uint)no_c_area.Length; System.Diagnostics.Debug.Assert(world.IsIdEA(eaId)); CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.TRI); 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][]; //for (uint inoes = 0; inoes < ndim; inoes++) //{ // coord_c[inoes] = new double[ndim]; //} // 節点の値の節点セグメント 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]; //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" ); } for (uint ino = 0; ino < nno; ino++) { System.Diagnostics.Debug.Assert(to_no_area.ContainsKey(no_c[ino])); uint ino_boundary = to_no_area[no_c[ino]]; System.Diagnostics.Debug.Assert(ino_boundary < node_cnt); value_c_all[ino_boundary] = value_c[ino]; //System.Diagnostics.Debug.WriteLine("value_c_all [ " + ino_boundary + " ] = " + "(" + value_c_all[ino_boundary].Real + ", " + value_c_all[ino_boundary].Imag + ") " + Complex.Norm(value_c_all[ino_boundary])); } } return true; }