public static double[,] matrix_Inverse(double[,] matA) { MyDoubleMatrix matA_ = new MyDoubleMatrix(matA); matA_ = matrix_Inverse(matA_); return(matA_.ToArray()); }
public static MyDoubleMatrix matrix_Inverse(MyDoubleMatrix matA) { System.Diagnostics.Debug.Assert(matA.RowSize == matA.ColumnSize); int n = matA.RowSize; double[] matA_ = matrix_ToBuffer(matA, true); double[] matB_ = new double[n * n]; // 単位行列 for (int i = 0; i < matB_.Length; i++) { matB_[i] = 0.0; } for (int i = 0; i < n; i++) { matB_[i * n + i] = 1.0; } // [A][X] = [B] // [B]の内容が書き換えられるので、matXを新たに生成せず、matBを出力に指定している int x_row = 0; int x_col = 0; KrdLab.clapack.Function.dgesv(ref matB_, ref x_row, ref x_col, matA_, n, n, matB_, n, n); MyDoubleMatrix matX = matrix_FromBuffer(matB_, x_row, x_col, false); return(matX); }
public static void printMatrix(string tag, MyDoubleMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { double val = mat[i, j]; System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + val); } } }
// [X] = alpha * [A] public static MyDoubleMatrix product(double alpha, MyDoubleMatrix matA) { MyDoubleMatrix matX = new MyDoubleMatrix(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 = sqrt(c) * public static Complex complex_Sqrt(Complex c) * { * System.Numerics.Complex work = new System.Numerics.Complex(c.Real, c.Imaginary); * work = System.Numerics.Complex.Sqrt(work); * return new Complex(work.Real, work.Imaginary); * } */ // [X] = [A]t public static MyDoubleMatrix matrix_Transpose(MyDoubleMatrix matA) { MyDoubleMatrix matX = new MyDoubleMatrix(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); }
public static MyDoubleMatrix matrix_FromBuffer(double[] mat_, int nRow, int nCol, bool copyFlg = true) { MyDoubleMatrix mat = null; if (copyFlg) { mat = new MyDoubleMatrix(mat_, nRow, nCol); } else { mat = new MyDoubleMatrix(nRow, nCol); mat._body = mat_; } return mat; }
// [X] = [A] - [B] public static MyDoubleMatrix minus(MyDoubleMatrix matA, MyDoubleMatrix matB) { System.Diagnostics.Debug.Assert(matA.RowSize == matB.RowSize); System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.ColumnSize); MyDoubleMatrix matX = new MyDoubleMatrix(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 MyDoubleMatrix matrix_FromBuffer(double[] mat_, int nRow, int nCol, bool copyFlg = true) { MyDoubleMatrix mat = null; if (copyFlg) { mat = new MyDoubleMatrix(mat_, nRow, nCol); } else { mat = new MyDoubleMatrix(nRow, nCol); mat._body = mat_; } return(mat); }
/* * public static void printVec(string tag, ValueType[] vec) * { * for (int i = 0; i < vec.Length; i++) * { * Complex val = (Complex)vec[i]; * System.Diagnostics.Debug.WriteLine(tag + "(" + i + ")" + " = " + "(" + val.Real + "," + val.Imaginary + ") " + Complex.Abs(val)); + } + } */ /* * public static void compressVec(ref ValueType[] vec) * { * KrdLab.clapack.FunctionExt.CompressMatFor_zgesv(ref vec); * } */ public static double[] matrix_ToBuffer(MyDoubleMatrix mat, bool copyFlg = true) { double[] mat_ = null; if (copyFlg) { int size = mat._rsize * mat._csize; mat_ = new double[size]; mat._body.CopyTo(mat_, 0); } else { mat_ = mat._body; } return(mat_); }
public static void printMatrixNoZero(string tag, MyDoubleMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { double val = mat[i, j]; if (Math.Abs(val) < Constants.PrecisionLowerLimit) { continue; } System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + val + " "); } } }
// {x} = [A]{v} public static Complex[] product(MyDoubleMatrix 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(MyDoubleMatrix 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 MyDoubleMatrix Transpose() { MyDoubleMatrix t = new MyDoubleMatrix(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]; } } this.Clear(); this._body = t._body; this._rsize = t._rsize; this._csize = t._csize; return(this); }
public static MyDoubleMatrix matrix_Inverse(MyDoubleMatrix matA) { System.Diagnostics.Debug.Assert(matA.RowSize == matA.ColumnSize); int n = matA.RowSize; double[] matA_ = matrix_ToBuffer(matA, true); double[] matB_ = new double[n * n]; // �P�ʍs�� for (int i = 0; i < matB_.Length; i++) { matB_[i] = 0.0; } for (int i = 0; i < n; i++) { matB_[i * n + i] = 1.0; } // [A][X] = [B] // [B]�̓�e��������������̂ŁAmatX��V���ɐ��������AmatB��o�͂Ɏw�肵�Ă��� int x_row = 0; int x_col = 0; KrdLab.clapack.Function.dgesv(ref matB_, ref x_row, ref x_col, matA_, n, n, matB_, n, n); MyDoubleMatrix matX = matrix_FromBuffer(matB_, x_row, x_col, false); return matX; }
/// <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> public static Complex GetWaveguidePortReflectionCoef( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, int iMode, bool isIncidentMode, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdXs, int[] nodesRegion, IList<FemElement> Elements, MediaInfo[] Medias, Complex[] valuesAll) { // 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); } } // ポート上の界を取得する int nodeCnt = nodesBoundary.Length; Complex[] valuesB = new Complex[nodeCnt]; for (int ino = 0; ino < nodeCnt; ino++) { int nodeNumber = nodesBoundary[ino]; int inoGlobal = toSorted[nodeNumber]; valuesB[ino] = valuesAll[inoGlobal]; } double k0 = 2.0 * pi / waveLength; double omega = k0 * c0; Complex s11 = new Complex(0.0, 0.0); int maxMode = eigenValues.Length; double periodicDistance = latticeA; // 正方格子 // {tmp_vec}*t = {fm}*t[ryy]*t // {tmp_vec}* = [ryy]* {fm}* // ([ryy]*)t = [ryy]* // [ryy]が実数のときは、[ryy]* -->[ryy] Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, iMode); Complex[] dFdXVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)iMode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam = eigenValues[iMode]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < fmVec_Modify.Length; ino++) { fmVec_Modify[ino] = fmVec[ino] - dFdXVec[ino] / (Complex.ImaginaryOne * betam_periodic); } // ryyが実数のとき //Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); // s11 = {tmp_vec}t {value_all} s11 = MyMatrixUtil.vector_Dot(tmp_vec, valuesB); { // H面、平行平板 if (WaveModeDv == FemSolver.WaveModeDV.TM) { //s11 *= (Complex.Abs(betam) / (omega * eps0)); s11 *= ((Complex.Abs(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * eps0)); if (isIncidentMode) { s11 += -1.0; } } else { //s11 *= (Complex.Abs(betam) / (omega * mu0)); s11 *= ((Complex.Abs(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * mu0)); if (isIncidentMode) { s11 += -1.0; } } } return s11; }
/// <summary> /// ポート固有値解析 /// </summary> public static void SolvePortWaveguideEigen( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, int maxModeSpecified, IList<FemNode> Nodes, Dictionary<string, IList<int>> EdgeToElementNoH, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, IList<int> portNodes, IList<uint> portElemNoPeriodic, IList<IList<int>> portNodePeriodicB, IList<int> defectNodePeriodic, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d, out Complex[] eigenValues, out Complex[,] eigenVecsB1, out Complex[,] eigen_dFdXsB1, out IList<int> nodePeriodic, out Dictionary<int, int> toNodePeriodic, out IList<double[]> coordsPeriodic, out KrdLab.clapack.Complex[][] eigenVecsPeriodic ) { // ポート境界上 nodesBoundary = null; ryy_1d = null; eigenValues = null; eigenVecsB1 = null; eigen_dFdXsB1 = null; // ポート周期構造領域 nodePeriodic = null; toNodePeriodic = null; coordsPeriodic = null; eigenVecsPeriodic = null; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; getPortFemMat1D( WaveModeDv, waveLength, latticeA, Nodes, EdgeToElementNoH, Elements, Medias, ForceNodeNumberH, portNodes, out nodesBoundary, out ryy_1d ); Dictionary<int, int> toNodesB = new Dictionary<int, int>(); for (int ino = 0; ino < nodesBoundary.Length; ino++) { int nodeNumber = nodesBoundary[ino]; //System.Diagnostics.Debug.WriteLine("nodesBoundary[{0}] = {1}", ino, nodesBoundary[ino]); toNodesB.Add(nodeNumber, ino); } ////////////////////////////////////////////////////////////////////////////// // 周期構造導波路 ///////////////////////////////////////////////////////////////////////////// int incidentModeIndex = 0; Constants.FemElementShapeDV elemShapeDv; FemElement workElement = Elements[0]; int order; int vertexCnt; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(workElement.NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt); // 領域の節点リスト、座標リストを取得する //IList<int> nodePeriodic = null; //Dictionary<int, int> toNodePeriodic = null; //IList<double[]> coordsPeriodic = null; getCoordListPeriodic( Nodes, Elements, portElemNoPeriodic, out nodePeriodic, out toNodePeriodic, out coordsPeriodic ); // 全節点数 int nodeCntPeriodic = nodePeriodic.Count; IList<IList<int>> nodePeriodicB = portNodePeriodicB; IList<int> nodePeriodicB1 = nodePeriodicB[0]; IList<int> nodePeriodicB2 = nodePeriodicB[1]; Dictionary<int, int> toNodePeriodicB1 = new Dictionary<int, int>(); Dictionary<int, int> toNodePeriodicB2 = new Dictionary<int, int>(); for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { int nodeNumber = nodePeriodicB1[ino]; toNodePeriodicB1.Add(nodeNumber, ino); } for (int ino = 0; ino < nodePeriodicB2.Count; ino++) { int nodeNumber = nodePeriodicB2[ino]; toNodePeriodicB2.Add(nodeNumber, ino); } // Y方向に周期構造? bool isYDirectionPeriodic = false; { int nodeNumber_first = nodePeriodicB1[0]; int nodeNumber_last = nodePeriodicB1[nodePeriodicB1.Count - 1]; int noB_first = toNodePeriodic[nodeNumber_first]; int noB_last = toNodePeriodic[nodeNumber_last]; double[] coord_first = coordsPeriodic[noB_first]; double[] coord_last = coordsPeriodic[noB_last]; if (Math.Abs(coord_first[1] - coord_last[1]) < 1.0e-12) { isYDirectionPeriodic = true; } } System.Diagnostics.Debug.WriteLine("isYDirectionPeriodic: {0}", isYDirectionPeriodic); // 節点の並び替え IList<int> sortedNodesPeriodic = new List<int>(); Dictionary<int, int> toSortedPeriodic = new Dictionary<int, int>(); // ポート境界1 for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点番号 int nodeNumberB1 = nodePeriodicB1[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumberB1)) { // 強制境界は除外 continue; } sortedNodesPeriodic.Add(nodeNumberB1); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumberB1, index); } int nodeCntBPeriodic = sortedNodesPeriodic.Count; // 境界1 // 内部領域 for (int ino = 0; ino < nodeCntPeriodic; ino++) { int nodeNumber = nodePeriodic[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumber)) { // 強制境界は除外 continue; } if (toNodePeriodicB1.ContainsKey(nodeNumber)) { // 境界1は除外 continue; } if (toNodePeriodicB2.ContainsKey(nodeNumber)) { // 境界2は除外 continue; } sortedNodesPeriodic.Add(nodeNumber); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumber, index); } int freeNodeCntPeriodic = sortedNodesPeriodic.Count; // 境界1 + 内部領域 // ポート境界2 for (int ino = 0; ino < nodePeriodicB2.Count; ino++) { // 境界2の節点番号 int nodeNumberB2 = nodePeriodicB2[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumberB2)) { // 強制境界は除外 continue; } sortedNodesPeriodic.Add(nodeNumberB2); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumberB2, index); } int freeNodeCntPeriodic_0 = sortedNodesPeriodic.Count; // 境界1 + 内部領域 + 境界2 // 周期構造導波路固有値問題用FEM行列の作成 //bool isSVEA = false; // Φを直接解く方法 bool isSVEA = true; // Φ= φexp(-jβx)と置く方法(SVEA) double[] KMat0 = null; double[] CMat0 = null; double[] MMat0 = null; if (isSVEA) { // Φ = φexp(-jβx)と置く方法 KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; CMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; MMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; } else { // Φを直接解く方法 KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; CMat0 = null; MMat0 = null; } IList<uint> elemNoPeriodic = portElemNoPeriodic; int elemCnt = elemNoPeriodic.Count; for (int ie = 0; ie < elemCnt; ie++) { int elemNo = (int)elemNoPeriodic[ie]; FemElement femElement = Elements[elemNo - 1]; System.Diagnostics.Debug.Assert(femElement.No == elemNo); if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder) { // 2次三角形要素 FemMat_Tri_Second.AddElementMatPeriodic( isYDirectionPeriodic, isSVEA, waveLength, nodeCntPeriodic, freeNodeCntPeriodic_0, toSortedPeriodic, femElement, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref KMat0, ref CMat0, ref MMat0); } else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder) { // 1次三角形要素 FemMat_Tri_First.AddElementMatPeriodic( isYDirectionPeriodic, isSVEA, waveLength, nodeCntPeriodic, freeNodeCntPeriodic_0, toSortedPeriodic, femElement, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref KMat0, ref CMat0, ref MMat0); } else { System.Diagnostics.Debug.Assert(false); } } double periodicDistance = latticeA; // 正方格子誘電体ロッド限定 bool isModeTrace = false; KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null; double minBeta = 0.00; // 正方格子誘電体ロッド限定 //double maxBeta = 0.90; // 正方格子誘電体ロッド限定 double maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0; bool isPortBc2Reverse = false; // 伝搬定数 KrdLab.clapack.Complex[] betamToSolveList = null; // 界ベクトルは全節点分作成 KrdLab.clapack.Complex[][] resVecList = null; if (isSVEA) { System.Diagnostics.Debug.Assert(isSVEA == true); solveSVEAAsQuadraticGeneralizedEigenToStandardWithRealMat( incidentModeIndex, k0, KMat0, CMat0, MMat0, isPortBc2Reverse, nodeCntPeriodic, freeNodeCntPeriodic_0, freeNodeCntPeriodic, nodeCntBPeriodic, sortedNodesPeriodic, toSortedPeriodic, toNodePeriodic, toNodePeriodicB1, defectNodePeriodic, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, k0, //(2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } else { System.Diagnostics.Debug.Assert(isSVEA == false); solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat( incidentModeIndex, periodicDistance, k0, KMat0, isPortBc2Reverse, nodeCntPeriodic, freeNodeCntPeriodic_0, freeNodeCntPeriodic, nodeCntBPeriodic, sortedNodesPeriodic, toSortedPeriodic, toNodePeriodic, toNodePeriodicB1, coordsPeriodic, defectNodePeriodic, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, (2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } // 固有値が1つでも取得できているかチェック if (betamToSolveList == null) { System.Diagnostics.Debug.WriteLine("betamToSolveList == null"); //System.Diagnostics.Debug.Assert(false); return; } for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resVec = resVecList[imode]; // ポート境界1の節点の値を境界2にも格納する for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点 int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; // 境界1の節点の界の値を取得 KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino; int nodeNumberPortBc2 = nodePeriodicB2[ino_B2]; int ino_InLoop_PortBc2 = toNodePeriodic[nodeNumberPortBc2]; if (isSVEA) { // 緩慢変化包絡線近似の場合は、Φ2 = Φ1 resVec[ino_InLoop_PortBc2] = cvalue; } else { // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1 KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance); resVec[ino_InLoop_PortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合 } } } ///////////////////////////////////////////////////////////////////////////////////// // 位相調整 for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex phaseShift = 1.0; double maxAbs = double.MinValue; KrdLab.clapack.Complex fValueAtMaxAbs = 0.0; { /* // 境界上で位相調整する for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } */ // 領域全体で位相調整する for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++) { KrdLab.clapack.Complex cvalue = resVec[ino_InLoop]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } } if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { phaseShift = fValueAtMaxAbs / maxAbs; } System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi); for (int i = 0; i < resVec.Length; i++) { resVec[i] /= phaseShift; } } ///////////////////////////////////////////////////////////////////////////////////// // X方向の微分値を取得する KrdLab.clapack.Complex[][] resDFDXVecList = new KrdLab.clapack.Complex[betamToSolveList.Length][]; for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = null; KrdLab.clapack.Complex[] resDFDYVec = null; double rotAngle = 0.0; // 暫定 double[] rotOrigin = null; // 暫定 if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder) { // 2次三角形要素 getDFDXValues_Tri_SecondOrder( WaveModeDv, k0, rotAngle, rotOrigin, Nodes, Elements, Medias, ForceNodeNumberH, elemNoPeriodic, nodePeriodicB, toNodePeriodic, resVec, out resDFDXVec, out resDFDYVec); } else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder) { // 1次三角形要素 getDFDXValues_Tri_FirstOrder( WaveModeDv, k0, rotAngle, rotOrigin, Nodes, Elements, Medias, ForceNodeNumberH, elemNoPeriodic, nodePeriodicB, toNodePeriodic, resVec, out resDFDXVec, out resDFDYVec); } else { System.Diagnostics.Debug.Assert(false); } if (isYDirectionPeriodic) { // Y方向周期構造の場合 resDFDXVecList[imode] = resDFDYVec; } else { // X方向周期構造の場合 resDFDXVecList[imode] = resDFDXVec; } } // 境界1と境界2の節点の微分値は同じという条件を弱形式で課している為、微分値は同じにならない。 // 加えて、getDFDXValuesは内部節点からの寄与を片側のみしか計算していない。 // →境界の両側からの寄与を考慮する為に境界1の微分値と境界2の微分値を平均してみる for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; // ポート境界1の節点の微分値、ポート境界2の微分値は、両者の平均をとる for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点 int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; // 境界1の節点の界の微分値値を取得 KrdLab.clapack.Complex cdFdXValue1 = resDFDXVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino; int nodeNumberPortBc2 = nodePeriodicB2[ino_B2]; int ino_InLoop_PortBc2 = toNodePeriodic[nodeNumberPortBc2]; // 境界2の節点の界の微分値値を取得 KrdLab.clapack.Complex cdFdXValue2 = resDFDXVec[ino_InLoop_PortBc2]; // 平均値を計算し、境界の微分値として再格納する if (isSVEA) { KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2) * 0.5; resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue; resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue; } else { // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1 KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance); // Φ2から逆算でΦ1を求め、平均をとる KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2 / expA) * 0.5; resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue; resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue * expA; } } } ////////////////////////////////////////////////////////////////////////////////////// if (!isSVEA) { // 緩慢変化包絡線近似でない場合は、緩慢変化包絡線近似の分布に変換する for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; System.Diagnostics.Debug.Assert(resVec.Length == coordsPeriodic.Count); int nodeNumber1st = sortedNodesPeriodic[0]; int ino_InLoop_1st = toNodePeriodic[nodeNumber1st]; double[] coord1st = coordsPeriodic[ino_InLoop_1st]; for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++) { // 節点の界の値 KrdLab.clapack.Complex fieldVal = resVec[ino_InLoop]; // 節点の界の微分値 KrdLab.clapack.Complex dFdXVal = resDFDXVec[ino_InLoop]; // 節点の座標 double[] coord = coordsPeriodic[ino_InLoop]; double x_pt = 0.0; if (isYDirectionPeriodic) { x_pt = (coord[1] - coord1st[1]); } else { x_pt = (coord[0] - coord1st[0]); } //KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * x_pt); KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * x_pt); // ΦのSVEA(φ) KrdLab.clapack.Complex fieldVal_SVEA = fieldVal / expX; resVec[ino_InLoop] = fieldVal_SVEA; // SVEAの微分( exp(-jβx)dφ/dx = dΦ/dx + jβφexp(-jβx)) //resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam * fieldVal_SVEA; resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * fieldVal_SVEA; } } } System.Diagnostics.Debug.WriteLine("betamToSolveList.Length {0}", betamToSolveList.Length); ////////////////////////////////////////////////////////////////////////////////////// // モード数の修正 int maxMode = maxModeSpecified; if (maxMode > betamToSolveList.Length) { maxMode = betamToSolveList.Length; } ////////////////////////////////////////////////////////////////////////////////////// // 表示用に周期構造領域の固有モード分布を格納する eigenVecsPeriodic = new KrdLab.clapack.Complex[maxMode][]; for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; System.Diagnostics.Debug.Assert(resVec.Length == nodePeriodic.Count); eigenVecsPeriodic[tagtModeIndex] = new KrdLab.clapack.Complex[nodePeriodic.Count]; resVec.CopyTo(eigenVecsPeriodic[tagtModeIndex], 0); } ////////////////////////////////////////////////////////////////////////////////////// // 固有値、固有ベクトル // 格納 int nodeCntB1 = nodePeriodicB1.Count; eigenValues = new Complex[maxMode]; //eigenVecsB1 = new Complex[maxMode, nodeCntB1]; //eigen_dFdXsB1 = new Complex[maxMode, nodeCntB1]; eigenVecsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く eigen_dFdXsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く for (int imode = 0; imode < maxMode; imode++) { eigenValues[imode] = new Complex(0, 0); for (int ino = 0; ino < eigenVecsB1.GetLength(1); ino++) { eigenVecsB1[imode, ino] = new Complex(0, 0); eigen_dFdXsB1[imode, ino] = new Complex(0, 0); } } for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++) { //System.Diagnostics.Debug.WriteLine("imode = {0}", imode); KrdLab.clapack.Complex workBetam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; Complex betam = new Complex(workBetam.Real, workBetam.Imaginary); bool isComplexConjugateMode = false; // 減衰定数は符号がマイナス(β = -jα) if (betam.Imaginary > 0.0 && Math.Abs(betam.Real) <= 1.0e-12) { betam = new Complex(betam.Real, -betam.Imaginary); isComplexConjugateMode = true; } //Complex[] evec = new Complex[nodeCntB1]; //Complex[] evec_dFdX = new Complex[nodeCntB1]; Complex[] evec = new Complex[nodesBoundary.Length]; // 強制境界を除く Complex[] evec_dFdX = new Complex[nodesBoundary.Length]; // 強制境界を除く for (int ino = 0; ino < nodeCntB1; ino++) { int nodeNumberPortBc1 = nodePeriodicB1[ino]; //System.Diagnostics.Debug.WriteLine("ino = {0} nodeNumberPortBc1 = {1}", ino, nodeNumberPortBc1); int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; Complex cvalue = new Complex(resVec[ino_InLoop_PortBc1].Real, resVec[ino_InLoop_PortBc1].Imaginary); Complex dFdXValue = new Complex(resDFDXVec[ino_InLoop_PortBc1].Real, resDFDXVec[ino_InLoop_PortBc1].Imaginary); if (isComplexConjugateMode) { cvalue = Complex.Conjugate(cvalue); dFdXValue = Complex.Conjugate(dFdXValue); } //evec[ino] = cvalue; //evec_dFdX[ino] = dFdXValue; /////////////////////////////////////////////////// // 強制境界を除く if (!toNodesB.ContainsKey(nodeNumberPortBc1)) { continue; } int ino_f = toNodesB[nodeNumberPortBc1]; //System.Diagnostics.Debug.WriteLine("ino_f = {0}", ino_f); evec[ino_f] = cvalue; evec_dFdX[ino_f] = dFdXValue; /////////////////////////////////////////////////// //if (tagtModeIndex == incidentModeIndex) { //System.Diagnostics.Debug.WriteLine("evec[{0}] = {1} + {2} i", ino_f, evec[ino_f].Real, evec[ino_f].Imaginary); } } // 規格化定数を求める Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec); //Complex[] evec_Modify = new Complex[nodeCntB1]; Complex[] evec_Modify = new Complex[nodesBoundary.Length];//強制境界を除く Complex imagOne = new Complex(0.0, 1.0); Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < nodeCntB1; ino++) { //evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam_periodic); /////////////////////////////////////////////////// // 強制境界を除く int nodeNumberPortBc1 = nodePeriodicB1[ino]; if (!toNodesB.ContainsKey(nodeNumberPortBc1)) { continue; } int ino_f = toNodesB[nodeNumberPortBc1]; evec_Modify[ino_f] = evec[ino_f] - evec_dFdX[ino_f] / (imagOne * betam_periodic); /////////////////////////////////////////////////// } //Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec); Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec_Modify), workVec); if (WaveModeDv == FemSolver.WaveModeDV.TM) { // TMモード dm = Complex.Sqrt(omega * eps0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm); } else { // TEモード dm = Complex.Sqrt(omega * mu0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm); } // 伝搬定数の格納 eigenValues[tagtModeIndex] = betam; if (tagtModeIndex < 10) { System.Diagnostics.Debug.WriteLine("β/k0 ( " + tagtModeIndex + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + ((incidentModeIndex == tagtModeIndex) ? " incident" : "")); } // 固有ベクトルの格納(規格化定数を掛ける) for (int ino = 0; ino < evec.Length; ino++) { Complex fm = dm * evec[ino]; Complex dfmdx = dm * evec_dFdX[ino]; eigenVecsB1[tagtModeIndex, ino] = fm; eigen_dFdXsB1[tagtModeIndex, ino] = dfmdx; //System.Diagnostics.Debug.WriteLine("eigen_vecs_Bc1({0}, {1}) = {2} + {3} i", imode, ino, fm.Real, fm.Imag); } } System.Diagnostics.Debug.WriteLine("eigen end"); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// ポート境界の1D FEM行列 ryy_1dを取得する /// </summary> /// <param name="WaveModeDv"></param> /// <param name="waveLength"></param> /// <param name="latticeA"></param> /// <param name="Nodes"></param> /// <param name="EdgeToElementNoH"></param> /// <param name="Elements"></param> /// <param name="Medias"></param> /// <param name="ForceNodeNumberH"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> private static void getPortFemMat1D( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, IList<FemNode> Nodes, Dictionary<string, IList<int>> EdgeToElementNoH, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, IList<int> portNodes, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d ) { nodesBoundary = null; ryy_1d = null; // 2D次元数 const int ndim2d = Constants.CoordDim2D; //2; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 節点番号リスト(要素インデックス: 1D節点番号 - 1 要素:2D節点番号) IList<int> nodes = portNodes; // 2D→1D節点番号マップ Dictionary<int, int> to1dNodes = new Dictionary<int, int>(); // 節点座標リスト IList<double> coords = new List<double>(); // 要素リスト IList<FemLineElement> elements = new List<FemLineElement>(); // 1D節点番号リスト(ソート済み) IList<int> sortedNodes = new List<int>(); // 1D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 2Dの要素から次数を取得する Constants.FemElementShapeDV elemShapeDv2d; int order; int vertexCnt2d; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(Elements[0].NodeNumbers.Length, out elemShapeDv2d, out order, out vertexCnt2d); // 2D→1D節点番号マップ作成 for (int i = 0; i < nodes.Count; i++) { int nodeNumber2d = nodes[i]; if (!to1dNodes.ContainsKey(nodeNumber2d)) { to1dNodes.Add(nodeNumber2d, i + 1); } } // 原点 int nodeNumber0 = nodes[0]; int nodeIndex0 = nodeNumber0 - 1; FemNode node0 = Nodes[nodeIndex0]; double[] coord0 = new double[ndim2d]; coord0[0] = node0.Coord[0]; coord0[1] = node0.Coord[1]; // 座標リスト作成 double[] coord = new double[ndim2d]; foreach (int nodeNumber in nodes) { int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; coord[0] = node.Coord[0]; coord[1] = node.Coord[1]; double x = FemMeshLogic.GetDistance(coord, coord0); //System.Diagnostics.Debug.WriteLine("{0},{1},{2},{3}", nodeIndex, coord[0], coord[1], x); coords.Add(x); } // 線要素を作成する if (order == Constants.FirstOrder) { // 1次線要素 FemMat_Line_First.MkElements( nodes, EdgeToElementNoH, Elements, ref elements); } else { // 2次線要素 FemMat_Line_Second.MkElements( nodes, EdgeToElementNoH, Elements, ref elements); } // 強制境界節点と内部領域節点を分離 foreach (int nodeNumber2d in nodes) { int nodeNumber = to1dNodes[nodeNumber2d]; if (ForceNodeNumberH.ContainsKey(nodeNumber2d)) { System.Diagnostics.Debug.WriteLine("{0}: {1} {2}", nodeNumber, Nodes[nodeNumber2d - 1].Coord[0], Nodes[nodeNumber2d - 1].Coord[1]); } else { sortedNodes.Add(nodeNumber); toSorted.Add(nodeNumber, sortedNodes.Count - 1); } } // 対称バンド行列のパラメータを取得する int rowcolSize = 0; int subdiaSize = 0; int superdiaSize = 0; { bool[,] matPattern = null; FemSolverPort.GetMatNonzeroPatternForEigen(elements, toSorted, out matPattern); FemSolverPort.GetBandMatrixSubDiaSizeAndSuperDiaSizeForEigen(matPattern, out rowcolSize, out subdiaSize, out superdiaSize); } // ソート済み1D節点インデックス→2D節点番号マップ nodesBoundary = new int[sortedNodes.Count]; for (int i = 0; i < sortedNodes.Count; i++) { int nodeNumber = sortedNodes[i]; int nodeIndex = nodeNumber - 1; int nodeNumber2d = nodes[nodeIndex]; nodesBoundary[i] = nodeNumber2d; } // 節点数 int nodeCnt = sortedNodes.Count; // 固有モード解析でのみ使用するuzz_1d, txx_1d MyDoubleMatrix txx_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); MyDoubleMatrix uzz_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); // ryy_1dマトリクス (線要素) ryy_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); for (int elemIndex = 0; elemIndex < elements.Count; elemIndex++) { // 線要素 FemLineElement element = elements[elemIndex]; // 1Dヘルムホルツ方程式固有値問題の要素行列を加算する if (order == Constants.FirstOrder) { // 1次線要素 FemMat_Line_First.AddElementMatOf1dEigenValueProblem( waveLength, // E面の場合のみ使用 element, coords, toSorted, Medias, WaveModeDv, ref txx_1d, ref ryy_1d, ref uzz_1d); } else { // 2次線要素 FemMat_Line_Second.AddElementMatOf1dEigenValueProblem( waveLength, // E面の場合のみ使用 element, coords, toSorted, Medias, WaveModeDv, ref txx_1d, ref ryy_1d, ref uzz_1d); } } }
/// <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]; } }
private Complex getPeriodicWaveguidePortReflectionCoef( double waveLength, int iMode, bool isIncidentMode, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdXs, int[] nodesRegion, Complex[] valuesAll) { Complex s11 = FemSolverPortPeriodic.GetWaveguidePortReflectionCoef( WaveModeDv, waveLength, LatticeA, iMode, isIncidentMode, nodesBoundary, ryy_1d, eigenValues, eigenVecs, eigen_dFdXs, nodesRegion, Elements, Medias, valuesAll ); return s11; }
private void solvePortPeriodicWaveguideEigen( int freqNo, string filename, double waveLength, int portNo, int maxModeSpecified, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d, out Complex[] eigenValues, out Complex[,] eigenVecs, out Complex[,] eigen_dFdX) { System.Diagnostics.Debug.WriteLine("/////////// solvePortWaveguideEigen: {0}, {1}", waveLength, portNo); // ポート周期構造領域の変数(表示用、伝達問題には必要ない) IList<int> nodePeriodic = null; Dictionary<int, int> toNodePeriodic = null; IList<double[]> coordsPeriodic = null; KrdLab.clapack.Complex[][] eigenVecsPeriodic = null; // 周期構造導波路固有値解析 FemSolverPortPeriodic.SolvePortWaveguideEigen( WaveModeDv, waveLength, LatticeA, maxModeSpecified, Nodes, EdgeToElementNoH, Elements, Medias, ForceNodeNumberH, Ports[portNo - 1], ElemNoPeriodicList[portNo - 1], NodePeriodicBList[portNo - 1], DefectNodePeriodicList[portNo - 1], out nodesBoundary, out ryy_1d, out eigenValues, out eigenVecs, out eigen_dFdX, out nodePeriodic, out toNodePeriodic, out coordsPeriodic, out eigenVecsPeriodic ); // 周期構造領域のモード分布をファイルに格納する string periodicDatFilename = FemOutputPeriodicDatFile.GetOutputPeriodicDatFilename(filename); FemOutputPeriodicDatFile.AppendToFile( periodicDatFilename, freqNo, portNo, waveLength, nodePeriodic, toNodePeriodic, coordsPeriodic, eigenValues, eigenVecsPeriodic ); }
/// <summary> /// �w�肳�ꂽ�s���R�s�[���āC�V�����s���쐬����D /// </summary> /// <param name="m">�R�s�[�����s��</param> public MyDoubleMatrix(MyDoubleMatrix m) { CopyFrom(m); }
/* /// <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 ); }
// [X] = alpha * [A] public static MyDoubleMatrix product(double alpha, MyDoubleMatrix matA) { MyDoubleMatrix matX = new MyDoubleMatrix(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; }
/// <summary> /// ベースクラスのコピーI/F (無効) /// </summary> /// <param name="m"></param> /// <returns></returns> public override sealed MyDoubleMatrix CopyFrom(MyDoubleMatrix m) { System.Diagnostics.Debug.Assert(false); //return base.CopyFrom(m); return(this); }
/// <summary> /// �x�[�X�N���X�̃R�s�[I/F (����) /// </summary> /// <param name="m"></param> /// <returns></returns> public override sealed MyDoubleMatrix CopyFrom(MyDoubleMatrix m) { System.Diagnostics.Debug.Assert(false); //return base.CopyFrom(m); return this; }
/* // x = sqrt(c) public static Complex complex_Sqrt(Complex c) { System.Numerics.Complex work = new System.Numerics.Complex(c.Real, c.Imaginary); work = System.Numerics.Complex.Sqrt(work); return new Complex(work.Real, work.Imaginary); } */ // [X] = [A]t public static MyDoubleMatrix matrix_Transpose(MyDoubleMatrix matA) { MyDoubleMatrix matX = new MyDoubleMatrix(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; }
public static double[,] matrix_Inverse(double[,] matA) { MyDoubleMatrix matA_ = new MyDoubleMatrix(matA); matA_ = matrix_Inverse(matA_); return matA_.ToArray(); }
/// <summary> /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する /// </summary> /// <param name="waveLength">波長(E面の場合のみ使用する)</param> /// <param name="element">線要素</param> /// <param name="coords">座標リスト</param> /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param> /// <param name="Medias">媒質情報リスト</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="txx_1d">txx行列</param> /// <param name="ryy_1d">ryy行列</param> /// <param name="uzz_1d">uzz行列</param> public static void AddElementMatOf1dEigenValueProblem( double waveLength, FemLineElement element, IList<double> coords, Dictionary<int, int> toSorted, MediaInfo[] Medias, FemSolver.WaveModeDV WaveModeDv, ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 2次線要素 const int nno = Constants.LineNodeCnt_SecondOrder; // 3; int[] nodeNumbers = element.NodeNumbers; System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length); // 座標の取得 double[] elementCoords = new double[nno]; for (int n = 0; n < nno; n++) { int nodeIndex = nodeNumbers[n] - 1; elementCoords[n] = coords[nodeIndex]; } // 線要素の長さ double elen = Math.Abs(elementCoords[1] - elementCoords[0]); // 媒質インデックス int mediaIndex = element.MediaIndex; // 媒質 MediaInfo media = Medias[mediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WaveModeDv, out media_P, out media_Q); double[,] integralN = new double[nno, nno] { { 4.0 / 30.0 * elen, -1.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { -1.0 / 30.0 * elen, 4.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { 2.0 / 30.0 * elen, 2.0 / 30.0 * elen, 16.0 / 30.0 * elen }, }; double[,] integralDNDY = new double[nno, nno] { { 7.0 / (3.0 * elen), 1.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { 1.0 / (3.0 * elen), 7.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) }, }; for (int ino = 0; ino < nno; ino++) { int inoBoundary = nodeNumbers[ino]; int inoSorted; if (!toSorted.ContainsKey(inoBoundary)) continue; inoSorted = toSorted[inoBoundary]; for (int jno = 0; jno < nno; jno++) { int jnoBoundary = nodeNumbers[jno]; int jnoSorted; if (!toSorted.ContainsKey(jnoBoundary)) continue; jnoSorted = toSorted[jnoBoundary]; // 対称バンド行列対応 if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted) { continue; } double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno]; double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno]; double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno]; //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno; //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno; //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno; txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno; ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno; uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno; } } }
/* public static void printVec(string tag, ValueType[] vec) { for (int i = 0; i < vec.Length; i++) { Complex val = (Complex)vec[i]; System.Diagnostics.Debug.WriteLine(tag + "(" + i + ")" + " = " + "(" + val.Real + "," + val.Imaginary + ") " + Complex.Abs(val)); } } */ /* public static void compressVec(ref ValueType[] vec) { KrdLab.clapack.FunctionExt.CompressMatFor_zgesv(ref vec); } */ public static double[] matrix_ToBuffer(MyDoubleMatrix mat, bool copyFlg = true) { double[] mat_ = null; if (copyFlg) { int size = mat._rsize * mat._csize; mat_ = new double[size]; mat._body.CopyTo(mat_, 0); } else { mat_ = mat._body; } return mat_; }
/* * /// <summary> * /// リサイズする. * /// </summary> * /// <param name="rowSize">新しい行数</param> * /// <param name="columnSize">新しい列数</param> * /// <param name="val">各要素の値</param> * /// <returns>リサイズ後の自身への参照</returns> * public MyDoubleMatrix Resize(int rowSize, int columnSize, double 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 MyDoubleMatrix CopyFrom(MyDoubleMatrix m) { return(CopyFrom(m._body, m._rsize, m._csize)); }
// [X] = [A] + [B] public static MyDoubleMatrix plus(MyDoubleMatrix matA, MyDoubleMatrix matB) { System.Diagnostics.Debug.Assert(matA.RowSize == matB.RowSize); System.Diagnostics.Debug.Assert(matA.ColumnSize == matB.ColumnSize); MyDoubleMatrix matX = new MyDoubleMatrix(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> /// 指定された行列をコピーして,新しい行列を作成する. /// </summary> /// <param name="m">コピーされる行列</param> public MyDoubleMatrix(MyDoubleMatrix m) { CopyFrom(m); }
public static void printMatrixNoZero(string tag, MyDoubleMatrix mat) { for (int i = 0; i < mat.RowSize; i++) { for (int j = 0; j < mat.ColumnSize; j++) { double val = mat[i, j]; if (Math.Abs(val) < Constants.PrecisionLowerLimit) continue; System.Diagnostics.Debug.WriteLine(tag + "(" + i + ", " + j + ")" + " = " + val + " "); } } }
/* /// <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 MyDoubleMatrix Resize(int rowSize, int columnSize, double 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 MyDoubleMatrix CopyFrom(MyDoubleMatrix m) { return CopyFrom(m._body, m._rsize, m._csize); }
public static MyComplexMatrix product(MyDoubleMatrix 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> /// �]�u����D /// </summary> /// <returns>�]�u��̎��g�ւ̎Q��</returns> public virtual MyDoubleMatrix Transpose() { MyDoubleMatrix t = new MyDoubleMatrix(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]; } } this.Clear(); this._body = t._body; this._rsize = t._rsize; this._csize = t._csize; return this; }
// {x} = [A]{v} public static Complex[] product(MyDoubleMatrix 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> /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する /// </summary> /// <param name="element">線要素</param> /// <param name="coords">座標リスト</param> /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param> /// <param name="Medias">媒質情報リスト</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="txx_1d">txx行列</param> /// <param name="ryy_1d">ryy行列</param> /// <param name="uzz_1d">uzz行列</param> public static void AddElementMatOf1dEigenValueProblem( FemLineElement element, IList<double> coords, Dictionary<int, int> toSorted, MediaInfo[] Medias, FemSolver.WaveModeDV WaveModeDv, ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d) { // 1次線要素 const int nno = Constants.LineNodeCnt_FirstOrder; // 2; int[] nodeNumbers = element.NodeNumbers; System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length); // 座標の取得 double[] elementCoords = new double[nno]; for (int n = 0; n < nno; n++) { int nodeIndex = nodeNumbers[n] - 1; elementCoords[n] = coords[nodeIndex]; } // 線要素の長さ double elen = Math.Abs(elementCoords[1] - elementCoords[0]); // 媒質インデックス int mediaIndex = element.MediaIndex; // 媒質 MediaInfo media = Medias[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); } media_P = MyMatrixUtil.matrix_Inverse(media_P); double[,] integralN = new double[nno, nno] { { elen / 3.0, elen / 6.0 }, { elen / 6.0, elen / 3.0 }, }; double[,] integralDNDY = new double[nno, nno] { { 1.0 / elen, -1.0 / elen }, { -1.0 / elen, 1.0 / elen }, }; for (int ino = 0; ino < nno; ino++) { int inoBoundary = nodeNumbers[ino]; int inoSorted; if (!toSorted.ContainsKey(inoBoundary)) continue; inoSorted = toSorted[inoBoundary]; for (int jno = 0; jno < nno; jno++) { int jnoBoundary = nodeNumbers[jno]; int jnoSorted; if (!toSorted.ContainsKey(jnoBoundary)) continue; jnoSorted = toSorted[jnoBoundary]; // 対称バンド行列対応 if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted) { continue; } double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno]; double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno]; double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno]; //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno; //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno; //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno; txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno; ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno; uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno; } } }