/// <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> /// ヘルムホルツの方程式 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; }
//////////////////////////////////////////////////////////////////////////////////////////////// // 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; } }
/// <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> /// 非対称複素行列の連立方程式をLisys(clapack)で解く /// </summary> /// <param name="Ls"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> private static void solveAsymmetricCompplexMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId) { // 非対称複素行列の連立方程式をLisys(clapack)で解く CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); uint nblk = femMat.NBlkMatCol(); KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[nblk * nblk]; System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow()); for (uint iblk = 0; iblk < nblk; iblk++) { ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk); System.Diagnostics.Debug.Assert(ptr.Count == 1); A[iblk + nblk * iblk].Real = ptr[0].Real; A[iblk + nblk * iblk].Imaginary = ptr[0].Imag; //Console.WriteLine(" ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i"); uint npsup = 0; ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup); ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup); System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count); for (int i = 0; i < ptrVal.Count; i++) { A[iblk + nblk * ptrInd[i]].Real = ptrVal[i].Real; A[iblk + nblk * ptrInd[i]].Imaginary = ptrVal[i].Imag; //Console.WriteLine(" ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i"); } } // 残差ベクトル CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen()); System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen()); KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk]; for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++) { Complex cvalue = resPtr.GetValue(iblk, 0); B[iblk].Real = cvalue.Real; B[iblk].Imaginary = cvalue.Imag; //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0)); } // 対称行列チェック bool isSymmetrix = true; for (int i = 0; i < nblk; i++) { for (int j = i; j < nblk; j++) { KrdLab.clapack.Complex aij = A[i + nblk * j]; KrdLab.clapack.Complex aji = A[j + nblk * i]; if (Math.Abs(aij.Real - aji.Real) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } if (Math.Abs(aij.Imaginary - aji.Imaginary) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } // 非対称行列の線形方程式を解く // 解ベクトル KrdLab.clapack.Complex[] X = null; // 連立方程式AX = Bを解く int x_row = (int)nblk; int x_col = 1; int a_row = (int)nblk; int a_col = (int)nblk; int b_row = (int)nblk; int b_col = 1; System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgesv"); KrdLab.clapack.FunctionExt.zgesv(ref X, ref x_row, ref x_col, A, a_row, a_col, B, b_row, b_col); // 解ベクトルをワールド座標系にセット Complex[] valuesAll = new Complex[nblk]; Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>(); for (uint i = 0; i < nblk; i++) { valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary); toNodeIndex.Add(i, i); } WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex); }
/// <summary> /// 非対称複素帯行列の連立方程式をclapackで解く /// </summary> /// <param name="Ls"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> private static void solveAsymmetricComplexBandMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId) { // エルミート帯行列の連立方程式をLisys(clapack)で解く CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); uint nblk = femMat.NBlkMatCol(); Complex[] A = new Complex[nblk * nblk]; // ポインタを格納 System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow()); for (uint iblk = 0; iblk < nblk; iblk++) { ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk); System.Diagnostics.Debug.Assert(ptr.Count == 1); A[iblk + nblk * iblk] = new Complex(ptr[0].Real, ptr[0].Imag); //Console.WriteLine(" ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i"); uint npsup = 0; ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup); ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup); System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count); for (int i = 0; i < ptrVal.Count; i++) { A[iblk + nblk * ptrInd[i]] = new Complex(ptrVal[i].Real, ptrVal[i].Imag); //Console.WriteLine(" ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i"); } } // 残差ベクトル CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen()); System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen()); KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk]; for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++) { Complex cvalue = resPtr.GetValue(iblk, 0); B[iblk].Real = cvalue.Real; B[iblk].Imaginary = cvalue.Imag; //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0)); } // 対称行列チェック bool isSymmetrix = true; for (int i = 0; i < nblk; i++) { for (int j = i; j < nblk; j++) { Complex aij = A[i + nblk * j]; Complex aji = A[j + nblk * i]; if (null == aij && null != aji) { isSymmetrix = false; break; } else if (null != aij && null == aji) { isSymmetrix = false; break; } else if (null != aij && null != aji) { if (Math.Abs(aij.Real - aji.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isSymmetrix = false; break; } else if (Math.Abs(aij.Imag - aji.Imag) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isSymmetrix = false; break; } } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } // 複素バンド行列の線形方程式を解く KrdLab.clapack.Complex[] X = null; { // 非0パターンを作成 bool[,] patternA = new bool[nblk, nblk]; for (int i = 0; i < nblk; i++) { for (int j = 0; j < nblk; j++) { Complex aij = A[i + nblk * j]; patternA[i, j] = (aij != null); } } // バンド行列のバンド幅を縮小する bool[,] optPatternA = new bool[nblk, nblk]; IList<int> optNodesA = null; Dictionary<int, int> toOptNodesA = null; // [A]のバンド幅を縮小する { WgUtilForPeriodicEigenExt.GetOptBandMatNodes(patternA, out optNodesA, out toOptNodesA); for (int i = 0; i < nblk; i++) { int ino_optA = toOptNodesA[i]; for (int j = 0; j < nblk; j++) { int jno_optA = toOptNodesA[j]; optPatternA[ino_optA, jno_optA] = patternA[i, j]; } } } patternA = null; // バンド行列のサイズ取得 int a_rowcolSize; int a_subdiaSize; int a_superdiaSize; WgUtilForPeriodicEigenExt.GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternA, out a_rowcolSize, out a_subdiaSize, out a_superdiaSize); // 扱っている問題ではsubdiagonalとsuperdiagonalは同じサイズ System.Diagnostics.Debug.Assert(a_subdiaSize == a_superdiaSize); // バンド行列作成 int _a_rsize = a_subdiaSize * 2 + a_superdiaSize + 1; int _a_csize = a_rowcolSize; KrdLab.clapack.Complex[] AB = new KrdLab.clapack.Complex[_a_rsize * _a_csize]; // [A]の値を[AB]にコピーする // [A]はバンド幅最適化前の並び、[AB]は最適化後の並び for (int c = 0; c < a_rowcolSize; c++) { int c_org = optNodesA[c]; // 対角成分 Complex a_c_org_c_org = A[c_org + c_org * a_rowcolSize]; if (a_c_org_c_org != null) { AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_c_org_c_org.Real; AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_c_org_c_org.Imag; } // subdiagonal成分 if (c < a_rowcolSize - 1) { for (int r = c + 1; r <= c + a_subdiaSize && r < a_rowcolSize; r++) { int r_org = optNodesA[r]; System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize); System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize)); Complex a_r_c = A[r_org + c_org * a_rowcolSize]; if (a_r_c != null) { AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real; AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag; } } } if (c > 0) { for (int r = c - 1; r >= c - a_superdiaSize && r >= 0; r--) { int r_org = optNodesA[r]; System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize); System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize)); Complex a_r_c = A[r_org + c_org * a_rowcolSize]; if (a_r_c != null) { AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real; AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag; } } } } // 残差ベクトル{B}をoptAにあわせて並び替える KrdLab.clapack.Complex[] optB = new KrdLab.clapack.Complex[nblk]; for (int i = 0; i < nblk; i++) { int ino_optA = toOptNodesA[i]; optB[ino_optA].Real = B[i].Real; optB[ino_optA].Imaginary = B[i].Imaginary; } A = null; B = null; // 解ベクトル KrdLab.clapack.Complex[] optX = null; // 連立方程式[AB]{X} = {B}を解く int x_row = (int)nblk; int x_col = 1; int a_row = a_rowcolSize; int a_col = a_rowcolSize; int kl = a_subdiaSize; int ku = a_superdiaSize; int b_row = (int)nblk; int b_col = 1; System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgbsv"); KrdLab.clapack.FunctionExt.zgbsv(ref optX, ref x_row, ref x_col, AB, a_row, a_col, kl, ku, optB, b_row, b_col); // 解ベクトルを元の並びに戻す X = new KrdLab.clapack.Complex[nblk]; for (int i = 0; i < nblk; i++) { int inoGlobal = optNodesA[i]; X[inoGlobal].Real = optX[i].Real; X[inoGlobal].Imaginary = optX[i].Imaginary; } optX = null; } // 解ベクトルをワールド座標系にセット Complex[] valuesAll = new Complex[nblk]; Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>(); for (uint i = 0; i < nblk; i++) { valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary); toNodeIndex.Add(i, i); } WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex); }
/// <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; }