/// <summary> /// 欠陥部セルのメッシュ取得 /// </summary> /// <param name="ndivForOneLattice">格子1辺の分割数</param> /// <param name="ptsInCell">セル内節点の座標リスト</param> /// <param name="nodeBInCell">セル境界節点の節点番号リスト</param> /// <param name="elemNodeInCell">要素内節点の節点番号リスト</param> public static void GetCellMesh_Defect_TriFirstOrder( int ndivForOneLattice, out double[,] ptsInCell, out uint[,] nodeBInCell, out uint[,] elemNodeInCell ) { uint[] dummy_elemLoopIdInCell = null; uint dummy_RodLoopId = 0; double dummy_rodRadiusRatio = 0.0; int dummy_rodCircleDiv = 0; int dummy_rodRadiusDiv = 0; uint FieldValId = 0; uint FieldLoopId = 0; uint FieldForceBcId = 0; IList <uint> FieldPortBcIds = new List <uint>(); CFieldWorld World = new CFieldWorld(); mkMeshCell_Rod_Tri_FirstOrder( false, /* isRodCell : fase 欠陥部 true ロッド部 */ ndivForOneLattice, dummy_rodRadiusRatio, dummy_rodCircleDiv, dummy_rodRadiusDiv, ref World, ref FieldValId, ref FieldLoopId, ref FieldForceBcId, ref FieldPortBcIds, out dummy_RodLoopId); getCoordListFromMeshCell_Tri_FirstOrder( World, FieldLoopId, FieldForceBcId, FieldPortBcIds, out ptsInCell, out nodeBInCell, out dummy_elemLoopIdInCell, out elemNodeInCell ); World.Dispose(); World = null; }
/// <summary> /// ロッド部セルメッシュの取得 /// </summary> /// <param name="ndivForOneLattice">格子1辺の分割数</param> /// <param name="rodRadiusRatio">ロッドの半径割合</param> /// <param name="rodCircleDiv">ロッドの円周方向分割数</param> /// <param name="rodRadiusDiv">ロッドの半径方向分割数(1でもメッシュサイズが小さければ複数に分割される)</param> /// <param name="ptsInCell">セル内節点の座標リスト</param> /// <param name="nodeBInCell">セル境界節点の節点番号リスト</param> /// <param name="elemLoopIdInCell">セル内要素のワールド座標系ループIDリスト</param> /// <param name="RodLoopId">ロッドのワールド座標系ループID</param> /// <param name="elemNodeInCell">要素内節点の節点番号リスト</param> public static void GetCellMesh_Rod_TriFirstOrder( int ndivForOneLattice, double rodRadiusRatio, int rodCircleDiv, int rodRadiusDiv, out double[,] ptsInCell, out uint[,] nodeBInCell, out uint[] elemLoopIdInCell, out uint RodLoopId, out uint[,] elemNodeInCell ) { uint FieldValId = 0; uint FieldLoopId = 0; uint FieldForceBcId = 0; IList <uint> FieldPortBcIds = new List <uint>(); CFieldWorld World = new CFieldWorld(); mkMeshCell_Rod_Tri_FirstOrder( true, /* isRodCell */ ndivForOneLattice, rodRadiusRatio, rodCircleDiv, rodRadiusDiv, ref World, ref FieldValId, ref FieldLoopId, ref FieldForceBcId, ref FieldPortBcIds, out RodLoopId); getCoordListFromMeshCell_Tri_FirstOrder( World, FieldLoopId, FieldForceBcId, FieldPortBcIds, out ptsInCell, out nodeBInCell, out elemLoopIdInCell, out elemNodeInCell ); World.Dispose(); World = null; }
//////////////////////////////////////////////////////////////////////////////////////////////// // 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"></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); }
//////////////////////////////////////////////////////////////////////////////////////////////// // 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"></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="ndivForOneLattice">格子1辺の分割数</param> /// <param name="ptsInCell">セル内節点の座標リスト</param> /// <param name="nodeBInCell">セル境界節点の節点番号リスト</param> /// <param name="elemNodeInCell">要素内節点の節点番号リスト</param> public static void GetCellMesh_Defect_TriFirstOrder( int ndivForOneLattice, out double[,] ptsInCell, out uint[,] nodeBInCell, out uint[,] elemNodeInCell ) { uint[] dummy_elemLoopIdInCell = null; uint dummy_RodLoopId = 0; double dummy_rodRadiusRatio = 0.0; int dummy_rodCircleDiv = 0; int dummy_rodRadiusDiv = 0; uint FieldValId = 0; uint FieldLoopId = 0; uint FieldForceBcId = 0; IList<uint> FieldPortBcIds = new List<uint>(); CFieldWorld World = new CFieldWorld(); mkMeshCell_Rod_Tri_FirstOrder( false, /* isRodCell : fase 欠陥部 true ロッド部 */ ndivForOneLattice, dummy_rodRadiusRatio, dummy_rodCircleDiv, dummy_rodRadiusDiv, ref World, ref FieldValId, ref FieldLoopId, ref FieldForceBcId, ref FieldPortBcIds, out dummy_RodLoopId); getCoordListFromMeshCell_Tri_FirstOrder( World, FieldLoopId, FieldForceBcId, FieldPortBcIds, out ptsInCell, out nodeBInCell, out dummy_elemLoopIdInCell, out elemNodeInCell ); World.Dispose(); World = null; }
/// <summary> /// ロッド部セルメッシュの取得 /// </summary> /// <param name="ndivForOneLattice">格子1辺の分割数</param> /// <param name="rodRadiusRatio">ロッドの半径割合</param> /// <param name="rodCircleDiv">ロッドの円周方向分割数</param> /// <param name="rodRadiusDiv">ロッドの半径方向分割数(1でもメッシュサイズが小さければ複数に分割される)</param> /// <param name="ptsInCell">セル内節点の座標リスト</param> /// <param name="nodeBInCell">セル境界節点の節点番号リスト</param> /// <param name="elemLoopIdInCell">セル内要素のワールド座標系ループIDリスト</param> /// <param name="RodLoopId">ロッドのワールド座標系ループID</param> /// <param name="elemNodeInCell">要素内節点の節点番号リスト</param> public static void GetCellMesh_Rod_TriFirstOrder( int ndivForOneLattice, double rodRadiusRatio, int rodCircleDiv, int rodRadiusDiv, out double[,] ptsInCell, out uint[,] nodeBInCell, out uint[] elemLoopIdInCell, out uint RodLoopId, out uint[,] elemNodeInCell ) { uint FieldValId = 0; uint FieldLoopId = 0; uint FieldForceBcId = 0; IList<uint> FieldPortBcIds = new List<uint>(); CFieldWorld World = new CFieldWorld(); mkMeshCell_Rod_Tri_FirstOrder( true, /* isRodCell */ ndivForOneLattice, rodRadiusRatio, rodCircleDiv, rodRadiusDiv, ref World, ref FieldValId, ref FieldLoopId, ref FieldForceBcId, ref FieldPortBcIds, out RodLoopId); getCoordListFromMeshCell_Tri_FirstOrder( World, FieldLoopId, FieldForceBcId, FieldPortBcIds, out ptsInCell, out nodeBInCell, out elemLoopIdInCell, out elemNodeInCell ); World.Dispose(); World = null; }