/// <summary> /// リニアシステム初期化(マージ開始までの処理) /// </summary> /// <param name="matPattern">行列の非0要素パターン</param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> public static void SetupLinearSystem( bool[,] matPattern, out CFieldWorld World, out uint FieldValId, out CZLinearSystem Ls, out CZPreconditioner_ILU Prec, out int[] tmpBuffer) { World = new CFieldWorld(); Ls = new CZLinearSystem(); Prec = new CZPreconditioner_ILU(); tmpBuffer = null; int matLen = matPattern.GetLength(0); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ 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) { //BUGFIX //for (int iblk = 0; iblk < (int)crs.Size(); iblk++) // indexのサイズは crs.Size() + 1 (crs.Size() > 0のとき) for (int iblk = 0; iblk < index.Count; 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; //System.Diagnostics.Debug.Assert(last_index == ary.Count - 1); int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { if (!matPattern[ino_global, jno_global]) { continue; } uint row = (uint)jno_global; //if (ino_global != jno_global) // 対角要素は除く if (col != row) // 対角要素は除く { if (!cur_rows.Contains(row)) { //ary.Insert(last_index + 1 + add_cnt, row); ary.Add(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); } } //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // 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); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ開始 //------------------------------------------------------------------ Ls.InitializeMarge(); uint ntmp = Ls.GetTmpBufferSize(); tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } }
//////////////////////////////////////////////////////////////////////////////////////////////// // 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="matPattern">行列の非0要素パターン</param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> public static void SetupLinearSystem( bool[,] matPattern, out CFieldWorld World, out uint FieldValId, out CZLinearSystem Ls, out CZPreconditioner_ILU Prec, out int[] tmpBuffer) { World = new CFieldWorld(); Ls = new CZLinearSystem(); Prec = new CZPreconditioner_ILU(); tmpBuffer = null; int matLen = matPattern.GetLength(0); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ 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) { //BUGFIX //for (int iblk = 0; iblk < (int)crs.Size(); iblk++) // indexのサイズは crs.Size() + 1 (crs.Size() > 0のとき) for (int iblk = 0; iblk < index.Count; 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; //System.Diagnostics.Debug.Assert(last_index == ary.Count - 1); int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { if (!matPattern[ino_global, jno_global]) { continue; } uint row = (uint)jno_global; //if (ino_global != jno_global) // 対角要素は除く if (col != row) // 対角要素は除く { if (!cur_rows.Contains(row)) { //ary.Insert(last_index + 1 + add_cnt, row); ary.Add(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); } } //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // 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); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ開始 //------------------------------------------------------------------ Ls.InitializeMarge(); uint ntmp = Ls.GetTmpBufferSize(); tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } }
//////////////////////////////////////////////////////////////////////////////////////////////// // 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="probNo">問題番号</param> /// <param name="freqIndex">周波数のインデックス</param> /// <param name="NormalizedFreq1">開始規格化周波数</param> /// <param name="NormalizedFreq2">終了規格化周波数</param> /// <param name="FreqDelta">計算刻み幅</param> /// <param name="initFlg">カメラ初期化フラグ</param> /// <param name="WaveguideWidth">導波路幅</param> /// <param name="WaveModeDv">波のモード区分</param> /// <param name="World">ワールド座標系</param> /// <param name="FieldValId">値のフィールドID</param> /// <param name="FieldLoopId">ループのフィールドID</param> /// <param name="FieldForceBcId">強制境界のフィールドID</param> /// <param name="FieldPortBcId1">ポート1境界のフィールドID</param> /// <param name="FieldPortBcId2">ポート2境界のフィールドID</param> /// <param name="Medias">媒質リスト</param> /// <param name="LoopDic">ループID→ループ情報マップ</param> /// <param name="EdgeDic">エッジID→エッジ情報マップ</param> /// <param name="IsShowAbsField">絶対値表示する?</param> /// <param name="Ls">リニアシステム</param> /// <param name="Prec">プリコンディショナ―</param> /// <param name="ScatterVecList">散乱係数リスト(ポート毎のモード散乱係数リストのリスト)</param> /// <param name="DrawerAry">描画オブジェクトアレイ</param> /// <param name="Camera">カメラ</param> /// <returns></returns> private static bool solveProblem( int probNo, ref int freqIndex, double NormalizedFreq1, double NormalizedFreq2, double FreqDelta, bool initFlg, double WaveguideWidth, WgUtil.WaveModeDV WaveModeDv, ref CFieldWorld World, uint FieldValId, uint FieldLoopId, uint FieldForceBcId, uint FieldPortBcId1, uint FieldPortBcId2, IList<MediaInfo> Medias, Dictionary<uint, World.Loop> LoopDic, Dictionary<uint, World.Edge> EdgeDic, bool IsShowAbsField, ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref IList<IList<Complex[]>> ScatterVecList, ref CDrawerArrayField DrawerAry, CCamera Camera) { //long memorySize1 = GC.GetTotalMemory(false); //Console.WriteLine(" total memory: {0}", memorySize1); bool success = false; // 入射モードインデックス int incidentModeIndex = 0; // ポート数 int portCnt = 2; int incidentPortNo = getIncidentPortNo(); int propModeCnt_port1 = 1; int propModeCnt_port2 = 1; // モード電力の合計を出力として表示する bool isShowTotalPortPower = false; if (probNo == 3) { /* // 入力5モード表示 //propModeCnt_port1 = 5; //propModeCnt_port2 = 1; // 出力5モード表示 //propModeCnt_port1 = 1; //propModeCnt_port2 = 5; propModeCnt_port1 = 3; propModeCnt_port2 = 3; */ //isShowTotalPortPower = true; // モード電力の合計を出力として表示する } try { // 規格化周波数 double normalizedFreq = getNormalizedFreq( ref freqIndex, NormalizedFreq1, NormalizedFreq2, FreqDelta); if (freqIndex == -1) { return success; } // 波数 double k0 = normalizedFreq * pi / WaveguideWidth; // 波長 double waveLength = 2.0 * pi / k0; System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq); //------------------------------------------------------------------ // リニアシステム //------------------------------------------------------------------ Ls.Clear(); Prec.Clear(); WgUtil.GC_Collect(); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ // ワールド座標系のフィールド値をクリア WgUtil.ClearFieldValues(World, FieldValId); // 領域全体の界パターンを追加 Ls.AddPattern_Field(FieldValId, World); // 上記界パターンでは、隣接する要素以外の剛性行列の値は追加できないようです。境界用に追加パターンを作成 uint[] fieldPortBcId_list = {FieldPortBcId1, FieldPortBcId2}; System.Diagnostics.Debug.Assert(fieldPortBcId_list.Length == portCnt); foreach (uint workFieldPortBcId in fieldPortBcId_list) { WgUtil.MakeWaveguidePortBCPattern(Ls, World, workFieldPortBcId); } //------------------------------------------------------------------ // 固定境界条件を設定 //------------------------------------------------------------------ if (FieldForceBcId != 0) { Ls.SetFixedBoundaryCondition_Field(FieldForceBcId, 0, World); // 固定境界条件を設定 } uint[] fixedBcNodes = null; // 強制境界条件を課す節点を取得する // 境界の固有モード解析で強制境界を指定する際に使用する(CZLinearSystemのBCFlagを参照できないので) Dictionary<uint, uint> tmp_to_no_boundary = null; if (FieldForceBcId != 0) { WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out fixedBcNodes, out tmp_to_no_boundary); } //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // set Preconditioner //Prec.SetFillInLevel(1); uint fillInLevel = 1; if (probNo == 3) { // 誘電体スラブ導波路ではILU(1)では収束しないので、フィルインレベルを大きくとる fillInLevel = 15; } System.Diagnostics.Debug.WriteLine("fillInLevel: {0}", fillInLevel); Prec.SetFillInLevel(fillInLevel); // ILU(0)のパターン初期化 Prec.SetLinearSystem(Ls); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ //------------------------------------------------------------------ Ls.InitializeMarge(); IList<double[,]> ryy_1d_port_list = new List<double[,]>(); IList<Complex[]> eigen_values_port_list = new List<Complex[]>(); IList<Complex[,]> eigen_vecs_port_list = new List<Complex[,]>(); System.Diagnostics.Debug.Assert(incidentPortNo == 1); // 境界の界に導波路開口条件を追加 bool retAddPort = false; // 境界の界に導波路開口条件を追加 for (int portIndex = 0; portIndex < portCnt; portIndex++) { uint workFieldPortBcId = fieldPortBcId_list[portIndex]; double[,] ryy_1d_port1 = null; Complex[] eigen_values_port1 = null; Complex[,] eigen_vecs_port1 = null; retAddPort = WgUtil.AddLinSys_WaveguidePortBC( Ls, waveLength, WaveModeDv, World, workFieldPortBcId, fixedBcNodes, (portIndex == (incidentPortNo - 1)), incidentModeIndex, Medias, EdgeDic, out ryy_1d_port1, out eigen_values_port1, out eigen_vecs_port1); // 格納する ryy_1d_port_list.Add(ryy_1d_port1); eigen_values_port_list.Add(eigen_values_port1); eigen_vecs_port_list.Add(eigen_vecs_port1); if (!retAddPort) { System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1)); // 表示用にデータを格納する if (freqIndex == 0) { ScatterVecList.Clear(); } { IList<Complex[]> work_portScatterVecList = new List<Complex[]>(); for (int p = 0; p < portCnt; p++) { int propModeCnt = 0; if (p == 0) { propModeCnt = propModeCnt_port1; } else if (p == 1) { propModeCnt = propModeCnt_port2; } else { System.Diagnostics.Debug.Assert(false); } Complex[] work_scatterVec = new Complex[propModeCnt]; for (int imode = 0; imode < propModeCnt; imode++) { work_scatterVec[imode] = 0; } work_portScatterVecList.Add(work_scatterVec); } ScatterVecList.Add(work_portScatterVecList); } return false; } System.Diagnostics.Debug.WriteLine("port{0} node_cnt: {1}", (portIndex + 1), eigen_vecs_port_list[portIndex].GetLength(1)); } // 領域 WgUtil.AddLinSysHelmholtz(Ls, waveLength, World, FieldLoopId, Medias, LoopDic); double res = Ls.FinalizeMarge(); //System.Diagnostics.Debug.WriteLine("Residual : " + res); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); double tol = 1.0e-6; uint maxIter = 2000; uint iter = maxIter; CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); if (iter == maxIter) { Console.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq); System.Diagnostics.Debug.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq); } //System.Diagnostics.Debug.WriteLine("Solved!"); // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 反射、透過係数 double totalPower = 0.0; IList<Complex[]> portScatterVecList = new List<Complex[]>(); for (int portIndex = 0; portIndex < portCnt; portIndex++) { Complex[] eigen_values_port1 = eigen_values_port_list[portIndex]; double[,] ryy_1d_port1 = ryy_1d_port_list[portIndex]; Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[portIndex]; int propModeCnt = 0; if (portIndex == 0) { propModeCnt = propModeCnt_port1; } else if (portIndex == 1) { propModeCnt = propModeCnt_port2; } else { System.Diagnostics.Debug.Assert(false); } Complex[] scatterVec = new Complex[propModeCnt]; for (int m = 0; m < propModeCnt; m++) { scatterVec[m] = 0.0; } uint workFieldPortBcId = fieldPortBcId_list[portIndex]; for (uint imode = 0; imode < eigen_values_port1.Length; imode++) { Complex s11 = WgUtil.GetWaveguidePortReflectionCoef( Ls, waveLength, WaveModeDv, World, workFieldPortBcId, imode, ((portIndex == (incidentPortNo - 1)) && imode == incidentModeIndex), ryy_1d_port1, eigen_values_port1, eigen_vecs_port1); if (imode < propModeCnt || Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { System.Diagnostics.Debug.WriteLine(" s" + (portIndex + 1) + incidentPortNo + " = (" + s11.Real + "," + s11.Imag + ")" + " |s" + (portIndex + 1) + incidentPortNo + "|^2 = " + Complex.SquaredNorm(s11) + ((imode == 0) ? " incident" : "")); } if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード { totalPower += Complex.SquaredNorm(s11); } if (isShowTotalPortPower) { if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード { // ポート電力を計算 scatterVec[0] += Complex.Norm(s11) * Complex.Norm(s11); } } else { if (imode < propModeCnt) { scatterVec[imode] = s11; } } } portScatterVecList.Add(scatterVec); } System.Diagnostics.Debug.WriteLine(" totalPower = {0}", totalPower); if (isShowTotalPortPower) { for (int p = 0; p < portCnt; p++) { // ルート電力に変換 Complex[] scatterVec = portScatterVecList[p]; double sqrtPower = Math.Sqrt(Complex.Norm(scatterVec[0])); scatterVec[0] = sqrtPower; //portScatterVecList[p] = scatterVec; System.Diagnostics.Debug.WriteLine("port total sqrt power s{0}{1} : {2}", (p + 1), incidentPortNo, sqrtPower); } } // 表示用にデータを格納する if (freqIndex == 0) { ScatterVecList.Clear(); } { ScatterVecList.Add(portScatterVecList); } // 描画する界の値を加工して置き換える // そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。 // 絶対値を表示したかったので、下記処理を追加しています。 if (IsShowAbsField) { WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 } // DEBUG //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示 //------------------------------------------------------------------ // 描画する界の追加 //------------------------------------------------------------------ DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId)); DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World)); if (initFlg) { // カメラの変換行列初期化 DrawerAry.InitTrans(Camera); // 表示位置調整 setupPanAndScale(probNo, Camera); } success = true; } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); // 表示用にデータを格納する if (freqIndex == 0) { ScatterVecList.Clear(); } { IList<Complex[]> work_portScatterVecList = new List<Complex[]>(); for (int p = 0; p < portCnt; p++) { int propModeCnt = 0; if (p == 0) { propModeCnt = propModeCnt_port1; } else if (p == 1) { propModeCnt = propModeCnt_port2; } else { System.Diagnostics.Debug.Assert(false); } Complex[] work_scatterVec = new Complex[propModeCnt]; for (int imode = 0; imode < propModeCnt; imode++) { work_scatterVec[imode] = 0; } work_portScatterVecList.Add(work_scatterVec); } ScatterVecList.Add(work_portScatterVecList); } } return success; }
/// <summary> /// 問題を設定する /// </summary> /// <returns></returns> private bool setNewProblem() { bool success = false; try { if (ProbNo == 0 || ProbNo == 1) { //////////////// // 波源の頂点 uint id_v = 0; // ワールド座標系のベースID uint id_base = 0; using (CCadObj2D cad2d = new CCadObj2D()) { // define shape IList<CVector2D> pts = new List<CVector2D>(); pts.Add(new CVector2D(0.0, 0.0)); // 頂点1 pts.Add(new CVector2D(2.0, 0.0)); // 頂点2 pts.Add(new CVector2D(2.0, 2.0)); // 頂点3 pts.Add(new CVector2D(0.0, 2.0)); // 頂点4 uint id_l = cad2d.AddPolygon(pts).id_l_add; id_v = cad2d.AddVertex(CAD_ELEM_TYPE.LOOP, id_l, new CVector2D(0.5, 0.05)).id_v_add; World.Clear(); id_base = World.AddMesh(new CMesher2D(cad2d, 0.04)); } // CADのIDからワールド座標系のIDへ変換するコンバーターを取得 CIDConvEAMshCad conv = World.GetIDConverter(id_base); // フィールドを作成する // 図形の次元2次元、値、コーナー(要素の角頂点) uint id_field_val = World.MakeField_FieldElemDim( id_base, 2, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); //uint id_field_bc0 = World.GetPartialField(id_field_val,conv.GetIdEA_fromCad(2, 1)); uint id_field_bc1 = 0; { IList<uint> aEA = new List<uint>(); aEA.Add(conv.GetIdEA_fromCad(1, CAD_ELEM_TYPE.EDGE)); aEA.Add(conv.GetIdEA_fromCad(2, CAD_ELEM_TYPE.EDGE)); aEA.Add(conv.GetIdEA_fromCad(3, CAD_ELEM_TYPE.EDGE)); aEA.Add(conv.GetIdEA_fromCad(4, CAD_ELEM_TYPE.EDGE)); id_field_bc1 = World.GetPartialField(id_field_val, aEA); } CFieldValueSetter.SetFieldValue_Constant(id_field_bc1, 0, FIELD_DERIVATION_TYPE.VALUE, World, 0); using (CZLinearSystem ls = new CZLinearSystem()) using (CZPreconditioner_ILU prec = new CZPreconditioner_ILU()) { // 場のパターンをリニアシステムに追加する ls.AddPattern_Field(id_field_val, World); // 境界条件 //ls.SetFixedBoundaryCondition_Field(id_field_bc0,World); //ls.SetFixedBoundaryCondition_Field(id_field_bc1,World); // プリコンディショナ―フィルインあり prec.SetFillInLevel(1); // プリコンディショナ―にリニアシステムをセットする prec.SetLinearSystem(ls); // 波長 double wave_length = 0.4; // 全体行列の作成 ls.InitializeMarge(); if (ProbNo == 0) { Console.WriteLine("///// DelFEM4NetFem.Eqn.CEqnHelmholtz"); // DelFEMのライブラリを使用 CEqnHelmholz.AddLinSys_Helmholtz(ls, wave_length, World, id_field_val); CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(ls, wave_length, World, id_field_bc1); } else { Console.WriteLine("///// CEqnHelmholtz_ForCSharp"); // C#で記述した関数を使用(TEST) System.Diagnostics.Debug.Assert(ProbNo == 1); CEqnHelmholtz_ForCSharp.AddLinSysHelmholtz(ls, wave_length, World, id_field_val); CEqnHelmholtz_ForCSharp.AddLinSys_SommerfeltRadiationBC(ls, wave_length, World, id_field_bc1); } double res = ls.FinalizeMarge(); // リニアシステムのマトリクスの値をセットしてILU分解を行う prec.SetValue(ls); // 励振:波源を設定する { // 波源の頂点IDからワールド座標系の要素アレイIDを取得する uint id_ea_v = conv.GetIdEA_fromCad(id_v, CAD_ELEM_TYPE.VERTEX); Console.WriteLine(id_ea_v); // 要素アレイを取得する CElemAry ea = World.GetEA(id_ea_v); // 要素セグメントを取得する CElemAry.CElemSeg es = ea.GetSeg(1); // セグメントID: 1 System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.POINT); // 最初の要素の節点番号を取り出す uint[] noes = new uint[1]; es.GetNodes(0, noes); // 要素インデックス: 0 Console.WriteLine(noes[0]); // 残差ベクトルのポインタを取得 using (CZVector_Blk_Ptr residualPtr = ls.GetResidualPtr(id_field_val, ELSEG_TYPE.CORNER, World)) { // 節点番号noes[0]の0番目の自由度に値を加算する residualPtr.AddValue(noes[0], 0, new Complex(1, 0)); } } Console.WriteLine("Residual : " + res); { double tol = 1.0e-6; uint iter = 2000; //CZSolverLsIter.Solve_CG(ref tol, ref iter, ls); //CZSolverLsIter.Solve_PCG(ref tol, ref iter,ls, prec); CZSolverLsIter.Solve_PCOCG(ref tol,ref iter,ls, prec); //CZSolverLsIter.Solve_CGNR(ref tol,ref iter, ls); //CZSolverLsIter.Solve_BiCGSTAB(ref tol,ref iter,ls); //CZSolverLsIter.Solve_BiCGStabP(ref tol, ref iter,ls, prec); Console.WriteLine(iter + " " + tol); } ls.UpdateValueOfField(id_field_val, World, FIELD_DERIVATION_TYPE.VALUE); } // 描画オブジェクトアレイの追加 DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(id_field_val, true, World, id_field_val, -0.05, 0.05)); //DrawerAry.PushBack( new CDrawerFaceContour(id_field_ val, World) ); DrawerAry.PushBack(new CDrawerEdge(id_field_val, true, World)); DrawerAry.InitTrans(Camera); } success = true; } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); } ProbNo++; if (ProbNo == ProbCnt) ProbNo = 0; return success; }