public static MyComplexMatrix matrix_Inverse(MyComplexMatrix matA) { System.Diagnostics.Debug.Assert(matA.RowSize == matA.ColumnSize); int n = matA.RowSize; Complex[] matA_ = matrix_ToBuffer(matA, true); Complex[] matB_ = new Complex[n * n]; // 単位行列 for (int i = 0; i < matB_.Length; i++) { matB_[i] = (Complex)0.0; } for (int i = 0; i < n; i++) { matB_[i * n + i] = (Complex)1.0; } // [A][X] = [B] // [B]の内容が書き換えられるので、matXを新たに生成せず、matBを出力に指定している int x_row = 0; int x_col = 0; KrdLab.clapack.FunctionExt.zgesv(ref matB_, ref x_row, ref x_col, matA_, n, n, matB_, n, n); MyComplexMatrix matX = matrix_FromBuffer(matB_, x_row, x_col, false); return(matX); }
public static Complex[,] matrix_Inverse(Complex[,] matA) { MyComplexMatrix matA_ = new MyComplexMatrix(matA); matA_ = matrix_Inverse(matA_); return(matA_.ToArray()); }
public static void matrix_setRowVec(MyComplexMatrix matA, int row, Complex[] rowVec) { System.Diagnostics.Debug.Assert(matA.ColumnSize == rowVec.Length); for (int j = 0; j < matA.ColumnSize; j++) { matA[row, j] = rowVec[j]; } }
// 行列の行ベクトルを抜き出す public static Complex[] matrix_GetRowVec(MyComplexMatrix matA, int row) { Complex[] rowVec = new Complex[matA.ColumnSize]; for (int j = 0; j < matA.ColumnSize; j++) { rowVec[j] = matA[row, j]; } return(rowVec); }
public static void printMatrix(string tag, MyComplexMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { Complex val = mat[i, j]; System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + "(" + val.Real + "," + val.Imaginary + ") " + Complex.Abs(val)); } } }
// [X] = ([A]*)t public static MyComplexMatrix matrix_ConjugateTranspose(MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.ColumnSize, matA.RowSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = new Complex(matA[j, i].Real, -matA[j, i].Imaginary); } } return matX; }
// [X] = [A]t public static MyComplexMatrix matrix_Transpose(MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.ColumnSize, matA.RowSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = matA[j, i]; } } return(matX); }
// [X] = ([A]*)t public static MyComplexMatrix matrix_ConjugateTranspose(MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.ColumnSize, matA.RowSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = new Complex(matA[j, i].Real, -matA[j, i].Imaginary); } } return(matX); }
// [X] = alpha * [A] public static MyComplexMatrix product(Complex alpha, MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matA.ColumnSize); for (int i = 0; i < matA.RowSize; i++) { for (int j = 0; j < matA.ColumnSize; j++) { matX[i, j] = alpha * matA[i, j]; } } return(matX); }
public static MyComplexMatrix matrix_FromBuffer(Complex[] mat_, int nRow, int nCol, bool copyFlg = true) { MyComplexMatrix mat = null; if (copyFlg) { mat = new MyComplexMatrix(mat_, nRow, nCol); } else { mat = new MyComplexMatrix(nRow, nCol); mat._body = mat_; } return(mat); }
public static Complex[] matrix_ToBuffer(MyComplexMatrix mat, bool copyFlg = true) { Complex[] mat_ = null; if (copyFlg) { int size = mat._rsize * mat._csize; mat_ = new Complex[size]; mat._body.CopyTo(mat_, 0); } else { mat_ = mat._body; } return(mat_); }
// [X] = [A] - [B] public static MyComplexMatrix minus(MyComplexMatrix matA, MyComplexMatrix matB) { System.Diagnostics.Debug.Assert(matA.RowSize == matB.RowSize); System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.ColumnSize); MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matA.ColumnSize); for (int i = 0; i < matA.RowSize; i++) { for (int j = 0; j < matA.ColumnSize; j++) { matX[i, j] = matA[i, j] - matB[i, j]; } } return(matX); }
public static void printMatrixNoZero(string tag, MyComplexMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { Complex val = mat[i, j]; if (Complex.Abs(val) < Constants.PrecisionLowerLimit) { continue; } System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + "(" + val.Real + "," + val.Imaginary + ") "); } } }
// {x} = [A]{v} public static Complex[] product(MyComplexMatrix matA, Complex[] vec) { System.Diagnostics.Debug.Assert(matA.ColumnSize == vec.Length); //BUGFIX //Complex[] retVec = new Complex[vec.Length]; Complex[] retVec = new Complex[matA.RowSize]; for (int i = 0; i < matA.RowSize; i++) { retVec[i] = new Complex(0.0, 0.0); for (int k = 0; k < matA.ColumnSize; k++) { retVec[i] += matA[i, k] * vec[k]; } } return(retVec); }
public static MyComplexMatrix product(MyComplexMatrix matA, MyComplexMatrix matB) { System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.RowSize); MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matB.ColumnSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = 0.0; for (int k = 0; k < matA.ColumnSize; k++) { matX[i, j] += matA[i, k] * matB[k, j]; } } } return(matX); }
/// <summary> /// 複素共役転置する. /// </summary> /// <returns>転置後の自身への参照</returns> public virtual MyComplexMatrix ConjugateTranspose() { MyComplexMatrix t = new MyComplexMatrix(this._csize, this._rsize); for (int r = 0; r < this._rsize; ++r) { for (int c = 0; c < this._csize; ++c) { //t[c, r] = Complex.Conjugate(this[r, c]); //t._body[c + r * this._csize] = Complex.Conjugate(this._body[r + c * this._rsize]); t._body[c + r * this._csize].Real = this._body[r + c * this._rsize].Real; t._body[c + r * this._csize].Imaginary = -this._body[r + c * this._rsize].Imaginary; } } this.Clear(); this._body = t._body; this._rsize = t._rsize; this._csize = t._csize; return(this); }
/// <summary> /// 周波数1箇所だけ計算する /// </summary> /// <param name="filename"></param> /// <param name="in_freqNo"></param> public void RunAtOneFreq(string filename, int in_freqNo, object eachDoneCallbackObj, Delegate eachDoneCallback, bool appendFileFlg = false) { IsCalcAborted = false; if (!isInputDataValid()) { return; } string basefilename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename); string outfilename = basefilename + Constants.FemOutputExt; //string indexfilename = basefilename + Constants.FemOutputIndexExt; // BUGFIX インデックスファイル名は.out.idx string indexfilename = outfilename + Constants.FemOutputIndexExt; if (!appendFileFlg) { // 結果出力ファイルの削除(結果を追記モードで書き込むため) if (File.Exists(outfilename)) { File.Delete(outfilename); } if (File.Exists(indexfilename)) { File.Delete(indexfilename); } } FemMat = null; SortedNodes = null; FemMatPattern = null; try { System.Diagnostics.Debug.WriteLine("TotalMemory: {0}", GC.GetTotalMemory(false)); // GC.Collect 呼び出し後に GC.WaitForPendingFinalizers を呼び出します。これにより、すべてのオブジェクトに対するファイナライザが呼び出されるまで、現在のスレッドは待機します。 // ファイナライザ作動後は、回収すべき、(ファイナライズされたばかりの) アクセス不可能なオブジェクトが増えます。もう1度 GC.Collect を呼び出し、それらを回収します。 GC.Collect(); // アクセス不可能なオブジェクトを除去 GC.WaitForPendingFinalizers(); // ファイナライゼーションが終わるまでスレッド待機 GC.Collect(0); // ファイナライズされたばかりのオブジェクトに関連するメモリを開放 System.Diagnostics.Debug.WriteLine("TotalMemory: {0}", GC.GetTotalMemory(false)); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } int calcFreqCnt = CalcFreqCnt; double firstNormalizedFreq = FirstNormalizedFreq; double lastNormalizedFreq = LastNormalizedFreq; int maxMode = MaxModeCnt; double deltaf = (lastNormalizedFreq - firstNormalizedFreq) / calcFreqCnt; { int freqIndex = in_freqNo - 1; if (freqIndex < 0 || freqIndex >= calcFreqCnt + 1) { return; } double normalizedFreq = firstNormalizedFreq + freqIndex * deltaf; if (normalizedFreq < Constants.PrecisionLowerLimit) { normalizedFreq = 1.0e-4; } double waveLength = GetWaveLengthFromNormalizedFreq(normalizedFreq, WaveguideWidth, LatticeA); System.Diagnostics.Debug.WriteLine("a/lamda = {0}", normalizedFreq); int freqNo = freqIndex + 1; runEach(freqNo, outfilename, waveLength, maxMode); eachDoneCallback.Method.Invoke(eachDoneCallbackObj, new object[] { new object[] { }, }); } FemMat = null; SortedNodes = null; FemMatPattern = null; }
/* /// <summary> /// 入出力ポート境界条件の追加 /// </summary> /// <param name="waveLength"></param> /// <param name="isInputPort"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="mat"></param> /// <param name="resVec"></param> private void addPortBC( double waveLength, bool isInputPort, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, int[] nodesRegion, MyComplexMatrix mat, Complex[] resVec) { FemSolverPort.AddPortBC( WaveModeDv, waveLength, isInputPort, IncidentModeIndex, nodesBoundary, ryy_1d, eigenValues, eigenVecs, nodesRegion, Elements, Medias, ForceNodeNumberH, mat, resVec ); } /// <summary> /// 散乱行列の計算 /// </summary> /// <param name="waveLength"></param> /// <param name="iMode"></param> /// <param name="isIncidentMode"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="valuesAll"></param> /// <returns></returns> private Complex getWaveguidePortReflectionCoef( double waveLength, int iMode, bool isIncidentMode, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, int[] nodesRegion, Complex[] valuesAll) { Complex s11 = FemSolverPort.GetWaveguidePortReflectionCoef( WaveModeDv, waveLength, iMode, isIncidentMode, nodesBoundary, ryy_1d, eigenValues, eigenVecs, nodesRegion, Elements, Medias, valuesAll ); return s11; } /// <summary> /// ポート固有値解析 /// </summary> private void solvePortWaveguideEigen( double waveLength, int portNo, int maxModeSpecified, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d, out Complex[] eigenValues, out Complex[,] eigenVecs) { FemSolverPort.SolvePortWaveguideEigen( WaveModeDv, waveLength, maxModeSpecified, Nodes, EdgeToElementNoH, Elements, Medias, ForceNodeNumberH, Ports[portNo - 1], out nodesBoundary, out ryy_1d, out eigenValues, out eigenVecs ); } */ /////////////////////////////////////////////////////////////////////////// /// <summary> /// 入出力ポート境界条件の追加 /// </summary> /// <param name="waveLength"></param> /// <param name="isInputPort"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="mat"></param> /// <param name="resVec"></param> private void addPeriodicPortBC( double waveLength, bool isInputPort, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdX, int[] nodesRegion, MyComplexMatrix mat, Complex[] resVec) { FemSolverPortPeriodic.AddPortBC( WaveModeDv, waveLength, LatticeA, isInputPort, IncidentModeIndex, nodesBoundary, ryy_1d, eigenValues, eigenVecs, eigen_dFdX, nodesRegion, Elements, Medias, ForceNodeNumberH, mat, resVec ); }
/// <summary> /// ヘルムホルツ方程式の剛性行列を作成する /// </summary> /// <param name="waveLength"></param> /// <param name="nodesRegion"></param> /// <param name="mat"></param> /// <returns>true: 成功 false:失敗(メモリの確保に失敗)</returns> private bool getHelmholtzLinearSystemMatrix(double waveLength, out int[] nodesRegion, out MyComplexMatrix mat) { nodesRegion = null; mat = null; // 2D節点番号リスト(ソート済み) IList<int> sortedNodes = new List<int>(); // 2D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 非0要素のパターン bool[,] matPattern = null; if (SortedNodes == null) { // 節点番号リストをソートする // 強制境界の除去する // バンドマトリクスのバンド幅を縮小する // 強制境界節点と内部領域節点を分離 foreach (FemNode node in Nodes) { int nodeNumber = node.No; if (ForceNodeNumberH.ContainsKey(nodeNumber)) { //forceNodes.Add(nodeNumber); } else { sortedNodes.Add(nodeNumber); toSorted.Add(nodeNumber, sortedNodes.Count - 1); } } { // バンド幅を縮小する // 非0要素のパターンを取得 getMatNonzeroPattern(Elements, Ports, toSorted, out matPattern); // subdiagonal、superdiagonalのサイズを取得する int subdiaSizeInitial = 0; int superdiaSizeInitial = 0; { System.Diagnostics.Debug.WriteLine("/////initial BandMat info///////"); int rowcolSize; int subdiaSize; int superdiaSize; getBandMatrixSubDiaSizeAndSuperDiaSize(matPattern, out rowcolSize, out subdiaSize, out superdiaSize); subdiaSizeInitial = subdiaSize; superdiaSizeInitial = superdiaSize; } // 非0要素出現順に節点番号を格納 IList<int> optNodes = new List<int>(); Queue<int> chkQueue = new Queue<int>(); int[] remainNodes = new int[matPattern.GetLength(0)]; for (int i = 0; i < matPattern.GetLength(0); i++) { remainNodes[i] = i; } while (optNodes.Count < sortedNodes.Count) { // 飛び地領域対応 for (int rIndex = 0; rIndex < remainNodes.Length; rIndex++) { int i = remainNodes[rIndex]; if (i == -1) continue; //System.Diagnostics.Debug.Assert(!optNodes.Contains(i)); chkQueue.Enqueue(i); remainNodes[rIndex] = -1; break; } while (chkQueue.Count > 0) { int i = chkQueue.Dequeue(); optNodes.Add(i); for (int rIndex = 0; rIndex < remainNodes.Length; rIndex++) { int j = remainNodes[rIndex]; if (j == -1) continue; //System.Diagnostics.Debug.Assert(i != j); if (matPattern[i, j]) { //System.Diagnostics.Debug.Assert(!optNodes.Contains(j) && !chkQueue.Contains(j)); chkQueue.Enqueue(j); remainNodes[rIndex] = -1; } } } } IList<int> optNodesGlobal = new List<int>(); Dictionary<int, int> toOptNodes = new Dictionary<int, int>(); foreach (int i in optNodes) { int ino = sortedNodes[i]; optNodesGlobal.Add(ino); toOptNodes.Add(ino, optNodesGlobal.Count - 1); } System.Diagnostics.Debug.Assert(optNodesGlobal.Count == sortedNodes.Count); // 改善できないこともあるのでチェックする bool improved = false; bool[,] optMatPattern = null; // 非0パターンを取得 getMatNonzeroPattern(Elements, Ports, toOptNodes, out optMatPattern); // check { System.Diagnostics.Debug.WriteLine("/////opt BandMat info///////"); int rowcolSize; int subdiaSize; int superdiaSize; getBandMatrixSubDiaSizeAndSuperDiaSize(optMatPattern, out rowcolSize, out subdiaSize, out superdiaSize); if (subdiaSize <= subdiaSizeInitial && superdiaSize <= superdiaSizeInitial) { improved = true; } } if (improved) { // 置き換え sortedNodes = optNodesGlobal; toSorted = toOptNodes; matPattern = optMatPattern; } else { System.Diagnostics.Debug.WriteLine("band with not optimized!"); } } SortedNodes = sortedNodes; FemMatPattern = matPattern; } else { // ソート済み節点番号リストを取得 sortedNodes = SortedNodes; // 2D節点番号→ソート済みリストインデックスのマップ作成 for (int i = 0; i < sortedNodes.Count; i++) { int nodeNumber = sortedNodes[i]; if (!toSorted.ContainsKey(nodeNumber)) { toSorted.Add(nodeNumber, i); } } // 非0パターンを取得 //getMatNonzeroPattern(Nodes, Elements, Ports, ForceBCNodes, toSorted, out matPattern); matPattern = FemMatPattern; } // 総節点数 int nodeCnt = sortedNodes.Count; // 全体節点を配列に格納 nodesRegion = sortedNodes.ToArray(); // 全体剛性行列初期化 //mat = new MyComplexMatrix(nodeCnt, nodeCnt); // メモリ割り当てのコストが高いので変更する if (FemMat == null) { try { { // バンドマトリクス(zgbsv) // バンドマトリクス情報を取得する int rowcolSize = 0; int subdiaSize = 0; int superdiaSize = 0; getBandMatrixSubDiaSizeAndSuperDiaSize(matPattern, out rowcolSize, out subdiaSize, out superdiaSize); FemMat = new MyComplexBandMatrix(rowcolSize, subdiaSize, superdiaSize); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show("メモリの確保に失敗しました。"); return false; } } else { System.Diagnostics.Debug.Assert(FemMat.RowSize == nodeCnt); int size = FemMat._rsize * FemMat._csize; for (int i = 0; i < size; i++) { FemMat._body[i].Real = 0; FemMat._body[i].Imaginary = 0; } } mat = FemMat; /* for (int i = 0; i < nodeCnt * nodeCnt; i++) { mat._body[i] = new Complex(); } */ foreach (FemElement element in Elements) { addElementMat(waveLength, toSorted, element, ref mat); } return true; }
/* 数値積分版 /// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDv WaveModeDv, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 2次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; if (WaveModeDv == FemSolver.WaveModeDv.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDv.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } //// 四角形の辺の長さを求める //double[] le = new double[4]; //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // ガウスルジャンドルの積分公式 double[][] g_pts = new double[5][] { // ポイント(ξ: [-1 +1]区間)、重み new double[] { -0.90617985, 0.23692689}, new double[] { -0.53846931, 0.47862867}, new double[] {0.0, 0.56888889}, new double[] {0.53846931, 0.47862867}, new double[] {0.90617985, 0.23692689} }; // 要素剛性行列を作る double[,] emat = new Complex[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = 0.0; double detjsum = 0; //check foreach (double[] s_g_pt in g_pts) { foreach (double[] r_g_pt in g_pts) { // 積分点 double r = r_g_pt[0]; double s = s_g_pt[0]; // 重み(2次元) double weight = r_g_pt[1] * s_g_pt[1]; // 形状関数 double[] N = new double[nno]; // 形状関数のr, s方向微分 double[] dNdr = new double[nno]; double[] dNds = new double[nno]; // 節点0~3 : 四角形の頂点 for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0); // 形状関数のr方向微分 dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s); // 形状関数のs方向微分 dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s); } // 節点4,6 : r方向辺上中点 foreach (int i in new int[]{ 4, 6}) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s); // 形状関数のr方向微分 dNdr[i] = -1.0 * r * (1.0 + si * s); // 形状関数のs方向微分 dNds[i] = 0.5 * si * (1.0 - r * r); } // 節点5,7 : s方向辺上中点 foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s); // 形状関数のr方向微分 dNdr[i] = 0.5 * ri * (1.0 - s * s); // 形状関数のs方向微分 dNds[i] = -1.0 * s * (1.0 + ri * r); } // ヤコビアン行列 double j11; double j12; double j21; double j22; j11 = 0; j12 = 0; j21 = 0; j22 = 0; //for (int i = 0; i < vertexCnt; i++) //{ // // 頂点の座標の微分 // // 座標の形状関数は一次四角形のものを使用する // // 節点の局所座標 // double ri = n_pts[i][0]; // double si = n_pts[i][1]; // double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s); // double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si; // j11 += dNdr_1stOrder * pp[i][0]; // j12 += dNdr_1stOrder * pp[i][1]; // j21 += dNds_1stOrder * pp[i][0]; // j22 += dNds_1stOrder * pp[i][1]; //} for (int i = 0; i < nno; i++) { j11 += dNdr[i] * pp[i][0]; j12 += dNdr[i] * pp[i][1]; j21 += dNds[i] * pp[i][0]; j22 += dNds[i] * pp[i][1]; } // ヤコビアン double detj = j11 * j22 - j12 * j21; detjsum += detj * weight; //System.Diagnostics.Debug.WriteLine("det:{0}", detj); // gradr[0] : gradrのx成分 grad[1] : gradrのy成分 // grads[0] : gradsのx成分 grads[1] : gradsのy成分 double[] gradr = new double[2]; double[] grads = new double[2]; gradr[0] = j22 / detj; gradr[1] = - j21 / detj; grads[0] = - j12 / detj; grads[1] = j11 / detj; // 形状関数のx, y方向微分 double[,] dNdX = new double[ndim, nno]; for (int i = 0; i < nno; i++) { for (int direction = 0; direction < ndim; direction++) { dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction]; } } // 汎関数 double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno] - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno]; emat[ino, jno] += detj * weight * functional; } } //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum); } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; mat[inoGlobal, jnoGlobal] += emat[ino, jno]; } } } */ /// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 2次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 四角形の辺の長さを求める double[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] Ni_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.25 * ri * ri * si; Ni_a[i, 1] = 0.25 * ri * ri; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.25 * ri * si; Ni_a[i, 4] = 0.25 * ri * si * si; Ni_a[i, 5] = 0.25 * si * si; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = -0.25; } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = -0.5 * si; Ni_a[i, 1] = -0.5; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = 0.0; Ni_a[i, 5] = 0.0; Ni_a[i, 6] = 0.5 * si; Ni_a[i, 7] = 0.5; } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.0; Ni_a[i, 1] = 0.0; Ni_a[i, 2] = 0.5 * ri; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = -0.5 * ri; Ni_a[i, 5] = -0.5; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = 0.5; } // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNidr_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri; // r dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.25 * ri * si * si; // s^2 dNidr_a[i, 6] = 0.25 * ri * si; // s dNidr_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = -1.0; // r dNidr_a[i, 3] = -si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.0; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.0; // 1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.0; // r dNidr_a[i, 3] = 0.0; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = -0.5 * ri; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.5 * ri; // 1 } // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNids_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.25 * ri * ri * si; // r^2 dNids_a[i, 2] = 0.25 * ri * si; // r dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.25 * 2.0 * si * si; // s dNids_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = -0.5 * si; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = 0.0; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.0; // s dNids_a[i, 7] = 0.5 * si; //1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.0; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = -ri; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = -1.0; // s dNids_a[i, 7] = 0.0; //1 } // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; // ∫N N dxdy double[,] integralN = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralN[ino, jno] = lx * ly / 4.0 * ( // r^4s^2 4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3] + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6]) // r^4 + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1] // r^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4] // s^4 + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5] // s^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7]) // 1 + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7] ); integralDNDX[0, ino, jno] = ly / lx * ( // r^4s^2 4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2] + dNidr_a[ino, 3] * dNidr_a[jno, 3] + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4] // s^4 + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7]) // 1 + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7] ); integralDNDX[1, ino, jno] = lx / ly * ( // r^4s^2 4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2] + dNids_a[ino, 3] * dNids_a[jno, 3] + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4] // s^4 + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7]) // 1 + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7] ); } } // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } } }
public static Complex[] matrix_ToBuffer(MyComplexMatrix mat, bool copyFlg = true) { Complex[] mat_ = null; if (copyFlg) { int size = mat._rsize * mat._csize; mat_ = new Complex[size]; mat._body.CopyTo(mat_, 0); } else { mat_ = mat._body; } return mat_; }
/// <summary> /// 指定された行列をコピーして,新しい行列を作成する. /// </summary> /// <param name="m">コピーされる行列</param> public MyComplexMatrix(MyComplexMatrix m) { CopyFrom(m); }
// �s��̍s�x�N�g�����o�� public static Complex[] matrix_GetRowVec(MyComplexMatrix matA, int row) { Complex[] rowVec = new Complex[matA.ColumnSize]; for (int j = 0; j < matA.ColumnSize; j++) { rowVec[j] = matA[row, j]; } return rowVec; }
public static Complex[,] matrix_Inverse(Complex[,] matA) { MyComplexMatrix matA_ = new MyComplexMatrix(matA); matA_ = matrix_Inverse(matA_); return matA_.ToArray(); }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_FirstOrder; //4; // 1次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 四角形の辺の長さを求める double[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ + +2 // | | | // ---+---+---+-->r // | | | // 0+ + +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno] { { { 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx) }, { -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx) }, { -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx) }, { 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx) }, }, { { 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly) }, { 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly) }, { -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly) }, { -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly) }, } }; // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 }, { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0 }, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="mat">マージされる全体行列</param> private void addElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, ref MyComplexMatrix mat) { Constants.FemElementShapeDV elemShapeDv; int order; int vertexCnt; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(element.NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt); if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder) { // 2次三角形要素の要素行列を全体行列に加算する FemMat_Tri_Second.AddElementMat( waveLength, toSorted, element, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref mat); } else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder) { // 1次三角形要素の要素行列を全体行列に加算する FemMat_Tri_First.AddElementMat( waveLength, toSorted, element, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref mat); } else { System.Diagnostics.Debug.Assert(false); } }
/// <summary> /// �w�肳�ꂽ�s���R�s�[���āC�V�����s���쐬����D /// </summary> /// <param name="m">�R�s�[�����s��</param> public MyComplexMatrix(MyComplexMatrix m) { CopyFrom(m); }
/// <summary> /// �]�u����D /// </summary> /// <returns>�]�u��̎��g�ւ̎Q��</returns> public virtual MyComplexMatrix Transpose() { MyComplexMatrix t = new MyComplexMatrix(this._csize, this._rsize); for (int r = 0; r < this._rsize; ++r) { for (int c = 0; c < this._csize; ++c) { //t[c, r] = this[r, c]; //t._body[c + r * this._csize] = this._body[r + c * this._rsize]; t._body[c + r * this._csize].Real = this._body[r + c * this._rsize].Real; t._body[c + r * this._csize].Imaginary = this._body[r + c * this._rsize].Imaginary; } } this.Clear(); this._body = t._body; this._rsize = t._rsize; this._csize = t._csize; return this; }
/* /// <summary> /// ���T�C�Y����D /// </summary> /// <param name="rowSize">�V�����s��</param> /// <param name="columnSize">�V������</param> /// <param name="val">�e�v�f�̒l</param> /// <returns>���T�C�Y��̎��g�ւ̎Q��</returns> public MyComplexMatrix Resize(int rowSize, int columnSize, Complex val) { Resize(rowSize, columnSize); for (int i = 0; i < this._body.Length; ++i) { this._body[i] = val; } return this; } */ /// <summary> /// �w�肳�ꂽ�s���R�s�[����D /// </summary> /// <param name="m">�R�s�[�����s��</param> /// <returns>�R�s�[��̎��g�ւ̎Q��</returns> public virtual MyComplexMatrix CopyFrom(MyComplexMatrix m) { return CopyFrom(m._body, m._rsize, m._csize); }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.TriVertexCnt; //3; // 要素内節点数 const int nno = Constants.TriNodeCnt_SecondOrder; //6; // 2次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得 double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //System.Diagnostics.Debug.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // 形状関数の微分の係数を求める // dndxC[ino,n,k] ino節点のn方向微分のLk(k面積座標)の係数 // dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3] double[, ,] dndxC = new double[nno, ndim, vertexCnt + 1] { { {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]}, {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]}, }, { {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]}, {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]}, }, { {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]}, {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]}, }, { {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0}, {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0}, }, { {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0}, {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0}, }, { {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0}, {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0}, }, }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; for (int n = 0; n < ndim; n++) { for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[n, ino, jno] = area / 6.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 1] + dndxC[ino, n, 2] * dndxC[jno, n, 2]) + area / 12.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 1] + dndxC[ino, n, 0] * dndxC[jno, n, 2] + dndxC[ino, n, 1] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 2] + dndxC[ino, n, 2] * dndxC[jno, n, 0] + dndxC[ino, n, 2] * dndxC[jno, n, 1]) + area / 3.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 3] + dndxC[ino, n, 1] * dndxC[jno, n, 3] + dndxC[ino, n, 2] * dndxC[jno, n, 3] + dndxC[ino, n, 3] * dndxC[jno, n, 0] + dndxC[ino, n, 3] * dndxC[jno, n, 1] + dndxC[ino, n, 3] * dndxC[jno, n, 2]) + area * dndxC[ino, n, 3] * dndxC[jno, n, 3]; } } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 6.0 * area / 180.0, -1.0 * area / 180.0, -1.0 * area / 180.0, 0.0, -4.0 * area / 180.0, 0.0}, { -1.0 * area / 180.0, 6.0 * area / 180.0, -1.0 * area / 180.0, 0.0, 0.0, -4.0 * area / 180.0}, { -1.0 * area / 180.0, -1.0 * area / 180.0, 6.0 * area / 180.0, -4.0 * area / 180.0, 0.0, 0.0}, { 0.0, 0.0, -4.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0, 16.0 * area / 180.0}, { -4.0 * area / 180.0, 0.0, 0.0, 16.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0}, { 0.0, -4.0 * area / 180.0, 0.0, 16.0 * area / 180.0, 16.0 * area / 180.0, 32.0 * area / 180.0}, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } }
/// <summary> /// ベースクラスのコピーI/F (無効) /// </summary> /// <param name="m"></param> /// <returns></returns> public override sealed MyComplexMatrix CopyFrom(MyComplexMatrix m) { System.Diagnostics.Debug.Assert(false); //return base.CopyFrom(m); return(this); }
/// <summary> /// 入出力ポート境界条件の追加 /// </summary> /// <param name="waveLength"></param> /// <param name="isInputPort"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="mat"></param> /// <param name="resVec"></param> public static void AddPortBC( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, bool isInputPort, int IncidentModeIndex, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdXs, int[] nodesRegion, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, MyComplexMatrix mat, Complex[] resVec) { double k0 = 2.0 * pi / waveLength; double omega = k0 / Math.Sqrt(mu0 * eps0); // 境界上の節点数(1次線要素を想定) int nodeCnt = nodesBoundary.Length; // 考慮するモード数 int maxMode = eigenValues.Length; // 全体剛性行列の作成 MyComplexMatrix matB = new MyComplexMatrix(nodeCnt, nodeCnt); double periodicDistance = latticeA; // 正方格子 for (int imode = 0; imode < maxMode; imode++) { Complex betam = eigenValues[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint inoB = 0; inoB < nodeCnt; inoB++) { fmVec_Modify[inoB] = fmVec[inoB] - dfmdxVec[inoB] / (Complex.ImaginaryOne * betam_periodic); } // 2Dの境界積分 //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); // モード電力規格化の積分(1Dの積分) // [ryy]が実数の場合 //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 (int inoB = 0; inoB < nodeCnt; inoB++) { for (int jnoB = 0; jnoB < nodeCnt; jnoB++) { Complex cvalue; { // H面、平行平板 if (WaveModeDv == FemSolver.WaveModeDV.TM) { //cvalue = (Complex.ImaginaryOne / (omega * eps0)) * betam * Complex.Abs(betam) * veci[inoB] * vecj[jnoB]; cvalue = (Complex.ImaginaryOne / (omega * eps0)) * (Complex.Abs(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[inoB] * vecj[jnoB]; } else { //cvalue = (Complex.ImaginaryOne / (omega * mu0)) * betam * Complex.Abs(betam) * veci[inoB] * vecj[jnoB]; cvalue = (Complex.ImaginaryOne / (omega * mu0)) * (Complex.Abs(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[inoB] * vecj[jnoB]; } } matB._body[inoB + jnoB * matB.RowSize] += cvalue; } } } // check 対称行列 bool isSymmetrix = true; for (int inoB = 0; inoB < matB.RowSize; inoB++) { for (int jnoB = inoB; jnoB < matB.ColumnSize; jnoB++) { if (Math.Abs(matB[inoB, jnoB].Real - matB[jnoB, inoB].Real) >= Constants.PrecisionLowerLimit) { //System.Diagnostics.Debug.Assert(false); isSymmetrix = false; break; } if (Math.Abs(matB[inoB, jnoB].Imaginary - matB[jnoB, inoB].Imaginary) >= Constants.PrecisionLowerLimit) { //System.Diagnostics.Debug.Assert(false); isSymmetrix = false; break; } } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } //MyMatrixUtil.printMatrix("matB", matB); // 残差ベクトルの作成 Complex[] resVecB = new Complex[nodeCnt]; if (isInputPort) { int imode = IncidentModeIndex; Complex betam = eigenValues[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint inoB = 0; inoB < nodeCnt; inoB++) { fmVec_Modify[inoB] = fmVec[inoB] - dfmdxVec[inoB] / (Complex.ImaginaryOne * betam_periodic); } // 2Dの境界積分 //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (int inoB = 0; inoB < nodeCnt; inoB++) { // H面、平行平板、E面 //Complex cvalue = 2.0 * Complex.ImaginaryOne * betam * veci[inoB]; Complex cvalue = 2.0 * Complex.ImaginaryOne * betam_periodic * veci[inoB]; resVecB[inoB].Real = cvalue.Real; resVecB[inoB].Imaginary = cvalue.Imaginary; } } //printVec("resVecB", resVecB); // 2D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 2D節点番号→ソート済みリストインデックスのマップ作成 for (int i = 0; i < nodesRegion.Length; i++) { int nodeNumber = nodesRegion[i]; if (!toSorted.ContainsKey(nodeNumber)) { toSorted.Add(nodeNumber, i); } } // 要素剛性行列にマージ // この定式化では行列のスパース性は失われている(隣接していない要素の節点間にも関連がある) // 要素剛性行列にマージする for (int inoB = 0; inoB < nodeCnt; inoB++) { int iNodeNumber = nodesBoundary[inoB]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jnoB = 0; jnoB < nodeCnt; jnoB++) { int jNodeNumber = nodesBoundary[jnoB]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; // Note: matBは一般行列 matはバンド行列 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)] += matB._body[inoB + jnoB * matB.RowSize]; } } // 残差ベクトルにマージ for (int inoB = 0; inoB < nodeCnt; inoB++) { int iNodeNumber = nodesBoundary[inoB]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; resVec[inoGlobal] += resVecB[inoB]; } }
/* 数値積分版 /// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDv WaveModeDv, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 2次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; if (WaveModeDv == FemSolver.WaveModeDv.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDv.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } //// 四角形の辺の長さを求める //double[] le = new double[4]; //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // ガウスルジャンドルの積分公式 double[][] g_pts = new double[5][] { // ポイント(ξ: [-1 +1]区間)、重み new double[] { -0.90617985, 0.23692689}, new double[] { -0.53846931, 0.47862867}, new double[] {0.0, 0.56888889}, new double[] {0.53846931, 0.47862867}, new double[] {0.90617985, 0.23692689} }; // 要素剛性行列を作る double[,] emat = new Complex[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = 0.0; double detjsum = 0; //check foreach (double[] s_g_pt in g_pts) { foreach (double[] r_g_pt in g_pts) { // 積分点 double r = r_g_pt[0]; double s = s_g_pt[0]; // 重み(2次元) double weight = r_g_pt[1] * s_g_pt[1]; // 形状関数 double[] N = new double[nno]; // 形状関数のr, s方向微分 double[] dNdr = new double[nno]; double[] dNds = new double[nno]; // 節点0~3 : 四角形の頂点 for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0); // 形状関数のr方向微分 dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s); // 形状関数のs方向微分 dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s); } // 節点4,6 : r方向辺上中点 foreach (int i in new int[]{ 4, 6}) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s); // 形状関数のr方向微分 dNdr[i] = -1.0 * r * (1.0 + si * s); // 形状関数のs方向微分 dNds[i] = 0.5 * si * (1.0 - r * r); } // 節点5,7 : s方向辺上中点 foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s); // 形状関数のr方向微分 dNdr[i] = 0.5 * ri * (1.0 - s * s); // 形状関数のs方向微分 dNds[i] = -1.0 * s * (1.0 + ri * r); } // ヤコビアン行列 double j11; double j12; double j21; double j22; j11 = 0; j12 = 0; j21 = 0; j22 = 0; //for (int i = 0; i < vertexCnt; i++) //{ // // 頂点の座標の微分 // // 座標の形状関数は一次四角形のものを使用する // // 節点の局所座標 // double ri = n_pts[i][0]; // double si = n_pts[i][1]; // double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s); // double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si; // j11 += dNdr_1stOrder * pp[i][0]; // j12 += dNdr_1stOrder * pp[i][1]; // j21 += dNds_1stOrder * pp[i][0]; // j22 += dNds_1stOrder * pp[i][1]; //} for (int i = 0; i < nno; i++) { j11 += dNdr[i] * pp[i][0]; j12 += dNdr[i] * pp[i][1]; j21 += dNds[i] * pp[i][0]; j22 += dNds[i] * pp[i][1]; } // ヤコビアン double detj = j11 * j22 - j12 * j21; detjsum += detj * weight; //System.Diagnostics.Debug.WriteLine("det:{0}", detj); // gradr[0] : gradrのx成分 grad[1] : gradrのy成分 // grads[0] : gradsのx成分 grads[1] : gradsのy成分 double[] gradr = new double[2]; double[] grads = new double[2]; gradr[0] = j22 / detj; gradr[1] = - j21 / detj; grads[0] = - j12 / detj; grads[1] = j11 / detj; // 形状関数のx, y方向微分 double[,] dNdX = new double[ndim, nno]; for (int i = 0; i < nno; i++) { for (int direction = 0; direction < ndim; direction++) { dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction]; } } // 汎関数 double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno] - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno]; emat[ino, jno] += detj * weight * functional; } } //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum); } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; mat[inoGlobal, jnoGlobal] += emat[ino, jno]; } } } */ /// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 2次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 四角形の辺の長さを求める double[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] Ni_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.25 * ri * ri * si; Ni_a[i, 1] = 0.25 * ri * ri; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.25 * ri * si; Ni_a[i, 4] = 0.25 * ri * si * si; Ni_a[i, 5] = 0.25 * si * si; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = -0.25; } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = -0.5 * si; Ni_a[i, 1] = -0.5; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = 0.0; Ni_a[i, 5] = 0.0; Ni_a[i, 6] = 0.5 * si; Ni_a[i, 7] = 0.5; } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.0; Ni_a[i, 1] = 0.0; Ni_a[i, 2] = 0.5 * ri; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = -0.5 * ri; Ni_a[i, 5] = -0.5; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = 0.5; } // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNidr_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri; // r dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.25 * ri * si * si; // s^2 dNidr_a[i, 6] = 0.25 * ri * si; // s dNidr_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = -1.0; // r dNidr_a[i, 3] = -si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.0; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.0; // 1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.0; // r dNidr_a[i, 3] = 0.0; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = -0.5 * ri; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.5 * ri; // 1 } // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNids_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.25 * ri * ri * si; // r^2 dNids_a[i, 2] = 0.25 * ri * si; // r dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.25 * 2.0 * si * si; // s dNids_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = -0.5 * si; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = 0.0; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.0; // s dNids_a[i, 7] = 0.5 * si; //1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.0; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = -ri; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = -1.0; // s dNids_a[i, 7] = 0.0; //1 } // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; // ∫N N dxdy double[,] integralN = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralN[ino, jno] = lx * ly / 4.0 * ( // r^4s^2 4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3] + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6]) // r^4 + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1] // r^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4] // s^4 + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5] // s^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7]) // 1 + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7] ); integralDNDX[0, ino, jno] = ly / lx * ( // r^4s^2 4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2] + dNidr_a[ino, 3] * dNidr_a[jno, 3] + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4] // s^4 + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7]) // 1 + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7] ); integralDNDX[1, ino, jno] = lx / ly * ( // r^4s^2 4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2] + dNids_a[ino, 3] * dNids_a[jno, 3] + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4] // s^4 + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7]) // 1 + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7] ); } } // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } }
public static MyComplexMatrix matrix_Inverse(MyComplexMatrix matA) { System.Diagnostics.Debug.Assert(matA.RowSize == matA.ColumnSize); int n = matA.RowSize; Complex[] matA_ = matrix_ToBuffer(matA, true); Complex[] matB_ = new Complex[n * n]; // �P�ʍs�� for (int i = 0; i < matB_.Length; i++) { matB_[i] = (Complex)0.0; } for (int i = 0; i < n; i++) { matB_[i * n + i] = (Complex)1.0; } // [A][X] = [B] // [B]�̓�e��������������̂ŁAmatX��V���ɐ��������AmatB��o�͂Ɏw�肵�Ă��� int x_row = 0; int x_col = 0; KrdLab.clapack.FunctionExt.zgesv(ref matB_, ref x_row, ref x_col, matA_, n, n, matB_, n, n); MyComplexMatrix matX = matrix_FromBuffer(matB_, x_row, x_col, false); return matX; }
public static MyComplexMatrix product(MyComplexMatrix matA, MyComplexMatrix matB) { System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.RowSize); MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matB.ColumnSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = 0.0; for (int k = 0; k < matA.ColumnSize; k++) { matX[i, j] += matA[i, k] * matB[k, j]; } } } return matX; }
// [X] = alpha * [A] public static MyComplexMatrix product(Complex alpha, MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matA.ColumnSize); for (int i = 0; i < matA.RowSize; i++) { for (int j = 0; j < matA.ColumnSize; j++) { matX[i, j] = alpha * matA[i, j]; } } return matX; }
// [X] = [A]t public static MyComplexMatrix matrix_Transpose(MyComplexMatrix matA) { MyComplexMatrix matX = new MyComplexMatrix(matA.ColumnSize, matA.RowSize); for (int i = 0; i < matX.RowSize; i++) { for (int j = 0; j < matX.ColumnSize; j++) { matX[i, j] = matA[j, i]; } } return matX; }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDV WaveModeDv, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_FirstOrder; //4; // 1次セレンディピティ // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; if (WaveModeDv == FemSolver.WaveModeDV.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 四角形の辺の長さを求める double[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ + +2 // | | | // ---+---+---+-->r // | | | // 0+ + +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno] { { { 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx) }, { -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx) }, { -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx) }, { 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx) }, }, { { 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly) }, { 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly) }, { -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly) }, { -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly) }, } }; // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 }, { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0 }, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } } }
// [X] = [A] + [B] public static MyComplexMatrix plus(MyComplexMatrix matA, MyComplexMatrix matB) { System.Diagnostics.Debug.Assert(matA.RowSize == matB.RowSize); System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.ColumnSize); MyComplexMatrix matX = new MyComplexMatrix(matA.RowSize, matA.ColumnSize); for (int i = 0; i < matA.RowSize; i++) { for (int j = 0; j < matA.ColumnSize; j++) { matX[i, j] = matA[i, j] + matB[i, j]; } } return matX; }
/// <summary> /// �x�[�X�N���X�̃R�s�[I/F (����) /// </summary> /// <param name="m"></param> /// <returns></returns> public override sealed MyComplexMatrix CopyFrom(MyComplexMatrix m) { System.Diagnostics.Debug.Assert(false); //return base.CopyFrom(m); return this; }
public static void printMatrixNoZero(string tag, MyComplexMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { Complex val = mat[i, j]; if (Complex.Abs(val) < Constants.PrecisionLowerLimit) continue; System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + "(" + val.Real + "," + val.Imaginary + ") "); } } }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.TriVertexCnt; //3; // 要素内節点数 const int nno = Constants.TriNodeCnt_FirstOrder; //3; // 1次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得 double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //System.Diagnostics.Debug.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[0, ino, jno] = area * dldx[ino, 0] * dldx[jno, 0]; integralDNDX[1, ino, jno] = area * dldx[ino, 1] * dldx[jno, 1]; } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { area / 6.0 , area / 12.0, area / 12.0 }, { area / 12.0, area / 6.0, area / 12.0 }, { area / 12.0, area / 12.0, area / 6.0 }, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } } }
// {x} = [A]{v} public static Complex[] product(MyComplexMatrix matA, Complex[] vec) { System.Diagnostics.Debug.Assert(matA.ColumnSize == vec.Length); //BUGFIX //Complex[] retVec = new Complex[vec.Length]; Complex[] retVec = new Complex[matA.RowSize]; for (int i = 0; i < matA.RowSize; i++) { retVec[i] = new Complex(0.0, 0.0); for (int k = 0; k < matA.ColumnSize; k++) { retVec[i] += matA[i, k] * vec[k]; } } return retVec; }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDV WaveModeDv, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.TriVertexCnt; //3; // 要素内節点数 const int nno = Constants.TriNodeCnt_SecondOrder; //6; // 2次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得 double[,] media_P = null; double[,] media_Q = null; if (WaveModeDv == FemSolver.WaveModeDV.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //Console.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // 形状関数の微分の係数を求める // dndxC[ino,n,k] ino節点のn方向微分のLk(k面積座標)の係数 // dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3] double[, ,] dndxC = new double[nno, ndim, vertexCnt + 1] { { {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]}, {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]}, }, { {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]}, {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]}, }, { {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]}, {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]}, }, { {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0}, {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0}, }, { {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0}, {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0}, }, { {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0}, {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0}, }, }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; for (int n = 0; n < ndim; n++) { for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[n, ino, jno] = area / 6.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 1] + dndxC[ino, n, 2] * dndxC[jno, n, 2]) + area / 12.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 1] + dndxC[ino, n, 0] * dndxC[jno, n, 2] + dndxC[ino, n, 1] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 2] + dndxC[ino, n, 2] * dndxC[jno, n, 0] + dndxC[ino, n, 2] * dndxC[jno, n, 1]) + area / 3.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 3] + dndxC[ino, n, 1] * dndxC[jno, n, 3] + dndxC[ino, n, 2] * dndxC[jno, n, 3] + dndxC[ino, n, 3] * dndxC[jno, n, 0] + dndxC[ino, n, 3] * dndxC[jno, n, 1] + dndxC[ino, n, 3] * dndxC[jno, n, 2]) + area * dndxC[ino, n, 3] * dndxC[jno, n, 3]; } } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 6.0 * area / 180.0, -1.0 * area / 180.0, -1.0 * area / 180.0, 0.0, -4.0 * area / 180.0, 0.0}, { -1.0 * area / 180.0, 6.0 * area / 180.0, -1.0 * area / 180.0, 0.0, 0.0, -4.0 * area / 180.0}, { -1.0 * area / 180.0, -1.0 * area / 180.0, 6.0 * area / 180.0, -4.0 * area / 180.0, 0.0, 0.0}, { 0.0, 0.0, -4.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0, 16.0 * area / 180.0}, { -4.0 * area / 180.0, 0.0, 0.0, 16.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0}, { 0.0, -4.0 * area / 180.0, 0.0, 16.0 * area / 180.0, 16.0 * area / 180.0, 32.0 * area / 180.0}, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } } }
public static MyComplexMatrix matrix_FromBuffer(Complex[] mat_, int nRow, int nCol, bool copyFlg = true) { MyComplexMatrix mat = null; if (copyFlg) { mat = new MyComplexMatrix(mat_, nRow, nCol); } else { mat = new MyComplexMatrix(nRow, nCol); mat._body = mat_; } return mat; }
/* * /// <summary> * /// リサイズする. * /// </summary> * /// <param name="rowSize">新しい行数</param> * /// <param name="columnSize">新しい列数</param> * /// <param name="val">各要素の値</param> * /// <returns>リサイズ後の自身への参照</returns> * public MyComplexMatrix Resize(int rowSize, int columnSize, Complex val) * { * Resize(rowSize, columnSize); * for (int i = 0; i < this._body.Length; ++i) * { * this._body[i] = val; * } * return this; * } */ /// <summary> /// 指定された行列をコピーする. /// </summary> /// <param name="m">コピーされる行列</param> /// <returns>コピー後の自身への参照</returns> public virtual MyComplexMatrix CopyFrom(MyComplexMatrix m) { return(CopyFrom(m._body, m._rsize, m._csize)); }