/// <summary> /// 境界上の節点番号と座標の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <param name="coord_c_all">座標リスト</param> /// <returns></returns> public static bool GetBoundaryCoordList( CFieldWorld world, uint fieldValId, double rotAngle, double[] rotOrigin, out uint[] no_c_all, out Dictionary <uint, uint> to_no_boundary, out double[][] coord_c_all) { no_c_all = null; to_no_boundary = null; coord_c_all = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return(false); } IList <uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 to_no_boundary = new Dictionary <uint, uint>(); IList <double[]> coord_c_list = new List <double[]>(); foreach (uint eaId in aIdEA) { bool res = getBoundaryCoordList_EachElementAry( world, fieldValId, eaId, rotAngle, rotOrigin, ref to_no_boundary, ref coord_c_list); if (!res) { return(false); } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_boundary.Count]; foreach (KeyValuePair <uint, uint> kvp in to_no_boundary) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } coord_c_all = coord_c_list.ToArray(); return(true); }
/// <summary> /// 境界上の節点番号の取得(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="eaId">要素アレイID</param> /// <param name="to_no_boundary">全体節点番号→境界上節点番号マップ</param> /// <returns></returns> private static bool getBoundaryNodeList_EachElementAry(CFieldWorld world, uint fieldValId, uint eaId, Dictionary <uint, uint> to_no_boundary) { // 要素アレイを取得する CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE); if (ea.ElemType() != ELEM_TYPE.LINE) { return(false); } // フィールドを取得 CField valField = world.GetField(fieldValId); // 座標セグメントを取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 uint node_cnt = ea.Size() + 1; // 全節点数 // 線要素の節点数 uint nno = 2; uint[] no_c = new uint[nno]; // 要素節点の全体節点番号 for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); for (uint ino = 0; ino < nno; ino++) { if (!to_no_boundary.ContainsKey(no_c[ino])) { uint ino_boundary_tmp = (uint)to_no_boundary.Count; to_no_boundary[no_c[ino]] = ino_boundary_tmp; } } } return(true); }
public const double eps0 = 8.85418782e-12;//1.0 / (mu0 * c0 * c0); /// <summary> /// 境界上の節点番号の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <returns></returns> public static bool GetBoundaryNodeList(CFieldWorld world, uint fieldValId, out uint[] no_c_all, out Dictionary <uint, uint> to_no_boundary) { no_c_all = null; to_no_boundary = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return(false); } IList <uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 to_no_boundary = new Dictionary <uint, uint>(); foreach (uint eaId in aIdEA) { bool res = getBoundaryNodeList_EachElementAry(world, fieldValId, eaId, to_no_boundary); if (!res) { return(false); } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_boundary.Count]; foreach (KeyValuePair <uint, uint> kvp in to_no_boundary) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } return(true); }
//////////////////////////////////////////////////////////////////////// // 型 //////////////////////////////////////////////////////////////////////// /// <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="medias">媒質リスト</param> /// <param name="loopDic">ループID→ループ情報マップ</param> /// <param name="node_cnt">解析領域全体の節点数</param> /// <param name="free_node_cnt">解析領域全体の自由節点数(強制境界を除いた節点数)</param> /// <param name="toSorted">節点番号→ソート済み(強制境界を除いた)節点リストのインデックスマップ</param> /// <param name="AMat">全体行列</param> /// <returns></returns> public static bool AddPmlMat( CFieldWorld world, uint fieldValId, bool isPmlYDirection, double pmlStPosX, double pmlLength, double dt, double newmarkBeta, IList<MediaInfo> medias, Dictionary<uint, World.Loop> loopDic, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, ref MyDoubleBandMatrix AMat) { // 値のフィールドIDかチェック if (!world.IsIdField(fieldValId)) { return false; } // 値のフィールドを取得する CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } // 要素アレイのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); foreach (uint eaId in aIdEA) { if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (loopDic.ContainsKey(lId)) { World.Loop loop = loopDic[lId]; media = medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } bool res = addPmlMat_EachElementAry( world, fieldValId, isPmlYDirection, pmlStPosX, pmlLength, dt, newmarkBeta, media, eaId, node_cnt, free_node_cnt, toSorted, ref AMat ); if (!res) { return false; } } } 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="medias"></param> /// <param name="loopDic"></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_List"></param> /// <param name="W2_G_e_List"></param> /// <param name="resVec"></param> /// <returns></returns> public static bool AddPmlResVec( int timeIndex, CFieldWorld world, uint fieldValId, bool isPmlYDirection, double pmlStPosX, double pmlLength, double dt, double newmarkBeta, IList<MediaInfo> medias, Dictionary<uint, World.Loop> loopDic, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, double[] Ez_Prev, double[] Ez_Prev2, ref double[][][] W2_F_e_List, ref double[][][] W2_G_e_List, ref double[] resVec) { // 値のフィールドIDかチェック if (!world.IsIdField(fieldValId)) { return false; } // 値のフィールドを取得する CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } // 要素アレイのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); // 要素毎のv, Φの値の初期化 if (timeIndex == 0) { W2_F_e_List = new double[aIdEA.Count][][]; W2_G_e_List = new double[aIdEA.Count][][]; } for(int iElemAry = 0; iElemAry < aIdEA.Count; iElemAry++) { uint eaId = aIdEA[iElemAry]; if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (loopDic.ContainsKey(lId)) { World.Loop loop = loopDic[lId]; media = medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } double[][] w2_F_e_EA = W2_F_e_List[iElemAry]; double[][] w2_G_e_EA = W2_G_e_List[iElemAry]; bool res = addPmlResVec_EachElementAry( timeIndex, world, fieldValId, isPmlYDirection, pmlStPosX, pmlLength, dt, newmarkBeta, media, eaId, node_cnt, free_node_cnt, toSorted, Ez_Prev, Ez_Prev2, ref w2_F_e_EA, ref w2_G_e_EA, ref resVec ); // 再格納 W2_F_e_List[iElemAry] = w2_F_e_EA; W2_G_e_List[iElemAry] = w2_G_e_EA; if (!res) { return false; } } } return true; }
/// <summary> /// 境界上の節点番号の取得(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="eaId">要素アレイID</param> /// <param name="to_no_boundary">全体節点番号→境界上節点番号マップ</param> /// <returns></returns> private static bool getBoundaryNodeList_EachElementAry(CFieldWorld world, uint fieldValId, uint eaId, Dictionary<uint, uint> to_no_boundary) { // 要素アレイを取得する CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE); if (ea.ElemType() != ELEM_TYPE.LINE) { return false; } // フィールドを取得 CField valField = world.GetField(fieldValId); // 座標セグメントを取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 uint node_cnt = ea.Size() + 1; // 全節点数 // 線要素の節点数 uint nno = 2; uint[] no_c = new uint[nno]; // 要素節点の全体節点番号 for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); for (uint ino = 0; ino < nno; ino++) { if (!to_no_boundary.ContainsKey(no_c[ino])) { uint ino_boundary_tmp = (uint)to_no_boundary.Count; to_no_boundary[no_c[ino]] = ino_boundary_tmp; } } } return true; }
/// <summary> /// 境界上の節点番号の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <returns></returns> public static bool GetBoundaryNodeList(CFieldWorld world, uint fieldValId, out uint[] no_c_all, out Dictionary<uint, uint> to_no_boundary) { no_c_all = null; to_no_boundary = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } IList<uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 to_no_boundary = new Dictionary<uint, uint>(); foreach (uint eaId in aIdEA) { bool res = getBoundaryNodeList_EachElementAry(world, fieldValId, eaId, to_no_boundary); if (!res) { return false; } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_boundary.Count]; foreach (KeyValuePair<uint, uint> kvp in to_no_boundary) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } 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="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; }
/// <summary> /// 表示用に界の値を置き換える(複素数を複素数絶対値にする) /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> public static void SetFieldValueForDisplay(CFieldWorld world, uint fieldValId, KrdLab.clapack.Complex[] resVec) { CField valField_base = world.GetField(fieldValId); System.Diagnostics.Debug.Assert(valField_base.GetFieldType() == FIELD_TYPE.ZSCALAR); IList<uint> aIdEA = valField_base.GetAryIdEA(); foreach (uint eaId in aIdEA) { CElemAry ea = world.GetEA(eaId); CField valField = world.GetField(fieldValId); if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { // 要素セグメントコーナー値 //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]; 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]; //} // 節点の値を絶対値にする for (uint inoes = 0; inoes < nno; inoes++) { uint inoGlobal = no_c[inoes]; KrdLab.clapack.Complex cvalue = resVec[inoGlobal]; ns_c_val.SetValue(no_c[inoes], 0, cvalue.Real); ns_c_val.SetValue(no_c[inoes], 1, cvalue.Imaginary); } } } } }
/// <summary> /// ループ内の節点番号と座標の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <param name="coord_c_all">座標リスト</param> /// <returns></returns> public static bool GetLoopCoordList(CFieldWorld world, uint fieldValId, double rotAngle, double[] rotOrigin, out uint[] no_c_all, out Dictionary <uint, uint> to_no_loop, out double[][] coord_c_all, out uint[][] elem_no_c, out uint[] elem_loopId) { no_c_all = null; to_no_loop = null; coord_c_all = null; elem_no_c = null; elem_loopId = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return(false); } IList <uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→ループ内節点番号変換テーブル作成 to_no_loop = new Dictionary <uint, uint>(); IList <double[]> coord_c_list = new List <double[]>(); // 要素の節点番号リスト IList <uint[]> elem_no_c_list = new List <uint[]>(); // 要素のループIDリスト IList <uint> elem_loopId_list = new List <uint>(); foreach (uint eaId in aIdEA) { bool res = getLoopCoordList_EachElementAry( world, fieldValId, eaId, rotAngle, rotOrigin, ref to_no_loop, ref coord_c_list, ref elem_no_c_list, ref elem_loopId_list); if (!res) { return(false); } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_loop.Count]; foreach (KeyValuePair <uint, uint> kvp in to_no_loop) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } coord_c_all = coord_c_list.ToArray(); int elemCnt = elem_no_c_list.Count; elem_no_c = new uint[elemCnt][]; elem_loopId = new uint[elemCnt]; for (int ie = 0; ie < elemCnt; ie++) { elem_no_c[ie] = new uint[3]; for (int i = 0; i < 3; i++) { elem_no_c[ie][i] = elem_no_c_list[ie][i]; elem_loopId[ie] = elem_loopId_list[ie]; } } return(true); }
private const bool DefIsSVEA = true; // Φ = φ(x, y) exp(-jβx) と置く方法 #endregion Fields #region Methods /// <summary> /// 周期構造導波路開口境界条件 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param> /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="isInputPort">入射ポート?</param> /// <param name="incidentModeIndex">入射モードのインデックス</param> /// <param name="isFreeBc">境界条件を課さない?</param> /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> public static bool AddLinSys_PeriodicWaveguidePortBC( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldInputWgLoopId, uint fieldPortBcId1, uint[] fixedBcNodes, bool isInputPort, int incidentModeIndex, Complex[] amps, bool isFreeBc, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs) { if (!world.IsIdField(fieldInputWgLoopId)) { return false; } // フィールドを取得 CField valField = world.GetField(fieldInputWgLoopId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 境界上のすべての節点番号を取り出す res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary); if (!res) { return false; } // 境界条件をリニアシステムに設定する uint ntmp = ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } res = addLinSys_PeriodicWaveguidePortBC_Core( ls, waveLength, waveModeDv, periodicDistance, world, fieldPortBcId1, isInputPort, incidentModeIndex, amps, isFreeBc, ryy_1d, eigen_values, eigen_vecs, eigen_dFdXs, no_c_all, ref tmpBuffer); if (!res) { return false; } return true; }
/// <summary> /// 周期構造導波路開口固有値解析(FEM行列と固有モードの取得) /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param> /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param> /// <param name="fieldInputWgBcId1">フィールド値ID(周期構造領域の境界2=内部側境界)</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="IsPCWaveguide">フォトニック結晶導波路?</param> /// <param name="PCWaveguidePorts">フォトニック結晶導波路のポート(ロッド欠陥部分)の節点のリスト</param> /// <param name="medias">媒質リスト</param> /// <param name="inputWgLoopDic1">周期構造領域のワールド座標系ループ→ループ情報マップ</param> /// <param name="inputWgEdgeDic1">周期構造領域のワールド座標系辺→辺情報マップ</param> /// <param name="isPortBc2Reverse">境界2の方向が境界1と逆方向?</param> /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> public static bool GetPortPeriodicWaveguideFemMatAndEigenVec( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, CFieldWorld world, uint fieldInputWgLoopId, uint fieldPortBcId1, uint fieldInputWgBcId1, uint[] fixedBcNodes, bool IsPCWaveguide, double latticeA, double periodicDistance, IList<IList<uint>> PCWaveguidePorts, int incidentModeIndex, bool isSolveEigenItr, int propModeCntToSolve, bool isSVEA, bool isModeTrace, ref KrdLab.clapack.Complex[][] PrevModalVecList, double minBeta, double maxBeta, double minWaveNum, double maxWaveNum, IList<MediaInfo> medias, Dictionary<uint, wg2d.World.Loop> inputWgLoopDic1, Dictionary<uint, World.Edge> inputWgEdgeDic1, bool isPortBc2Reverse, out double[,] ryy_1d, out Complex[] eigen_values, out Complex[,] eigen_vecs, out Complex[,] eigen_dFdXs) { ryy_1d = null; eigen_values = null; eigen_vecs = null; eigen_dFdXs = null; if (!world.IsIdField(fieldInputWgLoopId)) { return false; } // フィールドを取得 CField valField = world.GetField(fieldInputWgLoopId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 節点座標 double[,] coord_c_all = null; // 導波管の幅取得 double[] coord_c_first = null; double[] coord_c_last = null; double waveguideWidth = 0; res = WgUtil.getRectangleWaveguideStructInfo(world, fieldPortBcId1, out coord_c_first, out coord_c_last, out waveguideWidth); if (!res) { return false; } // Y方向に周期構造? bool isYDirectionPeriodic = false; if (Math.Abs(coord_c_first[1] - coord_c_last[1]) < 1.0e-12) { isYDirectionPeriodic = true; } // 回転移動 double[] rotOrigin = null; double rotAngle = 0.0; // ラジアン if (!isYDirectionPeriodic) { // 境界の傾きから回転角度を算出する if (Math.Abs(coord_c_first[0] - coord_c_last[0]) >= 1.0e-12) { // X軸からの回転角 rotAngle = Math.Atan2((coord_c_last[1] - coord_c_first[1]), (coord_c_last[0] - coord_c_first[0])); // Y軸からの回転角に変換 (境界はY軸に平行、X方向周期構造) rotAngle = rotAngle - 0.5 * pi; rotOrigin = coord_c_first; System.Diagnostics.Debug.WriteLine("rotAngle: {0} rotOrigin:{1} {2}", rotAngle * 180.0 / pi, rotOrigin[0], rotOrigin[1]); } } // 境界上のすべての節点番号を取り出す res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary); if (!res) { return false; } // 境界積分用ryy_1dを取得する // 周期境界1について取得する res = getPortWaveguideFemMat( waveLength, world, fieldPortBcId1, fixedBcNodes, coord_c_first, waveguideWidth, no_c_all, to_no_boundary, medias, inputWgEdgeDic1, out ryy_1d, out coord_c_all); if (!res) { return false; } // 周期構造導波路の固有値、固有ベクトルを取得する // 固有ベクトルは境界上のみを取得する //uint max_mode = 1; uint max_mode = int.MaxValue; res = solvePortPeriodicWaveguideEigen( ls, waveLength, waveModeDv, isYDirectionPeriodic, rotAngle, rotOrigin, world, fieldInputWgLoopId, fieldPortBcId1, fieldInputWgBcId1, fixedBcNodes, IsPCWaveguide, latticeA, periodicDistance, PCWaveguidePorts, incidentModeIndex, isSolveEigenItr, propModeCntToSolve, isSVEA, max_mode, isModeTrace, ref PrevModalVecList, minBeta, maxBeta, minWaveNum, maxWaveNum, medias, inputWgLoopDic1, inputWgEdgeDic1, isPortBc2Reverse, ryy_1d, out eigen_values, out eigen_vecs, out eigen_dFdXs); if (!res) { return false; } return true; }
/// <summary> /// 矩形導波管開口反射(透過)係数 /// ※要素アレイは1つに限定しています。 /// ポート境界を指定するときに複数の辺をリストで境界条件設定することでこの条件をクリアできます。 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="fieldValId">フィールド値のID</param> /// <param name="imode">固有モードのモード次数</param> /// <param name="isIncidentMode">入射モード?</param> /// <param name="ryy_1d">[ryy]FEM行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns>散乱係数</returns> public static Complex GetPeriodicWaveguidePortReflectionCoef( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldValId, uint imode, bool isIncidentMode, Complex[] amps, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs) { Complex s11 = new Complex(0.0, 0.0); if (ryy_1d == null || eigen_values == null || eigen_vecs == null) { return s11; } if (!world.IsIdField(fieldValId)) { return s11; } CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return s11; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 境界上のすべての節点番号を取り出す res = GetBoundaryNodeList(world, fieldValId, out no_c_all, out to_no_boundary); if (!res) { return s11; } // 境界上のすべての節点の界の値を取り出す Complex[] value_c_all = null; res = WgUtil.GetBoundaryFieldValueList(world, fieldValId, no_c_all, to_no_boundary, out value_c_all); if (!res) { return s11; } uint node_cnt = (uint)no_c_all.Length; System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(0)); System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(1)); System.Diagnostics.Debug.Assert(node_cnt == eigen_vecs.GetLength(1)); s11 = getPeriodicWaveguidePortReflectionCoef_Core( waveLength, waveModeDv, periodicDistance, imode, isIncidentMode, amps, no_c_all, to_no_boundary, value_c_all, ryy_1d, eigen_values, eigen_vecs, eigen_dFdXs); return s11; }
/// <summary> /// 界のx方向微分値を取得する /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> public static void getDFDXValues( CFieldWorld world, uint fieldValId, Dictionary<uint, uint> to_no_all, IList<MediaInfo> Medias, Dictionary<uint, wg2d.World.Loop> LoopDic, double rotAngle, double[] rotOrigin, KrdLab.clapack.Complex[] fVec, out KrdLab.clapack.Complex[] dFdXVec, out KrdLab.clapack.Complex[] dFdYVec) { dFdXVec = new KrdLab.clapack.Complex[fVec.Length]; dFdYVec = new KrdLab.clapack.Complex[fVec.Length]; CField valField_base = world.GetField(fieldValId); System.Diagnostics.Debug.Assert(valField_base.GetFieldType() == FIELD_TYPE.ZSCALAR); Dictionary<uint, int> nodeElemCntH = new Dictionary<uint, int>(); //Dictionary<uint, double> nodeMediaP11Sum = new Dictionary<uint,double>(); //境界に限ればこの計算は誤差がある Dictionary<uint, double> nodeAreaSum = new Dictionary<uint, double>(); IList<uint> aIdEA = valField_base.GetAryIdEA(); foreach (uint eaId in aIdEA) { CElemAry ea = world.GetEA(eaId); CField valField = world.GetField(fieldValId); if (valField.GetInterpolationType(eaId, world) != INTERPOLATION_TYPE.TRI11) continue; // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (LoopDic.ContainsKey(lId)) { World.Loop loop = LoopDic[lId]; media = Medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } // 要素セグメントコーナー値 //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]; //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]; } } if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit) { // 座標を回転移動する for (uint inoes = 0; inoes < nno; inoes++) { double[] srcPt = new double[] { coord_c[inoes, 0], coord_c[inoes, 1] }; double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin); for (int i = 0; i < ndim; i++) { coord_c[inoes, i] = destPt[i]; } } } // 節点座標 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); // 節点の値を取って来る //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]; //} // 界の微分値を計算 // 界の微分値は一次三角形要素の場合、要素内で一定値 KrdLab.clapack.Complex dFdX = 0.0; KrdLab.clapack.Complex dFdY = 0.0; for (int inoes = 0; inoes < nno; inoes++) { uint iNodeNumber = no_c[inoes]; if (!to_no_all.ContainsKey(iNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } uint inoGlobal = to_no_all[iNodeNumber]; KrdLab.clapack.Complex fVal = fVec[inoGlobal]; dFdX += dldx[inoes, 0] * fVal; dFdY += dldx[inoes, 1] * fVal; } // 格納 for (int inoes = 0; inoes < nno; inoes++) { uint iNodeNumber = no_c[inoes]; if (!to_no_all.ContainsKey(iNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } uint inoGlobal = to_no_all[iNodeNumber]; //dFdXVec[inoGlobal] += dFdX; //dFdYVec[inoGlobal] += dFdY; // Note: // TEzモードのとき -dHz/dx = jωDy dFdXVec[inoGlobal] += dFdX * area; dFdYVec[inoGlobal] += dFdY * area; /*境界に限ればこの計算は誤差がある // 媒質を考慮する double media_P11 = media.P[1, 1]; // pyy (dF/dx)を格納 // TEzのとき pyy (dF/dx) = (1/εyy)dHz/dx = -jωEy //dFdXVec[inoGlobal] += media_P11 * dFdX; //dFdYVec[inoGlobal] += media_P11 * dFdY; dFdXVec[inoGlobal] += media_P11 * dFdX * area; dFdYVec[inoGlobal] += media_P11 * dFdY * area; */ if (nodeElemCntH.ContainsKey(inoGlobal)) { nodeElemCntH[inoGlobal]++; /*境界に限ればこの計算は誤差がある // 媒質パラメータpyyの逆数を格納 //nodeMediaP11Sum[inoGlobal] += (1.0 / media_P11); nodeMediaP11Sum[inoGlobal] += (1.0 / media_P11) * area; */ // 面積を格納 nodeAreaSum[inoGlobal] += area; } else { nodeElemCntH.Add(inoGlobal, 1); /*境界に限ればこの計算は誤差がある // 媒質パラメータpyyの逆数を格納 //nodeMediaP11Sum.Add(inoGlobal, (1.0 / media_P11)); nodeMediaP11Sum.Add(inoGlobal, (1.0 / media_P11) * area); */ nodeAreaSum.Add(inoGlobal, area); } } } } for (uint i = 0; i < dFdXVec.Length; i++) { //int cnt = nodeElemCntH[i]; //dFdXVec[i] /= cnt; //dFdYVec[i] /= cnt; double areaSum = nodeAreaSum[i]; dFdXVec[i] = (dFdXVec[i] / areaSum); dFdYVec[i] = (dFdYVec[i] / areaSum); /*境界に限ればこの計算は誤差がある // 媒質を考慮する // 媒質パラメータpyyの平均 //int cnt = nodeElemCntH[i]; double areaSum = nodeAreaSum[i]; //double mediaP11 = 1.0 / (nodeMediaP11Sum[i] / cnt); double mediaP11 = 1.0 / (nodeMediaP11Sum[i] / areaSum); //System.Diagnostics.Debug.Assert((1.0 / mediaP11) >= 1.0); // dF/dxの平均 //dFdXVec[i] = (dFdXVec[i] / cnt) / mediaP11; //dFdYVec[i] = (dFdYVec[i] / cnt) / mediaP11; dFdXVec[i] = (dFdXVec[i] / areaSum) / mediaP11; dFdYVec[i] = (dFdYVec[i] / areaSum) / mediaP11; */ } }
/// <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> /// ryy_1d(1次線要素のpyy{N}t{N}マトリクス)取得 /// Note: 境界の要素はy = 0からy = waveguideWidth へ順番に要素アレイに格納され、節点2は次の要素の節点1となっていることを前提にしています。 /// </summary> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="coord_c_first">始点の座標</param> /// <param name="waveguideWidth">導波管の幅</param> /// <param name="no_c_all">節点番号配列</param> /// <param name="to_no_boundary">節点番号→境界上節点番号マップ</param> /// <param name="medias">媒質リスト</param> /// <param name="edgeDic">ワールド座標系の辺ID→辺情報のマップ</param> /// <param name="ryy_1d">[ryy]FEM行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列(i, j)i:固有値インデックス, j:節点</param> /// <param name="coord_c_all">節点座標配列</param> /// <returns></returns> private static bool getPortWaveguideFemMat( double waveLength, CFieldWorld world, uint fieldValId, uint[] fixedBcNodes, double[] coord_c_first, double waveguideWidth, uint[] no_c_all, Dictionary<uint, uint> to_no_boundary, IList<MediaInfo> medias, Dictionary<uint, World.Edge> edgeDic, out double[,] ryy_1d, out double[,] coord_c_all) { double k0 = 2.0 * pi / waveLength; double omega = k0 * c0; uint node_cnt = (uint)no_c_all.Length; // 節点座標 uint ndim = 2; coord_c_all = new double[node_cnt, ndim]; // 固有モード解析でのみ使用するuzz_1d, txx_1d double[,] txx_1d = new double[node_cnt, node_cnt]; double[,] uzz_1d = new double[node_cnt, node_cnt]; // ryy_1dマトリクス (1次線要素) ryy_1d = new double[node_cnt, node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { ryy_1d[ino_boundary, jno_boundary] = 0.0; txx_1d[ino_boundary, jno_boundary] = 0.0; uzz_1d[ino_boundary, jno_boundary] = 0.0; } } // フィールドを取得する CField valField = world.GetField(fieldValId); // 要素アレイIDのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); // ryy_1dマトリクスの取得 foreach (uint eaId in aIdEA) { // 媒質を取得する MediaInfo media = new MediaInfo(); { // 辺のIDのはず uint eId = eaId; if (edgeDic.ContainsKey(eId)) { World.Edge edge = edgeDic[eId]; media = medias[edge.MediaIndex]; } } bool res = WgUtil.addElementMatOf1dEigenValueProblem( world, fieldValId, eaId, no_c_all, to_no_boundary, media, ref txx_1d, ref ryy_1d, ref uzz_1d, ref coord_c_all); if (!res) { return false; } } if (fixedBcNodes != null) { // 強制境界 foreach (uint fixedBcNode in fixedBcNodes) { if (to_no_boundary.ContainsKey(fixedBcNode)) { uint ino_boundary = to_no_boundary[fixedBcNode]; //System.Diagnostics.Debug.WriteLine("fixedBcNode: " + fixedBcNode + " ino_boundary: " + ino_boundary); for (int k = 0; k < node_cnt; k++) { txx_1d[ino_boundary, k] = 0.0; txx_1d[k, ino_boundary] = 0.0; ryy_1d[ino_boundary, k] = 0.0; ryy_1d[k, ino_boundary] = 0.0; uzz_1d[ino_boundary, k] = 0.0; uzz_1d[k, ino_boundary] = 0.0; } //ryy_1d[ino_boundary, ino_boundary] = 1.0; } } } return true; }
/// <summary> /// ループ内の節点番号と座標の取得(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="eaId">要素アレイID</param> /// <param name="to_no_boundary">全体節点番号→境界上節点番号マップ</param> /// <returns></returns> private static bool getLoopCoordList_EachElementAry( CFieldWorld world, uint fieldValId, uint eaId, double rotAngle, double[] rotOrigin, ref Dictionary <uint, uint> to_no_loop, ref IList <double[]> coord_c_list, ref IList <uint[]> elem_no_c_list, ref IList <uint> elem_loopId_list) { // 要素アレイを取得する CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.TRI); if (ea.ElemType() != ELEM_TYPE.TRI) { return(false); } // フィールドを取得 CField valField = world.GetField(fieldValId); // 座標セグメントを取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); // 座標のノードセグメントを取得 CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world); uint node_cnt = ea.Size() + 1; // 全節点数 // 三角形要素の節点数 uint nno = 3; // 座標の次元 uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の座標 double[][] coord_c = new double[nno][]; for (int inoes = 0; inoes < nno; inoes++) { coord_c[inoes] = new double[ndim]; } for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // ループID elem_loopId_list.Add(eaId); // 要素内節点番号 { uint[] work_no_c = new uint[nno]; no_c.CopyTo(work_no_c, 0); elem_no_c_list.Add(work_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]; } } if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit) { // 座標を回転移動する for (uint inoes = 0; inoes < nno; inoes++) { double[] srcPt = coord_c[inoes]; double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin); for (int i = 0; i < ndim; i++) { coord_c[inoes][i] = destPt[i]; } } } for (uint ino = 0; ino < nno; ino++) { if (!to_no_loop.ContainsKey(no_c[ino])) { uint ino_loop_tmp = (uint)to_no_loop.Count; to_no_loop[no_c[ino]] = ino_loop_tmp; coord_c_list.Add(new double[] { coord_c[ino][0], coord_c[ino][1] }); System.Diagnostics.Debug.Assert(coord_c_list.Count == (ino_loop_tmp + 1)); } } } 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="value_c_all">フィールド値の配列</param> /// <returns></returns> protected static bool GetAreaFieldValueList(CFieldWorld world, uint fieldValId, uint[] no_c_area, Dictionary<uint, uint> to_no_area, out Complex[] value_c_all) { CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { value_c_all = null; return false; } IList<uint> aIdEA = valField.GetAryIdEA(); uint node_cnt = (uint)no_c_area.Length; // 境界上の界の値をすべて取得する value_c_all = new Complex[node_cnt]; foreach (uint eaId in aIdEA) { bool res = getAreaFieldValueList_EachElementAry(world, fieldValId, no_c_area, to_no_area, eaId, value_c_all); } return true; }
/// <summary> /// /// </summary> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="tmpBuffer"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> public static bool SolvePCOCG( ref CFieldWorld World, ref uint FieldValId, ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; //------------------------------------------------------------------ // マージの終了 //------------------------------------------------------------------ double res = Ls.FinalizeMarge(); tmpBuffer = null; // マトリクスサイズの取得 // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // マトリクスのサイズ int matLen = (int)mat_cc.NBlkMatCol(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList<uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); 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 = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る 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++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Ls = null; Prec.Clear(); Prec.Dispose(); Prec = null; World.Clear(); World.Dispose(); World = null; System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return success; }
/// <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; }
//////////////////////////////////////////////////////////////////////////////////////////////// // DekFEMの処理を隠ぺいした簡易版 //////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// PCOCGで線形方程式を解く /// </summary> /// <param name="mat"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged) public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; int matLen = mat.RowSize; System.Diagnostics.Debug.WriteLine("SolvePCOCG 1"); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; CFieldWorld World = new CFieldWorld(); setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 uint FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); System.Diagnostics.Debug.WriteLine("SolvePCOCG 2"); //------------------------------------------------------------------ // リニアシステム //------------------------------------------------------------------ CZLinearSystem Ls = new CZLinearSystem(); CZPreconditioner_ILU Prec = new CZPreconditioner_ILU(); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ Ls.AddPattern_Field(FieldValId, World); // POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない // 非対角要素のパターンの追加 { uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); // パターンを追加 using (CIndexedArray crs = new CIndexedArray()) { crs.InitializeSize(mat_cc.NBlkMatCol()); //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow()); using (UIntVectorIndexer index = crs.index) using (UIntVectorIndexer ary = crs.array) { for (int iblk = 0; iblk < (int)crs.Size(); iblk++) { index[iblk] = 0; } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 現在のマトリクスのインデックス設定をコピーする uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); foreach (uint row_index in cur_rows) { ary.Add(row_index); } index[iblk + 1] = (uint)ary.Count; //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup); // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0) // すべての節点に関して列を追加 int ino_global = iblk; int col = iblk; if (col != -1 && ino_global != -1) { // 関連付けられていない節点をその行の列データの最後に追加 int last_index = (int)index[col + 1] - 1; int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { // 行列の0要素を除く //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit) //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15) //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { continue; } uint row = (uint)jno_global; if (ino_global != jno_global) // 対角要素は除く { if (!cur_rows.Contains(row)) { ary.Insert(last_index + 1 + add_cnt, row); add_cnt++; //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row); } } } if (add_cnt > 0) { index[col + 1] = (uint)ary.Count; } } } } crs.Sort(); System.Diagnostics.Debug.Assert(crs.CheckValid()); // パターンを削除する mat_cc.DeletePattern(); // パターンを追加する mat_cc.AddPattern(crs); } } System.Diagnostics.Debug.WriteLine("SolvePCOCG 3"); //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // set Preconditioner //Prec.SetFillInLevel(1); // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した //Prec.SetFillInLevel(0); // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする //Prec.SetFillInLevel((uint)mat.RowSize); // 完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い //Prec.SetFillInLevel(3); // 誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある //以上から //メインの導波管の計算時間を短くしたいのでフィルインなしにする //Prec.SetFillInLevel(0); // 導波管だとこれで十分 // フィルインレベルの設定(既定値) Prec.SetFillInLevel(DefFillInLevel); // ILU(0)のパターン初期化 Prec.SetLinearSystem(Ls); System.Diagnostics.Debug.WriteLine("SolvePCOCG 4"); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ //------------------------------------------------------------------ Ls.InitializeMarge(); { uint ntmp = Ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; // 0要素はマージ対象でないので最初から除外する //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit) //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { add_flg[i, j] = true; } } } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応) uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); uint colcnt = 1; uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する Complex[] emattmp = new Complex[colcnt * rowcnt]; uint[] no_c_tmp_col = new uint[colcnt]; uint[] no_c_tmp_row = new uint[rowcnt]; no_c_tmp_col[0] = (uint)iblk; no_c_tmp_row[0] = (uint)iblk; for (int irow = 0; irow < cur_rows.Count; irow++) { no_c_tmp_row[irow + 1] = cur_rows[irow]; } { uint ino = 0; uint ino_global = no_c_tmp_col[ino]; for (int jno = 0; jno < rowcnt; jno++) { uint jno_global = no_c_tmp_row[jno]; //emat[ino, jno] if (!add_flg[ino_global, jno_global]) { //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global]; //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize]; KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary); add_flg[ino_global, jno_global] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); emattmp[ino * rowcnt + jno] = new Complex(0, 0); } } } // マージ! mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer); } for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } // 残差ベクトルにマージ for (uint ino_global = 0; ino_global < node_cnt; ino_global++) { // 残差ベクトルにマージする uint no_tmp = ino_global; //System.Numerics.Complex cvalue = resVec[ino_global]; KrdLab.clapack.Complex cvalue = resVec[ino_global]; Complex val = new Complex(cvalue.Real, cvalue.Imaginary); res_c.AddValue(no_tmp, 0, val); } } double res = Ls.FinalizeMarge(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList<uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); 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 = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る 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++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Prec.Clear(); Prec.Dispose(); World.Clear(); World.Dispose(); System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return success; }
/// <summary> /// 境界上の節点番号と座標の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <param name="coord_c_all">座標リスト</param> /// <returns></returns> public static bool GetBoundaryCoordList( CFieldWorld world, uint fieldValId, double rotAngle, double[] rotOrigin, out uint[] no_c_all, out Dictionary<uint, uint> to_no_boundary, out double[][] coord_c_all) { no_c_all = null; to_no_boundary = null; coord_c_all = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } IList<uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→境界節点番号変換テーブル(to_no_boundary)作成 to_no_boundary = new Dictionary<uint, uint>(); IList<double[]> coord_c_list = new List<double[]>(); foreach (uint eaId in aIdEA) { bool res = getBoundaryCoordList_EachElementAry( world, fieldValId, eaId, rotAngle, rotOrigin, ref to_no_boundary, ref coord_c_list); if (!res) { return false; } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_boundary.Count]; foreach (KeyValuePair<uint, uint> kvp in to_no_boundary) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } coord_c_all = coord_c_list.ToArray(); return true; }
/// <summary> /// /// </summary> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="tmpBuffer"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> public static bool SolvePCOCG( ref CFieldWorld World, ref uint FieldValId, ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; //------------------------------------------------------------------ // マージの終了 //------------------------------------------------------------------ double res = Ls.FinalizeMarge(); tmpBuffer = null; // マトリクスサイズの取得 // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // マトリクスのサイズ int matLen = (int)mat_cc.NBlkMatCol(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList <uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); 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 = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る 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++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Ls = null; Prec.Clear(); Prec.Dispose(); Prec = null; World.Clear(); World.Dispose(); World = null; System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return(success); }
/// <summary> /// ループ内の節点番号と座標の取得 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="no_c_all">全体節点番号配列</param> /// <param name="to_no_boundary">全体節点番号→境界上の節点番号のマップ</param> /// <param name="coord_c_all">座標リスト</param> /// <returns></returns> public static bool GetLoopCoordList(CFieldWorld world, uint fieldValId, double rotAngle, double[] rotOrigin, out uint[] no_c_all, out Dictionary<uint, uint> to_no_loop, out double[][] coord_c_all, out uint[][] elem_no_c, out uint[] elem_loopId) { no_c_all = null; to_no_loop = null; coord_c_all = null; elem_no_c = null; elem_loopId = null; // フィールドを取得 CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } IList<uint> aIdEA = valField.GetAryIdEA(); // 全体節点番号→ループ内節点番号変換テーブル作成 to_no_loop = new Dictionary<uint, uint>(); IList<double[]> coord_c_list = new List<double[]>(); // 要素の節点番号リスト IList<uint[]> elem_no_c_list = new List<uint[]>(); // 要素のループIDリスト IList<uint> elem_loopId_list = new List<uint>(); foreach (uint eaId in aIdEA) { bool res = getLoopCoordList_EachElementAry( world, fieldValId, eaId, rotAngle, rotOrigin, ref to_no_loop, ref coord_c_list, ref elem_no_c_list, ref elem_loopId_list); if (!res) { return false; } } //境界節点番号→全体節点番号変換テーブル(no_c_all)作成 no_c_all = new uint[to_no_loop.Count]; foreach (KeyValuePair<uint, uint> kvp in to_no_loop) { uint ino_boundary = kvp.Value; uint ino = kvp.Key; no_c_all[ino_boundary] = ino; } coord_c_all = coord_c_list.ToArray(); int elemCnt = elem_no_c_list.Count; elem_no_c = new uint[elemCnt][]; elem_loopId = new uint[elemCnt]; for (int ie = 0; ie < elemCnt; ie++) { elem_no_c[ie] = new uint[3]; for (int i = 0; i < 3; i++) { elem_no_c[ie][i] = elem_no_c_list[ie][i]; elem_loopId[ie] = elem_loopId_list[ie]; } } return true; }
//////////////////////////////////////////////////////////////////////////////////////////////// // DekFEMの処理を隠ぺいした簡易版 //////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// PCOCGで線形方程式を解く /// </summary> /// <param name="mat"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged) public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; int matLen = mat.RowSize; System.Diagnostics.Debug.WriteLine("SolvePCOCG 1"); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; CFieldWorld World = new CFieldWorld(); setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 uint FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); System.Diagnostics.Debug.WriteLine("SolvePCOCG 2"); //------------------------------------------------------------------ // リニアシステム //------------------------------------------------------------------ CZLinearSystem Ls = new CZLinearSystem(); CZPreconditioner_ILU Prec = new CZPreconditioner_ILU(); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ Ls.AddPattern_Field(FieldValId, World); // POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない // 非対角要素のパターンの追加 { uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); // パターンを追加 using (CIndexedArray crs = new CIndexedArray()) { crs.InitializeSize(mat_cc.NBlkMatCol()); //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow()); using (UIntVectorIndexer index = crs.index) using (UIntVectorIndexer ary = crs.array) { for (int iblk = 0; iblk < (int)crs.Size(); iblk++) { index[iblk] = 0; } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 現在のマトリクスのインデックス設定をコピーする uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); foreach (uint row_index in cur_rows) { ary.Add(row_index); } index[iblk + 1] = (uint)ary.Count; //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup); // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0) // すべての節点に関して列を追加 int ino_global = iblk; int col = iblk; if (col != -1 && ino_global != -1) { // 関連付けられていない節点をその行の列データの最後に追加 int last_index = (int)index[col + 1] - 1; int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { // 行列の0要素を除く //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit) //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15) //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { continue; } uint row = (uint)jno_global; if (ino_global != jno_global) // 対角要素は除く { if (!cur_rows.Contains(row)) { ary.Insert(last_index + 1 + add_cnt, row); add_cnt++; //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row); } } } if (add_cnt > 0) { index[col + 1] = (uint)ary.Count; } } } } crs.Sort(); System.Diagnostics.Debug.Assert(crs.CheckValid()); // パターンを削除する mat_cc.DeletePattern(); // パターンを追加する mat_cc.AddPattern(crs); } } System.Diagnostics.Debug.WriteLine("SolvePCOCG 3"); //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // set Preconditioner //Prec.SetFillInLevel(1); // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した //Prec.SetFillInLevel(0); // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする //Prec.SetFillInLevel((uint)mat.RowSize); // 完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い //Prec.SetFillInLevel(3); // 誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある //以上から //メインの導波管の計算時間を短くしたいのでフィルインなしにする //Prec.SetFillInLevel(0); // 導波管だとこれで十分 // フィルインレベルの設定(既定値) Prec.SetFillInLevel(DefFillInLevel); // ILU(0)のパターン初期化 Prec.SetLinearSystem(Ls); System.Diagnostics.Debug.WriteLine("SolvePCOCG 4"); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ //------------------------------------------------------------------ Ls.InitializeMarge(); { uint ntmp = Ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; // 0要素はマージ対象でないので最初から除外する //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit) //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { add_flg[i, j] = true; } } } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応) uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); uint colcnt = 1; uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する Complex[] emattmp = new Complex[colcnt * rowcnt]; uint[] no_c_tmp_col = new uint[colcnt]; uint[] no_c_tmp_row = new uint[rowcnt]; no_c_tmp_col[0] = (uint)iblk; no_c_tmp_row[0] = (uint)iblk; for (int irow = 0; irow < cur_rows.Count; irow++) { no_c_tmp_row[irow + 1] = cur_rows[irow]; } { uint ino = 0; uint ino_global = no_c_tmp_col[ino]; for (int jno = 0; jno < rowcnt; jno++) { uint jno_global = no_c_tmp_row[jno]; //emat[ino, jno] if (!add_flg[ino_global, jno_global]) { //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global]; //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize]; KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary); add_flg[ino_global, jno_global] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); emattmp[ino * rowcnt + jno] = new Complex(0, 0); } } } // マージ! mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer); } for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } // 残差ベクトルにマージ for (uint ino_global = 0; ino_global < node_cnt; ino_global++) { // 残差ベクトルにマージする uint no_tmp = ino_global; //System.Numerics.Complex cvalue = resVec[ino_global]; KrdLab.clapack.Complex cvalue = resVec[ino_global]; Complex val = new Complex(cvalue.Real, cvalue.Imaginary); res_c.AddValue(no_tmp, 0, val); } } double res = Ls.FinalizeMarge(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList <uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); 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 = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る 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++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Prec.Clear(); Prec.Dispose(); World.Clear(); World.Dispose(); System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return(success); }
/// <summary> /// ループ内の節点番号と座標の取得(要素アレイ単位) /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="eaId">要素アレイID</param> /// <param name="to_no_boundary">全体節点番号→境界上節点番号マップ</param> /// <returns></returns> private static bool getLoopCoordList_EachElementAry( CFieldWorld world, uint fieldValId, uint eaId, double rotAngle, double[] rotOrigin, ref Dictionary<uint, uint> to_no_loop, ref IList<double[]> coord_c_list, ref IList<uint[]> elem_no_c_list, ref IList<uint> elem_loopId_list) { // 要素アレイを取得する CElemAry ea = world.GetEA(eaId); System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.TRI); if (ea.ElemType() != ELEM_TYPE.TRI) { return false; } // フィールドを取得 CField valField = world.GetField(fieldValId); // 座標セグメントを取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); // 座標のノードセグメントを取得 CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world); uint node_cnt = ea.Size() + 1; // 全節点数 // 三角形要素の節点数 uint nno = 3; // 座標の次元 uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の座標 double[][] coord_c = new double[nno][]; for (int inoes = 0; inoes < nno; inoes++) { coord_c[inoes] = new double[ndim]; } for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // ループID elem_loopId_list.Add(eaId); // 要素内節点番号 { uint[] work_no_c = new uint[nno]; no_c.CopyTo(work_no_c, 0); elem_no_c_list.Add(work_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]; } } if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit) { // 座標を回転移動する for (uint inoes = 0; inoes < nno; inoes++) { double[] srcPt = coord_c[inoes]; double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin); for (int i = 0; i < ndim; i++) { coord_c[inoes][i] = destPt[i]; } } } for (uint ino = 0; ino < nno; ino++) { if (!to_no_loop.ContainsKey(no_c[ino])) { uint ino_loop_tmp = (uint)to_no_loop.Count; to_no_loop[no_c[ino]] = ino_loop_tmp; coord_c_list.Add(new double[] { coord_c[ino][0], coord_c[ino][1] }); System.Diagnostics.Debug.Assert(coord_c_list.Count == (ino_loop_tmp + 1)); } } } return true; }
/// <summary> /// 節点リストを取得する /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> public static void GetNodeList(CFieldWorld world, uint fieldValId, out uint[] node_c_all) { node_c_all = null; //IList<uint> nodeList = new List<uint>(); Dictionary<uint, bool> nodeNoH = new Dictionary<uint, bool>(); CField valField = world.GetField(fieldValId); uint nno = 3; //uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素アレイのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); foreach (uint eaId in aIdEA) { // 要素アレイを取得 CElemAry ea = world.GetEA(eaId); // 座標の要素セグメント(コーナー)を取得 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); for (int ino = 0; ino < nno; ino++) { uint inoGlobal = no_c[ino]; if (!nodeNoH.ContainsKey(inoGlobal)) { //nodeList.Add(inoGlobal); nodeNoH.Add(inoGlobal, true); } } } } //node_c_all = nodeList.ToArray(); node_c_all = nodeNoH.Keys.ToArray(); }
/// <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> /// ヘルムホルツの方程式 剛性行列、質量行列の作成 /// </summary> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">値のフィールドID</param> /// <param name="medias">媒質リスト</param> /// <param name="loopDic">ループ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> public static bool MkHelmholtzMat( CFieldWorld world, uint fieldValId, IList<MediaInfo> medias, Dictionary<uint, World.Loop> loopDic, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, int subdiaSize, int superdiaSize, out MyDoubleBandMatrix KMat, out MyDoubleBandMatrix MMat) { KMat = null; MMat = null; // 値のフィールドIDかチェック if (!world.IsIdField(fieldValId)) { return false; } // 値のフィールドを取得する CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } KMat = new MyDoubleBandMatrix((int)free_node_cnt, subdiaSize, superdiaSize); MMat = new MyDoubleBandMatrix((int)free_node_cnt, subdiaSize, superdiaSize); // 要素アレイのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); foreach (uint eaId in aIdEA) { if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (loopDic.ContainsKey(lId)) { World.Loop loop = loopDic[lId]; media = medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } bool res = MkHelmholtzMat_EachElementAry( world, fieldValId, media, eaId, node_cnt, free_node_cnt, toSorted, ref KMat, ref MMat ); if (!res) { return false; } } } 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> /// 非0パターンを作成する /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <param name="medias"></param> /// <param name="loopDic"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="toSorted"></param> /// <param name="matPattern"></param> /// <returns></returns> public static bool MkMatPattern( CFieldWorld world, uint fieldValId, IList<MediaInfo> medias, Dictionary<uint, World.Loop> loopDic, uint node_cnt, uint free_node_cnt, Dictionary<uint, uint> toSorted, out bool[,] matPattern) { matPattern = null; // 値のフィールドIDかチェック if (!world.IsIdField(fieldValId)) { return false; } // 値のフィールドを取得する CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } matPattern = new bool[free_node_cnt, free_node_cnt]; // 要素アレイのリストを取得する IList<uint> aIdEA = valField.GetAryIdEA(); foreach (uint eaId in aIdEA) { if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (loopDic.ContainsKey(lId)) { World.Loop loop = loopDic[lId]; media = medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } bool res = MkMatPattern_EachElementAry( world, fieldValId, media, eaId, node_cnt, free_node_cnt, toSorted, ref matPattern ); if (!res) { return false; } } } return true; }
/// <summary> /// ヘルムホルツの方程式 剛性行列 残差ベクトルの追加 /// </summary> /// <param name="ls"></param> /// <param name="waveLength"></param> /// <param name="world"></param> /// <param name="fieldValId"></param> /// <returns></returns> public static bool AddLinSysHelmholtz(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId) { if (!world.IsIdField(fieldValId)) { return false; } CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } IList<uint> aIdEA = valField.GetAryIdEA(); foreach (uint eaId in aIdEA) { if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11) { uint ntmp = ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } bool res = AddLinSysHelmholtz_EachElementAry(ls, waveLength, world, fieldValId, eaId, tmpBuffer); if (!res) { return false; } } } return true; }
/// <summary> /// 矩形導波管開口境界条件(要素アレイ単位) /// Note: 境界の要素はy = 0からy = waveguideWidth へ順番に要素アレイに格納され、節点2は次の要素の節点1となっていることが前提 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="isInputPort">入射ポート?</param> /// <param name="incidentModeIndex">入射モードのインデックス</param> /// <param name="isFreeBc">境界条件を課さない?</param> /// <param name="ryy_1d">FEM[ryy]行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <param name="no_c_all">節点番号配列</param> /// <param name="tmpBuffer">一時バッファ</param> /// <returns></returns> private static bool addLinSys_PeriodicWaveguidePortBC_Core( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldValId, bool isInputPort, int incidentModeIndex, Complex[] amps, bool isFreeBc, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs, uint[] no_c_all, ref int[] tmpBuffer) { double k0 = 2.0 * pi / waveLength; double omega = k0 / Math.Sqrt(myu0 * eps0); //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); // 境界上の節点数(1次線要素を想定) uint node_cnt = (uint)ryy_1d.GetLength(0); // 考慮するモード数 uint max_mode = (uint)eigen_values.Length; // 全体剛性行列の作成 Complex[,] mat_all = new Complex[node_cnt, node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { mat_all[ino_boundary, jno_boundary] = new Complex(0.0, 0.0); } } if (!isFreeBc) { for (uint imode = 0; imode < max_mode; imode++) { Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); //Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { Complex cvalue = 0.0; if (waveModeDv == WaveModeDV.TM) { // TMモード //cvalue = (imagOne / (omega * eps0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary]; cvalue = (imagOne / (omega * eps0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary]; } else { // TEモード //cvalue = (imagOne / (omega * myu0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary]; cvalue = (imagOne / (omega * myu0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary]; } mat_all[ino_boundary, jno_boundary] += cvalue; } } } // check 対称行列 bool isSymmetrix = true; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = ino_boundary; jno_boundary < node_cnt; jno_boundary++) { if (Math.Abs(mat_all[ino_boundary, jno_boundary].Real - mat_all[jno_boundary, ino_boundary].Real) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } if (Math.Abs(mat_all[ino_boundary, jno_boundary].Imag - mat_all[jno_boundary, ino_boundary].Imag) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } //MyMatrixUtil.printMatrix("emat_all", emat_all); } // 残差ベクトルの作成 Complex[] res_c_all = new Complex[node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { res_c_all[ino_boundary] = 0.0; } if (isInputPort && incidentModeIndex < eigen_values.Length) { if (amps != null) { // 全モードを入射させる for (uint imode = 0; imode < max_mode; imode++) { Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // TEモード、TMモード共通 //Complex cvalue = 2.0 * imagOne * betam * veci[ino_boundary] * amList[imode]; Complex cvalue = 2.0 * imagOne * betam_periodic * veci[ino_boundary] * amps[imode]; res_c_all[ino_boundary] += cvalue; } } } else { uint imode = (uint)incidentModeIndex; Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // TEモード、TMモード共通 //res_c_all[ino_boundary] = 2.0 * imagOne * betam * veci[ino_boundary]; res_c_all[ino_boundary] = 2.0 * imagOne * betam_periodic * veci[ino_boundary]; } } } //MyMatrixUtil.printVec("eres_c_all", eres_c_all); // 線要素の節点数 uint nno = 2; // 座標の次元 //uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[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); //System.Diagnostics.Debug.WriteLine("fieldValId: {0}", fieldValId); //System.Diagnostics.Debug.WriteLine("NBlkMatCol:" + mat_cc.NBlkMatCol()); // (境界でなく領域の総節点数と同じ?) if (!isFreeBc) { // 要素剛性行列にマージ // この定式化では行列のスパース性は失われている(隣接していない要素の節点間にも関連がある) // 要素剛性行列にマージする bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; } } // このケースではmat_ccへのマージは対角行列でマージしなければならないようです。 // 1 x node_cntの横ベクトルでマージしようとするとassertに引っかかります。 // 境界上の節点に関しては非0要素はないので、境界上の節点に関する // node_cnt x node_cntの行列を一括でマージできます。 // col, rowの全体節点番号ベクトル uint[] no_c_tmp = new uint[node_cnt]; // 要素行列(ここでは境界の剛性行列を一括でマージします) Complex[] emattmp = new Complex[node_cnt * node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // colブロックのインデックス(全体行列の節点番号) uint iblk = no_c_all[ino_boundary]; uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); //System.Diagnostics.Debug.WriteLine("chk3:{0} {1}", iblk, npsup); for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { if (ino_boundary != jno_boundary) { uint rowno = no_c_all[jno_boundary]; if (cur_rows.IndexOf(rowno) == -1) { System.Diagnostics.Debug.Assert(false); return false; } } if (!add_flg[ino_boundary, jno_boundary]) { // 要素行列を作成 Complex cvalue = mat_all[ino_boundary, jno_boundary]; //emattmp[ino_boundary, jno_boundary] emattmp[ino_boundary * node_cnt + jno_boundary] = cvalue; add_flg[ino_boundary, jno_boundary] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); //emattmp[ino_boundary, jno_boundary] emattmp[ino_boundary * node_cnt + jno_boundary] = new Complex(0, 0); } } no_c_tmp[ino_boundary] = iblk; } // 一括マージ mat_cc.Mearge(node_cnt, no_c_tmp, node_cnt, no_c_tmp, 1, emattmp, ref tmpBuffer); for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } } // 残差ベクトルにマージ for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // 残差ベクトルにマージする uint no_tmp = no_c_all[ino_boundary]; Complex val = res_c_all[ino_boundary]; res_c.AddValue(no_tmp, 0, val); } return true; }