/// <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> /// 周期構造導波路固有値問題を一般化固有値問題として解く(反復計算) (緩慢変化包絡線近似用) /// </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_boundary_fieldPortBcId1"></param> /// <param name="IsPCWaveguide"></param> /// <param name="PCWaveguidePorts"></param> /// <param name="IsCalcSecondMode"></param> /// <param name="betamToSolve"></param> /// <param name="resVec"></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_boundary_fieldPortBcId1, bool IsPCWaveguide, IList<IList<uint>> PCWaveguidePorts, bool IsCalcSecondMode, bool isModeTrace, ref KrdLab.clapack.Complex[] PrevModalVec, double minBeta, double maxBeta, ref KrdLab.clapack.Complex betamToSolve, out KrdLab.clapack.Complex[] resVec) { //初期値は引数で与える //betamToSolve = 0.0; resVec = new KrdLab.clapack.Complex[node_cnt]; //全節点 //const bool isSVEA = true; //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); betamToSolve = 0.0; 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, 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; for (int i = 0; i < resVec.Length; i++) { resVec[i] = 0; } 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; for (int i = 0; i < resVec.Length; i++) { resVec[i] = 0; } break; } // 伝搬定数、固有ベクトルの格納 // 収束判定用に前の伝搬定数を退避 KrdLab.clapack.Complex prevBetam = betamToSolve; // 伝搬定数 betamToSolve = work_betamToSolveList[tagtModeIndex]; // 固有ベクトル 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 = resVec; PrevModalVec = new KrdLab.clapack.Complex[node_cnt]; resVec.CopyTo(PrevModalVec, 0); } else { // クリアしない(特定周波数で固有値が求まらないときがある。その場合でも同じモードを追跡できるように) //PrevModalVec = null; } }