/// <summary> /// ヘルムホルツ方程式のパラメータP,Qを取得する /// </summary> /// <param name="k0">波数</param> /// <param name="media">媒質</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">波のモード区分</param> /// <param name="media_P">ヘルムホルツ方程式のパラメータP</param> /// <param name="media_Q">ヘルムホルツ方程式のパラメータQ</param> public static void GetHelmholtzMediaPQ( double k0, MediaInfo media, WaveModeDV WaveModeDv, out double[,] media_P, out double[,] media_Q) { media_P = null; media_Q = null; double[,] erMat = media.Q; double[,] urMat = media.P; // 平行平板導波路の場合 if (WaveModeDv == FemSolver.WaveModeDV.TE) { // TEモード(H面) // 界方程式: Ez(H面に垂直な電界) // p = (μr)-1 // q = εr //media_P = urMat; //media_Q = erMat; //// [p]は逆数をとる //media_P = MyMatrixUtil.matrix_Inverse(media_P); // 比透磁率の逆数 media_P = new double[3, 3]; media_P[0, 0] = 1.0 / urMat[0, 0]; media_P[1, 1] = 1.0 / urMat[1, 1]; media_P[2, 2] = 1.0 / urMat[2, 2]; // 比誘電率 media_Q = new double[3, 3]; media_Q[0, 0] = erMat[0, 0]; media_Q[1, 1] = erMat[1, 1]; media_Q[2, 2] = erMat[2, 2]; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { // TMモード(TEMモードを含む)(H面) // 界方程式: Hz(H面に垂直な磁界) // p = (εr)-1 // q = μr //media_P = erMat; //media_Q = urMat; //// [p]は逆数をとる //media_P = MyMatrixUtil.matrix_Inverse(media_P); // 比誘電率の逆数 media_P = new double[3, 3]; media_P[0, 0] = 1.0 / erMat[0, 0]; media_P[1, 1] = 1.0 / erMat[1, 1]; media_P[2, 2] = 1.0 / erMat[2, 2]; // 比透磁率 media_Q = new double[3, 3]; media_Q[0, 0] = urMat[0, 0]; media_Q[1, 1] = urMat[1, 1]; media_Q[2, 2] = urMat[2, 2]; } else { System.Diagnostics.Debug.Assert(false); } }
/// <summary> /// 入力データ読み込み /// </summary> /// <param name="filename"></param> public void Load(string filename) { // 入力データ初期化 init(); IList<FemNode> nodes = null; IList<FemElement> elements = null; IList<IList<int>> ports = null; IList<int> forceBCNodes = null; IList<IList<uint>> elemNoPeriodicList = null; IList<IList<IList<int>>> nodePeriodicBList = null; IList<IList<int>> defectNodePeriodicList = null; int incidentPortNo = 1; MediaInfo[] medias = null; double firstWaveLength = 0.0; double lastWaveLength = 0.0; int calcCnt = 0; WaveModeDV waveModeDv = WaveModeDV.TE; bool ret = FemInputDatFile.LoadFromFile( filename, out nodes, out elements, out ports, out forceBCNodes, out elemNoPeriodicList, out nodePeriodicBList, out defectNodePeriodicList, out incidentPortNo, out medias, out firstWaveLength, out lastWaveLength, out calcCnt, out waveModeDv); if (ret) { System.Diagnostics.Debug.Assert(medias.Length == Medias.Length); Nodes = nodes; Elements = elements; Ports = ports; ForceBCNodes = forceBCNodes; ElemNoPeriodicList = elemNoPeriodicList; NodePeriodicBList = nodePeriodicBList; DefectNodePeriodicList = defectNodePeriodicList; IncidentPortNo = incidentPortNo; Medias = medias; FirstWaveLength = firstWaveLength; LastWaveLength = lastWaveLength; CalcFreqCnt = calcCnt; WaveModeDv = waveModeDv; // 要素形状と次数の判定 if (Elements.Count > 0) { Constants.FemElementShapeDV elemShapeDv; int order; int vertexCnt; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(Elements[0].NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt); ElemShapeDvToBeSet = elemShapeDv; ElemOrderToBeSet = order; } { // H面の場合および平行平板導波路の場合 if ((BoundaryDv == BoundaryDV.ElectricWall && WaveModeDv == WaveModeDV.TM) // TMモード磁界Hz(H面に垂直な磁界)による解析では電気壁は自然境界 || (BoundaryDv == BoundaryDV.MagneticWall && WaveModeDv == WaveModeDV.TE) // TEST ) { // 自然境界条件なので強制境界をクリアする ForceBCNodes.Clear(); } } // 強制境界節点番号ハッシュの作成(2D節点番号) foreach (int nodeNumber in ForceBCNodes) { if (!ForceNodeNumberH.ContainsKey(nodeNumber)) { ForceNodeNumberH[nodeNumber] = true; } } // 辺と要素の対応マップ作成 MkEdgeToElementNoH(Elements, ref EdgeToElementNoH); // 導波管幅の決定 setupWaveguideWidth(); if (CalcFreqCnt == 0) { // 旧型式のデータの可能性があるので既定値をセットする(ファイル読み込みエラーにはなっていないので) FirstWaveLength = GetWaveLengthFromNormalizedFreq(Constants.DefNormalizedFreqRange[0], WaveguideWidth, LatticeA); LastWaveLength = GetWaveLengthFromNormalizedFreq(Constants.DefNormalizedFreqRange[1], WaveguideWidth, LatticeA); CalcFreqCnt = Constants.DefCalcFreqencyPointCount; } } }
private const bool DefIsSVEA = true; // Φ = φ(x, y) exp(-jβx) と置く方法 #endregion Fields #region Methods /// <summary> /// 周期構造導波路開口境界条件 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param> /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="isInputPort">入射ポート?</param> /// <param name="incidentModeIndex">入射モードのインデックス</param> /// <param name="isFreeBc">境界条件を課さない?</param> /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> public static bool AddLinSys_PeriodicWaveguidePortBC( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldInputWgLoopId, uint fieldPortBcId1, uint[] fixedBcNodes, bool isInputPort, int incidentModeIndex, Complex[] amps, bool isFreeBc, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs) { if (!world.IsIdField(fieldInputWgLoopId)) { return false; } // フィールドを取得 CField valField = world.GetField(fieldInputWgLoopId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 境界上のすべての節点番号を取り出す res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary); if (!res) { return false; } // 境界条件をリニアシステムに設定する uint ntmp = ls.GetTmpBufferSize(); int[] tmpBuffer = new int[ntmp]; for (int i = 0; i < ntmp; i++) { tmpBuffer[i] = -1; } res = addLinSys_PeriodicWaveguidePortBC_Core( ls, waveLength, waveModeDv, periodicDistance, world, fieldPortBcId1, isInputPort, incidentModeIndex, amps, isFreeBc, ryy_1d, eigen_values, eigen_vecs, eigen_dFdXs, no_c_all, ref tmpBuffer); if (!res) { return false; } return true; }
/// <summary> /// 入力データの初期化 /// </summary> private void init() { IsCalcAborted = false; Nodes.Clear(); Elements.Clear(); foreach (IList<int> portNodes in Ports) { portNodes.Clear(); } Ports.Clear(); ForceBCNodes.Clear(); ForceNodeNumberH.Clear(); ElemNoPeriodicList.Clear(); NodePeriodicBList.Clear(); DefectNodePeriodicList.Clear(); IncidentPortNo = 1; Color[] workColorList = { CadLogic.VacumnBackColor, CadLogic.RodBackColor }; for (int i = 0; i < Medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = workColorList[i]; Medias[i] = media; } EdgeToElementNoH.Clear(); //WaveguideWidth = 0.0; WaveguideWidth = DefWaveguideWidth; // 規格化周波数が定義できるように初期値を設定 FirstWaveLength = 0.0; LastWaveLength = 0.0; CalcFreqCnt = 0; WaveModeDv = Constants.DefWaveModeDv; BoundaryDv = BoundaryDV.ElectricWall; ElemShapeDvToBeSet = Constants.DefElemShapeDv; ElemOrderToBeSet = Constants.DefElementOrder; }
/// <summary> /// 周期構造導波路開口固有値解析(FEM行列と固有モードの取得) /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param> /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param> /// <param name="fieldInputWgBcId1">フィールド値ID(周期構造領域の境界2=内部側境界)</param> /// <param name="fixedBcNodes">強制境界節点配列</param> /// <param name="IsPCWaveguide">フォトニック結晶導波路?</param> /// <param name="PCWaveguidePorts">フォトニック結晶導波路のポート(ロッド欠陥部分)の節点のリスト</param> /// <param name="medias">媒質リスト</param> /// <param name="inputWgLoopDic1">周期構造領域のワールド座標系ループ→ループ情報マップ</param> /// <param name="inputWgEdgeDic1">周期構造領域のワールド座標系辺→辺情報マップ</param> /// <param name="isPortBc2Reverse">境界2の方向が境界1と逆方向?</param> /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> public static bool GetPortPeriodicWaveguideFemMatAndEigenVec( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, CFieldWorld world, uint fieldInputWgLoopId, uint fieldPortBcId1, uint fieldInputWgBcId1, uint[] fixedBcNodes, bool IsPCWaveguide, double latticeA, double periodicDistance, IList<IList<uint>> PCWaveguidePorts, int incidentModeIndex, bool isSolveEigenItr, int propModeCntToSolve, bool isSVEA, bool isModeTrace, ref KrdLab.clapack.Complex[][] PrevModalVecList, double minBeta, double maxBeta, double minWaveNum, double maxWaveNum, IList<MediaInfo> medias, Dictionary<uint, wg2d.World.Loop> inputWgLoopDic1, Dictionary<uint, World.Edge> inputWgEdgeDic1, bool isPortBc2Reverse, out double[,] ryy_1d, out Complex[] eigen_values, out Complex[,] eigen_vecs, out Complex[,] eigen_dFdXs) { ryy_1d = null; eigen_values = null; eigen_vecs = null; eigen_dFdXs = null; if (!world.IsIdField(fieldInputWgLoopId)) { return false; } // フィールドを取得 CField valField = world.GetField(fieldInputWgLoopId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return false; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 節点座標 double[,] coord_c_all = null; // 導波管の幅取得 double[] coord_c_first = null; double[] coord_c_last = null; double waveguideWidth = 0; res = WgUtil.getRectangleWaveguideStructInfo(world, fieldPortBcId1, out coord_c_first, out coord_c_last, out waveguideWidth); if (!res) { return false; } // Y方向に周期構造? bool isYDirectionPeriodic = false; if (Math.Abs(coord_c_first[1] - coord_c_last[1]) < 1.0e-12) { isYDirectionPeriodic = true; } // 回転移動 double[] rotOrigin = null; double rotAngle = 0.0; // ラジアン if (!isYDirectionPeriodic) { // 境界の傾きから回転角度を算出する if (Math.Abs(coord_c_first[0] - coord_c_last[0]) >= 1.0e-12) { // X軸からの回転角 rotAngle = Math.Atan2((coord_c_last[1] - coord_c_first[1]), (coord_c_last[0] - coord_c_first[0])); // Y軸からの回転角に変換 (境界はY軸に平行、X方向周期構造) rotAngle = rotAngle - 0.5 * pi; rotOrigin = coord_c_first; System.Diagnostics.Debug.WriteLine("rotAngle: {0} rotOrigin:{1} {2}", rotAngle * 180.0 / pi, rotOrigin[0], rotOrigin[1]); } } // 境界上のすべての節点番号を取り出す res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary); if (!res) { return false; } // 境界積分用ryy_1dを取得する // 周期境界1について取得する res = getPortWaveguideFemMat( waveLength, world, fieldPortBcId1, fixedBcNodes, coord_c_first, waveguideWidth, no_c_all, to_no_boundary, medias, inputWgEdgeDic1, out ryy_1d, out coord_c_all); if (!res) { return false; } // 周期構造導波路の固有値、固有ベクトルを取得する // 固有ベクトルは境界上のみを取得する //uint max_mode = 1; uint max_mode = int.MaxValue; res = solvePortPeriodicWaveguideEigen( ls, waveLength, waveModeDv, isYDirectionPeriodic, rotAngle, rotOrigin, world, fieldInputWgLoopId, fieldPortBcId1, fieldInputWgBcId1, fixedBcNodes, IsPCWaveguide, latticeA, periodicDistance, PCWaveguidePorts, incidentModeIndex, isSolveEigenItr, propModeCntToSolve, isSVEA, max_mode, isModeTrace, ref PrevModalVecList, minBeta, maxBeta, minWaveNum, maxWaveNum, medias, inputWgLoopDic1, inputWgEdgeDic1, isPortBc2Reverse, ryy_1d, out eigen_values, out eigen_vecs, out eigen_dFdXs); if (!res) { return false; } return true; }
/// <summary> /// 矩形導波管開口反射(透過)係数 /// ※要素アレイは1つに限定しています。 /// ポート境界を指定するときに複数の辺をリストで境界条件設定することでこの条件をクリアできます。 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="fieldValId">フィールド値のID</param> /// <param name="imode">固有モードのモード次数</param> /// <param name="isIncidentMode">入射モード?</param> /// <param name="ryy_1d">[ryy]FEM行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns>散乱係数</returns> public static Complex GetPeriodicWaveguidePortReflectionCoef( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldValId, uint imode, bool isIncidentMode, Complex[] amps, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs) { Complex s11 = new Complex(0.0, 0.0); if (ryy_1d == null || eigen_values == null || eigen_vecs == null) { return s11; } if (!world.IsIdField(fieldValId)) { return s11; } CField valField = world.GetField(fieldValId); if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR) { return s11; } bool res; //境界節点番号→全体節点番号変換テーブル(no_c_all) uint[] no_c_all = null; // 全体節点番号→境界節点番号変換テーブル(to_no_boundary Dictionary<uint, uint> to_no_boundary = null; // 境界上のすべての節点番号を取り出す res = GetBoundaryNodeList(world, fieldValId, out no_c_all, out to_no_boundary); if (!res) { return s11; } // 境界上のすべての節点の界の値を取り出す Complex[] value_c_all = null; res = WgUtil.GetBoundaryFieldValueList(world, fieldValId, no_c_all, to_no_boundary, out value_c_all); if (!res) { return s11; } uint node_cnt = (uint)no_c_all.Length; System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(0)); System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(1)); System.Diagnostics.Debug.Assert(node_cnt == eigen_vecs.GetLength(1)); s11 = getPeriodicWaveguidePortReflectionCoef_Core( waveLength, waveModeDv, periodicDistance, imode, isIncidentMode, amps, no_c_all, to_no_boundary, value_c_all, ryy_1d, eigen_values, eigen_vecs, eigen_dFdXs); return s11; }
/// <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> /// 矩形導波管開口反射(透過)係数(要素アレイ単位) /// Note: 境界の要素はy = 0からy = waveguideWidth へ順番に要素アレイに格納され、節点2は次の要素の節点1となっていることが前提です。 /// </summary> /// <param name="waveLength">波長</param> /// <param name="imode">モード次数</param> /// <param name="isIncidentMode">入射ポート?</param> /// <param name="no_c_all">節点番号配列</param> /// <param name="to_no_boundary">節点番号→境界節点番号マップ</param> /// <param name="value_c_all">フィールド値配列</param> /// <param name="ryy_1d">FEM[ryy]行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <returns></returns> private static Complex getPeriodicWaveguidePortReflectionCoef_Core( double waveLength, WaveModeDV waveModeDv, double periodicDistance, uint imode, bool isIncidentMode, Complex[] amps, uint[] no_c_all, Dictionary<uint, uint> to_no_boundary, Complex[] value_c_all, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs) { double k0 = 2.0 * pi / waveLength; double omega = k0 * c0; Complex s11 = new Complex(0.0, 0.0); //uint node_cnt = (uint)ryy_1d.GetLength(0); //uint max_mode = (uint)eigen_values.Length; Complex betam = eigen_values[imode]; Complex imagOne = new Complex(0.0, 1.0); // {tmp_vec}*t = {fm}*t[ryy]*t // {tmp_vec}* = [ryy]* {fm}* // ([ryy]*)t = [ryy]* // [ryy]が実数のときは、[ryy]* -->[ryy] Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dFdXVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < fmVec_Modify.Length; ino++) { //fmVec_Modify[ino] = fmVec[ino] - dFdXVec[ino] / (imagOne * betam); fmVec_Modify[ino] = fmVec[ino] - dFdXVec[ino] / (imagOne * betam_periodic); } //Complex[] tmp_vec = MyMatrixUtil.product(MyMatrixUtil.matrix_ConjugateTranspose(ryy_1d), MyMatrixUtil.vector_Conjugate(fmVec)); // ryyが実数のとき //Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); // s11 = {tmp_vec}t {value_all} s11 = MyMatrixUtil.vector_Dot(tmp_vec, value_c_all); if (waveModeDv == WaveModeDV.TM) { // TMモード //s11 *= (Complex.Norm(betam) / (omega * eps0)); s11 *= ((Complex.Norm(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * eps0)); if (isIncidentMode) { if (amps != null) { s11 += -1.0 * amps[imode]; } else { s11 += -1.0; } } } else { // TEモード //s11 *= (Complex.Norm(betam) / (omega * myu0)); s11 *= ((Complex.Norm(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * myu0)); if (isIncidentMode) { if (amps != null) { s11 += -1.0 * amps[imode]; } else { s11 += -1.0; } } } return s11; }
/// <summary> /// 矩形導波管開口境界条件(要素アレイ単位) /// Note: 境界の要素はy = 0からy = waveguideWidth へ順番に要素アレイに格納され、節点2は次の要素の節点1となっていることが前提 /// </summary> /// <param name="ls">リニアシステム</param> /// <param name="waveLength">波長</param> /// <param name="world">ワールド座標系</param> /// <param name="fieldValId">フィールド値ID</param> /// <param name="isInputPort">入射ポート?</param> /// <param name="incidentModeIndex">入射モードのインデックス</param> /// <param name="isFreeBc">境界条件を課さない?</param> /// <param name="ryy_1d">FEM[ryy]行列</param> /// <param name="eigen_values">固有値配列</param> /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param> /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param> /// <param name="no_c_all">節点番号配列</param> /// <param name="tmpBuffer">一時バッファ</param> /// <returns></returns> private static bool addLinSys_PeriodicWaveguidePortBC_Core( CZLinearSystem ls, double waveLength, WaveModeDV waveModeDv, double periodicDistance, CFieldWorld world, uint fieldValId, bool isInputPort, int incidentModeIndex, Complex[] amps, bool isFreeBc, double[,] ryy_1d, Complex[] eigen_values, Complex[,] eigen_vecs, Complex[,] eigen_dFdXs, uint[] no_c_all, ref int[] tmpBuffer) { double k0 = 2.0 * pi / waveLength; double omega = k0 / Math.Sqrt(myu0 * eps0); //System.Diagnostics.Debug.Assert(world.IsIdEA(eaId)); //CElemAry ea = world.GetEA(eaId); //System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE); if (!world.IsIdField(fieldValId)) { return false; } CField valField = world.GetField(fieldValId); //CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world); //CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world); // 境界上の節点数(1次線要素を想定) uint node_cnt = (uint)ryy_1d.GetLength(0); // 考慮するモード数 uint max_mode = (uint)eigen_values.Length; // 全体剛性行列の作成 Complex[,] mat_all = new Complex[node_cnt, node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { mat_all[ino_boundary, jno_boundary] = new Complex(0.0, 0.0); } } if (!isFreeBc) { for (uint imode = 0; imode < max_mode; imode++) { Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); //Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { Complex cvalue = 0.0; if (waveModeDv == WaveModeDV.TM) { // TMモード //cvalue = (imagOne / (omega * eps0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary]; cvalue = (imagOne / (omega * eps0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary]; } else { // TEモード //cvalue = (imagOne / (omega * myu0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary]; cvalue = (imagOne / (omega * myu0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary]; } mat_all[ino_boundary, jno_boundary] += cvalue; } } } // check 対称行列 bool isSymmetrix = true; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { for (uint jno_boundary = ino_boundary; jno_boundary < node_cnt; jno_boundary++) { if (Math.Abs(mat_all[ino_boundary, jno_boundary].Real - mat_all[jno_boundary, ino_boundary].Real) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } if (Math.Abs(mat_all[ino_boundary, jno_boundary].Imag - mat_all[jno_boundary, ino_boundary].Imag) >= 1.0e-12) { isSymmetrix = false; break; //System.Diagnostics.Debug.Assert(false); } } if (!isSymmetrix) { break; } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } //MyMatrixUtil.printMatrix("emat_all", emat_all); } // 残差ベクトルの作成 Complex[] res_c_all = new Complex[node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { res_c_all[ino_boundary] = 0.0; } if (isInputPort && incidentModeIndex < eigen_values.Length) { if (amps != null) { // 全モードを入射させる for (uint imode = 0; imode < max_mode; imode++) { Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // TEモード、TMモード共通 //Complex cvalue = 2.0 * imagOne * betam * veci[ino_boundary] * amList[imode]; Complex cvalue = 2.0 * imagOne * betam_periodic * veci[ino_boundary] * amps[imode]; res_c_all[ino_boundary] += cvalue; } } } else { uint imode = (uint)incidentModeIndex; Complex betam = eigen_values[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex imagOne = new Complex(0.0, 1.0); DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam); fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic); } //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // TEモード、TMモード共通 //res_c_all[ino_boundary] = 2.0 * imagOne * betam * veci[ino_boundary]; res_c_all[ino_boundary] = 2.0 * imagOne * betam_periodic * veci[ino_boundary]; } } } //MyMatrixUtil.printVec("eres_c_all", eres_c_all); // 線要素の節点数 uint nno = 2; // 座標の次元 //uint ndim = 2; // 要素節点の全体節点番号 uint[] no_c = new uint[nno]; // 要素剛性行列(コーナ-コーナー) CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world); // 要素残差ベクトル(コーナー) CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world); //System.Diagnostics.Debug.WriteLine("fieldValId: {0}", fieldValId); //System.Diagnostics.Debug.WriteLine("NBlkMatCol:" + mat_cc.NBlkMatCol()); // (境界でなく領域の総節点数と同じ?) if (!isFreeBc) { // 要素剛性行列にマージ // この定式化では行列のスパース性は失われている(隣接していない要素の節点間にも関連がある) // 要素剛性行列にマージする bool[,] add_flg = new bool[node_cnt, node_cnt]; for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { add_flg[i, j] = false; } } // このケースではmat_ccへのマージは対角行列でマージしなければならないようです。 // 1 x node_cntの横ベクトルでマージしようとするとassertに引っかかります。 // 境界上の節点に関しては非0要素はないので、境界上の節点に関する // node_cnt x node_cntの行列を一括でマージできます。 // col, rowの全体節点番号ベクトル uint[] no_c_tmp = new uint[node_cnt]; // 要素行列(ここでは境界の剛性行列を一括でマージします) Complex[] emattmp = new Complex[node_cnt * node_cnt]; for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // colブロックのインデックス(全体行列の節点番号) uint iblk = no_c_all[ino_boundary]; uint npsup = 0; ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup); //System.Diagnostics.Debug.WriteLine("chk3:{0} {1}", iblk, npsup); for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++) { if (ino_boundary != jno_boundary) { uint rowno = no_c_all[jno_boundary]; if (cur_rows.IndexOf(rowno) == -1) { System.Diagnostics.Debug.Assert(false); return false; } } if (!add_flg[ino_boundary, jno_boundary]) { // 要素行列を作成 Complex cvalue = mat_all[ino_boundary, jno_boundary]; //emattmp[ino_boundary, jno_boundary] emattmp[ino_boundary * node_cnt + jno_boundary] = cvalue; add_flg[ino_boundary, jno_boundary] = true; } else { // ここにはこない System.Diagnostics.Debug.Assert(false); //emattmp[ino_boundary, jno_boundary] emattmp[ino_boundary * node_cnt + jno_boundary] = new Complex(0, 0); } } no_c_tmp[ino_boundary] = iblk; } // 一括マージ mat_cc.Mearge(node_cnt, no_c_tmp, node_cnt, no_c_tmp, 1, emattmp, ref tmpBuffer); for (int i = 0; i < node_cnt; i++) { for (int j = 0; j < node_cnt; j++) { //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] ); System.Diagnostics.Debug.Assert(add_flg[i, j]); } } } // 残差ベクトルにマージ for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++) { // 残差ベクトルにマージする uint no_tmp = no_c_all[ino_boundary]; Complex val = res_c_all[ino_boundary]; res_c.AddValue(no_tmp, 0, val); } return true; }