/* /// <summary> /// 周期構造導波路固有値問題を2次一般化固有値問題として解く /// </summary> /// <param name="k0"></param> /// <param name="KMat"></param> /// <param name="CMat"></param> /// <param name="MMat"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="to_no_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> private static void solveAsQuadraticGeneralizedEigen( int incidentModeIndex, double k0, double[] KMat, double[] CMat, double[] MMat, uint node_cnt, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, Dictionary<uint, uint> to_no_boundary_fieldPortBcId1, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 非線形固有値問題 // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ= - jβとおくと // [K] + λ[C] + λ^2[M]{Φ}= {0} // // Lisys(Lapack)による固有値解析 // マトリクスサイズは、強制境界及び境界3を除いたサイズ int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; // 一般化固有値解析 KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[(matLen * 2) * (matLen * 2)]; KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[(matLen * 2) * (matLen * 2)]; for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { A[i + j * (matLen * 2)] = 0.0; A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0; // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合 //A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMat[i + j * matLen]; //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * CMat[i + j * matLen]; // // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // -[K] --> [K] // j[C] --> [C] // とおいてλ=βとした場合 A[(i + matLen) + j * (matLen * 2)] = KMat[i + j * matLen]; A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * KrdLab.clapack.Complex.ImaginaryOne * CMat[i + j * matLen]; } } for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { B[i + j * (matLen * 2)] = (i == j) ? 1.0 : 0.0; B[i + (j + matLen) * (matLen * 2)] = 0.0; B[(i + matLen) + j * (matLen * 2)] = 0.0; B[(i + matLen) + (j + matLen) * (matLen * 2)] = MMat[i + j * matLen]; } } KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[][] ret_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev"); KrdLab.clapack.FunctionExt.zggev(A, (matLen * 2), (matLen * 2), B, (matLen * 2), (matLen * 2), ref ret_evals, ref ret_evecs); //evals = ret_evals; evals = new KrdLab.clapack.Complex[ret_evals.Length]; // βを格納 for (int i = 0; i < ret_evals.Length; i++) { KrdLab.clapack.Complex eval = ret_evals[i]; // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合 //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne; // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // -[K] --> [K] // j[C] --> [C] // とおいてλ=βとした場合 evals[i] = eval; } System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_evecs.Length, (matLen * 2)]; for (int i = 0; i < ret_evecs.Length; i++) { KrdLab.clapack.Complex[] ret_evec = ret_evecs[i]; for (int j = 0; j < ret_evec.Length; j++) { evecs[i, j] = ret_evec[j]; } } // 固有値をソートする System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt * 2); GetSortedModes( incidentModeIndex, k0, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref PrevModalVec, minBeta, maxBeta, evals, evecs, true, // isDebugShow out betamToSolveList, out resVecList); } */ /// <summary> /// 周期構造導波路固有値問題を2次一般化固有値問題として解く(実行列として解く) /// </summary> /// <param name="k0"></param> /// <param name="KMat"></param> /// <param name="CMat"></param> /// <param name="MMat"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="to_no_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> private static void solveAsQuadraticGeneralizedEigenWithRealMat( int incidentModeIndex, bool isSVEA, double periodicDistance, double k0, double[] KMat, double[] CMat, double[] MMat, uint node_cnt, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, Dictionary<uint, uint> to_no_boundary_fieldPortBcId1, bool isYDirectionPeriodic, double[][] coord_c_all, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, double betaNormalizingFactor, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 非線形固有値問題 // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ= - jβとおくと // [K] + λ[C] + λ^2[M]{Φ}= {0} // // Lisys(Lapack)による固有値解析 // マトリクスサイズは、強制境界及び境界3を除いたサイズ int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; // 一般化固有値解析(実行列として解く) double[] A = new double[(matLen * 2) * (matLen * 2)]; double[] B = new double[(matLen * 2) * (matLen * 2)]; for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { if (isSVEA) { A[i + j * (matLen * 2)] = 0.0; A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0; // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合 //A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMat[i + j * matLen]; //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * CMat[i + j * matLen]; // λ = -j(β/k0)と置いた場合 //A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMat[i + j * matLen]; //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * k0 * CMat[i + j * matLen]; // λ = -j(β/betaNormalizingFactor)と置いた場合 A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMat[i + j * matLen]; A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * betaNormalizingFactor * CMat[i + j * matLen]; } else { A[i + j * (matLen * 2)] = 0.0; A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0; A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMat[i + j * matLen]; A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * CMat[i + j * matLen]; } } } for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { if (isSVEA) { B[i + j * (matLen * 2)] = (i == j) ? 1.0 : 0.0; B[i + (j + matLen) * (matLen * 2)] = 0.0; B[(i + matLen) + j * (matLen * 2)] = 0.0; // λ = -jβと置いた場合 //B[(i + matLen) + (j + matLen) * (matLen * 2)] = MMat[i + j * matLen]; // λ = -j(β/k0)と置いた場合 //B[(i + matLen) + (j + matLen) * (matLen * 2)] = k0 * k0 * MMat[i + j * matLen]; // λ = -j(β/betaNormalizingFactor)と置いた場合 B[(i + matLen) + (j + matLen) * (matLen * 2)] = betaNormalizingFactor * betaNormalizingFactor * MMat[i + j * matLen]; } else { B[i + j * (matLen * 2)] = (i == j) ? 1.0 : 0.0; B[i + (j + matLen) * (matLen * 2)] = 0.0; B[(i + matLen) + j * (matLen * 2)] = 0.0; B[(i + matLen) + (j + matLen) * (matLen * 2)] = MMat[i + j * matLen]; } } } double[] ret_r_evals = null; double[] ret_i_evals = null; double[][] ret_r_evecs = null; double[][] ret_i_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.dggev"); KrdLab.clapack.FunctionExt.dggev(A, (matLen * 2), (matLen * 2), B, (matLen * 2), (matLen * 2), ref ret_r_evals, ref ret_i_evals, ref ret_r_evecs, ref ret_i_evecs); evals = new KrdLab.clapack.Complex[ret_r_evals.Length]; // βを格納 for (int i = 0; i < ret_r_evals.Length; i++) { KrdLab.clapack.Complex eval = new KrdLab.clapack.Complex(ret_r_evals[i], ret_i_evals[i]); if (isSVEA) { // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合(β = jλ) //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne; // λ = -j(β/k0)と置いた場合 //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * k0; // λ = -j(β/betaNormalizingFactor)と置いた場合 evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * betaNormalizingFactor; } else { //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary); if ((Math.Abs(eval.Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(eval.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) || double.IsInfinity(eval.Real) || double.IsInfinity(eval.Imaginary) || double.IsNaN(eval.Real) || double.IsNaN(eval.Imaginary) ) { // 無効な固有値 //evals[i] = -1.0 * KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue; evals[i] = KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue; } else { //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary); KrdLab.clapack.Complex betatmp = -1.0 * MyUtilLib.Matrix.MyMatrixUtil.complex_Log(eval) / (KrdLab.clapack.Complex.ImaginaryOne * periodicDistance); evals[i] = new KrdLab.clapack.Complex(betatmp.Real, betatmp.Imaginary); } } } System.Diagnostics.Debug.Assert(ret_r_evals.Length == ret_r_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_r_evecs.Length, (matLen * 2)]; for (int i = 0; i < ret_r_evecs.Length; i++) { double[] ret_r_evec = ret_r_evecs[i]; double[] ret_i_evec = ret_i_evecs[i]; for (int j = 0; j < ret_r_evec.Length; j++) { evecs[i, j] = new KrdLab.clapack.Complex(ret_r_evec[j], ret_i_evec[j]); } } //////////////////////////////////////////////////////////////////// if (!isSVEA) { System.Diagnostics.Debug.Assert(free_node_cnt == (sortedNodes.Count - boundary_node_cnt)); for (int imode = 0; imode < evals.Length; imode++) { // 伝搬定数 KrdLab.clapack.Complex betatmp = evals[imode]; // 界ベクトル KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); KrdLab.clapack.Complex beta_d_tmp = betatmp * periodicDistance; if ( // [-π, 0]の解を[π, 2π]に移動する ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.0 && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && (beta_d_tmp.Real / (2.0 * pi)) >= (-0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (beta_d_tmp.Real / (2.0 * pi)) < 0.0) // [0, π]の解を[2π, 3π]に移動する || ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (1.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.5 && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && (beta_d_tmp.Real / (2.0 * pi)) >= (0.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (beta_d_tmp.Real / (2.0 * pi)) < 0.5) ) /* if ( // [-π, 0]の解を[π, 2π]に移動する ( Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && (beta_d_tmp.Real / (2.0 * pi)) >= (-0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (beta_d_tmp.Real / (2.0 * pi)) < 0.0) ) */ { // [0, π]の解を2πだけ移動する double delta_phase = 2.0 * pi; beta_d_tmp.Real += delta_phase; betatmp = beta_d_tmp / periodicDistance; //check System.Diagnostics.Debug.WriteLine("shift beta * d / (2π): {0} + {1} i to {2} + {3} i", evals[imode].Real * periodicDistance / (2.0 * pi), evals[imode].Imaginary * periodicDistance / (2.0 * pi), beta_d_tmp.Real / (2.0 * pi), beta_d_tmp.Imaginary / (2.0 * pi)); // 再設定 evals[imode] = betatmp; /* //βを与えてk0を求める方法で計算した分布Φは、Φ|β2 = Φ|β1 (β2 = β1 + 2π)のように思われる // したがって、界分布はずらさないことにする // 界分布の位相をexp(j((2π/d)x))ずらす uint nodeNumber1st = sortedNodes[0]; uint ino_InLoop_1st = to_no_all[nodeNumber1st]; double[] coord1st = coord_c_all[ino_InLoop_1st]; // 界ベクトルは{Φ}, {λΦ}の順にならんでいる System.Diagnostics.Debug.Assert(free_node_cnt == (fieldVec.Length / 2)); for (int ino = 0; ino < fieldVec.Length; ino++) { uint nodeNumber = 0; if (ino < free_node_cnt) { nodeNumber = sortedNodes[ino]; } else { nodeNumber = sortedNodes[ino - (int)free_node_cnt]; } uint ino_InLoop = to_no_all[nodeNumber]; double[] coord = coord_c_all[ino_InLoop]; // 界分布の位相をexp(j((2π/d)x))ずらす double x_pt = 0.0; if (isYDirectionPeriodic) { x_pt = (coord[1] - coord1st[1]); } else { x_pt = (coord[0] - coord1st[0]); } double delta_beta = -1.0 * delta_phase / periodicDistance; KrdLab.clapack.Complex delta_expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * delta_beta * x_pt); fieldVec[ino] *= delta_expX; } // 再設定 MyUtilLib.Matrix.MyMatrixUtil.matrix_setRowVec(evecs, imode, fieldVec); */ } } } // 固有値をソートする System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt * 2); GetSortedModes( incidentModeIndex, k0, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref PrevModalVec, minBeta, maxBeta, evals, evecs, true, // isDebugShow out betamToSolveList, out resVecList); }
/// <summary> /// /// </summary> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="tmpBuffer"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> public static bool SolvePCOCG( ref CFieldWorld World, ref uint FieldValId, ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; //------------------------------------------------------------------ // マージの終了 //------------------------------------------------------------------ double res = Ls.FinalizeMarge(); tmpBuffer = null; // マトリクスサイズの取得 // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // マトリクスのサイズ int matLen = (int)mat_cc.NBlkMatCol(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList <uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World); CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World); // 要素の節点数 uint nno = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る es_c_va.GetNodes(ielem, no_c); for (uint inoes = 0; inoes < nno; inoes++) { Complex[] tmpval = null; ns_c_val.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == 1); value_c[inoes] = tmpval[0]; //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" ); } for (uint ino = 0; ino < nno; ino++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Ls = null; Prec.Clear(); Prec.Dispose(); Prec = null; World.Clear(); World.Dispose(); World = null; System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return(success); }
// x = {v1}t{v2} public static KrdLab.clapack.Complex vector_Dot(KrdLab.clapack.Complex[] v1, KrdLab.clapack.Complex[] v2) { System.Diagnostics.Debug.Assert(v1.Length == v2.Length); int n = v1.Length; KrdLab.clapack.Complex sum = new KrdLab.clapack.Complex(0.0, 0.0); for (int i = 0; i < n; i++) { sum += v1[i] * v2[i]; } return sum; }
/// <summary> /// エルミートバンド行列の一般化固有値問題を解く(clapack) /// </summary> /// <param name="matLen"></param> /// <param name="A"></param> /// <param name="B"></param> /// <param name="evals"></param> /// <param name="evecs"></param> private static void solveHermitianBandMatGeneralizedEigen(int matLen, KrdLab.clapack.Complex[] A, KrdLab.clapack.Complex[] B, ref KrdLab.clapack.Complex[] evals, ref KrdLab.clapack.Complex[,] evecs) { // エルミート行列、正定値行列チェック bool isHermitianA = true; bool isHermitianB = true; bool isPositiveDefiniteB = true; for (int i = 0; i < matLen; i++) { // [B]の正定値行列チェック if (B[i + matLen * i].Real <= 0) { isPositiveDefiniteB = false; break; } for (int j = i; j < matLen; j++) { // [A]のエルミート行列チェック if (KrdLab.clapack.Complex.Abs(KrdLab.clapack.Complex.Conjugate(A[i + matLen * j]) - A[j + matLen * i]) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isHermitianA = false; break; } // [B]のエルミート行列チェック if (KrdLab.clapack.Complex.Abs(KrdLab.clapack.Complex.Conjugate(B[i + matLen * j]) - B[j + matLen * i]) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isHermitianB = false; break; } } if (!isHermitianA || !isHermitianB) { break; } } System.Diagnostics.Debug.Assert(isHermitianA); System.Diagnostics.Debug.Assert(isHermitianB); System.Diagnostics.Debug.Assert(isPositiveDefiniteB); // パターン取得 bool[,] patternA = new bool[matLen, matLen]; bool[,] patternB = new bool[matLen, matLen]; for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { //patternA[i, j] = (A[i + matLen * j].Magnitude >= Constants.PrecisionLowerLimit); //patternB[i, j] = (B[i + matLen * j].Magnitude >= Constants.PrecisionLowerLimit); patternA[i, j] = (A[i + matLen * j].Real != 0 || A[i + matLen * j].Imaginary != 0); patternB[i, j] = (B[i + matLen * j].Real != 0 || B[i + matLen * j].Imaginary != 0); } } // バンド行列のバンド幅を縮小する KrdLab.clapack.Complex[] optA = new KrdLab.clapack.Complex[matLen * matLen]; bool[,] optPatternA = new bool[matLen, matLen]; IList<int> optNodesA = null; Dictionary<int, int> toOptNodesA = null; KrdLab.clapack.Complex[] optB = new KrdLab.clapack.Complex[matLen * matLen]; bool[,] optPatternB = new bool[matLen, matLen]; IList<int> optNodesB = null; Dictionary<int, int> toOptNodesB = null; // [B]のバンド幅を縮小する { GetOptBandMatNodes(patternB, out optNodesB, out toOptNodesB); for (int i = 0; i < matLen; i++) { int ino_optB = toOptNodesB[i]; for (int j = 0; j < matLen; j++) { int jno_optB = toOptNodesB[j]; optPatternB[ino_optB, jno_optB] = patternB[i, j]; optB[ino_optB + matLen * jno_optB] = B[i + matLen * j]; } } } // [A]は[B]の節点並び替えに合わせて変更する { optNodesA = optNodesB; toOptNodesA = toOptNodesB; for (int i = 0; i < matLen; i++) { int ino_optA = toOptNodesA[i]; for (int j = 0; j < matLen; j++) { int jno_optA = toOptNodesA[j]; optPatternA[ino_optA, jno_optA] = patternA[i, j]; optA[ino_optA + matLen * jno_optA] = A[i + matLen * j]; } } } patternA = null; patternB = null; A = null; B = null; // バンド行列のサイズ取得 int a_rowcolSize; int a_subdiaSize; int a_superdiaSize; GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternA, out a_rowcolSize, out a_subdiaSize, out a_superdiaSize); int b_rowcolSize; int b_subdiaSize; int b_superdiaSize; GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternB, out b_rowcolSize, out b_subdiaSize, out b_superdiaSize); // バンド行列作成 int _a_rsize = a_superdiaSize + 1; int _a_csize = a_rowcolSize; int _b_rsize = b_superdiaSize + 1; int _b_csize = b_rowcolSize; KrdLab.clapack.Complex[] AB = new KrdLab.clapack.Complex[_a_rsize * _a_csize]; KrdLab.clapack.Complex[] BB = new KrdLab.clapack.Complex[_b_rsize * _b_csize]; // [A]の値を[AB]にコピーする for (int c = 0; c < a_rowcolSize; c++) { // 対角成分 AB[a_superdiaSize + c * _a_rsize] = optA[c + c * a_rowcolSize]; // superdiagonals成分 if (c > 0) { for (int r = c - 1; r >= c - a_superdiaSize && r >= 0; r--) { AB[(r - c) + a_superdiaSize + c * _a_rsize] = optA[r + c * a_rowcolSize]; } } } // [B]の値を[BB]にコピーする for (int c = 0; c < b_rowcolSize; c++) { // 対角成分 BB[b_superdiaSize + c * _b_rsize] = optB[c + c * b_rowcolSize]; // superdiagonals成分 if (c > 0) { for (int r = c - 1; r >= c - b_superdiaSize && r >= 0; r--) { BB[(r - c) + b_superdiaSize + c * _b_rsize] = optB[r + c * b_rowcolSize]; } } } optA = null; optB = null; double[] ret_evals = null; KrdLab.clapack.Complex[][] ret_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zhbgv"); KrdLab.clapack.FunctionExt.zhbgv(AB, matLen, matLen, a_superdiaSize, BB, matLen, matLen, b_superdiaSize, ref ret_evals, ref ret_evecs); // エルミート行列の固有値は実数なので複素数配列への移し替えを行う evals = new KrdLab.clapack.Complex[ret_evals.Length]; for (int i = 0; i < ret_evals.Length; i++) { evals[i].Real = ret_evals[i]; evals[i].Imaginary = 0; } System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen]; for (int i = 0; i < ret_evecs.Length; i++) { KrdLab.clapack.Complex[] ret_evec = ret_evecs[i]; for (int j = 0; j < ret_evec.Length; j++) { // バンド幅縮小で並び替えた節点→元の節点番号変換 int jnoGlobal = optNodesB[j]; evecs[i, jnoGlobal] = ret_evec[j]; } } }
public static KrdLab.clapack.Complex[] matrix_ToBuffer(Complex[,] mat) { KrdLab.clapack.Complex[] mat_ = new KrdLab.clapack.Complex[mat.GetLength(0) * mat.GetLength(1)]; // rowから先に埋めていく for (int j = 0; j < mat.GetLength(1); j++) //col { for (int i = 0; i < mat.GetLength(0); i++) // row { //mat_[j * mat.GetLength(0) + i] = new KrdLab.clapack.Complex(mat[i, j].Real, mat[i,j].Imag); mat_[j * mat.GetLength(0) + i].Real = mat[i, j].Real; mat_[j * mat.GetLength(0) + i].Imaginary = mat[i,j].Imag; } } return mat_; }
// {x} = [A]{v} public static KrdLab.clapack.Complex[] product(double[] matA, int a_row, int a_col, KrdLab.clapack.Complex[] vec, int vec_row) { System.Diagnostics.Debug.Assert(a_col == vec_row); KrdLab.clapack.Complex[] retVec = new KrdLab.clapack.Complex[a_row]; for (int i = 0; i < a_row; i++) { retVec[i] = new KrdLab.clapack.Complex(0.0, 0.0); for (int k = 0; k < a_col; k++) { retVec[i] += matA[i + k * a_row] * vec[k]; } } return retVec; }
/// <summary> /// /// </summary> /// <param name="probNo"></param> /// <param name="periodicDistanceX"></param> /// <param name="periodicDistanceY"></param> /// <param name="betaX"></param> /// <param name="betaY"></param> /// <param name="coord_c_all"></param> /// <param name="sharedNodes"></param> /// <param name="sharedNodeCoords"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="boundary_node_cnt_each"></param> /// <param name="boundary_node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="free_node_cnt0"></param> /// <param name="KMat0"></param> /// <param name="MMat0"></param> /// <param name="expA1"></param> /// <param name="expA2"></param> /// <param name="expA3"></param> /// <param name="KMat"></param> /// <param name="MMat"></param> private static void getSortedMatrix_Hex( int probNo, double periodicDistanceX, double periodicDistanceY, KrdLab.clapack.Complex betaX, KrdLab.clapack.Complex betaY, double[][] coord_c_all, uint[] sharedNodes, double[][] sharedNodeCoords, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, uint boundary_node_cnt_each, uint boundary_node_cnt, uint free_node_cnt, uint free_node_cnt0, KrdLab.clapack.Complex[] KMat0, KrdLab.clapack.Complex[] MMat0, out KrdLab.clapack.Complex expA1, out KrdLab.clapack.Complex expA2, out KrdLab.clapack.Complex expA3, out KrdLab.clapack.Complex[] KMat, out KrdLab.clapack.Complex[] MMat ) { KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; expA1 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5) * KrdLab.clapack.Complex.Exp(1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY * 0.75); expA2 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX); expA3 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5) * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY * 0.75); /* // check { // 境界4→境界1 for (int j = 0; j < (boundary_node_cnt_each - 1); j++) { int j_B1 = j; uint nodeNumber_B1 = sortedNodes[j_B1]; System.Diagnostics.Debug.WriteLine("B1 {0} {1} {2} {3}", j_B1, nodeNumber_B1, coord_c_all[nodeNumber_B1][0], coord_c_all[nodeNumber_B1][1]); int j_B4 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1)); uint nodeNumber_B4 = sortedNodes[j_B4]; System.Diagnostics.Debug.WriteLine("B4 {0} {1} {2} {3}", j_B4, nodeNumber_B4, coord_c_all[nodeNumber_B4][0], coord_c_all[nodeNumber_B4][1]); } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { int j_B2 = (int)(j + boundary_node_cnt_each); uint nodeNumber_B2 = sortedNodes[j_B2]; System.Diagnostics.Debug.WriteLine("B2 {0} {1} {2} {3}", j_B2, nodeNumber_B2, coord_c_all[nodeNumber_B2][0], coord_c_all[nodeNumber_B2][1]); int j_B5 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j); uint nodeNumber_B5 = sortedNodes[j_B5]; System.Diagnostics.Debug.WriteLine("B5 {0} {1} {2} {3}", j_B5, nodeNumber_B5, coord_c_all[nodeNumber_B5][0], coord_c_all[nodeNumber_B5][1]); } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { int j_B3 = (int)(j + boundary_node_cnt_each + (boundary_node_cnt_each - 2)); uint nodeNumber_B3 = sortedNodes[j_B3]; System.Diagnostics.Debug.WriteLine("B3 {0} {1} {2} {3}", j_B3, nodeNumber_B3, coord_c_all[nodeNumber_B3][0], coord_c_all[nodeNumber_B3][1]); int j_B6 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j); uint nodeNumber_B6 = sortedNodes[j_B6]; System.Diagnostics.Debug.WriteLine("B6 {0} {1} {2} {3}", j_B6, nodeNumber_B6, coord_c_all[nodeNumber_B6][0], coord_c_all[nodeNumber_B6][1]); } { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; uint nodeNumber_shared0 = sortedNodes[j0]; uint nodeNumber_shared4 = sortedNodes[j4]; uint nodeNumber_shared2 = sortedNodes[j2]; System.Diagnostics.Debug.WriteLine("shared0 {0} {1} {2} {3}", j0, nodeNumber_shared0, coord_c_all[nodeNumber_shared0][0], coord_c_all[nodeNumber_shared0][1]); System.Diagnostics.Debug.WriteLine("shared4 {0} {1} {2} {3}", j4, nodeNumber_shared4, coord_c_all[nodeNumber_shared4][0], coord_c_all[nodeNumber_shared4][1]); System.Diagnostics.Debug.WriteLine("shared2 {0} {1} {2} {3}", j2, nodeNumber_shared2, coord_c_all[nodeNumber_shared2][0], coord_c_all[nodeNumber_shared2][1]); } { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; uint nodeNumber_shared1 = sortedNodes[j1]; uint nodeNumber_shared3 = sortedNodes[j3]; uint nodeNumber_shared5 = sortedNodes[j5]; System.Diagnostics.Debug.WriteLine("shared1 {0} {1} {2} {3}", j1, nodeNumber_shared1, coord_c_all[nodeNumber_shared1][0], coord_c_all[nodeNumber_shared1][1]); System.Diagnostics.Debug.WriteLine("shared3 {0} {1} {2} {3}", j3, nodeNumber_shared3, coord_c_all[nodeNumber_shared3][0], coord_c_all[nodeNumber_shared3][1]); System.Diagnostics.Debug.WriteLine("shared5 {0} {1} {2} {3}", j5, nodeNumber_shared5, coord_c_all[nodeNumber_shared5][0], coord_c_all[nodeNumber_shared5][1]); } } */ ///////////////////////////////////////////////////////////////// // 境界1+2 + 3+内部 for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j]; } } ///////////////////////////////////////////////////////////////// // 境界1+2+3+内部 for (int i = 0; i < free_node_cnt; i++) { // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i + free_node_cnt * j] += expA1 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i + free_node_cnt * j] += expA1 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_each)] += expA2 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_each)] += expA2 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += expA3 * KMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += expA3 * MMat0[i + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; KMat[i + free_node_cnt * j0] += expA1 * KMat0[i + free_node_cnt0 * j4] + (1.0 / expA3) * KMat0[i + free_node_cnt0 * j2]; MMat[i + free_node_cnt * j0] += expA1 * MMat0[i + free_node_cnt0 * j4] + (1.0 / expA3) * MMat0[i + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; KMat[i + free_node_cnt * j1] += expA1 * KMat0[i + free_node_cnt0 * j3] + expA2 * KMat0[i + free_node_cnt0 * j5]; MMat[i + free_node_cnt * j1] += expA1 * MMat0[i + free_node_cnt0 * j3] + expA2 * MMat0[i + free_node_cnt0 * j5]; } } ///////////////////////////////////////////////////////////////// // 境界4 for (int i = 1; i < (boundary_node_cnt_each - 1); i++) { int i_B1 = i; // 境界1 int i_B4 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (i - 1)); // 境界4 // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i_B1 + free_node_cnt * j] += (1.0 / expA1) * KMat0[i_B4 + free_node_cnt0 * j]; MMat[i_B1 + free_node_cnt * j] += (1.0 / expA1) * MMat0[i_B4 + free_node_cnt0 * j]; } // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i_B1 + free_node_cnt * j] += KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i_B1 + free_node_cnt * j] += MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * KMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i_B1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * MMat0[i_B4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; KMat[i_B1 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * KMat0[i_B4 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * KMat0[i_B4 + free_node_cnt0 * j2]; MMat[i_B1 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * MMat0[i_B4 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * MMat0[i_B4 + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; KMat[i_B1 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * KMat0[i_B4 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * KMat0[i_B4 + free_node_cnt0 * j5]; MMat[i_B1 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * MMat0[i_B4 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * MMat0[i_B4 + free_node_cnt0 * j5]; } } ///////////////////////////////////////////////////////////////// // 境界5 for (int i = 0; i < (boundary_node_cnt_each - 2); i++) { int i_B2 = (int)(i + boundary_node_cnt_each); // 境界2 int i_B5 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - i); // 境界5 // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * KMat0[i_B5 + free_node_cnt0 * j]; MMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * MMat0[i_B5 + free_node_cnt0 * j]; } // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i_B2 + free_node_cnt * j] += (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each)] += KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each)] += MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA2) * expA3 * KMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i_B2 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA2) * expA3 * MMat0[i_B5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; KMat[i_B2 + free_node_cnt * j0] += (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * j4] + (1.0 / expA2) * (1.0 / expA3) * KMat0[i_B5 + free_node_cnt0 * j2]; MMat[i_B2 + free_node_cnt * j0] += (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * j4] + (1.0 / expA2) * (1.0 / expA3) * MMat0[i_B5 + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; KMat[i_B2 + free_node_cnt * j1] += (1.0 / expA2) * expA1 * KMat0[i_B5 + free_node_cnt0 * j3] + (1.0 / expA2) * expA2 * KMat0[i_B5 + free_node_cnt0 * j5]; MMat[i_B2 + free_node_cnt * j1] += (1.0 / expA2) * expA1 * MMat0[i_B5 + free_node_cnt0 * j3] + (1.0 / expA2) * expA2 * MMat0[i_B5 + free_node_cnt0 * j5]; } } ///////////////////////////////////////////////////////////////// // 境界6 for (int i = 0; i < (boundary_node_cnt_each - 2); i++) { int i_B3 = (int)(i + boundary_node_cnt_each + (boundary_node_cnt_each - 2)); // 境界3 int i_B6 = (int)(free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - i); // 境界6 // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * KMat0[i_B6 + free_node_cnt0 * j]; MMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * MMat0[i_B6 + free_node_cnt0 * j]; } // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i_B3 + free_node_cnt * j] += (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA3) * expA2 * KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA3) * expA2 * MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += KMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i_B3 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += MMat0[i_B6 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; KMat[i_B3 + free_node_cnt * j0] += (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * j4] + (1.0 / expA3) * (1.0 / expA3) * KMat0[i_B6 + free_node_cnt0 * j2]; MMat[i_B3 + free_node_cnt * j0] += (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * j4] + (1.0 / expA3) * (1.0 / expA3) * MMat0[i_B6 + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; KMat[i_B3 + free_node_cnt * j1] += (1.0 / expA3) * expA1 * KMat0[i_B6 + free_node_cnt0 * j3] + (1.0 / expA3) * expA2 * KMat0[i_B6 + free_node_cnt0 * j5]; MMat[i_B3 + free_node_cnt * j1] += (1.0 / expA3) * expA1 * MMat0[i_B6 + free_node_cnt0 * j3] + (1.0 / expA3) * expA2 * MMat0[i_B6 + free_node_cnt0 * j5]; } } ///////////////////////////////////////////////////////////////// // 頂点4→0, 頂点2→0 { int i0 = toSorted[sharedNodes[0]]; int i4 = toSorted[sharedNodes[4]]; int i2 = toSorted[sharedNodes[2]]; // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i0 + free_node_cnt * j] += (1.0 / expA1) * KMat0[i4 + free_node_cnt0 * j] + expA3 * KMat0[i2 + free_node_cnt0 * j]; MMat[i0 + free_node_cnt * j] += (1.0 / expA1) * MMat0[i4 + free_node_cnt0 * j] + expA3 * MMat0[i2 + free_node_cnt0 * j]; } // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i0 + free_node_cnt * j] += (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))] + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i0 + free_node_cnt * j] += (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))] + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i0 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)] + expA3 * expA2 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i0 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)] + expA3 * expA2 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i0 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * KMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)] + expA3 * expA3 * KMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i0 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * MMat0[i4 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)] + expA3 * expA3 * MMat0[i2 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = i0; int j4 = i4; int j2 = i2; KMat[i0 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * KMat0[i4 + free_node_cnt0 * j2] + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * j4] + expA3 * (1.0 / expA3) * KMat0[i2 + free_node_cnt0 * j2]; MMat[i0 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * MMat0[i4 + free_node_cnt0 * j2] + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * j4] + expA3 * (1.0 / expA3) * MMat0[i2 + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = toSorted[sharedNodes[1]]; int j3 = toSorted[sharedNodes[3]]; int j5 = toSorted[sharedNodes[5]]; KMat[i0 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * KMat0[i4 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * KMat0[i4 + free_node_cnt0 * j5] + expA3 * expA1 * KMat0[i2 + free_node_cnt0 * j3] + expA3 * expA2 * KMat0[i2 + free_node_cnt0 * j5]; MMat[i0 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * MMat0[i4 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * MMat0[i4 + free_node_cnt0 * j5] + expA3 * expA1 * MMat0[i2 + free_node_cnt0 * j3] + expA3 * expA2 * MMat0[i2 + free_node_cnt0 * j5]; } } ///////////////////////////////////////////////////////////////// // 頂点3→1, 頂点5→1 { int i1 = toSorted[sharedNodes[1]]; int i3 = toSorted[sharedNodes[3]]; int i5 = toSorted[sharedNodes[5]]; // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i1 + free_node_cnt * j] += (1.0 / expA1) * KMat0[i3 + free_node_cnt0 * j] + (1.0 / expA2) * KMat0[i5 + free_node_cnt0 * j]; MMat[i1 + free_node_cnt * j] += (1.0 / expA1) * MMat0[i3 + free_node_cnt0 * j] + (1.0 / expA2) * MMat0[i5 + free_node_cnt0 * j]; } // 境界4→境界1 for (int j = 1; j < (boundary_node_cnt_each - 1); j++) { KMat[i1 + free_node_cnt * j] += (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))] + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; MMat[i1 + free_node_cnt * j] += (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))] + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) - 1 - (j - 1))]; } // 境界5→境界2 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i1 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)] + (1.0 / expA2) * expA2 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; MMat[i1 + free_node_cnt * (j + boundary_node_cnt_each)] += (1.0 / expA1) * expA2 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)] + (1.0 / expA2) * expA2 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 2 - 1 - j)]; } // 境界6→境界3 for (int j = 0; j < (boundary_node_cnt_each - 2); j++) { KMat[i1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * KMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)] + (1.0 / expA2) * expA3 * KMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; MMat[i1 + free_node_cnt * (j + boundary_node_cnt_each + (boundary_node_cnt_each - 2))] += (1.0 / expA1) * expA3 * MMat0[i3 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)] + (1.0 / expA2) * expA3 * MMat0[i5 + free_node_cnt0 * (free_node_cnt + (boundary_node_cnt_each - 2) * 3 - 1 - j)]; } // 頂点4→0, 頂点2→0 { int j0 = toSorted[sharedNodes[0]]; int j4 = toSorted[sharedNodes[4]]; int j2 = toSorted[sharedNodes[2]]; KMat[i1 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * KMat0[i3 + free_node_cnt0 * j2] + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * j4] + (1.0 / expA2) * (1.0 / expA3) * KMat0[i5 + free_node_cnt0 * j2]; MMat[i1 + free_node_cnt * j0] += (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * j4] + (1.0 / expA1) * (1.0 / expA3) * MMat0[i3 + free_node_cnt0 * j2] + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * j4] + (1.0 / expA2) * (1.0 / expA3) * MMat0[i5 + free_node_cnt0 * j2]; } // 頂点3→1, 頂点5→1 { int j1 = i1; int j3 = i3; int j5 = i5; KMat[i1 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * KMat0[i3 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * KMat0[i3 + free_node_cnt0 * j5] + (1.0 / expA2) * expA1 * KMat0[i5 + free_node_cnt0 * j3] + (1.0 / expA2) * expA2 * KMat0[i5 + free_node_cnt0 * j5]; MMat[i1 + free_node_cnt * j1] += (1.0 / expA1) * expA1 * MMat0[i3 + free_node_cnt0 * j3] + (1.0 / expA1) * expA2 * MMat0[i3 + free_node_cnt0 * j5] + (1.0 / expA2) * expA1 * MMat0[i5 + free_node_cnt0 * j3] + (1.0 / expA2) * expA2 * MMat0[i5 + free_node_cnt0 * j5]; } } }
public static Complex[,] matrix_Inverse(Complex[,] matA) { System.Diagnostics.Debug.Assert(matA.GetLength(0) == matA.GetLength(1)); int n = matA.GetLength(0); KrdLab.clapack.Complex[] matA_ = matrix_ToBuffer(matA); KrdLab.clapack.Complex[] matB_ = new KrdLab.clapack.Complex[n * n]; // 単位行列 for (int i = 0; i < matB_.Length; i++) { matB_[i] = (KrdLab.clapack.Complex)0.0; } for (int i = 0; i < n; i++) { matB_[i * n + i] = (KrdLab.clapack.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); Complex[,] matX = matrix_FromBuffer(matB_, x_row, x_col); return matX; }
/// <summary> /// 周期構造導波路の固有モード取得 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="isYDirectionPeriodic">Y方向周期構造?</param> /// <param name="World">ワールド座標系</param> /// <param name="FieldLoopId">フィールド値ID(周期構造領域のループ)</param> /// <param name="FieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param> /// <param name="FieldPortBcId2">フィールド値ID(周期構造領域の境界2=内部側境界)</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="IsPCWaveguide">フォトニック結晶導波路?</param> /// <param name="PCWaveguidePorts">フォトニック結晶導波路のポート(ロッド欠陥部分)の節点のリスト</param> /// <param name="propModeCntToSolve">解く伝搬モードの数(固有値解法の選択基準に用いる)</param> /// <param name="max_mode">固有モードの考慮数</param> /// <param name="Medias">媒質リスト</param> /// <param name="LoopDic">周期構造領域のワールド座標系ループ→ループ情報マップ</param> /// <param name="EdgeDic">周期構造領域のワールド座標系辺→辺情報マップ</param> /// <param name="isPortBc2Reverse">境界2の方向が境界1と逆方向?</param> /// <param name="ryy_1d">[ryy]FEM行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs_Bc1">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs_Bc1">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> private static bool solvePortPeriodicWaveguideEigen( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, bool isYDirectionPeriodic, double rotAngle, double[] rotOrigin, CFieldWorld World, uint FieldLoopId, uint FieldPortBcId1, uint FieldPortBcId2, uint[] fixedBcNodes, bool IsPCWaveguide, double latticeA, double periodicDistance, IList<IList<uint>> PCWaveguidePorts, int incidentModeIndex, bool isSolveEigenItr, int propModeCntToSolve, bool isSVEA, uint max_mode, bool isModeTrace, ref KrdLab.clapack.Complex[][] PrevModalVecList, double minEffN, double maxEffN, double minWaveNum, double maxWaveNum, IList<MediaInfo> Medias, Dictionary<uint, wg2d.World.Loop> LoopDic, Dictionary<uint, wg2d.World.Edge> EdgeDic, bool isPortBc2Reverse, double[,] ryy_1d, out Complex[] eigen_values, out Complex[,] eigen_vecs_Bc1, out Complex[,] eigen_dFdXs_Bc1) { double k0 = 2.0 * pi / waveLength; double omega = k0 * c0; eigen_values = null; eigen_vecs_Bc1 = null; eigen_dFdXs_Bc1 = null; //System.Diagnostics.Debug.Assert(max_mode == 1); double minBeta = minEffN; double maxBeta = maxEffN; ////////////////////////////////////////////////////////////////////////////////////// // 周期構造導波路の固有値解析 // 全節点数を取得する uint node_cnt = 0; //node_cnt = WgUtilForPeriodicEigen.GetNodeCnt(world, fieldLoopId); //uint[] no_c_all = null; //Dictionary<uint, uint> to_no_all = new Dictionary<uint, uint>(); //WgUtilForPeriodicEigen.GetNodeList(World, FieldLoopId, out no_c_all); //node_cnt = (uint)no_c_all.Length; //for (int i = 0; i < node_cnt; i++) //{ // uint nodeNumber = no_c_all[i]; // to_no_all.Add(nodeNumber, (uint)i); //} uint[] no_c_all = null; Dictionary<uint, uint> to_no_all = null; double[][] coord_c_all = null; WgUtil.GetLoopCoordList(World, FieldLoopId, rotAngle, rotOrigin, out no_c_all, out to_no_all, out coord_c_all); node_cnt = (uint)no_c_all.Length; System.Diagnostics.Debug.WriteLine("solvePortPeriodicWaveguideEigen node_cnt: {0}", node_cnt); // 境界の節点リストを取得する uint[] no_boundary_fieldForceBcId = null; Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null; if (fixedBcNodes != null) { to_no_boundary_fieldForceBcId = new Dictionary<uint, uint>(); IList<uint> fixedBcNodesInLoop = new List<uint>(); foreach (uint nodeNumber in fixedBcNodes) { if (to_no_all.ContainsKey(nodeNumber)) { fixedBcNodesInLoop.Add(nodeNumber); to_no_boundary_fieldForceBcId.Add(nodeNumber, (uint)(fixedBcNodesInLoop.Count - 1)); } } no_boundary_fieldForceBcId = fixedBcNodesInLoop.ToArray(); } uint[] no_c_all_fieldPortBcId1 = null; Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = null; WgUtil.GetBoundaryNodeList(World, FieldPortBcId1, out no_c_all_fieldPortBcId1, out to_no_boundary_fieldPortBcId1); uint[] no_c_all_fieldPortBcId2 = null; Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = null; WgUtil.GetBoundaryNodeList(World, FieldPortBcId2, out no_c_all_fieldPortBcId2, out to_no_boundary_fieldPortBcId2); // 節点のソート IList<uint> sortedNodes = new List<uint>(); Dictionary<uint, int> toSorted = new Dictionary<uint, int>(); // 境界1と境界2は周期構造条件より同じ界の値をとる // ポート境界1 for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++) { // 境界1の節点を追加 uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i]; if (fixedBcNodes != null) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc1)) continue; } sortedNodes.Add(nodeNumberPortBc1); int nodeIndex = sortedNodes.Count - 1; toSorted.Add(nodeNumberPortBc1, nodeIndex); } uint boundary_node_cnt = (uint)sortedNodes.Count; // 境界1 // 内部領域 for (int i = 0; i < node_cnt; i++) { uint nodeNumber = no_c_all[i]; // 追加済み節点はスキップ //if (toSorted.ContainsKey(nodeNumber)) continue; // 境界1は除く if (to_no_boundary_fieldPortBcId1.ContainsKey(nodeNumber)) continue; // 境界2は除く if (to_no_boundary_fieldPortBcId2.ContainsKey(nodeNumber)) continue; if (fixedBcNodes != null) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumber)) continue; } sortedNodes.Add(nodeNumber); toSorted.Add(nodeNumber, sortedNodes.Count - 1); } uint free_node_cnt = (uint)sortedNodes.Count; // 境界1 + 内部領域 for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++) { // 境界2の節点を追加 uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i]; if (fixedBcNodes != null) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc2)) continue; } sortedNodes.Add(nodeNumberPortBc2); int nodeIndex = sortedNodes.Count - 1; toSorted.Add(nodeNumberPortBc2, nodeIndex); } uint free_node_cnt0 = (uint)sortedNodes.Count; // 境界1 + 内部領域 + 境界2 // 剛性行列、質量行列を作成 double[] KMat0 = null; double[] CMat0 = null; double[] MMat0 = null; WgUtilForPeriodicEigen.MkPeriodicHelmholtzMat( waveLength, isYDirectionPeriodic, rotAngle, rotOrigin, World, FieldLoopId, Medias, LoopDic, node_cnt, free_node_cnt0, toSorted, out KMat0, out CMat0, out MMat0); // 緩慢変化包絡線近似? //bool isSVEA = true; // 緩慢変化包絡線近似 Φ = φ(x, y) exp(-jβx) と置く方法 //bool isSVEA = false; // Φを直接解く方法(exp(-jβd)を固有値として扱う) System.Diagnostics.Debug.WriteLine("isSVEA: {0}", isSVEA); System.Diagnostics.Debug.WriteLine("isModeTrace: {0}, isSolveEigenItr: {1}, propModeCntToSolve: {2}", isModeTrace, isSolveEigenItr, propModeCntToSolve); // 逆行列を使う? //bool isUseInvMat = false; // 逆行列を使用しない bool isUseInvMat = true; // 逆行列を使用する System.Diagnostics.Debug.WriteLine("isUseInvMat: {0}", isUseInvMat); /* // 反復計算のときはモード追跡をOFFにする(うまくいかないときがあるので) if (isSolveEigenItr && isModeTrace) { isModeTrace = false; System.Diagnostics.Debug.WriteLine("isModeTrace force to false.(isSolveEigenItr == true)"); } */ // 境界2の節点は境界1の節点と同一とみなす // 境界上の分割が同じであることが前提条件 double[] KMat = null; double[] CMat = null; double[] MMat = null; if (isSVEA) { KMat = new double[free_node_cnt * free_node_cnt]; CMat = new double[free_node_cnt * free_node_cnt]; MMat = new double[free_node_cnt * free_node_cnt]; for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; CMat[i + free_node_cnt * j] = CMat0[i + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j]; } } for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); KMat[i + free_node_cnt * j] += KMat0[i + free_node_cnt0 * jno_B2]; CMat[i + free_node_cnt * j] += CMat0[i + free_node_cnt0 * jno_B2]; MMat[i + free_node_cnt * j] += MMat0[i + free_node_cnt0 * jno_B2]; } } for (int i = 0; i < boundary_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i); KMat[i + free_node_cnt * j] += KMat0[ino_B2 + free_node_cnt0 * j]; CMat[i + free_node_cnt * j] += CMat0[ino_B2 + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] += MMat0[ino_B2 + free_node_cnt0 * j]; } for (int j = 0; j < boundary_node_cnt; j++) { int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i); int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); KMat[i + free_node_cnt * j] += KMat0[ino_B2 + free_node_cnt0 * jno_B2]; CMat[i + free_node_cnt * j] += CMat0[ino_B2 + free_node_cnt0 * jno_B2]; MMat[i + free_node_cnt * j] += MMat0[ino_B2 + free_node_cnt0 * jno_B2]; } } // 行列要素check { for (int i = 0; i < free_node_cnt; i++) { for (int j = i; j < free_node_cnt; j++) { // [K]は対称行列 System.Diagnostics.Debug.Assert(Math.Abs(KMat[i + free_node_cnt * j] - KMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit); // [M]は対称行列 System.Diagnostics.Debug.Assert(Math.Abs(MMat[i + free_node_cnt * j] - MMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit); // [C]は反対称行列 System.Diagnostics.Debug.Assert(Math.Abs((-CMat[i + free_node_cnt * j]) - CMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit); } } } } else { if (!isUseInvMat) { KMat = new double[free_node_cnt * free_node_cnt]; CMat = new double[free_node_cnt * free_node_cnt]; MMat = new double[free_node_cnt * free_node_cnt]; CMat0 = null; MMat0 = null; uint inner_node_cnt = free_node_cnt - boundary_node_cnt; for (int i = 0; i < boundary_node_cnt; i++) { int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i); for (int j = 0; j < boundary_node_cnt; j++) { int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); // [K21] KMat[i + free_node_cnt * j] = KMat0[ino_B2 + free_node_cnt0 * j]; // [K11] + [K22] CMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j] + KMat0[ino_B2 + free_node_cnt0 * jno_B2]; // [K12] MMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * jno_B2]; } for (int j = 0; j < inner_node_cnt; j++) { // [K20] KMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[ino_B2 + free_node_cnt0 * (j + boundary_node_cnt)]; // [K10] CMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[i + free_node_cnt0 * (j + boundary_node_cnt)]; // [0] MMat[i + free_node_cnt * (j + boundary_node_cnt)] = 0.0; } } for (int i = 0; i < inner_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); // [0] KMat[(i + boundary_node_cnt) + free_node_cnt * j] = 0.0; // [K01] CMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * j]; // [K02] MMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * jno_B2]; } for (int j = 0; j < inner_node_cnt; j++) { // [0] KMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0; // [K00] CMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * (j + boundary_node_cnt)]; // [0] MMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0; } } } else { KMat = null; CMat = null; MMat = null; } } // 伝搬定数 KrdLab.clapack.Complex[] betamToSolveList = null; // 界ベクトルは全節点分作成 KrdLab.clapack.Complex[][] resVecList = null; // PC導波路の場合は、波数が[0, π]の領域から探索する if (IsPCWaveguide) { //minBeta = 0.0; //maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0; //minBeta = minWaveNum * (2.0 * pi / periodicDistance) / k0; //maxBeta = maxWaveNum * (2.0 * pi / periodicDistance) / k0; double minBeta_BZ = minWaveNum * (2.0 * pi / periodicDistance) / k0; double maxBeta_BZ = maxWaveNum * (2.0 * pi / periodicDistance) / k0; if (minBeta_BZ > minBeta) { minBeta = minBeta_BZ; } if (maxBeta_BZ < maxBeta) { maxBeta = maxBeta_BZ; } System.Diagnostics.Debug.WriteLine("minWaveNum:{0}, maxWaveNum: {1}", minWaveNum, maxWaveNum); System.Diagnostics.Debug.WriteLine("minBeta: {0}, maxBeta: {1}", minBeta, maxBeta); } // 緩慢変化包絡線近似でない場合は反復計算しない方法を使用する if (!isSolveEigenItr || propModeCntToSolve >= 3 || !isSVEA) { KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null; if (isModeTrace && PrevModalVecList != null) { // 前回の固有モードベクトルを取得する // 現状1つだけ if (PrevModalVecList.Length >= 0) { tmpPrevModalVec_1stMode = PrevModalVecList[0]; } } /* // マルチモードの場合 // 周期構造導波路固有値問題を2次一般化固有値問題として解く solveAsQuadraticGeneralizedEigen( k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, isModeTrace, ref PrevModalVec, IsPCWaveguide, PCWaveguidePorts, out betamToSolveList, out resVecList); */ if (!isUseInvMat) { // マルチモードの場合 // 周期構造導波路固有値問題を2次一般化固有値問題として解く(実行列として解く) solveAsQuadraticGeneralizedEigenWithRealMat( incidentModeIndex, isSVEA, periodicDistance, k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, isYDirectionPeriodic, coord_c_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, (2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } else { // 逆行列を使用する方法 if (isSVEA) { // マルチモードの場合 // 周期構造導波路固有値問題を2次一般化固有値問題→標準固有値問題として解く(実行列として解く)(緩慢変化包絡線近似用) System.Diagnostics.Debug.Assert(isSVEA == true); solveAsQuadraticGeneralizedEigenToStandardWithRealMat( incidentModeIndex, k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, IsPCWaveguide, PCWaveguidePorts, 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, node_cnt, free_node_cnt0, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, isYDirectionPeriodic, coord_c_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, (2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } } if (isModeTrace && tmpPrevModalVec_1stMode != null) { PrevModalVecList = new KrdLab.clapack.Complex[1][]; PrevModalVecList[0] = tmpPrevModalVec_1stMode; } } else if (isSolveEigenItr && propModeCntToSolve == 2) { // 2次の固有値問題として解くより、シングルモードのルーチンで // 基本モードと高次モードを計算した方が速い // 基本モード // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null; KrdLab.clapack.Complex[] tmpPrevModalVec_2ndMode = null; if (isModeTrace && PrevModalVecList != null) { // 前回の固有モードベクトルを後ろから順に取得する if (PrevModalVecList.Length >= 1) { tmpPrevModalVec_1stMode = PrevModalVecList[PrevModalVecList.Length - 1]; } if (PrevModalVecList.Length >= 2) { tmpPrevModalVec_2ndMode = PrevModalVecList[PrevModalVecList.Length - 2]; } } System.Diagnostics.Debug.Assert(isSVEA == true); solveItrAsLinearGeneralizedEigen( k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, IsPCWaveguide, PCWaveguidePorts, false, // isCalcSecondMode: false isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, out betamToSolveList, out resVecList); if (isModeTrace && tmpPrevModalVec_1stMode != null) { PrevModalVecList = new KrdLab.clapack.Complex[1][]; PrevModalVecList[0] = tmpPrevModalVec_1stMode; } if (betamToSolveList != null) { // 基本モードの解を退避 KrdLab.clapack.Complex[] betamToSolveList_1stMode = betamToSolveList; KrdLab.clapack.Complex[][] resVecList_1stMode = resVecList; // 高次モード KrdLab.clapack.Complex[] betamToSolveList_2ndMode = null; KrdLab.clapack.Complex[][] resVecList_2ndMode = null; // 高次モードを反復計算で解く // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く System.Diagnostics.Debug.Assert(isSVEA == true); solveItrAsLinearGeneralizedEigen( k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, IsPCWaveguide, PCWaveguidePorts, true, // isCalcSecondMode: true isModeTrace, ref tmpPrevModalVec_2ndMode, minBeta, maxBeta, out betamToSolveList_2ndMode, out resVecList_2ndMode); if (betamToSolveList_2ndMode != null) { // betamToSolveListは伝搬定数の実部の昇順で並べる // したがって、基本モードは最後に格納 betamToSolveList = new KrdLab.clapack.Complex[2]; resVecList = new KrdLab.clapack.Complex[2][]; // 2nd mode betamToSolveList[0] = betamToSolveList_2ndMode[0]; resVecList[0] = resVecList_2ndMode[0]; // 1st mode betamToSolveList[1] = betamToSolveList_1stMode[0]; resVecList[1] = resVecList_1stMode[0]; if (isModeTrace) { PrevModalVecList = new KrdLab.clapack.Complex[2][]; // 2nd mode PrevModalVecList[0] = tmpPrevModalVec_2ndMode; // 1st mode PrevModalVecList[1] = tmpPrevModalVec_1stMode; } } } } else if (isSolveEigenItr && propModeCntToSolve == 1) { KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null; if (isModeTrace && PrevModalVecList != null) { // 前回の固有モードベクトルを後ろから順に取得する if (PrevModalVecList.Length >= 1) { tmpPrevModalVec_1stMode = PrevModalVecList[PrevModalVecList.Length - 1]; } } // シングルモードの場合 // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く System.Diagnostics.Debug.Assert(isSVEA == true); solveItrAsLinearGeneralizedEigen( k0, KMat, CMat, MMat, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, to_no_boundary_fieldPortBcId1, IsPCWaveguide, PCWaveguidePorts, false, // isCalcSecondMode: false isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, out betamToSolveList, out resVecList); if (isModeTrace && tmpPrevModalVec_1stMode != null) { PrevModalVecList = new KrdLab.clapack.Complex[1][]; PrevModalVecList[0] = tmpPrevModalVec_1stMode; } } else { System.Diagnostics.Debug.Assert(false); return false; } // 固有値が1つでも取得できているかチェック if (betamToSolveList == null) { return false; } 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 < no_c_all_fieldPortBcId1.Length; ino++) { // 境界1の節点 uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino]; uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1]; // 境界1の節点の界の値を取得 KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(no_c_all_fieldPortBcId2.Length - 1 - ino) : (int)ino; uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[ino_B2]; uint ino_InLoop_PortBc2 = to_no_all[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 < no_c_all_fieldPortBcId1.Length; ino++) { uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino]; uint ino_InLoop_PortBc1 = to_no_all[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; getDFDXValues(World, FieldLoopId, to_no_all, Medias, LoopDic, rotAngle, rotOrigin, resVec, out resDFDXVec, out resDFDYVec); 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 < no_c_all_fieldPortBcId1.Length; ino++) { // 境界1の節点 uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino]; uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1]; // 境界1の節点の界の微分値値を取得 KrdLab.clapack.Complex cdFdXValue1 = resDFDXVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(no_c_all_fieldPortBcId2.Length - 1 - ino) : (int)ino; uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[ino_B2]; uint ino_InLoop_PortBc2 = to_no_all[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 == coord_c_all.Length); uint nodeNumber1st = sortedNodes[0]; uint ino_InLoop_1st = to_no_all[nodeNumber1st]; double[] coord1st = coord_c_all[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 = coord_c_all[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; } } } ////////////////////////////////////////////////////////////////////////////////////// // 固有値、固有ベクトル // モード数の修正 if (max_mode > betamToSolveList.Length) { max_mode = (uint)betamToSolveList.Length; } // 格納 uint node_cnt_Bc1 = (uint)no_c_all_fieldPortBcId1.Length; eigen_values = new DelFEM4NetCom.Complex[max_mode]; eigen_vecs_Bc1 = new DelFEM4NetCom.Complex[max_mode, node_cnt_Bc1]; eigen_dFdXs_Bc1 = new DelFEM4NetCom.Complex[max_mode, node_cnt_Bc1]; for (int imode = 0; imode < max_mode; imode++) { eigen_values[imode] = new DelFEM4NetCom.Complex(0, 0); for (int ino = 0; ino < node_cnt_Bc1; ino++) { eigen_vecs_Bc1[imode, ino] = new DelFEM4NetCom.Complex(0, 0); eigen_dFdXs_Bc1[imode, ino] = new DelFEM4NetCom.Complex(0, 0); } } for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < max_mode; imode--, tagtModeIndex++) { KrdLab.clapack.Complex workBetam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; DelFEM4NetCom.Complex betam = new DelFEM4NetCom.Complex(workBetam.Real, workBetam.Imaginary); bool isComplexConjugateMode = false; // 減衰定数は符号がマイナス(β = -jα) if (betam.Imag > 0.0 && Math.Abs(betam.Real) <= 1.0e-12) { betam = new Complex(betam.Real, -betam.Imag); isComplexConjugateMode = true; } DelFEM4NetCom.Complex[] evec = new DelFEM4NetCom.Complex[node_cnt_Bc1]; DelFEM4NetCom.Complex[] evec_dFdX = new DelFEM4NetCom.Complex[node_cnt_Bc1]; for (int ino = 0; ino < node_cnt_Bc1; ino++) { uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino]; uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1]; DelFEM4NetCom.Complex cvalue = new DelFEM4NetCom.Complex(resVec[ino_InLoop_PortBc1].Real, resVec[ino_InLoop_PortBc1].Imaginary); DelFEM4NetCom.Complex dFdXValue = new DelFEM4NetCom.Complex(resDFDXVec[ino_InLoop_PortBc1].Real, resDFDXVec[ino_InLoop_PortBc1].Imaginary); if (isComplexConjugateMode) { cvalue = DelFEM4NetCom.Complex.Conjugate(cvalue); dFdXValue = DelFEM4NetCom.Complex.Conjugate(dFdXValue); } evec[ino] = cvalue; evec_dFdX[ino] = dFdXValue; if (tagtModeIndex == incidentModeIndex) { //System.Diagnostics.Debug.WriteLine("phase: {0} evec {1} evec_dFdX {2}", ino, Math.Atan2(cvalue.Imag, cvalue.Real) * 180 / pi, Math.Atan2(dFdXValue.Imag, dFdXValue.Real) * 180 / pi); } } // 規格化定数を求める DelFEM4NetCom.Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec); DelFEM4NetCom.Complex[] evec_Modify = new DelFEM4NetCom.Complex[node_cnt_Bc1]; DelFEM4NetCom.Complex imagOne = new DelFEM4NetCom.Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < node_cnt_Bc1; ino++) { //evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam); evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (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 == WaveModeDV.TM) { // TMモード //dm = MyMatrixUtil.complex_Sqrt(omega * eps0 / Complex.Norm(betam) / dm); dm = MyMatrixUtil.complex_Sqrt(omega * eps0 * Complex.Conjugate(betam) / (Complex.Norm(betam) * Complex.Conjugate(betam_periodic)) / dm); } else { // TEモード //dm = MyMatrixUtil.complex_Sqrt(omega * myu0 / Complex.Norm(betam) / dm); dm = MyMatrixUtil.complex_Sqrt(omega * myu0 * Complex.Conjugate(betam) / (Complex.Norm(betam) * Complex.Conjugate(betam_periodic)) / dm); } // 伝搬定数の格納 eigen_values[tagtModeIndex] = betam; if (tagtModeIndex < 10) { System.Diagnostics.Debug.WriteLine("β/k0 ( " + tagtModeIndex + " ) = " + betam.Real / k0 + " + " + betam.Imag / k0 + " i " + ((incidentModeIndex == tagtModeIndex) ? " incident" : "")); } // 固有ベクトルの格納(規格化定数を掛ける) for (int ino = 0; ino < evec.Length; ino++) { DelFEM4NetCom.Complex fm = dm * evec[ino]; DelFEM4NetCom.Complex dfmdx = dm * evec_dFdX[ino]; eigen_vecs_Bc1[tagtModeIndex, ino] = fm; eigen_dFdXs_Bc1[tagtModeIndex, ino] = dfmdx; //System.Diagnostics.Debug.WriteLine("eigen_vecs_Bc1({0}, {1}) = {2} + {3} i", imode, ino, fm.Real, fm.Imag); } /* //DEBUG モード確認 if (tagtModeIndex == incidentModeIndex) { DelFEM4NetCom.Complex[] values_all = new DelFEM4NetCom.Complex[resVec.Length]; for (int ino = 0; ino < values_all.Length; ino++) { KrdLab.clapack.Complex cval = resVec[ino]; //KrdLab.clapack.Complex cval = resDFDXVec[ino]; values_all[ino] = new DelFEM4NetCom.Complex(cval.Real, cval.Imaginary); //values_all[ino] = Complex.Norm(values_all[ino]); } WgUtil.SetFieldValueForDisplay(World, FieldLoopId, values_all, to_no_all); } */ } return true; }
/// <summary> /// 固有値をソートする /// </summary> /// <param name="incidentModeIndex"></param> /// <param name="k0"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="isModeTrace"></param> /// <param name="PrevModalVec"></param> /// <param name="minBeta"></param> /// <param name="maxBeta"></param> /// <param name="evals"></param> /// <param name="evecs"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> public static void GetSortedModes( int incidentModeIndex, double k0, uint node_cnt, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, KrdLab.clapack.Complex[] evals, KrdLab.clapack.Complex[,] evecs, bool isDebugShow, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 固有値のソート WgUtilForPeriodicEigen.Sort1DEigenMode(evals, evecs); // 欠陥モードを取得 IList<int> defectModeIndexList = new List<int>(); // 追跡するモードのインデックス退避 int traceModeIndex = -1; // フォトニック結晶導波路解析用 if (IsPCWaveguide) { double hitNorm = 0.0; for (int imode = 0; imode < evals.Length; imode++) { // 伝搬定数 KrdLab.clapack.Complex betam = evals[imode]; // 界ベクトル KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); // フォトニック結晶導波路の導波モードを判定する //System.Diagnostics.Debug.Assert((free_node_cnt * 2) == fieldVec.Length); bool isHitDefectMode = isDefectMode( k0, free_node_cnt, sortedNodes, toSorted, PCWaveguidePorts, minBeta, maxBeta, betam, fieldVec); // 入射モードを追跡する if (isHitDefectMode && isModeTrace && PrevModalVec != null) { // 同じ固有モード? double ret_norm = 0.0; bool isHitSameMode = isSameMode( k0, node_cnt, PrevModalVec, free_node_cnt, to_no_all, sortedNodes, toSorted, PCWaveguidePorts, betam, fieldVec, out ret_norm); if (isHitSameMode) { // より分布の近いモードを採用する if (Math.Abs(ret_norm - 1.0) < Math.Abs(hitNorm - 1.0)) { // 追跡するモードのインデックス退避 traceModeIndex = imode; hitNorm = ret_norm; if (isDebugShow) { System.Diagnostics.Debug.WriteLine("PCWaveguideMode(ModeTrace): imode = {0} β/k0 = {1} + {2} i", imode, betam.Real / k0, betam.Imaginary / k0); } } } } if (isHitDefectMode) { if (isDebugShow) { System.Diagnostics.Debug.WriteLine("PCWaveguideMode: imode = {0} β/k0 = {1} + {2} i", imode, betam.Real / k0, betam.Imaginary / k0); } if (imode != traceModeIndex) // 追跡するモードは除外、あとで追加 { defectModeIndexList.Add(imode); } } } if (isModeTrace && traceModeIndex != -1) { if (isDebugShow) { System.Diagnostics.Debug.WriteLine("traceModeIndex:{0}", traceModeIndex); } // 追跡している入射モードがあれば最後に追加する //defectModeIndexList.Add(traceModeIndex); // 追跡している入射モードがあれば最後から入射モードインデックス分だけシフトした位置に挿入する if (defectModeIndexList.Count >= (0 + incidentModeIndex)) { defectModeIndexList.Insert(defectModeIndexList.Count - incidentModeIndex, traceModeIndex); } else { System.Diagnostics.Debug.WriteLine("other modes dissappeared ! defectModeIndexList cleared."); traceModeIndex = -1; defectModeIndexList.Clear(); } } } IList<int> selectedModeList = new List<int>(); // フォトニック結晶導波路解析用 if (IsPCWaveguide) { // フォトニック結晶導波路 if (defectModeIndexList.Count > 0) { // フォトニック結晶欠陥部閉じ込めモード for (int iDefectModeIndex = defectModeIndexList.Count - 1; iDefectModeIndex >= 0; iDefectModeIndex--) { int imode = defectModeIndexList[iDefectModeIndex]; // 伝搬定数 KrdLab.clapack.Complex betam = evals[imode]; // 界ベクトル KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); if (Math.Abs(betam.Real) < 1.0e-12 && Math.Abs(betam.Imaginary) >= 1.0e-12) { // 減衰モード // 正しく計算できていないように思われる if (selectedModeList.Count > incidentModeIndex) { // 基本モード以外の減衰モードは除外する //System.Diagnostics.Debug.WriteLine("skip evanesent mode:β/k0 ( " + imode + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i "); continue; } } selectedModeList.Add(imode); } } else { System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not converged photonic crystal waveguide mode"); } } else { // 通常の導波路 for (int imode = evals.Length - 1; imode >= 0; imode--) { KrdLab.clapack.Complex betam = evals[imode]; // 範囲外の伝搬モードを除外 //if (Math.Abs(betam.Real / k0) > maxBeta) if (Math.Abs(betam.Real / k0) > maxBeta || Math.Abs(betam.Real / k0) < minBeta) { if (isDebugShow) { System.Diagnostics.Debug.WriteLine("skip: β/k0 ({0}) = {1} + {2} i at 2.0/λ = {3}", imode, betam.Real / k0, betam.Imaginary / k0, 2.0 / (2.0 * pi / k0)); Console.WriteLine("skip: β/k0 ({0}) = {1} + {2} i at 2.0/λ = {3}", imode, betam.Real / k0, betam.Imaginary / k0, 2.0 / (2.0 * pi / k0)); } continue; } if (Math.Abs(betam.Real) >= 1.0e-12 && Math.Abs(betam.Imaginary) >= 1.0e-12) { // 複素モード continue; } else if (Math.Abs(betam.Real) < 1.0e-12 && Math.Abs(betam.Imaginary) >= 1.0e-12) { // 減衰モード //// 正の減衰定数の場合は除外する //if (betam.Imaginary > 0) //{ // continue; //} // 正しく計算できていないように思われる if (selectedModeList.Count > 0) { // 基本モード以外の減衰モードは除外する //System.Diagnostics.Debug.WriteLine("skip evanesent mode:β/k0 ( " + imode + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i "); continue; } } else if (Math.Abs(betam.Real) >= 1.0e-12 && Math.Abs(betam.Imaginary) < 1.0e-12) { // 伝搬モード // 負の伝搬定数の場合は除外する if (betam.Real < 0) { continue; } } selectedModeList.Add(imode); } } if (selectedModeList.Count > 0) { betamToSolveList = new KrdLab.clapack.Complex[selectedModeList.Count]; resVecList = new KrdLab.clapack.Complex[selectedModeList.Count][]; for (int imode = 0; imode < betamToSolveList.Length; imode++) { resVecList[imode] = new KrdLab.clapack.Complex[node_cnt]; // 全節点 } for (int i = selectedModeList.Count - 1, selectedModeIndex = 0; i >= 0; i--, selectedModeIndex++) { int imode = selectedModeList[i]; // 伝搬定数、固有ベクトルの格納 betamToSolveList[selectedModeIndex] = evals[imode]; KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); // 非線形固有値方程式の解は{Φ} {λΦ}の順になっている //System.Diagnostics.Debug.Assert((evec.Length == free_node_cnt * 2)); // 前半の{Φ}のみ取得する for (int ino = 0; ino < free_node_cnt; ino++) { uint nodeNumber = sortedNodes[ino]; uint ino_InLoop = to_no_all[nodeNumber]; resVecList[selectedModeIndex][ino_InLoop] = evec[ino]; } if (isDebugShow) { System.Diagnostics.Debug.WriteLine("mode({0}): index:{1} β/k0 = {2} + {3} i", selectedModeIndex, imode, (betamToSolveList[selectedModeIndex].Real / k0), (betamToSolveList[selectedModeIndex].Imaginary / k0)); } } } if (isModeTrace) { if (PrevModalVec != null && (traceModeIndex == -1)) { // モード追跡に失敗した場合 betamToSolveList = null; resVecList = null; System.Diagnostics.Debug.WriteLine("fail to trace mode at k0 = {0}", k0); Console.WriteLine("fail to trace mode at k0 = {0}", k0); return; } // 前回の固有ベクトルを更新 if ((PrevModalVec == null || (PrevModalVec != null && traceModeIndex != -1)) // 初回格納、またはモード追跡に成功した場合だけ更新 && (betamToSolveList != null && betamToSolveList.Length >= (1 + incidentModeIndex)) ) { // 返却用リストでは伝搬定数の昇順に並んでいる→入射モードは最後 KrdLab.clapack.Complex betam = betamToSolveList[betamToSolveList.Length - 1 - incidentModeIndex]; KrdLab.clapack.Complex[] resVec = resVecList[betamToSolveList.Length - 1 - incidentModeIndex]; if (betam.Real != 0.0 && Math.Abs(betam.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { //PrevModalVec = resVec; PrevModalVec = new KrdLab.clapack.Complex[node_cnt]; resVec.CopyTo(PrevModalVec, 0); } else { // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように) //PrevModalVec = null; } } else { // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように) //PrevModalVec = null; } } }
/// <summary> /// 周期構造導波路固有値問題を2次一般化固有値問題として解く(実行列として解く)(Φを直接解く方法) /// </summary> /// <param name="k0"></param> /// <param name="KMat0"></param> /// <param name="CMat0"></param> /// <param name="MMat0"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="to_no_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> private static void solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat( int incidentModeIndex, double periodicDistance, double k0, double[] KMat0, bool isPortBc2Reverse, uint node_cnt, uint free_node_cnt0, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, Dictionary<uint, uint> to_no_boundary_fieldPortBcId1, bool isYDirectionPeriodic, double[][] coord_c_all, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, double betaNormalizingFactor, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 複素モード、エバネセントモードの固有ベクトル計算をスキップする? (計算時間短縮するため) bool isSkipCalcComplexAndEvanescentModeVec = true; System.Diagnostics.Debug.WriteLine("isSkipCalcComplexAndEvanescentModeVec: {0}", isSkipCalcComplexAndEvanescentModeVec); // 緩慢変化包絡線近似? Φを直接解く方法なので常にfalse const bool isSVEA = false; // Φを直接解く方法 // 境界1のみの式に変換 uint inner_node_cnt = free_node_cnt - boundary_node_cnt; double[] P11 = new double[boundary_node_cnt * boundary_node_cnt]; double[] P10 = new double[boundary_node_cnt * inner_node_cnt]; double[] P12 = new double[boundary_node_cnt * boundary_node_cnt]; double[] P01 = new double[inner_node_cnt * boundary_node_cnt]; double[] P00 = new double[inner_node_cnt * inner_node_cnt]; double[] P02 = new double[inner_node_cnt * boundary_node_cnt]; double[] P21 = new double[boundary_node_cnt * boundary_node_cnt]; double[] P20 = new double[boundary_node_cnt * inner_node_cnt]; double[] P22 = new double[boundary_node_cnt * boundary_node_cnt]; for (int i = 0; i < boundary_node_cnt; i++) { int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i); for (int j = 0; j < boundary_node_cnt; j++) { int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); // [K11] P11[i + boundary_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; // [K12] P12[i + boundary_node_cnt * j] = KMat0[i + free_node_cnt0 * jno_B2]; // [K21] P21[i + boundary_node_cnt * j] = KMat0[ino_B2 + free_node_cnt0 * j]; // [K22] P22[i + boundary_node_cnt * j] = KMat0[ino_B2 + free_node_cnt0 * jno_B2]; } for (int j = 0; j < inner_node_cnt; j++) { // [K10] P10[i + boundary_node_cnt * j] = KMat0[i + free_node_cnt0 * (j + boundary_node_cnt)]; // [K20] P20[i + boundary_node_cnt * j] = KMat0[ino_B2 + free_node_cnt0 * (j + boundary_node_cnt)]; } } for (int i = 0; i < inner_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j); // [K01] P01[i + inner_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * j]; // [K02] P02[i + inner_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * jno_B2]; } for (int j = 0; j < inner_node_cnt; j++) { // [K00] P00[i + inner_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * (j + boundary_node_cnt)]; } } System.Diagnostics.Debug.WriteLine("setup [K]B [C]B [M]B"); double[] invP00 = MyMatrixUtil.matrix_Inverse(P00, (int)(free_node_cnt - boundary_node_cnt)); double[] P10_invP00 = MyMatrixUtil.product( P10, (int)boundary_node_cnt, (int)inner_node_cnt, invP00, (int)inner_node_cnt, (int)inner_node_cnt); double[] P20_invP00 = MyMatrixUtil.product( P20, (int)boundary_node_cnt, (int)inner_node_cnt, invP00, (int)inner_node_cnt, (int)inner_node_cnt); // for [C]B double[] P10_invP00_P01 = MyMatrixUtil.product( P10_invP00, (int)boundary_node_cnt, (int)inner_node_cnt, P01, (int)inner_node_cnt, (int)boundary_node_cnt); double[] P20_invP00_P02 = MyMatrixUtil.product( P20_invP00, (int)boundary_node_cnt, (int)inner_node_cnt, P02, (int)inner_node_cnt, (int)boundary_node_cnt); // for [M]B double[] P10_invP00_P02 = MyMatrixUtil.product( P10_invP00, (int)boundary_node_cnt, (int)inner_node_cnt, P02, (int)inner_node_cnt, (int)boundary_node_cnt); // for [K]B double[] P20_invP00_P01 = MyMatrixUtil.product( P20_invP00, (int)boundary_node_cnt, (int)inner_node_cnt, P01, (int)inner_node_cnt, (int)boundary_node_cnt); // [C]B double[] CMatB = new double[boundary_node_cnt * boundary_node_cnt]; // [M]B double[] MMatB = new double[boundary_node_cnt * boundary_node_cnt]; // [K]B double[] KMatB = new double[boundary_node_cnt * boundary_node_cnt]; for (int i = 0; i < boundary_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { CMatB[i + boundary_node_cnt * j] = - P10_invP00_P01[i + boundary_node_cnt * j] + P11[i + boundary_node_cnt * j] - P20_invP00_P02[i + boundary_node_cnt * j] + P22[i + boundary_node_cnt * j]; MMatB[i + boundary_node_cnt * j] = - P10_invP00_P02[i + boundary_node_cnt * j] + P12[i + boundary_node_cnt * j]; KMatB[i + boundary_node_cnt * j] = - P20_invP00_P01[i + boundary_node_cnt * j] + P21[i + boundary_node_cnt * j]; } } // 非線形固有値問題 // [K] + λ[C] + λ^2[M]{Φ}= {0} // // Lisys(Lapack)による固有値解析 // マトリクスサイズは、強制境界及び境界3を除いたサイズ int matLen = (int)boundary_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; // 一般化固有値解析(実行列として解く) double[] A = new double[(matLen * 2) * (matLen * 2)]; double[] B = new double[(matLen * 2) * (matLen * 2)]; for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { A[i + j * (matLen * 2)] = 0.0; A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0; A[(i + matLen) + j * (matLen * 2)] = -1.0 * KMatB[i + j * matLen]; A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * CMatB[i + j * matLen]; } } for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { B[i + j * (matLen * 2)] = (i == j) ? 1.0 : 0.0; B[i + (j + matLen) * (matLen * 2)] = 0.0; B[(i + matLen) + j * (matLen * 2)] = 0.0; B[(i + matLen) + (j + matLen) * (matLen * 2)] = MMatB[i + j * matLen]; } } double[] ret_r_evals = null; double[] ret_i_evals = null; double[][] ret_r_evecs = null; double[][] ret_i_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.dggev"); KrdLab.clapack.FunctionExt.dggev(A, (matLen * 2), (matLen * 2), B, (matLen * 2), (matLen * 2), ref ret_r_evals, ref ret_i_evals, ref ret_r_evecs, ref ret_i_evecs); evals = new KrdLab.clapack.Complex[ret_r_evals.Length]; // βを格納 for (int i = 0; i < ret_r_evals.Length; i++) { KrdLab.clapack.Complex eval = new KrdLab.clapack.Complex(ret_r_evals[i], ret_i_evals[i]); //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary); if ((Math.Abs(eval.Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(eval.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) || double.IsInfinity(eval.Real) || double.IsInfinity(eval.Imaginary) || double.IsNaN(eval.Real) || double.IsNaN(eval.Imaginary) ) { // 無効な固有値 //evals[i] = -1.0 * KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue; evals[i] = KrdLab.clapack.Complex.ImaginaryOne * double.MaxValue; } else { //System.Diagnostics.Debug.WriteLine("exp(-jβd) = {0} + {1} i", eval.Real, eval.Imaginary); KrdLab.clapack.Complex betatmp = -1.0 * MyUtilLib.Matrix.MyMatrixUtil.complex_Log(eval) / (KrdLab.clapack.Complex.ImaginaryOne * periodicDistance); evals[i] = new KrdLab.clapack.Complex(betatmp.Real, betatmp.Imaginary); } } System.Diagnostics.Debug.Assert(ret_r_evals.Length == ret_r_evecs.Length); // 2次元配列に格納する ({Φ}のみ格納) evecs = new KrdLab.clapack.Complex[ret_r_evecs.Length, free_node_cnt]; System.Diagnostics.Debug.WriteLine("calc {Φ}0"); double[] invP00_P01 = MyMatrixUtil.product( invP00, (int)inner_node_cnt, (int)inner_node_cnt, P01, (int)inner_node_cnt, (int)boundary_node_cnt); double[] invP00_P02 = MyMatrixUtil.product( invP00, (int)inner_node_cnt, (int)inner_node_cnt, P02, (int)inner_node_cnt, (int)boundary_node_cnt); KrdLab.clapack.Complex[] transMat = new KrdLab.clapack.Complex[inner_node_cnt * boundary_node_cnt]; System.Diagnostics.Debug.Assert(evals.Length == ret_r_evecs.Length); System.Diagnostics.Debug.Assert(evals.Length == ret_i_evecs.Length); for (int imode = 0; imode < evals.Length; imode++) { KrdLab.clapack.Complex betam = evals[imode]; // 複素モード、エバネセントモードの固有モード計算をスキップする? if (isSkipCalcComplexAndEvanescentModeVec) { if (Math.Abs(betam.Imaginary) >= Constants.PrecisionLowerLimit) { // 複素モード、エバネセントモードの固有モード計算をスキップする continue; } } KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance); double[] ret_r_evec = ret_r_evecs[imode]; double[] ret_i_evec = ret_i_evecs[imode]; System.Diagnostics.Debug.Assert(ret_r_evec.Length == boundary_node_cnt * 2); KrdLab.clapack.Complex[] fVecB = new KrdLab.clapack.Complex[boundary_node_cnt]; /////////////////////////////// // {Φ}Bのみ格納 for (int ino = 0; ino < boundary_node_cnt; ino++) { KrdLab.clapack.Complex cvalue = new KrdLab.clapack.Complex(ret_r_evec[ino], ret_i_evec[ino]); evecs[imode, ino] = cvalue; fVecB[ino] = cvalue; } /////////////////////////////// // {Φ}0を計算 // 変換行列を計算 for (int i = 0; i < inner_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { transMat[i + inner_node_cnt * j] = -1.0 * (invP00_P01[i + inner_node_cnt * j] + expA * invP00_P02[i + inner_node_cnt * j]); } } // {Φ}0を計算 KrdLab.clapack.Complex[] fVecInner = MyMatrixUtil.product( transMat, (int)inner_node_cnt, (int)boundary_node_cnt, fVecB, (int)boundary_node_cnt); // {Φ}0を格納 for (int ino = 0; ino < inner_node_cnt; ino++) { evecs[imode, ino + boundary_node_cnt] = fVecInner[ino]; } } //////////////////////////////////////////////////////////////////// if (!isSVEA) { System.Diagnostics.Debug.Assert(free_node_cnt == (sortedNodes.Count - boundary_node_cnt)); for (int imode = 0; imode < evals.Length; imode++) { // 伝搬定数 KrdLab.clapack.Complex betatmp = evals[imode]; // 界ベクトル KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); KrdLab.clapack.Complex beta_d_tmp = betatmp * periodicDistance; if ( // [-π, 0]の解を[π, 2π]に移動する ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.0 && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && (beta_d_tmp.Real / (2.0 * pi)) >= (-0.5 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (beta_d_tmp.Real / (2.0 * pi)) < 0.0) // [0, π]の解を[2π, 3π]に移動する || ((minBeta * k0 * periodicDistance / (2.0 * pi)) >= (1.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (minBeta * k0 * periodicDistance / (2.0 * pi)) < 1.5 && Math.Abs(betatmp.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit && Math.Abs(betatmp.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit && (beta_d_tmp.Real / (2.0 * pi)) >= (0.0 - MyUtilLib.Matrix.Constants.PrecisionLowerLimit) && (beta_d_tmp.Real / (2.0 * pi)) < 0.5) ) { // [0, π]の解を2πだけ移動する double delta_phase = 2.0 * pi; beta_d_tmp.Real += delta_phase; betatmp = beta_d_tmp / periodicDistance; //check System.Diagnostics.Debug.WriteLine("shift beta * d / (2π): {0} + {1} i to {2} + {3} i", evals[imode].Real * periodicDistance / (2.0 * pi), evals[imode].Imaginary * periodicDistance / (2.0 * pi), beta_d_tmp.Real / (2.0 * pi), beta_d_tmp.Imaginary / (2.0 * pi)); // 再設定 evals[imode] = betatmp; /* //βを与えてk0を求める方法で計算した分布Φは、Φ|β2 = Φ|β1 (β2 = β1 + 2π)のように思われる // したがって、界分布はずらさないことにする // 界分布の位相をexp(j((2π/d)x))ずらす uint nodeNumber1st = sortedNodes[0]; uint ino_InLoop_1st = to_no_all[nodeNumber1st]; double[] coord1st = coord_c_all[ino_InLoop_1st]; // 界ベクトルは{Φ}, {λΦ}の順にならんでいる System.Diagnostics.Debug.Assert(free_node_cnt == (fieldVec.Length / 2)); for (int ino = 0; ino < fieldVec.Length; ino++) { uint nodeNumber = 0; if (ino < free_node_cnt) { nodeNumber = sortedNodes[ino]; } else { nodeNumber = sortedNodes[ino - (int)free_node_cnt]; } uint ino_InLoop = to_no_all[nodeNumber]; double[] coord = coord_c_all[ino_InLoop]; // 界分布の位相をexp(j((2π/d)x))ずらす double x_pt = 0.0; if (isYDirectionPeriodic) { x_pt = (coord[1] - coord1st[1]); } else { x_pt = (coord[0] - coord1st[0]); } double delta_beta = -1.0 * delta_phase / periodicDistance; KrdLab.clapack.Complex delta_expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * delta_beta * x_pt); fieldVec[ino] *= delta_expX; } // 再設定 MyUtilLib.Matrix.MyMatrixUtil.matrix_setRowVec(evecs, imode, fieldVec); */ } } } // 固有値をソートする System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt); GetSortedModes( incidentModeIndex, k0, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref PrevModalVec, minBeta, maxBeta, evals, evecs, true, // isDebugShow out betamToSolveList, out resVecList); }
/// <summary> /// 周期構造導波路固有値問題を一般化固有値問題として解く(反復計算) (緩慢変化包絡線近似用) /// </summary> /// <param name="k0"></param> /// <param name="KMat"></param> /// <param name="CMat"></param> /// <param name="MMat"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="to_no_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="isCalcSecondMode"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> private static void solveItrAsLinearGeneralizedEigen( double k0, double[] KMat, double[] CMat, double[] MMat, uint node_cnt, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, Dictionary<uint, uint> to_no_boundary_fieldPortBcId1, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool isCalcSecondMode, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 伝搬定数の初期値を設定 KrdLab.clapack.Complex betamToSolve = 0.0; //int itrMax = 10; //int itrMax = 20; int itrMax = 400; //double resMin = 1.0e-4; //double resMin = 1.0e-12; double resMin = 1.0e-6; double prevRes = double.MaxValue; bool isModeTraceWithinItr = true; KrdLab.clapack.Complex[] prevResVecItr = PrevModalVec; int itr = 0; for (itr = 0; itr < itrMax; itr++) { int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[KMat.Length]; KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[MMat.Length]; for (int i = 0; i < matLen * matLen; i++) { A[i] = KMat[i] - KrdLab.clapack.Complex.ImaginaryOne * betamToSolve * CMat[i]; B[i] = MMat[i]; } // 複素エルミートバンド行列の一般化固有値問題 if (Math.Abs(betamToSolve.Imaginary) >= Constants.PrecisionLowerLimit) // 伝搬定数が実数の時のみに限定 { //Console.WriteLine("!!!!!!!!Not propagation mode. Skip calculate: betamToSolve: {0} + {1}i", betamToSolve.Real, betamToSolve.Imaginary); System.Diagnostics.Debug.WriteLine("!!!!!!!!Not propagation mode. Skip calculate: betamToSolve: {0} + {1}i", betamToSolve.Real, betamToSolve.Imaginary); betamToSolveList = null; break; } else { // エルミートバンド行列の一般化固有値問題を解く solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref evals, ref evecs); /* { // 複素一般化固有値問題を解く // 複素非対称行列の一般化固有値問題 // 一般化複素固有値解析 // [A],[B]は内部で書き換えられるので注意 KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[][] ret_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev"); KrdLab.clapack.FunctionExt.zggev(A, matLen, matLen, B, matLen, matLen, ref ret_evals, ref ret_evecs); evals = ret_evals; System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen]; for (int i = 0; i < ret_evecs.Length; i++) { KrdLab.clapack.Complex[] ret_evec = ret_evecs[i]; for (int j = 0; j < ret_evec.Length; j++) { evecs[i, j] = ret_evec[j]; } } } */ } // βを格納 for (int i = 0; i < evals.Length; i++) { KrdLab.clapack.Complex eval = evals[i]; // 固有値がβ2の場合 // Note: 固有値は2乗で求まる // βを求める KrdLab.clapack.Complex eval_sqrt = KrdLab.clapack.Complex.Sqrt(eval); if (eval_sqrt.Real > 0 && eval_sqrt.Imaginary > 0) { eval_sqrt.Imaginary = -eval_sqrt.Imaginary; } evals[i] = eval_sqrt; } // 固有値をソートする KrdLab.clapack.Complex[] work_betamToSolveList = null; KrdLab.clapack.Complex[][] work_resVecList = null; int work_incidentModeIndex = (isCalcSecondMode ? 1 : 0); bool work_isModeTrace = isModeTrace; KrdLab.clapack.Complex[] workPrevModalVec = null; if (!IsPCWaveguide) { work_isModeTrace = false; workPrevModalVec = isModeTraceWithinItr ? prevResVecItr : PrevModalVec; } System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt); GetSortedModes( work_incidentModeIndex, k0, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, IsPCWaveguide, PCWaveguidePorts, work_isModeTrace, ref workPrevModalVec, minBeta, maxBeta, evals, evecs, false, // isDebugShow out work_betamToSolveList, out work_resVecList); if (work_betamToSolveList == null || work_betamToSolveList.Length == 0) { System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode"); betamToSolve = 0; betamToSolveList = null; resVecList = null; break; } if (isCalcSecondMode && work_incidentModeIndex >= work_betamToSolveList.Length) { // 高次モード反復計算時 // 反復によって固有値を取得する場合は、基本モードがなくなるときがある(特定固有モードに収束させているため) // fail safe if (itr != 0 && work_incidentModeIndex >= work_betamToSolveList.Length) { work_incidentModeIndex = 0; } } int tagtModeIndex = work_betamToSolveList.Length - 1 - work_incidentModeIndex; if (tagtModeIndex < 0 || tagtModeIndex >= work_betamToSolveList.Length) { System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode [Error] tagtModeIndex = {0}", tagtModeIndex); betamToSolve = 0; betamToSolveList = null; resVecList = null; break; } // 伝搬定数、固有ベクトルの格納 betamToSolveList = new KrdLab.clapack.Complex[1]; resVecList = new KrdLab.clapack.Complex[1][]; resVecList[0] = new KrdLab.clapack.Complex[node_cnt]; // 全節点 // 収束判定用に前の伝搬定数を退避 KrdLab.clapack.Complex prevBetam = betamToSolve; // 伝搬定数 betamToSolve = work_betamToSolveList[tagtModeIndex]; // 反復による固有モード計算ではモードは1つしか計算できない betamToSolveList[0] = betamToSolve; // 固有ベクトル KrdLab.clapack.Complex[] resVec = resVecList[0]; work_resVecList[tagtModeIndex].CopyTo(resVec, 0); // 収束判定 double res = KrdLab.clapack.Complex.Abs(prevBetam - betamToSolve); if (res < resMin) { System.Diagnostics.Debug.WriteLine("converged itr:{0} betam:{1} + {2} i", itr, betamToSolve.Real, betamToSolve.Imaginary); break; } // 発散判定 if (itr >= 20 && Math.Abs(res) > Math.Abs(prevRes)) { System.Diagnostics.Debug.WriteLine("!!!!!!!! Not converged : prevRes = {0} res = {1} at 2/λ = {2}", prevRes, res, 2.0 / (2.0 * pi / k0)); Console.WriteLine("!!!!!!!! Not converged : prevRes = {0} res = {1} at 2/λ = {2}", prevRes, res, 2.0 / (2.0 * pi / k0)); betamToSolve = 0.0; break; } prevRes = res; if (isModeTraceWithinItr && resVec != null) { if (prevResVecItr == null) { // 初回のみメモリ確保 prevResVecItr = new KrdLab.clapack.Complex[node_cnt]; //全節点 } // resVecは同じバッファを使いまわすので、退避用のprevResVecItrへはコピーする必要がある resVec.CopyTo(prevResVecItr, 0); } // check if (itr % 20 == 0 && itr >= 20) { System.Diagnostics.Debug.WriteLine("itr: {0}", itr); Console.WriteLine("itr: {0}", itr); } } if (itr == itrMax) { System.Diagnostics.Debug.WriteLine("!!!!!!!! Not converged itr:{0} betam:{1} + {2} i at 2/λ = {3}", itr, betamToSolve.Real, betamToSolve.Imaginary, 2.0 / (2.0 * pi / k0)); Console.WriteLine("!!!!!!!! Not converged itr:{0} betam:{1} + {2} i at 2/λ = {3}", itr, betamToSolve.Real, betamToSolve.Imaginary, 2.0 / (2.0 * pi / k0)); } else if (itr >= 20 && (Math.Abs(betamToSolve.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit || Math.Abs(betamToSolve.Imaginary) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)) { System.Diagnostics.Debug.WriteLine("converged but too slow!!!: itr: {0} at 2/λ = {1}", itr, 2.0 / (2.0 * pi / k0)); Console.WriteLine("converged but too slow!!!: itr: {0} at 2/λ = {1}", itr, 2.0 / (2.0 * pi / k0)); } // 前回の固有ベクトルを更新 if (isModeTrace && betamToSolve.Real != 0.0 && Math.Abs(betamToSolve.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { //PrevModalVec = resVecList[0]; PrevModalVec = new KrdLab.clapack.Complex[node_cnt]; resVecList[0].CopyTo(PrevModalVec, 0); } else { // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように) //PrevModalVec = null; } }
/// <summary> /// 界のx方向微分値を取得する /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> public static void getDFDXValues( CFieldWorld world, uint fieldValId, Dictionary<uint, uint> to_no_all, IList<MediaInfo> Medias, Dictionary<uint, wg2d.World.Loop> LoopDic, double rotAngle, double[] rotOrigin, KrdLab.clapack.Complex[] fVec, out KrdLab.clapack.Complex[] dFdXVec, out KrdLab.clapack.Complex[] dFdYVec) { dFdXVec = new KrdLab.clapack.Complex[fVec.Length]; dFdYVec = new KrdLab.clapack.Complex[fVec.Length]; CField valField_base = world.GetField(fieldValId); System.Diagnostics.Debug.Assert(valField_base.GetFieldType() == FIELD_TYPE.ZSCALAR); Dictionary<uint, int> nodeElemCntH = new Dictionary<uint, int>(); //Dictionary<uint, double> nodeMediaP11Sum = new Dictionary<uint,double>(); //境界に限ればこの計算は誤差がある Dictionary<uint, double> nodeAreaSum = new Dictionary<uint, double>(); IList<uint> aIdEA = valField_base.GetAryIdEA(); foreach (uint eaId in aIdEA) { CElemAry ea = world.GetEA(eaId); CField valField = world.GetField(fieldValId); if (valField.GetInterpolationType(eaId, world) != INTERPOLATION_TYPE.TRI11) continue; // 媒質を取得する MediaInfo media = new MediaInfo(); { // ループのIDのはず uint lId = eaId; if (LoopDic.ContainsKey(lId)) { World.Loop loop = LoopDic[lId]; media = Medias[loop.MediaIndex]; } else { System.Diagnostics.Debug.Assert(false); } } // 要素セグメントコーナー値 //CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world); // 要素セグメントコーナー座標 CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); uint nno = 3; uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 //Complex[] value_c = new Complex[nno]; // 要素節点の座標 double[,] coord_c = new double[nno, ndim]; //CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, world); CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 座標を取得 for (uint inoes = 0; inoes < nno; inoes++) { double[] tmpval = null; ns_c_co.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == ndim); for (int i = 0; i < tmpval.Length; i++) { coord_c[inoes, i] = tmpval[i]; } } if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit) { // 座標を回転移動する for (uint inoes = 0; inoes < nno; inoes++) { double[] srcPt = new double[] { coord_c[inoes, 0], coord_c[inoes, 1] }; double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin); for (int i = 0; i < ndim; i++) { coord_c[inoes, i] = destPt[i]; } } } // 節点座標 double[] p1 = new double[ndim]; double[] p2 = new double[ndim]; double[] p3 = new double[ndim]; for (int i = 0; i < ndim; i++) { p1[i] = coord_c[0, i]; p2[i] = coord_c[1, i]; p3[i] = coord_c[2, i]; } // 面積を求める double area = CKerEMatTri.TriArea(p1, p2, p3); // 形状関数の微分を求める double[,] dldx = null; double[] const_term = null; CKerEMatTri.TriDlDx(out dldx, out const_term, p1, p2, p3); // 節点の値を取って来る //es_c_va.GetNodes(ielem, no_c); //for (uint inoes = 0; inoes < nno; inoes++) //{ // Complex[] tmpval = null; // ns_c_val.GetValue(no_c[inoes], out tmpval); // System.Diagnostics.Debug.Assert(tmpval.Length == 1); // value_c[inoes] = tmpval[0]; //} // 界の微分値を計算 // 界の微分値は一次三角形要素の場合、要素内で一定値 KrdLab.clapack.Complex dFdX = 0.0; KrdLab.clapack.Complex dFdY = 0.0; for (int inoes = 0; inoes < nno; inoes++) { uint iNodeNumber = no_c[inoes]; if (!to_no_all.ContainsKey(iNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } uint inoGlobal = to_no_all[iNodeNumber]; KrdLab.clapack.Complex fVal = fVec[inoGlobal]; dFdX += dldx[inoes, 0] * fVal; dFdY += dldx[inoes, 1] * fVal; } // 格納 for (int inoes = 0; inoes < nno; inoes++) { uint iNodeNumber = no_c[inoes]; if (!to_no_all.ContainsKey(iNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } uint inoGlobal = to_no_all[iNodeNumber]; //dFdXVec[inoGlobal] += dFdX; //dFdYVec[inoGlobal] += dFdY; // Note: // TEzモードのとき -dHz/dx = jωDy dFdXVec[inoGlobal] += dFdX * area; dFdYVec[inoGlobal] += dFdY * area; /*境界に限ればこの計算は誤差がある // 媒質を考慮する double media_P11 = media.P[1, 1]; // pyy (dF/dx)を格納 // TEzのとき pyy (dF/dx) = (1/εyy)dHz/dx = -jωEy //dFdXVec[inoGlobal] += media_P11 * dFdX; //dFdYVec[inoGlobal] += media_P11 * dFdY; dFdXVec[inoGlobal] += media_P11 * dFdX * area; dFdYVec[inoGlobal] += media_P11 * dFdY * area; */ if (nodeElemCntH.ContainsKey(inoGlobal)) { nodeElemCntH[inoGlobal]++; /*境界に限ればこの計算は誤差がある // 媒質パラメータpyyの逆数を格納 //nodeMediaP11Sum[inoGlobal] += (1.0 / media_P11); nodeMediaP11Sum[inoGlobal] += (1.0 / media_P11) * area; */ // 面積を格納 nodeAreaSum[inoGlobal] += area; } else { nodeElemCntH.Add(inoGlobal, 1); /*境界に限ればこの計算は誤差がある // 媒質パラメータpyyの逆数を格納 //nodeMediaP11Sum.Add(inoGlobal, (1.0 / media_P11)); nodeMediaP11Sum.Add(inoGlobal, (1.0 / media_P11) * area); */ nodeAreaSum.Add(inoGlobal, area); } } } } for (uint i = 0; i < dFdXVec.Length; i++) { //int cnt = nodeElemCntH[i]; //dFdXVec[i] /= cnt; //dFdYVec[i] /= cnt; double areaSum = nodeAreaSum[i]; dFdXVec[i] = (dFdXVec[i] / areaSum); dFdYVec[i] = (dFdYVec[i] / areaSum); /*境界に限ればこの計算は誤差がある // 媒質を考慮する // 媒質パラメータpyyの平均 //int cnt = nodeElemCntH[i]; double areaSum = nodeAreaSum[i]; //double mediaP11 = 1.0 / (nodeMediaP11Sum[i] / cnt); double mediaP11 = 1.0 / (nodeMediaP11Sum[i] / areaSum); //System.Diagnostics.Debug.Assert((1.0 / mediaP11) >= 1.0); // dF/dxの平均 //dFdXVec[i] = (dFdXVec[i] / cnt) / mediaP11; //dFdYVec[i] = (dFdYVec[i] / cnt) / mediaP11; dFdXVec[i] = (dFdXVec[i] / areaSum) / mediaP11; dFdYVec[i] = (dFdYVec[i] / areaSum) / mediaP11; */ } }
//////////////////////////////////////////////////////////////////////////////////////////////// // DekFEMの処理を隠ぺいした簡易版 //////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// PCOCGで線形方程式を解く /// </summary> /// <param name="mat"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged) public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; int matLen = mat.RowSize; System.Diagnostics.Debug.WriteLine("SolvePCOCG 1"); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; CFieldWorld World = new CFieldWorld(); setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 uint FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); System.Diagnostics.Debug.WriteLine("SolvePCOCG 2"); //------------------------------------------------------------------ // リニアシステム //------------------------------------------------------------------ CZLinearSystem Ls = new CZLinearSystem(); CZPreconditioner_ILU Prec = new CZPreconditioner_ILU(); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ Ls.AddPattern_Field(FieldValId, World); // POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない // 非対角要素のパターンの追加 { uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); // パターンを追加 using (CIndexedArray crs = new CIndexedArray()) { crs.InitializeSize(mat_cc.NBlkMatCol()); //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow()); using (UIntVectorIndexer index = crs.index) using (UIntVectorIndexer ary = crs.array) { for (int iblk = 0; iblk < (int)crs.Size(); iblk++) { index[iblk] = 0; } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 現在のマトリクスのインデックス設定をコピーする uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); foreach (uint row_index in cur_rows) { ary.Add(row_index); } index[iblk + 1] = (uint)ary.Count; //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup); // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0) // すべての節点に関して列を追加 int ino_global = iblk; int col = iblk; if (col != -1 && ino_global != -1) { // 関連付けられていない節点をその行の列データの最後に追加 int last_index = (int)index[col + 1] - 1; int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { // 行列の0要素を除く //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit) //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15) //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { continue; } uint row = (uint)jno_global; if (ino_global != jno_global) // 対角要素は除く { if (!cur_rows.Contains(row)) { ary.Insert(last_index + 1 + add_cnt, row); add_cnt++; //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row); } } } if (add_cnt > 0) { index[col + 1] = (uint)ary.Count; } } } } crs.Sort(); System.Diagnostics.Debug.Assert(crs.CheckValid()); // パターンを削除する mat_cc.DeletePattern(); // パターンを追加する mat_cc.AddPattern(crs); } } System.Diagnostics.Debug.WriteLine("SolvePCOCG 3"); //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // set Preconditioner //Prec.SetFillInLevel(1); // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した //Prec.SetFillInLevel(0); // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする //Prec.SetFillInLevel((uint)mat.RowSize); // 完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い //Prec.SetFillInLevel(3); // 誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある //以上から //メインの導波管の計算時間を短くしたいのでフィルインなしにする //Prec.SetFillInLevel(0); // 導波管だとこれで十分 // フィルインレベルの設定(既定値) Prec.SetFillInLevel(DefFillInLevel); // ILU(0)のパターン初期化 Prec.SetLinearSystem(Ls); System.Diagnostics.Debug.WriteLine("SolvePCOCG 4"); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ //------------------------------------------------------------------ Ls.InitializeMarge(); { uint ntmp = Ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; // 0要素はマージ対象でないので最初から除外する //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit) //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { add_flg[i, j] = true; } } } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応) uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); uint colcnt = 1; uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する Complex[] emattmp = new Complex[colcnt * rowcnt]; uint[] no_c_tmp_col = new uint[colcnt]; uint[] no_c_tmp_row = new uint[rowcnt]; no_c_tmp_col[0] = (uint)iblk; no_c_tmp_row[0] = (uint)iblk; for (int irow = 0; irow < cur_rows.Count; irow++) { no_c_tmp_row[irow + 1] = cur_rows[irow]; } { uint ino = 0; uint ino_global = no_c_tmp_col[ino]; for (int jno = 0; jno < rowcnt; jno++) { uint jno_global = no_c_tmp_row[jno]; //emat[ino, jno] if (!add_flg[ino_global, jno_global]) { //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global]; //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize]; KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary); add_flg[ino_global, jno_global] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); emattmp[ino * rowcnt + jno] = new Complex(0, 0); } } } // マージ! mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer); } for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } // 残差ベクトルにマージ for (uint ino_global = 0; ino_global < node_cnt; ino_global++) { // 残差ベクトルにマージする uint no_tmp = ino_global; //System.Numerics.Complex cvalue = resVec[ino_global]; KrdLab.clapack.Complex cvalue = resVec[ino_global]; Complex val = new Complex(cvalue.Real, cvalue.Imaginary); res_c.AddValue(no_tmp, 0, val); } } double res = Ls.FinalizeMarge(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList <uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World); CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World); // 要素の節点数 uint nno = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る es_c_va.GetNodes(ielem, no_c); for (uint inoes = 0; inoes < nno; inoes++) { Complex[] tmpval = null; ns_c_val.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == 1); value_c[inoes] = tmpval[0]; //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" ); } for (uint ino = 0; ino < nno; ino++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Prec.Clear(); Prec.Dispose(); World.Clear(); World.Dispose(); System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return(success); }
/// <summary> /// 四角形領域:ソートされた行列を取得する /// </summary> /// <param name="probNo"></param> /// <param name="periodicDistanceX"></param> /// <param name="periodicDistanceY"></param> /// <param name="betaX"></param> /// <param name="betaY"></param> /// <param name="no_c_all_fieldPortBcId1"></param> /// <param name="no_c_all_fieldPortBcId3"></param> /// <param name="coord_c_all"></param> /// <param name="sharedNodes"></param> /// <param name="sharedNodeCoords"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="boundary_node_cnt_B1"></param> /// <param name="boundary_node_cnt_B3"></param> /// <param name="boundary_node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="free_node_cnt0"></param> /// <param name="KMat0"></param> /// <param name="MMat0"></param> /// <param name="expAX"></param> /// <param name="expAY"></param> /// <param name="expAY1"></param> /// <param name="expAY2"></param> /// <param name="KMat"></param> /// <param name="MMat"></param> private static void getSortedMatrix_Rect( int probNo, double periodicDistanceX, double periodicDistanceY, KrdLab.clapack.Complex betaX, KrdLab.clapack.Complex betaY, uint[] no_c_all_fieldPortBcId1, uint[] no_c_all_fieldPortBcId3, double[][] coord_c_all, uint[] sharedNodes, double[][] sharedNodeCoords, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, uint boundary_node_cnt_B1, uint boundary_node_cnt_B3, uint boundary_node_cnt, uint free_node_cnt, uint free_node_cnt0, KrdLab.clapack.Complex[] KMat0, KrdLab.clapack.Complex[] MMat0, out KrdLab.clapack.Complex expAX, out KrdLab.clapack.Complex expAY, out KrdLab.clapack.Complex expAY1, out KrdLab.clapack.Complex expAY2, out KrdLab.clapack.Complex[] KMat, out KrdLab.clapack.Complex[] MMat ) { // 境界2の節点は境界1の節点と同一とみなす // 境界上の分割が同じであることが前提条件 KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; // 直接Bloch境界条件を指定する場合 expAX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX); expAY = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY); // 左下と左上のX座標オフセット double ofsX = sharedNodeCoords[0][0] - sharedNodeCoords[1][0]; if (Math.Abs(ofsX) >= Constants.PrecisionLowerLimit) { // 斜め領域の場合 // Y方向の周期境界条件にはオフセット分のX方向成分の因子が入る System.Diagnostics.Debug.WriteLine("ofsX: {0}", ofsX); expAY *= KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * ofsX); } expAY1 = 0.0; expAY2 = 0.0; if (probNo == 3) { expAY = 1.0; expAY1 = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5) * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY); expAY2 = KrdLab.clapack.Complex.Exp(1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaX * periodicDistanceX * 0.5) * KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betaY * periodicDistanceY); } int nodeIndexShared0 = toSorted[sharedNodes[0]]; // 左上頂点 System.Diagnostics.Debug.Assert((free_node_cnt + boundary_node_cnt_B1 - 1 - nodeIndexShared0) == toSorted[sharedNodes[2]]);//左上と右上 if (probNo == 3) { nodeIndexShared0 = -1; } uint boundary_node_cnt_Half_B3 = 0; if (probNo == 3) { System.Diagnostics.Debug.Assert(no_c_all_fieldPortBcId3.Length % 2 == 1); boundary_node_cnt_Half_B3 = ((uint)no_c_all_fieldPortBcId3.Length - 1) / 2; System.Diagnostics.Debug.Assert(boundary_node_cnt_B3 == (no_c_all_fieldPortBcId3.Length - 2)); System.Diagnostics.Debug.Assert(boundary_node_cnt_B3 == (boundary_node_cnt_Half_B3 * 2 - 1)); } /* if (probNo == 3) { //////////////////////////////////////////////////////////////////////////////////// // check { // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { int j_3_L = (int)(j + boundary_node_cnt_B1); uint nodeNumber_3_L = sortedNodes[j_3_L]; double[] coord_3_L = coord_c_all[nodeNumber_3_L]; System.Diagnostics.Debug.WriteLine("3_L: {0} {1} {2} {3}", j_3_L, nodeNumber_3_L, coord_3_L[0], coord_3_L[1]); int j_4_R = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j); uint nodeNumber_4_R = sortedNodes[j_4_R]; double[] coord_4_R = coord_c_all[nodeNumber_4_R]; System.Diagnostics.Debug.WriteLine("4_R: {0} {1} {2} {3}", j_4_R, nodeNumber_4_R, coord_4_R[0], coord_4_R[1]); } // 境界4中点 { // 左下頂点 uint nodeNumber_shared1 = sharedNodes[1]; int j_shared1 = toSorted[nodeNumber_shared1]; double[] coord_shared1 = coord_c_all[nodeNumber_shared1]; System.Diagnostics.Debug.WriteLine("shared1: {0} {1} {2} {3}", j_shared1, nodeNumber_shared1, coord_shared1[0], coord_shared1[1]); // 境界4中点 int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); uint nodeNumber_m_B4 = sortedNodes[jm_B4]; double[] coord_m_B4 = coord_c_all[nodeNumber_m_B4]; System.Diagnostics.Debug.WriteLine("m_B4: {0} {1} {2} {3}", jm_B4, nodeNumber_m_B4, coord_m_B4[0], coord_m_B4[1]); } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { int j_3_R = (int)(j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3); uint nodeNumber_3_R = sortedNodes[j_3_R]; double[] coord_3_R = coord_c_all[nodeNumber_3_R]; System.Diagnostics.Debug.WriteLine("3_R: {0} {1} {2} {3}", j_3_R, nodeNumber_3_R, coord_3_R[0], coord_3_R[1]); int j_4_L = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j); uint nodeNumber_4_L = sortedNodes[j_4_L]; double[] coord_4_L = coord_c_all[nodeNumber_4_L]; System.Diagnostics.Debug.WriteLine("4_L: {0} {1} {2} {3}", j_4_L, nodeNumber_4_L, coord_4_L[0], coord_4_L[1]); } } //////////////////////////////////////////////////////////////////////////////////// } */ ///////////////////////////////////////////////////////////////// // 境界1+3+内部 for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j]; } } ///////////////////////////////////////////////////////////////// // 境界1+3+内部 for (int i = 0; i < free_node_cnt; i++) { // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { if (probNo == 3) { } else { if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理 } KMat[i + free_node_cnt * j] += expAX * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i + free_node_cnt * j] += expAX * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } if (probNo == 3) { //////////////////////////////////////////////////////////////////////////////////// // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY1 * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY1 * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; } // 境界4中点 { // 左下頂点 int j1 = toSorted[sharedNodes[1]]; // 境界4中点 int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); KMat[i + free_node_cnt * j1] += expAY1 * KMat0[i + free_node_cnt0 * jm_B4]; MMat[i + free_node_cnt * j1] += expAY1 * MMat0[i + free_node_cnt0 * jm_B4]; } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += expAY2 * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += expAY2 * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } //////////////////////////////////////////////////////////////////////////////////// } else { // 通常の処理 // 境界4 for (int j = 0; j < boundary_node_cnt_B3; j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } // 左上頂点と左下頂点 { int j0 = toSorted[sharedNodes[0]]; // 左上頂点 int j1 = toSorted[sharedNodes[1]]; // 左下頂点 int j2 = toSorted[sharedNodes[2]]; // 右上頂点 int j3 = toSorted[sharedNodes[3]]; // 右下頂点 KMat[i + free_node_cnt * j0] += (1.0 / expAY) * KMat0[i + free_node_cnt0 * j1] + expAX * KMat0[i + free_node_cnt0 * j2] + (expAX / expAY) * KMat0[i + free_node_cnt0 * j3]; MMat[i + free_node_cnt * j0] += (1.0 / expAY) * MMat0[i + free_node_cnt0 * j1] + expAX * MMat0[i + free_node_cnt0 * j2] + (expAX / expAY) * MMat0[i + free_node_cnt0 * j3]; } } } ///////////////////////////////////////////////////////////////// // 境界2 for (int i = 0; i < boundary_node_cnt_B1; i++) { if (probNo == 3) { } else { if (i == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理 } // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] += (1.0 / expAX) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] += (1.0 / expAX) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { if (probNo == 3) { } else { if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理 } KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } if (probNo == 3) { //////////////////////////////////////////////////////////////////////////////////// // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAX) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAX) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; } // 境界4中点 { // 左下頂点 int j1 = toSorted[sharedNodes[1]]; // 境界4中点 int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); KMat[i + free_node_cnt * j1] += (1.0 / expAX) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * jm_B4]; MMat[i + free_node_cnt * j1] += (1.0 / expAX) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * jm_B4]; } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAX) * expAY2 * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAX) * expAY2 * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } //////////////////////////////////////////////////////////////////////////////////// } else { // 通常の処理 // 境界4 for (int j = 0; j < boundary_node_cnt_B3; j++) { KMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAX) * expAY * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAX) * expAY * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } { int j0 = toSorted[sharedNodes[0]]; // 左上頂点 int j1 = toSorted[sharedNodes[1]]; // 左下頂点 int j2 = toSorted[sharedNodes[2]]; // 右上頂点 int j3 = toSorted[sharedNodes[3]]; // 右下頂点 KMat[i + free_node_cnt * j0] += (1.0 / expAX) * (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j1] + (1.0 / expAX) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j2] + (1.0 / expAX) * (expAX / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j3]; MMat[i + free_node_cnt * j0] += (1.0 / expAX) * (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j1] + (1.0 / expAX) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j2] + (1.0 / expAX) * (expAX / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 - 1 - i) + free_node_cnt0 * j3]; } } } if (probNo == 3) { //////////////////////////////////////////////////////////////////////////////////// // 境界4右半分 for (int i = 0; i < (boundary_node_cnt_Half_B3 - 1); i++) { // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY1) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * j]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY1) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] += KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] += MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; } // 境界4中点 { // 左下頂点 int j1 = toSorted[sharedNodes[1]]; // 境界4中点 int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); KMat[i + boundary_node_cnt_B1 + free_node_cnt * j1] += (1.0 / expAY1) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * jm_B4]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j1] += (1.0 / expAY1) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * jm_B4]; } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAY1) * expAY2 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAY1) * expAY2 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } } // 境界4中点 { // 左下頂点 int i1 = toSorted[sharedNodes[1]]; // 境界4中点 int im_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * KMat0[im_B4 + free_node_cnt0 * j]; MMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * MMat0[im_B4 + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { KMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i1 + free_node_cnt * j] += (1.0 / expAY1) * expAX * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAY1) * expAY1 * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; MMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAY1) * expAY1 * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; } // 境界4中点 { // 左下頂点 int j1 = i1; // 境界4中点 int jm_B4 = im_B4; KMat[i1 + free_node_cnt * j1] += KMat0[im_B4 + free_node_cnt0 * jm_B4]; MMat[i1 + free_node_cnt * j1] += MMat0[im_B4 + free_node_cnt0 * jm_B4]; } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAY1) * expAY2 * KMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i1 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += (1.0 / expAY1) * expAY2 * MMat0[im_B4 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } } // 境界4左半分 for (int i = 0; i < (boundary_node_cnt_Half_B3 - 1); i++) { // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] += (1.0 / expAY2) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j]; MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] += (1.0 / expAY2) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] += (1.0 / expAY2) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j] += (1.0 / expAY2) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } // 境界4右半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAY2) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1)] += (1.0 / expAY2) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 2 - j)]; } // 境界4中点 { // 左下頂点 int j1 = toSorted[sharedNodes[1]]; // 境界4中点 int jm_B4 = (int)(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 - 1); KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j1] += (1.0 / expAY2) * expAY1 * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * jm_B4]; MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * j1] += (1.0 / expAY2) * expAY1 * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * jm_B4]; } // 境界4左半分 for (int j = 0; j < (boundary_node_cnt_Half_B3 - 1); j++) { KMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3 + free_node_cnt * (j + boundary_node_cnt_B1 + boundary_node_cnt_Half_B3)] += MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } } //////////////////////////////////////////////////////////////////////////////////// } else { // 通常の処理 // 境界4 for (int i = 0; i < boundary_node_cnt_B3; i++) { // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理 KMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j] += (1.0 / expAY) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } // 境界4 for (int j = 0; j < boundary_node_cnt_B3; j++) { KMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] += KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * (j + boundary_node_cnt_B1)] += MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } { int j0 = toSorted[sharedNodes[0]]; // 左上頂点 int j1 = toSorted[sharedNodes[1]]; // 左下頂点 int j2 = toSorted[sharedNodes[2]]; // 右上頂点 int j3 = toSorted[sharedNodes[3]]; // 右下頂点 KMat[i + boundary_node_cnt_B1 + free_node_cnt * j0] += (1.0 / expAY) * (1.0 / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j1] + (1.0 / expAY) * expAX * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j2] + (1.0 / expAY) * (expAX / expAY) * KMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j3]; MMat[i + boundary_node_cnt_B1 + free_node_cnt * j0] += (1.0 / expAY) * (1.0 / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j1] + (1.0 / expAY) * expAX * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j2] + (1.0 / expAY) * (expAX / expAY) * MMat0[(free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - i) + free_node_cnt0 * j3]; } } // 左下頂点、右上頂点、右下頂点 { int i0 = toSorted[sharedNodes[0]]; // 左上頂点 int i1 = toSorted[sharedNodes[1]]; // 左下頂点 int i2 = toSorted[sharedNodes[2]]; // 右上頂点 int i3 = toSorted[sharedNodes[3]]; // 右下頂点 // 境界1+3+内部 for (int j = 0; j < free_node_cnt; j++) { KMat[i0 + free_node_cnt * j] += expAY * KMat0[i1 + free_node_cnt0 * j] + (1.0 / expAX) * KMat0[i2 + free_node_cnt0 * j] + (expAY / expAX) * KMat0[i3 + free_node_cnt0 * j]; MMat[i0 + free_node_cnt * j] += expAY * MMat0[i1 + free_node_cnt0 * j] + (1.0 / expAX) * MMat0[i2 + free_node_cnt0 * j] + (expAY / expAX) * MMat0[i3 + free_node_cnt0 * j]; } // 境界2 for (int j = 0; j < boundary_node_cnt_B1; j++) { if (j == nodeIndexShared0) continue; // 右上頂点(左上頂点に対応)は別処理 KMat[i0 + free_node_cnt * j] += expAY * expAX * KMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)] + (1.0 / expAX) * expAX * KMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)] + (expAY / expAX) * expAX * KMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; MMat[i0 + free_node_cnt * j] += expAY * expAX * MMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)] + (1.0 / expAX) * expAX * MMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)] + (expAY / expAX) * expAX * MMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 - 1 - j)]; } // 境界4 for (int j = 0; j < boundary_node_cnt_B3; j++) { KMat[i0 + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY * expAY * KMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)] + (1.0 / expAX) * expAY * KMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)] + (expAY / expAX) * expAY * KMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; MMat[i0 + free_node_cnt * (j + boundary_node_cnt_B1)] += expAY * expAY * MMat0[i1 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)] + (1.0 / expAX) * expAY * MMat0[i2 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)] + (expAY / expAX) * expAY * MMat0[i3 + free_node_cnt0 * (free_node_cnt + boundary_node_cnt_B1 + boundary_node_cnt_B3 - 1 - j)]; } { int j0 = i0; int j1 = i1; int j2 = i2; int j3 = i3; KMat[i0 + free_node_cnt * j0] += expAY * (1.0 / expAY) * KMat0[i1 + free_node_cnt0 * j1] + expAY * expAX * KMat0[i1 + free_node_cnt0 * j2] + expAY * (expAX / expAY) * KMat0[i1 + free_node_cnt0 * j3] + (1.0 / expAX) * (1.0 / expAY) * KMat0[i2 + free_node_cnt0 * j1] + (1.0 / expAX) * expAX * KMat0[i2 + free_node_cnt0 * j2] + (1.0 / expAX) * (expAX / expAY) * KMat0[i2 + free_node_cnt0 * j3] + (expAY / expAX) * (1.0 / expAY) * KMat0[i3 + free_node_cnt0 * j1] + (expAY / expAX) * expAX * KMat0[i3 + free_node_cnt0 * j2] + (expAY / expAX) * (expAX / expAY) * KMat0[i3 + free_node_cnt0 * j3]; MMat[i0 + free_node_cnt * j0] += expAY * (1.0 / expAY) * MMat0[i1 + free_node_cnt0 * j1] + expAY * expAX * MMat0[i1 + free_node_cnt0 * j2] + expAY * (expAX / expAY) * MMat0[i1 + free_node_cnt0 * j3] + (1.0 / expAX) * (1.0 / expAY) * MMat0[i2 + free_node_cnt0 * j1] + (1.0 / expAX) * expAX * MMat0[i2 + free_node_cnt0 * j2] + (1.0 / expAX) * (expAX / expAY) * MMat0[i2 + free_node_cnt0 * j3] + (expAY / expAX) * (1.0 / expAY) * MMat0[i3 + free_node_cnt0 * j1] + (expAY / expAX) * expAX * MMat0[i3 + free_node_cnt0 * j2] + (expAY / expAX) * (expAX / expAY) * MMat0[i3 + free_node_cnt0 * j3]; } } } }
// 行列の行ベクトルを抜き出す public static KrdLab.clapack.Complex[] matrix_GetRowVec(KrdLab.clapack.Complex[,] matA, int row) { KrdLab.clapack.Complex[] rowVec = new KrdLab.clapack.Complex[matA.GetLength(1)]; for (int j = 0; j < matA.GetLength(1); j++) { rowVec[j] = matA[row, j]; } return rowVec; }
/// <summary> /// 問題を解く /// </summary> /// <param name="probNo"></param> /// <param name="betaIndex"></param> /// <param name="isTriLattice"></param> /// <param name="calcBetaCnt"></param> /// <param name="initFlg"></param> /// <param name="periodicDistanceY"></param> /// <param name="WaveModeDv"></param> /// <param name="latticeA"></param> /// <param name="periodicDistanceX"></param> /// <param name="IsShowAbsField"></param> /// <param name="MinNormalizedFreq"></param> /// <param name="MaxNormalizedFreq"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="FieldLoopId"></param> /// <param name="FieldForceBcId"></param> /// <param name="FieldPortBcIds"></param> /// <param name="Medias"></param> /// <param name="LoopDic"></param> /// <param name="EdgeDic"></param> /// <param name="EigenValueList"></param> /// <param name="DrawerAry"></param> /// <param name="Camera"></param> /// <returns></returns> private static bool solveProblem( int probNo, ref int betaIndex, bool isTriLattice, int calcBetaCnt, bool initFlg, double periodicDistanceY, WgUtil.WaveModeDV WaveModeDv, double latticeA, double periodicDistanceX, bool IsShowAbsField, double MinNormalizedFreq, double MaxNormalizedFreq, ref CFieldWorld World, uint FieldValId, uint FieldLoopId, uint FieldForceBcId, IList<uint> FieldPortBcIds, IList<MediaInfo> Medias, Dictionary<uint, wg2d.World.Loop> LoopDic, Dictionary<uint, wg2d.World.Edge> EdgeDic, ref IList<Complex[]> EigenValueList, ref CDrawerArrayField DrawerAry, CCamera Camera) { //long memorySize1 = GC.GetTotalMemory(false); //Console.WriteLine(" total memory: {0}", memorySize1); bool success = false; bool showException = true; try { // 規格化伝搬定数 double beta = 0.0; double betaX = 0.0; double betaY = 0.0; getBeta( ref betaIndex, isTriLattice, calcBetaCnt, latticeA, periodicDistanceX, periodicDistanceY, ref betaX, ref betaY); if (betaIndex == -1) { return success; } System.Diagnostics.Debug.WriteLine("beta: {0} beta*d/(2.0 * pi): {1}", beta, beta * latticeA / (2.0 * pi)); // 全節点数を取得する uint node_cnt = 0; //node_cnt = WgUtilForPeriodicEigenBetaSpecified.GetNodeCnt(World, FieldLoopId); double[][] coord_c_all = null; { uint[] no_c_all_tmp = null; Dictionary<uint, uint> to_no_all_tmp = null; double[][] coord_c_all_tmp = null; WgUtilForPeriodicEigenBetaSpecified.GetLoopCoordList(World, FieldLoopId, out no_c_all_tmp, out to_no_all_tmp, out coord_c_all_tmp); node_cnt = (uint)no_c_all_tmp.Length; // 座標リストを節点番号順に並び替えて格納 coord_c_all = new double[node_cnt][]; for (int ino = 0; ino < node_cnt; ino++) { uint nodeNumber = no_c_all_tmp[ino]; double[] coord = coord_c_all_tmp[ino]; coord_c_all[nodeNumber] = coord; } } System.Diagnostics.Debug.WriteLine("node_cnt: {0}", node_cnt); // 境界の節点リストを取得する uint[] no_c_all_fieldForceBcId = null; Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null; if (FieldForceBcId != 0) { WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out no_c_all_fieldForceBcId, out to_no_boundary_fieldForceBcId); } int boundaryCnt = FieldPortBcIds.Count; IList<uint[]> no_c_all_fieldPortBcId_list = new List<uint[]>(); IList<Dictionary<uint, uint>> to_no_boundary_fieldPortBcId_list = new List<Dictionary<uint, uint>>(); for (int i = 0; i < boundaryCnt; i++) { uint[] work_no_c_all_fieldPortBcId = null; Dictionary<uint, uint> work_to_no_boundary_fieldPortBcId = null; uint work_fieldPortBcId = FieldPortBcIds[i]; WgUtil.GetBoundaryNodeList(World, work_fieldPortBcId, out work_no_c_all_fieldPortBcId, out work_to_no_boundary_fieldPortBcId); no_c_all_fieldPortBcId_list.Add(work_no_c_all_fieldPortBcId); to_no_boundary_fieldPortBcId_list.Add(work_to_no_boundary_fieldPortBcId); } uint[] no_c_all_fieldPortBcId1 = no_c_all_fieldPortBcId_list[0]; uint[] no_c_all_fieldPortBcId2 = no_c_all_fieldPortBcId_list[1]; uint[] no_c_all_fieldPortBcId3 = no_c_all_fieldPortBcId_list[2]; uint[] no_c_all_fieldPortBcId4 = no_c_all_fieldPortBcId_list[3]; uint[] no_c_all_fieldPortBcId5 = null; uint[] no_c_all_fieldPortBcId6 = null; if (boundaryCnt == 6) { no_c_all_fieldPortBcId5 = no_c_all_fieldPortBcId_list[4]; no_c_all_fieldPortBcId6 = no_c_all_fieldPortBcId_list[5]; } Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = to_no_boundary_fieldPortBcId_list[0]; Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = to_no_boundary_fieldPortBcId_list[1]; Dictionary<uint, uint> to_no_boundary_fieldPortBcId3 = to_no_boundary_fieldPortBcId_list[2]; Dictionary<uint, uint> to_no_boundary_fieldPortBcId4 = to_no_boundary_fieldPortBcId_list[3]; Dictionary<uint, uint> to_no_boundary_fieldPortBcId5 = null; Dictionary<uint, uint> to_no_boundary_fieldPortBcId6 = null; if (boundaryCnt == 6) { to_no_boundary_fieldPortBcId5 = to_no_boundary_fieldPortBcId_list[4]; to_no_boundary_fieldPortBcId6 = to_no_boundary_fieldPortBcId_list[5]; } ///////////////////////////////////////////////////////////////// // コーナーの節点 uint[] sharedNodes = new uint[boundaryCnt]; if (boundaryCnt == 6) { // 六角形領域の場合 // 境界の始点 for (int boundaryIndex = 0; boundaryIndex < boundaryCnt; boundaryIndex++) { uint[] work_no_c_all_fieldPortBcId = no_c_all_fieldPortBcId_list[boundaryIndex]; Dictionary<uint, uint> work_to_no_boundary_fieldPortBcId_prev = to_no_boundary_fieldPortBcId_list[(boundaryIndex - 1 + boundaryCnt) % boundaryCnt]; for (int i = 0; i < work_no_c_all_fieldPortBcId.Length; i++) { uint work_nodeNumberPortBc = work_no_c_all_fieldPortBcId[i]; if (work_to_no_boundary_fieldPortBcId_prev.ContainsKey(work_nodeNumberPortBc)) { // 前の境界との共有頂点 sharedNodes[boundaryIndex] = work_nodeNumberPortBc; break; } } } } else { // 四角形領域の場合 System.Diagnostics.Debug.Assert(boundaryCnt == 4); // 境界1の両端 for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++) { uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i]; if (to_no_boundary_fieldPortBcId4.ContainsKey(nodeNumberPortBc1)) { // 境界1と境界4の共有の頂点 // 左上頂点 sharedNodes[0] = nodeNumberPortBc1; } // 境界1と境界3の共有の頂点 if (to_no_boundary_fieldPortBcId3.ContainsKey(nodeNumberPortBc1)) { // 左下頂点 sharedNodes[1] = nodeNumberPortBc1; } } // 境界2の両端 for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++) { // 境界2の節点を追加 uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i]; // 境界2と境界4の共有の頂点 if (to_no_boundary_fieldPortBcId4.ContainsKey(nodeNumberPortBc2)) { // 右上頂点 sharedNodes[2] = nodeNumberPortBc2; } // 境界2と境界3の共有の頂点 if (to_no_boundary_fieldPortBcId3.ContainsKey(nodeNumberPortBc2)) { // 右下頂点 sharedNodes[3] = nodeNumberPortBc2; } } } // 共有境界の節点座標 double[][] sharedNodeCoords = new double[sharedNodes.Length][]; for (int i = 0; i < sharedNodes.Length; i++) { sharedNodeCoords[i] = coord_c_all[sharedNodes[i]]; } ///////////////////////////////////////////////////////////////////////////////// // 節点のソート IList<uint> sortedNodes = new List<uint>(); Dictionary<uint, int> toSorted = new Dictionary<uint, int>(); // 四角形領域の場合 uint boundary_node_cnt_B1 = 0; // 境界1 uint boundary_node_cnt_B3 = 0; // 境界3 uint boundary_node_cnt = 0; // 境界1 + 3 // 六角形領域の場合 uint boundary_node_cnt_each = 0; uint free_node_cnt = 0; uint free_node_cnt0 = 0; // ソートされた節点を取得する if (boundaryCnt == 6) { // 六角形領域の場合 uint work_boundary_node_cnt_B1 = 0; uint work_boundary_node_cnt_B2 = 0; uint work_boundary_node_cnt_B3 = 0; uint work_boundary_node_cnt_B4 = 0; uint work_boundary_node_cnt_B5 = 0; uint work_boundary_node_cnt_B6 = 0; getSortedNodes_Hex( probNo, node_cnt, FieldForceBcId, to_no_boundary_fieldForceBcId, no_c_all_fieldPortBcId_list, to_no_boundary_fieldPortBcId_list, sharedNodes, ref sortedNodes, ref toSorted, ref work_boundary_node_cnt_B1, ref work_boundary_node_cnt_B2, ref work_boundary_node_cnt_B3, ref work_boundary_node_cnt_B4, ref work_boundary_node_cnt_B5, ref work_boundary_node_cnt_B6, ref boundary_node_cnt, ref free_node_cnt, ref free_node_cnt0 ); boundary_node_cnt_each = work_boundary_node_cnt_B1; System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B2 == (boundary_node_cnt_each - 2)); System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B3 == (boundary_node_cnt_each - 2)); System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B4 == (boundary_node_cnt_each - 2)); System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B5 == (boundary_node_cnt_each - 2)); System.Diagnostics.Debug.Assert(work_boundary_node_cnt_B6 == (boundary_node_cnt_each - 2)); } else { // 四角形領域の場合 getSortedNodes_Rect( probNo, node_cnt, FieldForceBcId, to_no_boundary_fieldForceBcId, no_c_all_fieldPortBcId1, no_c_all_fieldPortBcId2, no_c_all_fieldPortBcId3, no_c_all_fieldPortBcId4, to_no_boundary_fieldPortBcId1, to_no_boundary_fieldPortBcId2, to_no_boundary_fieldPortBcId3, to_no_boundary_fieldPortBcId4, sharedNodes, ref sortedNodes, ref toSorted, ref boundary_node_cnt_B1, ref boundary_node_cnt_B3, ref boundary_node_cnt, ref free_node_cnt, ref free_node_cnt0 ); } // バンド構造計算時は、強制境界なし System.Diagnostics.Debug.Assert(FieldForceBcId == 0); System.Diagnostics.Debug.Assert(free_node_cnt0 == node_cnt); // 剛性行列、質量行列を作成 KrdLab.clapack.Complex[] KMat0 = null; KrdLab.clapack.Complex[] MMat0 = null; { KrdLab.clapack.Complex betaForMakingMat = 0.0; betaForMakingMat = 0.0; // 直接Bloch境界条件を指定する場合 WgUtilForPeriodicEigenBetaSpecified.MkPeriodicHelmholtzMat( betaForMakingMat, false, // isYDirectionPeriodic: false World, FieldLoopId, Medias, LoopDic, node_cnt, free_node_cnt0, toSorted, out KMat0, out MMat0); } // ソートされた行列を取得する KrdLab.clapack.Complex[] KMat = null; KrdLab.clapack.Complex[] MMat = null; // 四角形領域 KrdLab.clapack.Complex expAX = 0.0; KrdLab.clapack.Complex expAY = 0.0; // 四角形領域 問題3 KrdLab.clapack.Complex expAY1 = 0.0; KrdLab.clapack.Complex expAY2 = 0.0; // 六角形領域 KrdLab.clapack.Complex expA1 = 0.0; KrdLab.clapack.Complex expA2 = 0.0; KrdLab.clapack.Complex expA3 = 0.0; if (boundaryCnt == 6) { getSortedMatrix_Hex( probNo, periodicDistanceX, periodicDistanceY, betaX, betaY, coord_c_all, sharedNodes, sharedNodeCoords, sortedNodes, toSorted, boundary_node_cnt_each, boundary_node_cnt, free_node_cnt, free_node_cnt0, KMat0, MMat0, out expA1, out expA2, out expA3, out KMat, out MMat ); } else { getSortedMatrix_Rect( probNo, periodicDistanceX, periodicDistanceY, betaX, betaY, no_c_all_fieldPortBcId1, no_c_all_fieldPortBcId3, coord_c_all, sharedNodes, sharedNodeCoords, sortedNodes, toSorted, boundary_node_cnt_B1, boundary_node_cnt_B3, boundary_node_cnt, free_node_cnt, free_node_cnt0, KMat0, MMat0, out expAX, out expAY, out expAY1, out expAY2, out KMat, out MMat ); } // 規格化周波数 KrdLab.clapack.Complex complexNormalizedFreq_ans = 0.0; // 界ベクトルは全節点分作成 KrdLab.clapack.Complex[] resVec = null; resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点 { int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[KMat.Length]; KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[MMat.Length]; for (int i = 0; i < matLen * matLen; i++) { A[i] = KMat[i]; B[i] = MMat[i]; } /* // 一般化複素固有値解析 // [A],[B]は内部で書き換えられるので注意 KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[][] ret_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev"); KrdLab.clapack.FunctionExt.zggev(A, matLen, matLen, B, matLen, matLen, ref ret_evals, ref ret_evecs); evals = ret_evals; System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen]; for (int i = 0; i < ret_evecs.Length; i++) { KrdLab.clapack.Complex[] ret_evec = ret_evecs[i]; for (int j = 0; j < ret_evec.Length; j++) { evecs[i, j] = ret_evec[j]; } } */ // エルミートバンド行列の固有値解析 { KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[,] ret_evecs = null; solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref ret_evals, ref ret_evecs); evals = ret_evals; evecs = ret_evecs; } // 固有値のソート WgUtilForPeriodicEigenBetaSpecified.Sort1DEigenMode(evals, evecs); // 表示用にデータを格納する if (betaIndex == 0) { EigenValueList.Clear(); } Complex[] complexNormalizedFreqList = new Complex[MaxModeCnt]; for (int imode = 0; imode < evals.Length; imode++) { // 固有周波数 KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]); // 規格化周波数 KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi)); if (imode < MaxModeCnt) { System.Diagnostics.Debug.WriteLine("a/λ ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i "); complexNormalizedFreqList[imode] = new Complex(complexNormalizedFreq.Real, complexNormalizedFreq.Imaginary); } } EigenValueList.Add(complexNormalizedFreqList); // 固有ベクトルの格納(1つだけ格納) int tagtModeIndex = 0; KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIndex); for (int ino = 0; ino < evec.Length; ino++) { uint nodeNumber = sortedNodes[ino]; resVec[nodeNumber] = evec[ino]; } } // 従属な節点の界をセットする if (boundaryCnt == 6) { // 六角形 setDependentFieldVal_Hex( probNo, no_c_all_fieldPortBcId1, no_c_all_fieldPortBcId2, no_c_all_fieldPortBcId3, no_c_all_fieldPortBcId4, no_c_all_fieldPortBcId5, no_c_all_fieldPortBcId6, sharedNodes, expA1, expA2, expA3, ref resVec); } else { // 四角形 setDependentFieldVal_Rect( probNo, no_c_all_fieldPortBcId1, no_c_all_fieldPortBcId2, no_c_all_fieldPortBcId3, no_c_all_fieldPortBcId4, sharedNodes, expAX, expAY, expAY1, expAY2, ref resVec); } // 位相調整 KrdLab.clapack.Complex phaseShift = 1.0; double maxAbs = double.MinValue; KrdLab.clapack.Complex fValueAtMaxAbs = 0.0; { for (int ino = 0; ino < resVec.Length; ino++) { KrdLab.clapack.Complex cvalue = resVec[ino]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } } if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { phaseShift = fValueAtMaxAbs / maxAbs; } for (int i = 0; i < resVec.Length; i++) { resVec[i] /= phaseShift; } //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 固有ベクトルの計算結果をワールド座標系にセットする WgUtilForPeriodicEigenBetaSpecified.SetFieldValueForDisplay(World, FieldValId, resVec); // 描画する界の値を加工して置き換える // そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。 // 絶対値を表示したかったので、下記処理を追加しています。 if (IsShowAbsField) { WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 } // DEBUG //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示 //------------------------------------------------------------------ // 描画する界の追加 //------------------------------------------------------------------ DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId)); DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World)); if (initFlg) { // カメラの変換行列初期化 DrawerAry.InitTrans(Camera); // 表示位置調整 setupPanAndScale(probNo, Camera); } success = true; } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); if (showException) { Console.WriteLine(exception.Message + " " + exception.StackTrace); } // 表示用にデータを格納する if (betaIndex == 0) { EigenValueList.Clear(); } Complex[] work_complexNormalizedFreqList = new Complex[MaxModeCnt]; for (int imode = 0; imode < MaxModeCnt; imode++) { work_complexNormalizedFreqList[imode] = new Complex(0.0, 0.0); } EigenValueList.Add(work_complexNormalizedFreqList); DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId)); DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World)); if (initFlg) { // カメラの変換行列初期化 DrawerAry.InitTrans(Camera); // 表示位置調整 setupPanAndScale(probNo, Camera); } } return success; }
public static KrdLab.clapack.Complex[] matrix_Inverse(KrdLab.clapack.Complex[] matA, int n) { System.Diagnostics.Debug.Assert(matA.Length == (n * n)); KrdLab.clapack.Complex[] matA_ = new KrdLab.clapack.Complex[n * n]; matA.CopyTo(matA_, 0); KrdLab.clapack.Complex[] matB_ = new KrdLab.clapack.Complex[n * n]; // 単位行列 for (int i = 0; i < matB_.Length; i++) { matB_[i] = 0.0; } for (int i = 0; i < n; i++) { matB_[i + i * n] = 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); KrdLab.clapack.Complex[] matX = matB_; return matX; }
/// <summary> /// 非対称複素帯行列の連立方程式をclapackで解く /// </summary> /// <param name="Ls"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> private static void solveAsymmetricComplexBandMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId) { // エルミート帯行列の連立方程式をLisys(clapack)で解く CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); uint nblk = femMat.NBlkMatCol(); Complex[] A = new Complex[nblk * nblk]; // ポインタを格納 System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow()); for (uint iblk = 0; iblk < nblk; iblk++) { ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk); System.Diagnostics.Debug.Assert(ptr.Count == 1); A[iblk + nblk * iblk] = new Complex(ptr[0].Real, ptr[0].Imag); //Console.WriteLine(" ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i"); uint npsup = 0; ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup); ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup); System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count); for (int i = 0; i < ptrVal.Count; i++) { A[iblk + nblk * ptrInd[i]] = new Complex(ptrVal[i].Real, ptrVal[i].Imag); //Console.WriteLine(" ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i"); } } // 残差ベクトル CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen()); System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen()); KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk]; for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++) { Complex cvalue = resPtr.GetValue(iblk, 0); B[iblk].Real = cvalue.Real; B[iblk].Imaginary = cvalue.Imag; //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0)); } // 対称行列チェック bool isSymmetrix = true; for (int i = 0; i < nblk; i++) { for (int j = i; j < nblk; j++) { Complex aij = A[i + nblk * j]; Complex aji = A[j + nblk * i]; if (null == aij && null != aji) { isSymmetrix = false; break; } else if (null != aij && null == aji) { isSymmetrix = false; break; } else if (null != aij && null != aji) { if (Math.Abs(aij.Real - aji.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isSymmetrix = false; break; } else if (Math.Abs(aij.Imag - aji.Imag) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { isSymmetrix = false; break; } } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } // 複素バンド行列の線形方程式を解く KrdLab.clapack.Complex[] X = null; { // 非0パターンを作成 bool[,] patternA = new bool[nblk, nblk]; for (int i = 0; i < nblk; i++) { for (int j = 0; j < nblk; j++) { Complex aij = A[i + nblk * j]; patternA[i, j] = (aij != null); } } // バンド行列のバンド幅を縮小する bool[,] optPatternA = new bool[nblk, nblk]; IList<int> optNodesA = null; Dictionary<int, int> toOptNodesA = null; // [A]のバンド幅を縮小する { WgUtilForPeriodicEigenExt.GetOptBandMatNodes(patternA, out optNodesA, out toOptNodesA); for (int i = 0; i < nblk; i++) { int ino_optA = toOptNodesA[i]; for (int j = 0; j < nblk; j++) { int jno_optA = toOptNodesA[j]; optPatternA[ino_optA, jno_optA] = patternA[i, j]; } } } patternA = null; // バンド行列のサイズ取得 int a_rowcolSize; int a_subdiaSize; int a_superdiaSize; WgUtilForPeriodicEigenExt.GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternA, out a_rowcolSize, out a_subdiaSize, out a_superdiaSize); // 扱っている問題ではsubdiagonalとsuperdiagonalは同じサイズ System.Diagnostics.Debug.Assert(a_subdiaSize == a_superdiaSize); // バンド行列作成 int _a_rsize = a_subdiaSize * 2 + a_superdiaSize + 1; int _a_csize = a_rowcolSize; KrdLab.clapack.Complex[] AB = new KrdLab.clapack.Complex[_a_rsize * _a_csize]; // [A]の値を[AB]にコピーする // [A]はバンド幅最適化前の並び、[AB]は最適化後の並び for (int c = 0; c < a_rowcolSize; c++) { int c_org = optNodesA[c]; // 対角成分 Complex a_c_org_c_org = A[c_org + c_org * a_rowcolSize]; if (a_c_org_c_org != null) { AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_c_org_c_org.Real; AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_c_org_c_org.Imag; } // subdiagonal成分 if (c < a_rowcolSize - 1) { for (int r = c + 1; r <= c + a_subdiaSize && r < a_rowcolSize; r++) { int r_org = optNodesA[r]; System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize); System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize)); Complex a_r_c = A[r_org + c_org * a_rowcolSize]; if (a_r_c != null) { AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real; AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag; } } } if (c > 0) { for (int r = c - 1; r >= c - a_superdiaSize && r >= 0; r--) { int r_org = optNodesA[r]; System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize); System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize)); Complex a_r_c = A[r_org + c_org * a_rowcolSize]; if (a_r_c != null) { AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real; AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag; } } } } // 残差ベクトル{B}をoptAにあわせて並び替える KrdLab.clapack.Complex[] optB = new KrdLab.clapack.Complex[nblk]; for (int i = 0; i < nblk; i++) { int ino_optA = toOptNodesA[i]; optB[ino_optA].Real = B[i].Real; optB[ino_optA].Imaginary = B[i].Imaginary; } A = null; B = null; // 解ベクトル KrdLab.clapack.Complex[] optX = null; // 連立方程式[AB]{X} = {B}を解く int x_row = (int)nblk; int x_col = 1; int a_row = a_rowcolSize; int a_col = a_rowcolSize; int kl = a_subdiaSize; int ku = a_superdiaSize; int b_row = (int)nblk; int b_col = 1; System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgbsv"); KrdLab.clapack.FunctionExt.zgbsv(ref optX, ref x_row, ref x_col, AB, a_row, a_col, kl, ku, optB, b_row, b_col); // 解ベクトルを元の並びに戻す X = new KrdLab.clapack.Complex[nblk]; for (int i = 0; i < nblk; i++) { int inoGlobal = optNodesA[i]; X[inoGlobal].Real = optX[i].Real; X[inoGlobal].Imaginary = optX[i].Imaginary; } optX = null; } // 解ベクトルをワールド座標系にセット Complex[] valuesAll = new Complex[nblk]; Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>(); for (uint i = 0; i < nblk; i++) { valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary); toNodeIndex.Add(i, i); } WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex); }
public static KrdLab.clapack.Complex[] product( KrdLab.clapack.Complex[] matA, int a_row, int a_col, KrdLab.clapack.Complex[] matB, int b_row, int b_col) { System.Diagnostics.Debug.Assert(a_col == b_row); int x_row = a_row; int x_col = b_col; KrdLab.clapack.Complex[] matX = new KrdLab.clapack.Complex[x_row * x_col]; for (int i = 0; i < x_row; i++) { for (int j = 0; j < x_col; j++) { matX[i + j * x_row] = 0.0; for (int k = 0; k < a_col; k++) { matX[i + j * x_row] += matA[i + k * a_row] * matB[k + j * b_row]; } } } return matX; }
/// <summary> /// 非対称複素行列の連立方程式をLisys(clapack)で解く /// </summary> /// <param name="Ls"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> private static void solveAsymmetricCompplexMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId) { // 非対称複素行列の連立方程式をLisys(clapack)で解く CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); uint nblk = femMat.NBlkMatCol(); KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[nblk * nblk]; System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow()); for (uint iblk = 0; iblk < nblk; iblk++) { ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk); System.Diagnostics.Debug.Assert(ptr.Count == 1); A[iblk + nblk * iblk].Real = ptr[0].Real; A[iblk + nblk * iblk].Imaginary = ptr[0].Imag; //Console.WriteLine(" ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i"); uint npsup = 0; ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup); ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup); System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count); for (int i = 0; i < ptrVal.Count; i++) { A[iblk + nblk * ptrInd[i]].Real = ptrVal[i].Real; A[iblk + nblk * ptrInd[i]].Imaginary = ptrVal[i].Imag; //Console.WriteLine(" ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i"); } } // 残差ベクトル CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen()); System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen()); KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk]; for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++) { Complex cvalue = resPtr.GetValue(iblk, 0); B[iblk].Real = cvalue.Real; B[iblk].Imaginary = cvalue.Imag; //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0)); } // 対称行列チェック bool isSymmetrix = true; for (int i = 0; i < nblk; i++) { for (int j = i; j < nblk; j++) { KrdLab.clapack.Complex aij = A[i + nblk * j]; KrdLab.clapack.Complex aji = A[j + nblk * i]; if (Math.Abs(aij.Real - aji.Real) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } if (Math.Abs(aij.Imaginary - aji.Imaginary) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } // 非対称行列の線形方程式を解く // 解ベクトル KrdLab.clapack.Complex[] X = null; // 連立方程式AX = Bを解く int x_row = (int)nblk; int x_col = 1; int a_row = (int)nblk; int a_col = (int)nblk; int b_row = (int)nblk; int b_col = 1; System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgesv"); KrdLab.clapack.FunctionExt.zgesv(ref X, ref x_row, ref x_col, A, a_row, a_col, B, b_row, b_col); // 解ベクトルをワールド座標系にセット Complex[] valuesAll = new Complex[nblk]; Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>(); for (uint i = 0; i < nblk; i++) { valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary); toNodeIndex.Add(i, i); } WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex); }
// {x} = ({v})* public static KrdLab.clapack.Complex[] vector_Conjugate(KrdLab.clapack.Complex[] vec) { KrdLab.clapack.Complex[] retVec = new KrdLab.clapack.Complex[vec.Length]; for (int i = 0; i < retVec.Length; i++) { retVec[i] = KrdLab.clapack.Complex.Conjugate(vec[i]); } return retVec; }
/// <summary> /// /// </summary> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="Ls"></param> /// <param name="Prec"></param> /// <param name="tmpBuffer"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> public static bool SolvePCOCG( ref CFieldWorld World, ref uint FieldValId, ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; //------------------------------------------------------------------ // マージの終了 //------------------------------------------------------------------ double res = Ls.FinalizeMarge(); tmpBuffer = null; // マトリクスサイズの取得 // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // マトリクスのサイズ int matLen = (int)mat_cc.NBlkMatCol(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList<uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World); CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World); // 要素の節点数 uint nno = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る es_c_va.GetNodes(ielem, no_c); for (uint inoes = 0; inoes < nno; inoes++) { Complex[] tmpval = null; ns_c_val.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == 1); value_c[inoes] = tmpval[0]; //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" ); } for (uint ino = 0; ino < nno; ino++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Ls = null; Prec.Clear(); Prec.Dispose(); Prec = null; World.Clear(); World.Dispose(); World = null; System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return success; }
/// <summary> /// 同じ固有モード? /// </summary> /// <param name="k0"></param> /// <param name="node_cnt"></param> /// <param name="PrevModalVec"></param> /// <param name="free_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="minNormalizedFreq"></param> /// <param name="maxNormalizedFreq"></param> /// <param name="complexNormalizedFreq"></param> /// <param name="fieldVec"></param> /// <returns></returns> private static bool isSameModeBetaSpecified( uint node_cnt, KrdLab.clapack.Complex[] PrevModalVec, uint free_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, IList<IList<uint>> PCWaveguidePorts, double minNormalizedFreq, double maxNormalizedFreq, KrdLab.clapack.Complex complexNormalizedFreq, KrdLab.clapack.Complex[] fieldVec, out double ret_norm) { bool isHit = false; ret_norm = 0.0; if (complexNormalizedFreq.Real > 0.0 && Math.Abs(complexNormalizedFreq.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { KrdLab.clapack.Complex[] workModalVec1 = new KrdLab.clapack.Complex[node_cnt]; // 前回 KrdLab.clapack.Complex[] workModalVec2 = new KrdLab.clapack.Complex[node_cnt]; // 今回 // 前半の{Φ}のみ取得する for (int ino = 0; ino < free_node_cnt; ino++) { // 今回の固有ベクトル //System.Diagnostics.Debug.WriteLine(" ( " + imode + ", " + ino + " ) = " + evec[ino].Real + " + " + evec[ino].Imaginary + " i "); uint nodeNumber = sortedNodes[ino]; workModalVec2[nodeNumber] = fieldVec[ino]; // 対応する前回の固有ベクトル workModalVec1[nodeNumber] = PrevModalVec[nodeNumber]; } KrdLab.clapack.Complex norm1 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec1), workModalVec1); KrdLab.clapack.Complex norm2 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec2), workModalVec2); for (int i = 0; i < node_cnt; i++) { workModalVec1[i] /= Math.Sqrt(norm1.Magnitude); workModalVec2[i] /= Math.Sqrt(norm2.Magnitude); } KrdLab.clapack.Complex norm12 = MyUtilLib.Matrix.MyMatrixUtil.vector_Dot(MyUtilLib.Matrix.MyMatrixUtil.vector_Conjugate(workModalVec1), workModalVec2); double thLikeMin = 0.9; double thLikeMax = 1.1; if (norm12.Magnitude >= thLikeMin && norm12.Magnitude < thLikeMax) { System.Diagnostics.Debug.WriteLine("norm (prev * current): {0} + {1}i (Abs: {2})", norm12.Real, norm12.Imaginary, norm12.Magnitude); if (complexNormalizedFreq.Real >= minNormalizedFreq && complexNormalizedFreq.Real <= maxNormalizedFreq) { isHit = true; ret_norm = norm12.Magnitude; } else { System.Diagnostics.Debug.WriteLine("skip: a/λ = {0} + {1} i", complexNormalizedFreq.Real, complexNormalizedFreq.Imaginary); } } } return isHit; }
//////////////////////////////////////////////////////////////////////////////////////////////// // DekFEMの処理を隠ぺいした簡易版 //////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// PCOCGで線形方程式を解く /// </summary> /// <param name="mat"></param> /// <param name="resVec"></param> /// <param name="value_c_all"></param> /// <param name="isConverged"></param> /// <returns></returns> //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged) public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged) { bool success = false; int matLen = mat.RowSize; System.Diagnostics.Debug.WriteLine("SolvePCOCG 1"); //------------------------------------------------------------------ // ワールド座標系を生成 //------------------------------------------------------------------ uint baseId = 0; CFieldWorld World = new CFieldWorld(); setupWorld((uint)matLen, ref World, out baseId); // 界の値を扱うバッファ?を生成する。 // フィールド値IDが返却される。 // 要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点 uint FieldValId = World.MakeField_FieldElemDim(baseId, 0, FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER); System.Diagnostics.Debug.WriteLine("SolvePCOCG 2"); //------------------------------------------------------------------ // リニアシステム //------------------------------------------------------------------ CZLinearSystem Ls = new CZLinearSystem(); CZPreconditioner_ILU Prec = new CZPreconditioner_ILU(); //------------------------------------------------------------------ // 界パターン追加 //------------------------------------------------------------------ Ls.AddPattern_Field(FieldValId, World); // POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない // 非対角要素のパターンの追加 { uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); // パターンを追加 using (CIndexedArray crs = new CIndexedArray()) { crs.InitializeSize(mat_cc.NBlkMatCol()); //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow()); using (UIntVectorIndexer index = crs.index) using (UIntVectorIndexer ary = crs.array) { for (int iblk = 0; iblk < (int)crs.Size(); iblk++) { index[iblk] = 0; } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 現在のマトリクスのインデックス設定をコピーする uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); foreach (uint row_index in cur_rows) { ary.Add(row_index); } index[iblk + 1] = (uint)ary.Count; //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup); // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0) // すべての節点に関して列を追加 int ino_global = iblk; int col = iblk; if (col != -1 && ino_global != -1) { // 関連付けられていない節点をその行の列データの最後に追加 int last_index = (int)index[col + 1] - 1; int add_cnt = 0; for (int jno_global = 0; jno_global < node_cnt; jno_global++) { // 行列の0要素を除く //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit) //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15) //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { continue; } uint row = (uint)jno_global; if (ino_global != jno_global) // 対角要素は除く { if (!cur_rows.Contains(row)) { ary.Insert(last_index + 1 + add_cnt, row); add_cnt++; //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row); } } } if (add_cnt > 0) { index[col + 1] = (uint)ary.Count; } } } } crs.Sort(); System.Diagnostics.Debug.Assert(crs.CheckValid()); // パターンを削除する mat_cc.DeletePattern(); // パターンを追加する mat_cc.AddPattern(crs); } } System.Diagnostics.Debug.WriteLine("SolvePCOCG 3"); //------------------------------------------------------------------ // プリコンディショナ― //------------------------------------------------------------------ // set Preconditioner //Prec.SetFillInLevel(1); // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した //Prec.SetFillInLevel(0); // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする //Prec.SetFillInLevel((uint)mat.RowSize); // 完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い //Prec.SetFillInLevel(3); // 誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある //以上から //メインの導波管の計算時間を短くしたいのでフィルインなしにする //Prec.SetFillInLevel(0); // 導波管だとこれで十分 // フィルインレベルの設定(既定値) Prec.SetFillInLevel(DefFillInLevel); // ILU(0)のパターン初期化 Prec.SetLinearSystem(Ls); System.Diagnostics.Debug.WriteLine("SolvePCOCG 4"); //------------------------------------------------------------------ // 剛性行列、残差ベクトルのマージ //------------------------------------------------------------------ Ls.InitializeMarge(); { uint ntmp = Ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } uint node_cnt = (uint)matLen; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World); bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; // 0要素はマージ対象でないので最初から除外する //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit) //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit) KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize]; if (cvalue.Real == 0 && cvalue.Imaginary == 0) { add_flg[i, j] = true; } } } for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++) { // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応) uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); uint colcnt = 1; uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する Complex[] emattmp = new Complex[colcnt * rowcnt]; uint[] no_c_tmp_col = new uint[colcnt]; uint[] no_c_tmp_row = new uint[rowcnt]; no_c_tmp_col[0] = (uint)iblk; no_c_tmp_row[0] = (uint)iblk; for (int irow = 0; irow < cur_rows.Count; irow++) { no_c_tmp_row[irow + 1] = cur_rows[irow]; } { uint ino = 0; uint ino_global = no_c_tmp_col[ino]; for (int jno = 0; jno < rowcnt; jno++) { uint jno_global = no_c_tmp_row[jno]; //emat[ino, jno] if (!add_flg[ino_global, jno_global]) { //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global]; //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize]; KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize]; emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary); add_flg[ino_global, jno_global] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); emattmp[ino * rowcnt + jno] = new Complex(0, 0); } } } // マージ! mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer); } for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } // 残差ベクトルにマージ for (uint ino_global = 0; ino_global < node_cnt; ino_global++) { // 残差ベクトルにマージする uint no_tmp = ino_global; //System.Numerics.Complex cvalue = resVec[ino_global]; KrdLab.clapack.Complex cvalue = resVec[ino_global]; Complex val = new Complex(cvalue.Real, cvalue.Imaginary); res_c.AddValue(no_tmp, 0, val); } } double res = Ls.FinalizeMarge(); //------------------------------------------------------------------ // リニアシステムを解く //------------------------------------------------------------------ System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG"); // プリコンディショナに値を設定してILU分解を行う Prec.SetValue(Ls); //double tol = 1.0e-1; //double tol = 1.0e-2; //double tol = 0.5e-3; //double tol = 1.0e-4; double tol = 1.0e-6; //uint maxIter = 500; //uint maxIter = 1000; //uint maxIter = 2000; //uint maxIter = 5000; //uint maxIter = 10000; uint maxIter = 20000; //uint maxIter = uint.MaxValue; uint iter = maxIter; bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec); System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret); if (iter == maxIter) { System.Diagnostics.Debug.WriteLine("Not converged"); isConverged = false; } else { isConverged = true; } System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6"); //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 計算結果をワールド座標系に反映する Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE); { uint node_cnt = (uint)matLen; //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値 value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値 CField valField = World.GetField(FieldValId); // 要素アレイIDのリストを取得 IList<uint> aIdEA = valField.GetAryIdEA(); // 要素アレイを走査 foreach (uint eaId in aIdEA) { CElemAry ea = World.GetEA(eaId); CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World); CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World); // 要素の節点数 uint nno = 1; //点 // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素節点の値 Complex[] value_c = new Complex[nno]; // 節点の値の節点セグメント CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World); for (uint ielem = 0; ielem < ea.Size(); ielem++) { // 要素配列から要素セグメントの節点番号を取り出す es_c_co.GetNodes(ielem, no_c); // 節点の値を取って来る es_c_va.GetNodes(ielem, no_c); for (uint inoes = 0; inoes < nno; inoes++) { Complex[] tmpval = null; ns_c_val.GetValue(no_c[inoes], out tmpval); System.Diagnostics.Debug.Assert(tmpval.Length == 1); value_c[inoes] = tmpval[0]; //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" ); } for (uint ino = 0; ino < nno; ino++) { //DelFEMの節点番号は0開始 //uint ino_global = no_c[ino] - 1; uint ino_global = no_c[ino]; Complex cvalue = value_c[ino]; //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag); value_c_all[ino_global].Real = cvalue.Real; value_c_all[ino_global].Imaginary = cvalue.Imag; } } } } Ls.Clear(); Ls.Dispose(); Prec.Clear(); Prec.Dispose(); World.Clear(); World.Dispose(); System.Diagnostics.Debug.WriteLine("Solve_PCOCG End"); return success; }
/// <summary> /// 問題を解く /// </summary> /// <param name="probNo"></param> /// <param name="betaIndex"></param> /// <param name="Beta1"></param> /// <param name="Beta2"></param> /// <param name="BetaDelta"></param> /// <param name="initFlg"></param> /// <param name="WaveguideWidth"></param> /// <param name="WaveModeDv"></param> /// <param name="IsPCWaveguide"></param> /// <param name="latticeA"></param> /// <param name="periodicDistance"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="CalcModeIndex"></param> /// <param name="isSVEA"></param> /// <param name="PrevModalVec"></param> /// <param name="IsShowAbsField"></param> /// <param name="MinNormalizedFreq"></param> /// <param name="MaxNormalizedFreq"></param> /// <param name="World"></param> /// <param name="FieldValId"></param> /// <param name="FieldLoopId"></param> /// <param name="FieldForceBcId"></param> /// <param name="FieldPortBcId1"></param> /// <param name="FieldPortBcId2"></param> /// <param name="Medias"></param> /// <param name="LoopDic"></param> /// <param name="EdgeDic"></param> /// <param name="EigenValueList"></param> /// <param name="DrawerAry"></param> /// <param name="Camera"></param> /// <returns></returns> private static bool solveProblem( int probNo, ref int betaIndex, double Beta1, double Beta2, double BetaDelta, bool initFlg, double WaveguideWidth, WgUtil.WaveModeDV WaveModeDv, bool IsPCWaveguide, double latticeA, double periodicDistance, IList<IList<uint>> PCWaveguidePorts, int CalcModeIndex, bool isSVEA, ref KrdLab.clapack.Complex[] PrevModalVec, bool IsShowAbsField, double MinNormalizedFreq, double MaxNormalizedFreq, ref CFieldWorld World, uint FieldValId, uint FieldLoopId, uint FieldForceBcId, uint FieldPortBcId1, uint FieldPortBcId2, IList<MediaInfo> Medias, Dictionary<uint, wg2d.World.Loop> LoopDic, Dictionary<uint, wg2d.World.Edge> EdgeDic, ref IList<Complex> EigenValueList, ref CDrawerArrayField DrawerAry, CCamera Camera) { //long memorySize1 = GC.GetTotalMemory(false); //Console.WriteLine(" total memory: {0}", memorySize1); bool success = false; bool showException = true; try { // 緩慢変化包絡線近似 SVEA(slowly varying envelope approximation)で表現? // true: v = v(x, y)exp(-jβx)と置いた場合 // false: 直接Bloch境界条件を指定する場合 //bool isSVEA = false; // falseの時の方が妥当な解が得られる //bool isSVEA = false; // モード追跡する? bool isModeTrace = true; if (!IsPCWaveguide) { isModeTrace = false; } System.Diagnostics.Debug.WriteLine("isSVEA: {0}", isSVEA); System.Diagnostics.Debug.WriteLine("isModeTrace: {0}, CalcModeIndex: {1}", isModeTrace, CalcModeIndex); if (betaIndex == 0) { PrevModalVec = null; } // 規格化伝搬定数 double beta = getBeta( ref betaIndex, Beta1, Beta2, BetaDelta); if (betaIndex == -1) { return success; } System.Diagnostics.Debug.WriteLine("beta: {0} beta*d/(2.0 * pi): {1}", beta, beta * periodicDistance / (2.0 * pi)); if (probNo == 3) { /* // probNo == 3 theta = 45 defectRodCnt = 3 even 1st if (beta < 0.32 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } */ /* // probNo == 3 theta = 60 defectRodCnt = 1 r = 0.30 even if (beta < 0.20 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } */ /* // probNo == 3 theta = 30 defectRodCnt = 1 r = 0.30 n = 3.4 even if (beta < 0.08 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.92 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // probNo == 3 theta = 60 defectRodCnt = 1 r = 0.35 even if (beta < 0.08 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.92 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 even 1st if (beta < 0.16 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } */ /* // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 even 2nd if (beta > 0.39 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // probNo == 3 theta = 30 defectRodCnt = 3 r = 0.28 odd 2nd if (beta > 0.20 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ if (beta < 0.10 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } } else if (probNo == 5) { /* // for latticeTheta = 60 r = 0.30a n = 3.4 air hole even 1st above decoupling point // for latticeTheta = 60 r = 0.30a n = 3.4 air hole odd 1st above decoupling point if (beta < 0.13 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.2501 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // for latticeTheta = 60 r = 0.30a air hole n = 3.4 even 1st below decoupling point // for latticeTheta = 60 r = 0.30a air hole n = 3.4 odd 1st below decoupling point if (beta < 0.2501 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.4801 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // for latticeTheta = 60 r = 0.30a n = 2.76 air hole even 1st above & below decoupling point if (beta < 0.1601 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.4801 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ /* // for latticeTheta = 60 r = 0.30a n = 2.76 air hole odd 1st above decoupling point if (beta < 0.1601 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.2601 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } */ // for latticeTheta = 60 r = 0.30a air hole n = 2.76 even 1st below decoupling point // for latticeTheta = 60 r = 0.30a air hole n = 2.76 odd 1st below decoupling point if (beta < 0.2601 * (2.0 * pi / periodicDistance)) { showException = false; throw new Exception(); } if (beta > 0.4801 * (2.0 * pi / periodicDistance)) { betaIndex = -1; return success; } } // 全節点数を取得する uint node_cnt = 0; node_cnt = WgUtilForPeriodicEigenBetaSpecified.GetNodeCnt(World, FieldLoopId); System.Diagnostics.Debug.WriteLine("node_cnt: {0}", node_cnt); // 境界の節点リストを取得する uint[] no_c_all_fieldForceBcId = null; Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null; if (FieldForceBcId != 0) { WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out no_c_all_fieldForceBcId, out to_no_boundary_fieldForceBcId); } uint[] no_c_all_fieldPortBcId1 = null; Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = null; WgUtil.GetBoundaryNodeList(World, FieldPortBcId1, out no_c_all_fieldPortBcId1, out to_no_boundary_fieldPortBcId1); uint[] no_c_all_fieldPortBcId2 = null; Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = null; WgUtil.GetBoundaryNodeList(World, FieldPortBcId2, out no_c_all_fieldPortBcId2, out to_no_boundary_fieldPortBcId2); // 節点のソート IList<uint> sortedNodes = new List<uint>(); Dictionary<uint, int> toSorted = new Dictionary<uint, int>(); // 境界1と境界2は周期構造条件より同じ界の値をとる // ポート境界1 for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++) { // 境界1の節点を追加 uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i]; if (FieldForceBcId != 0) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc1)) continue; } sortedNodes.Add(nodeNumberPortBc1); int nodeIndex = sortedNodes.Count - 1; toSorted.Add(nodeNumberPortBc1, nodeIndex); } uint boundary_node_cnt = (uint)sortedNodes.Count; // 境界1 // 内部領域 for (uint nodeNumber = 0; nodeNumber < node_cnt; nodeNumber++) { // 追加済み節点はスキップ //if (toSorted.ContainsKey(nodeNumber)) continue; // 境界1は除く if (to_no_boundary_fieldPortBcId1.ContainsKey(nodeNumber)) continue; // 境界2は除く if (to_no_boundary_fieldPortBcId2.ContainsKey(nodeNumber)) continue; if (FieldForceBcId != 0) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumber)) continue; } sortedNodes.Add(nodeNumber); toSorted.Add(nodeNumber, sortedNodes.Count - 1); } uint free_node_cnt = (uint)sortedNodes.Count; // 境界1 + 内部領域 for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++) { // 境界2の節点を追加 uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i]; if (FieldForceBcId != 0) { // 強制境界を除く if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc2)) continue; } sortedNodes.Add(nodeNumberPortBc2); int nodeIndex = sortedNodes.Count - 1; toSorted.Add(nodeNumberPortBc2, nodeIndex); } uint free_node_cnt0 = (uint)sortedNodes.Count; // 境界1 + 内部領域 + 境界2 // 剛性行列、質量行列を作成 KrdLab.clapack.Complex[] KMat0 = null; KrdLab.clapack.Complex[] MMat0 = null; { KrdLab.clapack.Complex betaForMakingMat = 0.0; if (isSVEA) { betaForMakingMat = new KrdLab.clapack.Complex(beta, 0.0); // v = v(x, y)exp(-jβx)と置いた場合 } else { betaForMakingMat = 0.0; // 直接Bloch境界条件を指定する場合 } WgUtilForPeriodicEigenBetaSpecified.MkPeriodicHelmholtzMat( betaForMakingMat, false, // isYDirectionPeriodic: false World, FieldLoopId, Medias, LoopDic, node_cnt, free_node_cnt0, toSorted, out KMat0, out MMat0); } // 境界2の節点は境界1の節点と同一とみなす // 境界上の分割が同じであることが前提条件 KrdLab.clapack.Complex[] KMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; KrdLab.clapack.Complex[] MMat = new KrdLab.clapack.Complex[free_node_cnt * free_node_cnt]; /* // v = v(x, y)exp(-jβx)と置いた場合 for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j]; } } for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { KMat[i + free_node_cnt * j] += KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; MMat[i + free_node_cnt * j] += MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; } } for (int i = 0; i < boundary_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j]; } for (int j = 0; j < boundary_node_cnt; j++) { KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; } } */ // 直接Bloch境界条件を指定する場合 KrdLab.clapack.Complex expA = 1.0; if (isSVEA) { expA = 1.0; } else { expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * beta * periodicDistance); } for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j]; } } for (int i = 0; i < free_node_cnt; i++) { for (int j = 0; j < boundary_node_cnt; j++) { KMat[i + free_node_cnt * j] += expA * KMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; MMat[i + free_node_cnt * j] += expA * MMat0[i + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; } } for (int i = 0; i < boundary_node_cnt; i++) { for (int j = 0; j < free_node_cnt; j++) { KMat[i + free_node_cnt * j] += (1.0 / expA) * KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j]; MMat[i + free_node_cnt * j] += (1.0 / expA) * MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * j]; } for (int j = 0; j < boundary_node_cnt; j++) { //KMat[i + free_node_cnt * j] += (1.0 / expA) * expA * KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; //MMat[i + free_node_cnt * j] += (1.0 / expA) * expA * MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; //より下記と等価 KMat[i + free_node_cnt * j] += KMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; MMat[i + free_node_cnt * j] += MMat0[(free_node_cnt + boundary_node_cnt - 1 - i) + free_node_cnt0 * (free_node_cnt + boundary_node_cnt - 1 - j)]; } } // 規格化周波数 KrdLab.clapack.Complex complexNormalizedFreq_ans = 0.0; // 界ベクトルは全節点分作成 KrdLab.clapack.Complex[] resVec = null; resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点 { int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[KMat.Length]; KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[MMat.Length]; for (int i = 0; i < matLen * matLen; i++) { A[i] = KMat[i]; B[i] = MMat[i]; } /* // 一般化複素固有値解析 // [A],[B]は内部で書き換えられるので注意 KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[][] ret_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.zggev"); KrdLab.clapack.FunctionExt.zggev(A, matLen, matLen, B, matLen, matLen, ref ret_evals, ref ret_evecs); evals = ret_evals; System.Diagnostics.Debug.Assert(ret_evals.Length == ret_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_evecs.Length, matLen]; for (int i = 0; i < ret_evecs.Length; i++) { KrdLab.clapack.Complex[] ret_evec = ret_evecs[i]; for (int j = 0; j < ret_evec.Length; j++) { evecs[i, j] = ret_evec[j]; } } */ // エルミートバンド行列の固有値解析 { KrdLab.clapack.Complex[] ret_evals = null; KrdLab.clapack.Complex[,] ret_evecs = null; solveHermitianBandMatGeneralizedEigen(matLen, A, B, ref ret_evals, ref ret_evecs); evals = ret_evals; evecs = ret_evecs; } // 固有値のソート WgUtilForPeriodicEigenBetaSpecified.Sort1DEigenMode(evals, evecs); /* // check for (int imode = 0; imode < evals.Length; imode++) { // 固有周波数 KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]); // 規格化周波数 KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi)); System.Diagnostics.Debug.WriteLine("a/λ ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i "); } */ // 欠陥モードを取得 IList<int> defectModeIndexList = new List<int>(); // フォトニック結晶導波路解析用 if (IsPCWaveguide) { int hitModeIndex = -1; double hitNorm = 0.0; for (int imode = 0; imode < evals.Length; imode++) { // 固有周波数 KrdLab.clapack.Complex complex_k0_eigen = KrdLab.clapack.Complex.Sqrt(evals[imode]); // 規格化周波数 KrdLab.clapack.Complex complexNormalizedFreq = latticeA * (complex_k0_eigen / (2.0 * pi)); // 界ベクトル KrdLab.clapack.Complex[] fieldVec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, imode); // フォトニック結晶導波路の導波モードを判定する System.Diagnostics.Debug.Assert(free_node_cnt == fieldVec.Length); bool isHitDefectMode = isDefectModeBetaSpecified( free_node_cnt, sortedNodes, toSorted, PCWaveguidePorts, MinNormalizedFreq, MaxNormalizedFreq, complexNormalizedFreq, fieldVec); if (isHitDefectMode && isModeTrace && PrevModalVec != null) { // 同じ固有モード? double ret_norm = 0.0; bool isHitSameMode = isSameModeBetaSpecified( node_cnt, PrevModalVec, free_node_cnt, sortedNodes, toSorted, PCWaveguidePorts, MinNormalizedFreq, MaxNormalizedFreq, complexNormalizedFreq, fieldVec, out ret_norm); if (isHitSameMode) { // より分布の近いモードを採用する if (Math.Abs(ret_norm - 1.0) < Math.Abs(hitNorm - 1.0)) { hitModeIndex = imode; hitNorm = ret_norm; System.Diagnostics.Debug.WriteLine("PC defectMode(ModeTrace): a/λ ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i "); } } } if (isHitDefectMode) { System.Diagnostics.Debug.WriteLine("PC defectMode: a/λ ( " + imode + " ) = " + complexNormalizedFreq.Real + " + " + complexNormalizedFreq.Imaginary + " i "); if (!isModeTrace || PrevModalVec == null) // モード追跡でないとき、またはモード追跡用の参照固有モードベクトルがないとき { defectModeIndexList.Add(imode); } } } if (isModeTrace && hitModeIndex != -1) { System.Diagnostics.Debug.Assert(defectModeIndexList.Count == 0); System.Diagnostics.Debug.WriteLine("hitModeIndex: {0}", hitModeIndex); defectModeIndexList.Add(hitModeIndex); } } // 基本モードを取得する(k0^2最小値) int tagtModeIndex = 0; // フォトニック結晶導波路解析用 if (IsPCWaveguide) { tagtModeIndex = -1; if (isModeTrace && PrevModalVec != null) { if (defectModeIndexList.Count > 0) { tagtModeIndex = defectModeIndexList[0]; } } else { if (defectModeIndexList.Count > 0) { if ((defectModeIndexList.Count - 1) >= CalcModeIndex) { tagtModeIndex = defectModeIndexList[CalcModeIndex]; } else { tagtModeIndex = -1; } } else { tagtModeIndex = -1; System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not converged photonic crystal waveguide mode"); } } } if (tagtModeIndex == -1) { System.Diagnostics.Debug.WriteLine("!!!!!!!!! Not found mode"); complexNormalizedFreq_ans = 0; for (int i = 0; i < resVec.Length; i++) { resVec[i] = 0; } } else { // 伝搬定数、固有ベクトルの格納 KrdLab.clapack.Complex complex_k0_eigen_ans = KrdLab.clapack.Complex.Sqrt(evals[tagtModeIndex]); complexNormalizedFreq_ans = latticeA * (complex_k0_eigen_ans / (2.0 * pi)); KrdLab.clapack.Complex[] evec = MyUtilLib.Matrix.MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIndex); System.Diagnostics.Debug.WriteLine("a/λ ( " + tagtModeIndex + " ) = " + complexNormalizedFreq_ans.Real + " + " + complexNormalizedFreq_ans.Imaginary + " i "); for (int ino = 0; ino < evec.Length; ino++) { //System.Diagnostics.Debug.WriteLine(" ( " + imode + ", " + ino + " ) = " + evec[ino].Real + " + " + evec[ino].Imaginary + " i "); uint nodeNumber = sortedNodes[ino]; resVec[nodeNumber] = evec[ino]; } } } // ポート境界1の節点の値を境界2にも格納する for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++) { // 境界1の節点 uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i]; // 境界1の節点の界の値を取得 KrdLab.clapack.Complex cvalue = resVec[nodeNumberPortBc1]; // 境界2の節点 uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[no_c_all_fieldPortBcId2.Length - 1 - i]; //resVec[nodeNumberPortBc2] = cvalue; // v = v(x, y)exp(-jβx)と置いた場合 resVec[nodeNumberPortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合 } // 位相調整 KrdLab.clapack.Complex phaseShift = 1.0; double maxAbs = double.MinValue; KrdLab.clapack.Complex fValueAtMaxAbs = 0.0; { /* for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++) { uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino]; KrdLab.clapack.Complex cvalue = resVec[ino]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } */ for (int ino = 0; ino < resVec.Length; ino++) { KrdLab.clapack.Complex cvalue = resVec[ino]; 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; } // 前回の固有ベクトルを更新 if (isModeTrace && complexNormalizedFreq_ans.Real != 0.0 && Math.Abs(complexNormalizedFreq_ans.Imaginary) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { //PrevModalVec = resVec; PrevModalVec = new KrdLab.clapack.Complex[node_cnt]; resVec.CopyTo(PrevModalVec, 0); } else { // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように) //PrevModalVec = null; } //------------------------------------------------------------------ // 計算結果の後処理 //------------------------------------------------------------------ // 固有ベクトルの計算結果をワールド座標系にセットする WgUtilForPeriodicEigenBetaSpecified.SetFieldValueForDisplay(World, FieldValId, resVec); // 表示用にデータを格納する if (betaIndex == 0) { EigenValueList.Clear(); } // 表示用加工 Complex evalueToShow = new Complex(complexNormalizedFreq_ans.Real, complexNormalizedFreq_ans.Imaginary); EigenValueList.Add(evalueToShow); // 描画する界の値を加工して置き換える // そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。 // 絶対値を表示したかったので、下記処理を追加しています。 if (IsShowAbsField) { WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 } // DEBUG //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示 //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示 //------------------------------------------------------------------ // 描画する界の追加 //------------------------------------------------------------------ DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId)); DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World)); if (initFlg) { // カメラの変換行列初期化 DrawerAry.InitTrans(Camera); // 表示位置調整 setupPanAndScale(probNo, Camera); } success = true; } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); if (showException) { Console.WriteLine(exception.Message + " " + exception.StackTrace); } // 表示用にデータを格納する if (betaIndex == 0) { EigenValueList.Clear(); } EigenValueList.Add(new Complex(0.0, 0.0)); DrawerAry.Clear(); DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId)); DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World)); if (initFlg) { // カメラの変換行列初期化 DrawerAry.InitTrans(Camera); // 表示位置調整 setupPanAndScale(probNo, Camera); } } return success; }
/// <summary> /// 周期構造導波路固有値問題を2次一般化固有値問題→標準固有値問題として解く(実行列として解く)(緩慢変化包絡線近似用) /// </summary> /// <param name="k0"></param> /// <param name="KMat"></param> /// <param name="CMat"></param> /// <param name="MMat"></param> /// <param name="node_cnt"></param> /// <param name="free_node_cnt"></param> /// <param name="boundary_node_cnt"></param> /// <param name="sortedNodes"></param> /// <param name="toSorted"></param> /// <param name="to_no_all"></param> /// <param name="to_no_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="betamToSolveList"></param> /// <param name="resVecList"></param> private static void solveAsQuadraticGeneralizedEigenToStandardWithRealMat( int incidentModeIndex, double k0, double[] KMat, double[] CMat, double[] MMat, uint node_cnt, uint free_node_cnt, uint boundary_node_cnt, IList<uint> sortedNodes, Dictionary<uint, int> toSorted, Dictionary<uint, uint> to_no_all, Dictionary<uint, uint> to_no_boundary_fieldPortBcId1, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, double betaNormalizingFactor, out KrdLab.clapack.Complex[] betamToSolveList, out KrdLab.clapack.Complex[][] resVecList) { betamToSolveList = null; resVecList = null; // 非線形固有値問題 // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ= - jβとおくと // [K] + λ[C] + λ^2[M]{Φ}= {0} // // Lisys(Lapack)による固有値解析 // マトリクスサイズは、強制境界及び境界3を除いたサイズ int matLen = (int)free_node_cnt; KrdLab.clapack.Complex[] evals = null; KrdLab.clapack.Complex[,] evecs = null; // [M]の逆行列が存在する緩慢変化包絡線近似の場合のみ有効な方法 // Φを直接解く場合は使えない System.Diagnostics.Debug.WriteLine("calc [M]-1"); // [M]の逆行列を求める double[] invMMat = MyUtilLib.Matrix.MyMatrixUtil.matrix_Inverse(MMat, matLen); System.Diagnostics.Debug.WriteLine("calc [M]-1[K]"); // [M]-1[K] double[] invMKMat = MyUtilLib.Matrix.MyMatrixUtil.product(invMMat, matLen, matLen, KMat, matLen, matLen); System.Diagnostics.Debug.WriteLine("calc [M]-1[C]"); // [M]-1[C] double[] invMCMat = MyUtilLib.Matrix.MyMatrixUtil.product(invMMat, matLen, matLen, CMat, matLen, matLen); // 標準固有値解析(実行列として解く) double[] A = new double[(matLen * 2) * (matLen * 2)]; System.Diagnostics.Debug.WriteLine("set [A]"); for (int i = 0; i < matLen; i++) { for (int j = 0; j < matLen; j++) { A[i + j * (matLen * 2)] = 0.0; A[i + (j + matLen) * (matLen * 2)] = (i == j) ? 1.0 : 0.0; // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合 //A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen]; //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen]; // λ = -j(β/k0)と置いた場合 //A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen] / (k0 * k0); //A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen] / (k0); // λ = -j(β/betaNormalizingFactor)と置いた場合 A[(i + matLen) + j * (matLen * 2)] = -1.0 * invMKMat[i + j * matLen] / (betaNormalizingFactor * betaNormalizingFactor); A[(i + matLen) + (j + matLen) * (matLen * 2)] = -1.0 * invMCMat[i + j * matLen] / (betaNormalizingFactor); } } double[] ret_r_evals = null; double[] ret_i_evals = null; double[][] ret_r_evecs = null; double[][] ret_i_evecs = null; System.Diagnostics.Debug.WriteLine("KrdLab.clapack.FunctionExt.dgeev"); KrdLab.clapack.FunctionExt.dgeev(A, (matLen * 2), (matLen * 2), ref ret_r_evals, ref ret_i_evals, ref ret_r_evecs, ref ret_i_evecs); evals = new KrdLab.clapack.Complex[ret_r_evals.Length]; // βを格納 for (int i = 0; i < ret_r_evals.Length; i++) { KrdLab.clapack.Complex eval = new KrdLab.clapack.Complex(ret_r_evals[i], ret_i_evals[i]); // { [K] - jβ[C] - β^2[M] }{Φ}= {0} // λ = -jβと置いた場合(β = jλ) //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne; // λ = -j(β/k0)と置いた場合 //evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * k0; // λ = -j(β/betaNormalizingFactor)と置いた場合 evals[i] = eval * KrdLab.clapack.Complex.ImaginaryOne * betaNormalizingFactor; } System.Diagnostics.Debug.Assert(ret_r_evals.Length == ret_r_evecs.Length); // 2次元配列に格納する evecs = new KrdLab.clapack.Complex[ret_r_evecs.Length, (matLen * 2)]; for (int i = 0; i < ret_r_evecs.Length; i++) { double[] ret_r_evec = ret_r_evecs[i]; double[] ret_i_evec = ret_i_evecs[i]; for (int j = 0; j < ret_r_evec.Length; j++) { evecs[i, j] = new KrdLab.clapack.Complex(ret_r_evec[j], ret_i_evec[j]); } } // 固有値をソートする System.Diagnostics.Debug.Assert(evecs.GetLength(1) == free_node_cnt * 2); GetSortedModes( incidentModeIndex, k0, node_cnt, free_node_cnt, boundary_node_cnt, sortedNodes, toSorted, to_no_all, IsPCWaveguide, PCWaveguidePorts, isModeTrace, ref PrevModalVec, minBeta, maxBeta, evals, evecs, true, // isDebugShow out betamToSolveList, out resVecList); }