/// <summary> /// コンストラクタ /// </summary> /// <param name="normalizedFreq1">計算開始規格化周波数</param> /// <param name="normalizedFreq2">計算終了規格化周波数</param> /// <param name="calcFreqCnt">計算点数</param> /// <param name="waveModeDv">モード区分</param> /// <param name="elemShapeDv">要素形状区分</param> /// <param name="elemOrder">要素次数</param> public CalcSettingFrm(double normalizedFreq1, double normalizedFreq2, int calcFreqCnt, FemSolver.WaveModeDV waveModeDv, Constants.FemElementShapeDV elemShapeDv, int elemOrder) { InitializeComponent(); DialogResult = DialogResult.None; // フィールドに格納 NormalizedFreq1 = normalizedFreq1; NormalizedFreq2 = normalizedFreq2; CalcFreqCnt = calcFreqCnt; WaveModeDv = waveModeDv; ElemShapeDv = elemShapeDv; ElemOrder = elemOrder; if (CalcFreqCnt == 0) { // 既定値を設定 NormalizedFreq1 = Constants.DefNormalizedFreqRange[0]; NormalizedFreq2 = Constants.DefNormalizedFreqRange[1]; CalcFreqCnt = Constants.DefCalcFreqencyPointCount; } // GUIにセット // 計算範囲 textBoxMinFreq.Text = string.Format("{0:F5}", NormalizedFreq1); textBoxMaxFreq.Text = string.Format("{0:F5}", NormalizedFreq2); double delta = (NormalizedFreq2 - NormalizedFreq1) / CalcFreqCnt; textBoxDeltaFreq.Text = string.Format("{0:F5}", delta); // 計算モード RadioBtnModeDvs = new RadioButton[]{ radioBtnWaveModeDvTE, radioBtnWaveModeDvTM }; FemSolver.WaveModeDV[] waveModeDvOf_radioBtnModeDvs = { FemSolver.WaveModeDV.TE, FemSolver.WaveModeDV.TM }; for (int i = 0; i < RadioBtnModeDvs.Length; i++) { RadioBtnModeDvs[i].Tag = waveModeDvOf_radioBtnModeDvs[i]; if ((FemSolver.WaveModeDV)RadioBtnModeDvs[i].Tag == WaveModeDv) { RadioBtnModeDvs[i].Checked = true; } } // 要素形状・次数 ElemShapeStruct[] esList = { new ElemShapeStruct(Constants.FemElementShapeDV.Triangle, Constants.SecondOrder, "2次三角形要素"), new ElemShapeStruct(Constants.FemElementShapeDV.Triangle, Constants.FirstOrder, "1次三角形要素"), }; foreach (ElemShapeStruct es in esList) { cboxElemShapeDv.Items.Add(es); if (es.ElemShapeDv == ElemShapeDv && es.Order == ElemOrder) { cboxElemShapeDv.SelectedItem = es; } } }
/// <summary> /// ポート固有値解析 /// </summary> public static void SolvePortWaveguideEigen( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, int maxModeSpecified, IList<FemNode> Nodes, Dictionary<string, IList<int>> EdgeToElementNoH, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, IList<int> portNodes, IList<uint> portElemNoPeriodic, IList<IList<int>> portNodePeriodicB, IList<int> defectNodePeriodic, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d, out Complex[] eigenValues, out Complex[,] eigenVecsB1, out Complex[,] eigen_dFdXsB1, out IList<int> nodePeriodic, out Dictionary<int, int> toNodePeriodic, out IList<double[]> coordsPeriodic, out KrdLab.clapack.Complex[][] eigenVecsPeriodic ) { // ポート境界上 nodesBoundary = null; ryy_1d = null; eigenValues = null; eigenVecsB1 = null; eigen_dFdXsB1 = null; // ポート周期構造領域 nodePeriodic = null; toNodePeriodic = null; coordsPeriodic = null; eigenVecsPeriodic = null; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; getPortFemMat1D( WaveModeDv, waveLength, latticeA, Nodes, EdgeToElementNoH, Elements, Medias, ForceNodeNumberH, portNodes, out nodesBoundary, out ryy_1d ); Dictionary<int, int> toNodesB = new Dictionary<int, int>(); for (int ino = 0; ino < nodesBoundary.Length; ino++) { int nodeNumber = nodesBoundary[ino]; //System.Diagnostics.Debug.WriteLine("nodesBoundary[{0}] = {1}", ino, nodesBoundary[ino]); toNodesB.Add(nodeNumber, ino); } ////////////////////////////////////////////////////////////////////////////// // 周期構造導波路 ///////////////////////////////////////////////////////////////////////////// int incidentModeIndex = 0; Constants.FemElementShapeDV elemShapeDv; FemElement workElement = Elements[0]; int order; int vertexCnt; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(workElement.NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt); // 領域の節点リスト、座標リストを取得する //IList<int> nodePeriodic = null; //Dictionary<int, int> toNodePeriodic = null; //IList<double[]> coordsPeriodic = null; getCoordListPeriodic( Nodes, Elements, portElemNoPeriodic, out nodePeriodic, out toNodePeriodic, out coordsPeriodic ); // 全節点数 int nodeCntPeriodic = nodePeriodic.Count; IList<IList<int>> nodePeriodicB = portNodePeriodicB; IList<int> nodePeriodicB1 = nodePeriodicB[0]; IList<int> nodePeriodicB2 = nodePeriodicB[1]; Dictionary<int, int> toNodePeriodicB1 = new Dictionary<int, int>(); Dictionary<int, int> toNodePeriodicB2 = new Dictionary<int, int>(); for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { int nodeNumber = nodePeriodicB1[ino]; toNodePeriodicB1.Add(nodeNumber, ino); } for (int ino = 0; ino < nodePeriodicB2.Count; ino++) { int nodeNumber = nodePeriodicB2[ino]; toNodePeriodicB2.Add(nodeNumber, ino); } // Y方向に周期構造? bool isYDirectionPeriodic = false; { int nodeNumber_first = nodePeriodicB1[0]; int nodeNumber_last = nodePeriodicB1[nodePeriodicB1.Count - 1]; int noB_first = toNodePeriodic[nodeNumber_first]; int noB_last = toNodePeriodic[nodeNumber_last]; double[] coord_first = coordsPeriodic[noB_first]; double[] coord_last = coordsPeriodic[noB_last]; if (Math.Abs(coord_first[1] - coord_last[1]) < 1.0e-12) { isYDirectionPeriodic = true; } } System.Diagnostics.Debug.WriteLine("isYDirectionPeriodic: {0}", isYDirectionPeriodic); // 節点の並び替え IList<int> sortedNodesPeriodic = new List<int>(); Dictionary<int, int> toSortedPeriodic = new Dictionary<int, int>(); // ポート境界1 for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点番号 int nodeNumberB1 = nodePeriodicB1[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumberB1)) { // 強制境界は除外 continue; } sortedNodesPeriodic.Add(nodeNumberB1); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumberB1, index); } int nodeCntBPeriodic = sortedNodesPeriodic.Count; // 境界1 // 内部領域 for (int ino = 0; ino < nodeCntPeriodic; ino++) { int nodeNumber = nodePeriodic[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumber)) { // 強制境界は除外 continue; } if (toNodePeriodicB1.ContainsKey(nodeNumber)) { // 境界1は除外 continue; } if (toNodePeriodicB2.ContainsKey(nodeNumber)) { // 境界2は除外 continue; } sortedNodesPeriodic.Add(nodeNumber); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumber, index); } int freeNodeCntPeriodic = sortedNodesPeriodic.Count; // 境界1 + 内部領域 // ポート境界2 for (int ino = 0; ino < nodePeriodicB2.Count; ino++) { // 境界2の節点番号 int nodeNumberB2 = nodePeriodicB2[ino]; if (ForceNodeNumberH.ContainsKey(nodeNumberB2)) { // 強制境界は除外 continue; } sortedNodesPeriodic.Add(nodeNumberB2); int index = sortedNodesPeriodic.Count - 1; toSortedPeriodic.Add(nodeNumberB2, index); } int freeNodeCntPeriodic_0 = sortedNodesPeriodic.Count; // 境界1 + 内部領域 + 境界2 // 周期構造導波路固有値問題用FEM行列の作成 //bool isSVEA = false; // Φを直接解く方法 bool isSVEA = true; // Φ= φexp(-jβx)と置く方法(SVEA) double[] KMat0 = null; double[] CMat0 = null; double[] MMat0 = null; if (isSVEA) { // Φ = φexp(-jβx)と置く方法 KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; CMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; MMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; } else { // Φを直接解く方法 KMat0 = new double[freeNodeCntPeriodic_0 * freeNodeCntPeriodic_0]; CMat0 = null; MMat0 = null; } IList<uint> elemNoPeriodic = portElemNoPeriodic; int elemCnt = elemNoPeriodic.Count; for (int ie = 0; ie < elemCnt; ie++) { int elemNo = (int)elemNoPeriodic[ie]; FemElement femElement = Elements[elemNo - 1]; System.Diagnostics.Debug.Assert(femElement.No == elemNo); if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder) { // 2次三角形要素 FemMat_Tri_Second.AddElementMatPeriodic( isYDirectionPeriodic, isSVEA, waveLength, nodeCntPeriodic, freeNodeCntPeriodic_0, toSortedPeriodic, femElement, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref KMat0, ref CMat0, ref MMat0); } else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder) { // 1次三角形要素 FemMat_Tri_First.AddElementMatPeriodic( isYDirectionPeriodic, isSVEA, waveLength, nodeCntPeriodic, freeNodeCntPeriodic_0, toSortedPeriodic, femElement, Nodes, Medias, ForceNodeNumberH, WaveModeDv, ref KMat0, ref CMat0, ref MMat0); } else { System.Diagnostics.Debug.Assert(false); } } double periodicDistance = latticeA; // 正方格子誘電体ロッド限定 bool isModeTrace = false; KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null; double minBeta = 0.00; // 正方格子誘電体ロッド限定 //double maxBeta = 0.90; // 正方格子誘電体ロッド限定 double maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0; bool isPortBc2Reverse = false; // 伝搬定数 KrdLab.clapack.Complex[] betamToSolveList = null; // 界ベクトルは全節点分作成 KrdLab.clapack.Complex[][] resVecList = null; if (isSVEA) { System.Diagnostics.Debug.Assert(isSVEA == true); solveSVEAAsQuadraticGeneralizedEigenToStandardWithRealMat( incidentModeIndex, k0, KMat0, CMat0, MMat0, isPortBc2Reverse, nodeCntPeriodic, freeNodeCntPeriodic_0, freeNodeCntPeriodic, nodeCntBPeriodic, sortedNodesPeriodic, toSortedPeriodic, toNodePeriodic, toNodePeriodicB1, defectNodePeriodic, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, k0, //(2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } else { System.Diagnostics.Debug.Assert(isSVEA == false); solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat( incidentModeIndex, periodicDistance, k0, KMat0, isPortBc2Reverse, nodeCntPeriodic, freeNodeCntPeriodic_0, freeNodeCntPeriodic, nodeCntBPeriodic, sortedNodesPeriodic, toSortedPeriodic, toNodePeriodic, toNodePeriodicB1, coordsPeriodic, defectNodePeriodic, isModeTrace, ref tmpPrevModalVec_1stMode, minBeta, maxBeta, (2.0 * pi / periodicDistance), //k0, //1.0, out betamToSolveList, out resVecList); } // 固有値が1つでも取得できているかチェック if (betamToSolveList == null) { System.Diagnostics.Debug.WriteLine("betamToSolveList == null"); //System.Diagnostics.Debug.Assert(false); return; } for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resVec = resVecList[imode]; // ポート境界1の節点の値を境界2にも格納する for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点 int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; // 境界1の節点の界の値を取得 KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino; int nodeNumberPortBc2 = nodePeriodicB2[ino_B2]; int ino_InLoop_PortBc2 = toNodePeriodic[nodeNumberPortBc2]; if (isSVEA) { // 緩慢変化包絡線近似の場合は、Φ2 = Φ1 resVec[ino_InLoop_PortBc2] = cvalue; } else { // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1 KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance); resVec[ino_InLoop_PortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合 } } } ///////////////////////////////////////////////////////////////////////////////////// // 位相調整 for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex phaseShift = 1.0; double maxAbs = double.MinValue; KrdLab.clapack.Complex fValueAtMaxAbs = 0.0; { /* // 境界上で位相調整する for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } */ // 領域全体で位相調整する for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++) { KrdLab.clapack.Complex cvalue = resVec[ino_InLoop]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } } if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { phaseShift = fValueAtMaxAbs / maxAbs; } System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi); for (int i = 0; i < resVec.Length; i++) { resVec[i] /= phaseShift; } } ///////////////////////////////////////////////////////////////////////////////////// // X方向の微分値を取得する KrdLab.clapack.Complex[][] resDFDXVecList = new KrdLab.clapack.Complex[betamToSolveList.Length][]; for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = null; KrdLab.clapack.Complex[] resDFDYVec = null; double rotAngle = 0.0; // 暫定 double[] rotOrigin = null; // 暫定 if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.SecondOrder) { // 2次三角形要素 getDFDXValues_Tri_SecondOrder( WaveModeDv, k0, rotAngle, rotOrigin, Nodes, Elements, Medias, ForceNodeNumberH, elemNoPeriodic, nodePeriodicB, toNodePeriodic, resVec, out resDFDXVec, out resDFDYVec); } else if (elemShapeDv == Constants.FemElementShapeDV.Triangle && order == Constants.FirstOrder) { // 1次三角形要素 getDFDXValues_Tri_FirstOrder( WaveModeDv, k0, rotAngle, rotOrigin, Nodes, Elements, Medias, ForceNodeNumberH, elemNoPeriodic, nodePeriodicB, toNodePeriodic, resVec, out resDFDXVec, out resDFDYVec); } else { System.Diagnostics.Debug.Assert(false); } if (isYDirectionPeriodic) { // Y方向周期構造の場合 resDFDXVecList[imode] = resDFDYVec; } else { // X方向周期構造の場合 resDFDXVecList[imode] = resDFDXVec; } } // 境界1と境界2の節点の微分値は同じという条件を弱形式で課している為、微分値は同じにならない。 // 加えて、getDFDXValuesは内部節点からの寄与を片側のみしか計算していない。 // →境界の両側からの寄与を考慮する為に境界1の微分値と境界2の微分値を平均してみる for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; // ポート境界1の節点の微分値、ポート境界2の微分値は、両者の平均をとる for (int ino = 0; ino < nodePeriodicB1.Count; ino++) { // 境界1の節点 int nodeNumberPortBc1 = nodePeriodicB1[ino]; int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; // 境界1の節点の界の微分値値を取得 KrdLab.clapack.Complex cdFdXValue1 = resDFDXVec[ino_InLoop_PortBc1]; // 境界2の節点 int ino_B2 = isPortBc2Reverse ? (int)(nodePeriodicB2.Count - 1 - ino) : (int)ino; int nodeNumberPortBc2 = nodePeriodicB2[ino_B2]; int ino_InLoop_PortBc2 = toNodePeriodic[nodeNumberPortBc2]; // 境界2の節点の界の微分値値を取得 KrdLab.clapack.Complex cdFdXValue2 = resDFDXVec[ino_InLoop_PortBc2]; // 平均値を計算し、境界の微分値として再格納する if (isSVEA) { KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2) * 0.5; resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue; resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue; } else { // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1 KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance); // Φ2から逆算でΦ1を求め、平均をとる KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2 / expA) * 0.5; resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue; resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue * expA; } } } ////////////////////////////////////////////////////////////////////////////////////// if (!isSVEA) { // 緩慢変化包絡線近似でない場合は、緩慢変化包絡線近似の分布に変換する for (int imode = 0; imode < betamToSolveList.Length; imode++) { KrdLab.clapack.Complex betam = betamToSolveList[imode]; KrdLab.clapack.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; System.Diagnostics.Debug.Assert(resVec.Length == coordsPeriodic.Count); int nodeNumber1st = sortedNodesPeriodic[0]; int ino_InLoop_1st = toNodePeriodic[nodeNumber1st]; double[] coord1st = coordsPeriodic[ino_InLoop_1st]; for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++) { // 節点の界の値 KrdLab.clapack.Complex fieldVal = resVec[ino_InLoop]; // 節点の界の微分値 KrdLab.clapack.Complex dFdXVal = resDFDXVec[ino_InLoop]; // 節点の座標 double[] coord = coordsPeriodic[ino_InLoop]; double x_pt = 0.0; if (isYDirectionPeriodic) { x_pt = (coord[1] - coord1st[1]); } else { x_pt = (coord[0] - coord1st[0]); } //KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * x_pt); KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * x_pt); // ΦのSVEA(φ) KrdLab.clapack.Complex fieldVal_SVEA = fieldVal / expX; resVec[ino_InLoop] = fieldVal_SVEA; // SVEAの微分( exp(-jβx)dφ/dx = dΦ/dx + jβφexp(-jβx)) //resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam * fieldVal_SVEA; resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * fieldVal_SVEA; } } } System.Diagnostics.Debug.WriteLine("betamToSolveList.Length {0}", betamToSolveList.Length); ////////////////////////////////////////////////////////////////////////////////////// // モード数の修正 int maxMode = maxModeSpecified; if (maxMode > betamToSolveList.Length) { maxMode = betamToSolveList.Length; } ////////////////////////////////////////////////////////////////////////////////////// // 表示用に周期構造領域の固有モード分布を格納する eigenVecsPeriodic = new KrdLab.clapack.Complex[maxMode][]; for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++) { KrdLab.clapack.Complex[] resVec = resVecList[imode]; System.Diagnostics.Debug.Assert(resVec.Length == nodePeriodic.Count); eigenVecsPeriodic[tagtModeIndex] = new KrdLab.clapack.Complex[nodePeriodic.Count]; resVec.CopyTo(eigenVecsPeriodic[tagtModeIndex], 0); } ////////////////////////////////////////////////////////////////////////////////////// // 固有値、固有ベクトル // 格納 int nodeCntB1 = nodePeriodicB1.Count; eigenValues = new Complex[maxMode]; //eigenVecsB1 = new Complex[maxMode, nodeCntB1]; //eigen_dFdXsB1 = new Complex[maxMode, nodeCntB1]; eigenVecsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く eigen_dFdXsB1 = new Complex[maxMode, nodesBoundary.Length]; // 強制境界を除く for (int imode = 0; imode < maxMode; imode++) { eigenValues[imode] = new Complex(0, 0); for (int ino = 0; ino < eigenVecsB1.GetLength(1); ino++) { eigenVecsB1[imode, ino] = new Complex(0, 0); eigen_dFdXsB1[imode, ino] = new Complex(0, 0); } } for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < maxMode; imode--, tagtModeIndex++) { //System.Diagnostics.Debug.WriteLine("imode = {0}", imode); KrdLab.clapack.Complex workBetam = betamToSolveList[imode]; KrdLab.clapack.Complex[] resVec = resVecList[imode]; KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode]; Complex betam = new Complex(workBetam.Real, workBetam.Imaginary); bool isComplexConjugateMode = false; // 減衰定数は符号がマイナス(β = -jα) if (betam.Imaginary > 0.0 && Math.Abs(betam.Real) <= 1.0e-12) { betam = new Complex(betam.Real, -betam.Imaginary); isComplexConjugateMode = true; } //Complex[] evec = new Complex[nodeCntB1]; //Complex[] evec_dFdX = new Complex[nodeCntB1]; Complex[] evec = new Complex[nodesBoundary.Length]; // 強制境界を除く Complex[] evec_dFdX = new Complex[nodesBoundary.Length]; // 強制境界を除く for (int ino = 0; ino < nodeCntB1; ino++) { int nodeNumberPortBc1 = nodePeriodicB1[ino]; //System.Diagnostics.Debug.WriteLine("ino = {0} nodeNumberPortBc1 = {1}", ino, nodeNumberPortBc1); int ino_InLoop_PortBc1 = toNodePeriodic[nodeNumberPortBc1]; Complex cvalue = new Complex(resVec[ino_InLoop_PortBc1].Real, resVec[ino_InLoop_PortBc1].Imaginary); Complex dFdXValue = new Complex(resDFDXVec[ino_InLoop_PortBc1].Real, resDFDXVec[ino_InLoop_PortBc1].Imaginary); if (isComplexConjugateMode) { cvalue = Complex.Conjugate(cvalue); dFdXValue = Complex.Conjugate(dFdXValue); } //evec[ino] = cvalue; //evec_dFdX[ino] = dFdXValue; /////////////////////////////////////////////////// // 強制境界を除く if (!toNodesB.ContainsKey(nodeNumberPortBc1)) { continue; } int ino_f = toNodesB[nodeNumberPortBc1]; //System.Diagnostics.Debug.WriteLine("ino_f = {0}", ino_f); evec[ino_f] = cvalue; evec_dFdX[ino_f] = dFdXValue; /////////////////////////////////////////////////// //if (tagtModeIndex == incidentModeIndex) { //System.Diagnostics.Debug.WriteLine("evec[{0}] = {1} + {2} i", ino_f, evec[ino_f].Real, evec[ino_f].Imaginary); } } // 規格化定数を求める Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec); //Complex[] evec_Modify = new Complex[nodeCntB1]; Complex[] evec_Modify = new Complex[nodesBoundary.Length];//強制境界を除く Complex imagOne = new Complex(0.0, 1.0); Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < nodeCntB1; ino++) { //evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam_periodic); /////////////////////////////////////////////////// // 強制境界を除く int nodeNumberPortBc1 = nodePeriodicB1[ino]; if (!toNodesB.ContainsKey(nodeNumberPortBc1)) { continue; } int ino_f = toNodesB[nodeNumberPortBc1]; evec_Modify[ino_f] = evec[ino_f] - evec_dFdX[ino_f] / (imagOne * betam_periodic); /////////////////////////////////////////////////// } //Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec); Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec_Modify), workVec); if (WaveModeDv == FemSolver.WaveModeDV.TM) { // TMモード dm = Complex.Sqrt(omega * eps0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm); } else { // TEモード dm = Complex.Sqrt(omega * mu0 * Complex.Conjugate(betam) / (Complex.Abs(betam) * Complex.Conjugate(betam_periodic)) / dm); } // 伝搬定数の格納 eigenValues[tagtModeIndex] = betam; if (tagtModeIndex < 10) { System.Diagnostics.Debug.WriteLine("β/k0 ( " + tagtModeIndex + " ) = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + ((incidentModeIndex == tagtModeIndex) ? " incident" : "")); } // 固有ベクトルの格納(規格化定数を掛ける) for (int ino = 0; ino < evec.Length; ino++) { Complex fm = dm * evec[ino]; Complex dfmdx = dm * evec_dFdX[ino]; eigenVecsB1[tagtModeIndex, ino] = fm; eigen_dFdXsB1[tagtModeIndex, ino] = dfmdx; //System.Diagnostics.Debug.WriteLine("eigen_vecs_Bc1({0}, {1}) = {2} + {3} i", imode, ino, fm.Real, fm.Imag); } } System.Diagnostics.Debug.WriteLine("eigen end"); }
/// <summary> /// 散乱行列の計算 /// </summary> /// <param name="waveLength"></param> /// <param name="iMode"></param> /// <param name="isIncidentMode"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="valuesAll"></param> /// <returns></returns> public static Complex GetWaveguidePortReflectionCoef( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, int iMode, bool isIncidentMode, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdXs, int[] nodesRegion, IList<FemElement> Elements, MediaInfo[] Medias, Complex[] valuesAll) { // 2D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 2D節点番号→ソート済みリストインデックスのマップ作成 for (int i = 0; i < nodesRegion.Length; i++) { int nodeNumber = nodesRegion[i]; if (!toSorted.ContainsKey(nodeNumber)) { toSorted.Add(nodeNumber, i); } } // ポート上の界を取得する int nodeCnt = nodesBoundary.Length; Complex[] valuesB = new Complex[nodeCnt]; for (int ino = 0; ino < nodeCnt; ino++) { int nodeNumber = nodesBoundary[ino]; int inoGlobal = toSorted[nodeNumber]; valuesB[ino] = valuesAll[inoGlobal]; } double k0 = 2.0 * pi / waveLength; double omega = k0 * c0; Complex s11 = new Complex(0.0, 0.0); int maxMode = eigenValues.Length; double periodicDistance = latticeA; // 正方格子 // {tmp_vec}*t = {fm}*t[ryy]*t // {tmp_vec}* = [ryy]* {fm}* // ([ryy]*)t = [ryy]* // [ryy]が実数のときは、[ryy]* -->[ryy] Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, iMode); Complex[] dFdXVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)iMode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam = eigenValues[iMode]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (int ino = 0; ino < fmVec_Modify.Length; ino++) { fmVec_Modify[ino] = fmVec[ino] - dFdXVec[ino] / (Complex.ImaginaryOne * betam_periodic); } // ryyが実数のとき //Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); // s11 = {tmp_vec}t {value_all} s11 = MyMatrixUtil.vector_Dot(tmp_vec, valuesB); { // H面、平行平板 if (WaveModeDv == FemSolver.WaveModeDV.TM) { //s11 *= (Complex.Abs(betam) / (omega * eps0)); s11 *= ((Complex.Abs(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * eps0)); if (isIncidentMode) { s11 += -1.0; } } else { //s11 *= (Complex.Abs(betam) / (omega * mu0)); s11 *= ((Complex.Abs(betam) * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) / (omega * mu0)); if (isIncidentMode) { s11 += -1.0; } } } return s11; }
/// <summary> /// 入出力ポート境界条件の追加 /// </summary> /// <param name="waveLength"></param> /// <param name="isInputPort"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> /// <param name="eigenValues"></param> /// <param name="eigenVecs"></param> /// <param name="nodesRegion"></param> /// <param name="mat"></param> /// <param name="resVec"></param> public static void AddPortBC( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, bool isInputPort, int IncidentModeIndex, int[] nodesBoundary, MyDoubleMatrix ryy_1d, Complex[] eigenValues, Complex[,] eigenVecs, Complex[,] eigen_dFdXs, int[] nodesRegion, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, MyComplexMatrix mat, Complex[] resVec) { double k0 = 2.0 * pi / waveLength; double omega = k0 / Math.Sqrt(mu0 * eps0); // 境界上の節点数(1次線要素を想定) int nodeCnt = nodesBoundary.Length; // 考慮するモード数 int maxMode = eigenValues.Length; // 全体剛性行列の作成 MyComplexMatrix matB = new MyComplexMatrix(nodeCnt, nodeCnt); double periodicDistance = latticeA; // 正方格子 for (int imode = 0; imode < maxMode; imode++) { Complex betam = eigenValues[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint inoB = 0; inoB < nodeCnt; inoB++) { fmVec_Modify[inoB] = fmVec[inoB] - dfmdxVec[inoB] / (Complex.ImaginaryOne * betam_periodic); } // 2Dの境界積分 //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); // モード電力規格化の積分(1Dの積分) // [ryy]が実数の場合 //Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec)); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify)); for (int inoB = 0; inoB < nodeCnt; inoB++) { for (int jnoB = 0; jnoB < nodeCnt; jnoB++) { Complex cvalue; { // H面、平行平板 if (WaveModeDv == FemSolver.WaveModeDV.TM) { //cvalue = (Complex.ImaginaryOne / (omega * eps0)) * betam * Complex.Abs(betam) * veci[inoB] * vecj[jnoB]; cvalue = (Complex.ImaginaryOne / (omega * eps0)) * (Complex.Abs(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[inoB] * vecj[jnoB]; } else { //cvalue = (Complex.ImaginaryOne / (omega * mu0)) * betam * Complex.Abs(betam) * veci[inoB] * vecj[jnoB]; cvalue = (Complex.ImaginaryOne / (omega * mu0)) * (Complex.Abs(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[inoB] * vecj[jnoB]; } } matB._body[inoB + jnoB * matB.RowSize] += cvalue; } } } // check 対称行列 bool isSymmetrix = true; for (int inoB = 0; inoB < matB.RowSize; inoB++) { for (int jnoB = inoB; jnoB < matB.ColumnSize; jnoB++) { if (Math.Abs(matB[inoB, jnoB].Real - matB[jnoB, inoB].Real) >= Constants.PrecisionLowerLimit) { //System.Diagnostics.Debug.Assert(false); isSymmetrix = false; break; } if (Math.Abs(matB[inoB, jnoB].Imaginary - matB[jnoB, inoB].Imaginary) >= Constants.PrecisionLowerLimit) { //System.Diagnostics.Debug.Assert(false); isSymmetrix = false; break; } } } if (!isSymmetrix) { System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix is NOT symmetric!!!!!!!!!!!!!!"); //System.Diagnostics.Debug.Assert(false); } //MyMatrixUtil.printMatrix("matB", matB); // 残差ベクトルの作成 Complex[] resVecB = new Complex[nodeCnt]; if (isInputPort) { int imode = IncidentModeIndex; Complex betam = eigenValues[imode]; Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, (int)imode); Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode); Complex[] fmVec_Modify = new Complex[fmVec.Length]; Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance); for (uint inoB = 0; inoB < nodeCnt; inoB++) { fmVec_Modify[inoB] = fmVec[inoB] - dfmdxVec[inoB] / (Complex.ImaginaryOne * betam_periodic); } // 2Dの境界積分 //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec); Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify); for (int inoB = 0; inoB < nodeCnt; inoB++) { // H面、平行平板、E面 //Complex cvalue = 2.0 * Complex.ImaginaryOne * betam * veci[inoB]; Complex cvalue = 2.0 * Complex.ImaginaryOne * betam_periodic * veci[inoB]; resVecB[inoB].Real = cvalue.Real; resVecB[inoB].Imaginary = cvalue.Imaginary; } } //printVec("resVecB", resVecB); // 2D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 2D節点番号→ソート済みリストインデックスのマップ作成 for (int i = 0; i < nodesRegion.Length; i++) { int nodeNumber = nodesRegion[i]; if (!toSorted.ContainsKey(nodeNumber)) { toSorted.Add(nodeNumber, i); } } // 要素剛性行列にマージ // この定式化では行列のスパース性は失われている(隣接していない要素の節点間にも関連がある) // 要素剛性行列にマージする for (int inoB = 0; inoB < nodeCnt; inoB++) { int iNodeNumber = nodesBoundary[inoB]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jnoB = 0; jnoB < nodeCnt; jnoB++) { int jNodeNumber = nodesBoundary[jnoB]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; // Note: matBは一般行列 matはバンド行列 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)] += matB._body[inoB + jnoB * matB.RowSize]; } } // 残差ベクトルにマージ for (int inoB = 0; inoB < nodeCnt; inoB++) { int iNodeNumber = nodesBoundary[inoB]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; resVec[inoGlobal] += resVecB[inoB]; } }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// ポート境界の1D FEM行列 ryy_1dを取得する /// </summary> /// <param name="WaveModeDv"></param> /// <param name="waveLength"></param> /// <param name="latticeA"></param> /// <param name="Nodes"></param> /// <param name="EdgeToElementNoH"></param> /// <param name="Elements"></param> /// <param name="Medias"></param> /// <param name="ForceNodeNumberH"></param> /// <param name="nodesBoundary"></param> /// <param name="ryy_1d"></param> private static void getPortFemMat1D( FemSolver.WaveModeDV WaveModeDv, double waveLength, double latticeA, IList<FemNode> Nodes, Dictionary<string, IList<int>> EdgeToElementNoH, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, IList<int> portNodes, out int[] nodesBoundary, out MyDoubleMatrix ryy_1d ) { nodesBoundary = null; ryy_1d = null; // 2D次元数 const int ndim2d = Constants.CoordDim2D; //2; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 節点番号リスト(要素インデックス: 1D節点番号 - 1 要素:2D節点番号) IList<int> nodes = portNodes; // 2D→1D節点番号マップ Dictionary<int, int> to1dNodes = new Dictionary<int, int>(); // 節点座標リスト IList<double> coords = new List<double>(); // 要素リスト IList<FemLineElement> elements = new List<FemLineElement>(); // 1D節点番号リスト(ソート済み) IList<int> sortedNodes = new List<int>(); // 1D節点番号→ソート済みリストインデックスのマップ Dictionary<int, int> toSorted = new Dictionary<int, int>(); // 2Dの要素から次数を取得する Constants.FemElementShapeDV elemShapeDv2d; int order; int vertexCnt2d; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(Elements[0].NodeNumbers.Length, out elemShapeDv2d, out order, out vertexCnt2d); // 2D→1D節点番号マップ作成 for (int i = 0; i < nodes.Count; i++) { int nodeNumber2d = nodes[i]; if (!to1dNodes.ContainsKey(nodeNumber2d)) { to1dNodes.Add(nodeNumber2d, i + 1); } } // 原点 int nodeNumber0 = nodes[0]; int nodeIndex0 = nodeNumber0 - 1; FemNode node0 = Nodes[nodeIndex0]; double[] coord0 = new double[ndim2d]; coord0[0] = node0.Coord[0]; coord0[1] = node0.Coord[1]; // 座標リスト作成 double[] coord = new double[ndim2d]; foreach (int nodeNumber in nodes) { int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; coord[0] = node.Coord[0]; coord[1] = node.Coord[1]; double x = FemMeshLogic.GetDistance(coord, coord0); //System.Diagnostics.Debug.WriteLine("{0},{1},{2},{3}", nodeIndex, coord[0], coord[1], x); coords.Add(x); } // 線要素を作成する if (order == Constants.FirstOrder) { // 1次線要素 FemMat_Line_First.MkElements( nodes, EdgeToElementNoH, Elements, ref elements); } else { // 2次線要素 FemMat_Line_Second.MkElements( nodes, EdgeToElementNoH, Elements, ref elements); } // 強制境界節点と内部領域節点を分離 foreach (int nodeNumber2d in nodes) { int nodeNumber = to1dNodes[nodeNumber2d]; if (ForceNodeNumberH.ContainsKey(nodeNumber2d)) { System.Diagnostics.Debug.WriteLine("{0}: {1} {2}", nodeNumber, Nodes[nodeNumber2d - 1].Coord[0], Nodes[nodeNumber2d - 1].Coord[1]); } else { sortedNodes.Add(nodeNumber); toSorted.Add(nodeNumber, sortedNodes.Count - 1); } } // 対称バンド行列のパラメータを取得する int rowcolSize = 0; int subdiaSize = 0; int superdiaSize = 0; { bool[,] matPattern = null; FemSolverPort.GetMatNonzeroPatternForEigen(elements, toSorted, out matPattern); FemSolverPort.GetBandMatrixSubDiaSizeAndSuperDiaSizeForEigen(matPattern, out rowcolSize, out subdiaSize, out superdiaSize); } // ソート済み1D節点インデックス→2D節点番号マップ nodesBoundary = new int[sortedNodes.Count]; for (int i = 0; i < sortedNodes.Count; i++) { int nodeNumber = sortedNodes[i]; int nodeIndex = nodeNumber - 1; int nodeNumber2d = nodes[nodeIndex]; nodesBoundary[i] = nodeNumber2d; } // 節点数 int nodeCnt = sortedNodes.Count; // 固有モード解析でのみ使用するuzz_1d, txx_1d MyDoubleMatrix txx_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); MyDoubleMatrix uzz_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); // ryy_1dマトリクス (線要素) ryy_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); for (int elemIndex = 0; elemIndex < elements.Count; elemIndex++) { // 線要素 FemLineElement element = elements[elemIndex]; // 1Dヘルムホルツ方程式固有値問題の要素行列を加算する if (order == Constants.FirstOrder) { // 1次線要素 FemMat_Line_First.AddElementMatOf1dEigenValueProblem( waveLength, // E面の場合のみ使用 element, coords, toSorted, Medias, WaveModeDv, ref txx_1d, ref ryy_1d, ref uzz_1d); } else { // 2次線要素 FemMat_Line_Second.AddElementMatOf1dEigenValueProblem( waveLength, // E面の場合のみ使用 element, coords, toSorted, Medias, WaveModeDv, ref txx_1d, ref ryy_1d, ref uzz_1d); } } }
/// <summary> /// 界のx方向微分値を取得する (2次三角形要素) /// </summary> /// <param name="world"></param> /// <param name="fieldValId"></param> private static void getDFDXValues_Tri_SecondOrder( FemSolver.WaveModeDV WaveModeDv, double k0, double rotAngle, double[] rotOrigin, IList<FemNode> Nodes, IList<FemElement> Elements, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, IList<uint> elemNoPeriodic, IList<IList<int>> nodePeriodicB, Dictionary<int, int> toNodePeriodic, 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]; Dictionary<int, int> nodeElemCntH = new Dictionary<int, int>(); Dictionary<int, double> nodeAreaSum = new Dictionary<int, double>(); int elemCnt = elemNoPeriodic.Count; for (int ie = 0; ie < elemCnt; ie++) { int elemNo = (int)elemNoPeriodic[ie]; FemElement element = Elements[elemNo - 1]; System.Diagnostics.Debug.Assert(element.No == elemNo); // 要素内節点数 const int nno = Constants.TriNodeCnt_SecondOrder; //6; // 2次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WaveModeDv, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } if (Math.Abs(rotAngle) >= Constants.PrecisionLowerLimit) { // 座標を回転移動する for (uint inoes = 0; inoes < nno; inoes++) { double[] srcPt = new double[] { pp[inoes][0], pp[inoes][1] }; double[] destPt = GetRotCoord(srcPt, rotAngle, rotOrigin); for (int i = 0; i < ndim; i++) { pp[inoes][i] = destPt[i]; } } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //System.Diagnostics.Debug.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // 形状関数の微分の係数を求める // dndxC[ino,n,k] ino節点のn方向微分のLk(k面積座標)の係数 // dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3] double[, ,] dndxC = new double[nno, ndim, Constants.TriVertexCnt + 1] { { {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]}, {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]}, }, { {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]}, {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]}, }, { {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]}, {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]}, }, { {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0}, {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0}, }, { {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0}, {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0}, }, { {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0}, {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0}, }, }; // 界の微分値を計算 KrdLab.clapack.Complex[] dFdXs = new KrdLab.clapack.Complex[nno]; KrdLab.clapack.Complex[] dFdYs = new KrdLab.clapack.Complex[nno]; // 節点の面積座標 double[,] L_node = new double[Constants.TriNodeCnt_SecondOrder, 3] { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}, {0.5, 0.5, 0.0}, {0.0, 0.5, 0.5}, {0.5, 0.0, 0.5} }; for (int inoes = 0; inoes < nno; inoes++) { for (int jnoes = 0; jnoes < nno; jnoes++) { int jNodeNumber = no_c[jnoes]; if (!toNodePeriodic.ContainsKey(jNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } int jnoGlobal = toNodePeriodic[jNodeNumber]; KrdLab.clapack.Complex fVal = fVec[jnoGlobal]; double[] dNdx_node = new double[ndim]; for (int n = 0; n < ndim; n++) { dNdx_node[n] = dndxC[jnoes, n, 0] * L_node[inoes, 0] + dndxC[jnoes, n, 1] * L_node[inoes, 1] + dndxC[jnoes, n, 2] * L_node[inoes, 2] + dndxC[jnoes, n, 3]; } dFdXs[inoes] += dNdx_node[0] * fVal; dFdYs[inoes] += dNdx_node[1] * fVal; } } // 格納 for (int inoes = 0; inoes < nno; inoes++) { int iNodeNumber = no_c[inoes]; if (!toNodePeriodic.ContainsKey(iNodeNumber)) { System.Diagnostics.Debug.Assert(false); continue; } int inoGlobal = toNodePeriodic[iNodeNumber]; //dFdXVec[inoGlobal] += dFdXs[inoes]; //dFdYVec[inoGlobal] += dFdYs[inoes]; // Note: // TEzモードのとき -dHz/dx = jωDy dFdXVec[inoGlobal] += dFdXs[inoes] * area; dFdYVec[inoGlobal] += dFdYs[inoes] * area; if (nodeElemCntH.ContainsKey(inoGlobal)) { nodeElemCntH[inoGlobal]++; // 面積を格納 nodeAreaSum[inoGlobal] += area; } else { nodeElemCntH.Add(inoGlobal, 1); nodeAreaSum.Add(inoGlobal, area); } } } for (int 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); } }
/// <summary> /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する /// </summary> /// <param name="waveLength">波長(E面の場合のみ使用する)</param> /// <param name="element">線要素</param> /// <param name="coords">座標リスト</param> /// <param name="toSorted">節点番号→ソート済み節点インデックスマップ</param> /// <param name="Medias">媒質情報リスト</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="txx_1d">txx行列</param> /// <param name="ryy_1d">ryy行列</param> /// <param name="uzz_1d">uzz行列</param> public static void AddElementMatOf1dEigenValueProblem( double waveLength, FemLineElement element, IList<double> coords, Dictionary<int, int> toSorted, MediaInfo[] Medias, FemSolver.WaveModeDV WaveModeDv, ref MyDoubleMatrix txx_1d, ref MyDoubleMatrix ryy_1d, ref MyDoubleMatrix uzz_1d) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 2次線要素 const int nno = Constants.LineNodeCnt_SecondOrder; // 3; int[] nodeNumbers = element.NodeNumbers; System.Diagnostics.Debug.Assert(nno == nodeNumbers.Length); // 座標の取得 double[] elementCoords = new double[nno]; for (int n = 0; n < nno; n++) { int nodeIndex = nodeNumbers[n] - 1; elementCoords[n] = coords[nodeIndex]; } // 線要素の長さ double elen = Math.Abs(elementCoords[1] - elementCoords[0]); // 媒質インデックス int mediaIndex = element.MediaIndex; // 媒質 MediaInfo media = Medias[mediaIndex]; double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WaveModeDv, out media_P, out media_Q); double[,] integralN = new double[nno, nno] { { 4.0 / 30.0 * elen, -1.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { -1.0 / 30.0 * elen, 4.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { 2.0 / 30.0 * elen, 2.0 / 30.0 * elen, 16.0 / 30.0 * elen }, }; double[,] integralDNDY = new double[nno, nno] { { 7.0 / (3.0 * elen), 1.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { 1.0 / (3.0 * elen), 7.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) }, }; for (int ino = 0; ino < nno; ino++) { int inoBoundary = nodeNumbers[ino]; int inoSorted; if (!toSorted.ContainsKey(inoBoundary)) continue; inoSorted = toSorted[inoBoundary]; for (int jno = 0; jno < nno; jno++) { int jnoBoundary = nodeNumbers[jno]; int jnoSorted; if (!toSorted.ContainsKey(jnoBoundary)) continue; jnoSorted = toSorted[jnoBoundary]; // 対称バンド行列対応 if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted) { continue; } double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno]; double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno]; double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno]; //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno; //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno; //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno; txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno; ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno; uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno; } } }
/// <summary> /// 入出力データの初期化 /// </summary> public void InitData( FemSolver solver, Panel CadPanel, Panel FValuePanel, Panel FValueLegendPanel, Label labelFreqValue, Chart SMatChart, Chart BetaChart, Chart EigenVecChart ) { initInput(); initOutput(); // 一度だけの初期化処理 initDataOnce(FValueLegendPanel, labelFreqValue); // ポストプロセッサに入力データをコピー // 入力データの取得 solver.GetFemInputInfo(out Nodes, out Elements, out Medias, out Ports, out ForceNodes, out IncidentPortNo, out WaveguideWidth, out LatticeA); // チャートの設定用に開始終了波長を取得 FirstWaveLength = solver.FirstWaveLength; LastWaveLength = solver.LastWaveLength; CalcFreqCnt = solver.CalcFreqCnt; // 波のモード区分を取得 WaveModeDv = solver.WaveModeDv; //if (isInputDataReady()) // ポートが指定されていなくてもメッシュを表示できるように条件を変更 if (Elements != null && Elements.Length > 0 && Nodes != null && Nodes.Length > 0 && Medias != null && Medias.Length > 0) { // 各要素に節点情報を補完する foreach (FemElement element in Elements) { element.SetNodesFromAllNodes(Nodes); element.LineColor = Color.Black; element.BackColor = Medias[element.MediaIndex].BackColor; } } // メッシュ描画 //using (Graphics g = CadPanel.CreateGraphics()) //{ // DrawMesh(g, CadPanel); //} //CadPanel.Invalidate(); if (!IsAutoCalc) { // チャート初期化 ResetSMatChart(SMatChart); // 等高線図の凡例 UpdateFValueLegend(FValueLegendPanel, labelFreqValue); // 等高線図 //FValuePanel.Invalidate(); FValuePanel.Refresh(); // 固有値チャート初期化 // この段階ではMaxModeの値が0なので、後に計算値ロード後一回だけ初期化する ResetEigenValueChart(BetaChart); // 固有ベクトル表示(空のデータで初期化) SetEigenVecToChart(EigenVecChart); } }
/// <summary> /// 計算モードのラベル表示 /// </summary> /// <param name="waveModeDv"></param> private void setLabelCalcModeText(FemSolver.WaveModeDV waveModeDv) { string text; text =((waveModeDv == FemSolver.WaveModeDV.TM) ? "TM" : "TE"); labelCalcMode.Text = text; }
/// <summary> /// Fem入力データファイルへ保存 /// I/FがCadの内部データ寄りになっているので、変更したいが後回し /// </summary> /// <param name="filename">ファイル名(*.fem)</param> /// <param name="nodeCnt">節点数</param> /// <param name="doubleCoords">節点座標リスト</param> /// <param name="elementCnt">要素数</param> /// <param name="elements">要素リスト</param> /// <param name="portCnt">ポート数</param> /// <param name="portList">ポートの節点番号リストのリスト</param> /// <param name="forceBCNodeNumbers">強制境界節点番号のリスト</param> /// <param name="incidentPortNo">入射ポート番号</param> /// <param name="medias">媒質情報リスト</param> /// <param name="firstWaveLength">計算開始波長</param> /// <param name="lastWaveLength">計算終了波長</param> /// <param name="calcCnt">計算周波数件数</param> /// <param name="waveModeDv">波のモード区分</param> public static void SaveToFileFromCad(string filename, int nodeCnt, IList<double[]> doubleCoords, int elementCnt, IList<int[]> elements, int portCnt, IList<IList<int>> portList, int[] forceBCNodeNumbers, IList<IList<uint>> elemNoPeriodicList, IList<IList<IList<int>>> nodePeriodicBList, IList<IList<int>> defectNodePeriodicList, int incidentPortNo, MediaInfo[] medias, double firstWaveLength, double lastWaveLength, int calcCnt, FemSolver.WaveModeDV waveModeDv) { ////////////////////////////////////////// // ファイル出力 ////////////////////////////////////////// try { using (StreamWriter sw = new StreamWriter(filename)) { string line; // 節点番号と座標の出力 line = string.Format("Nodes,{0}", nodeCnt); sw.WriteLine(line); for (int i = 0; i < doubleCoords.Count; i++) { double[] doubleCoord = doubleCoords[i]; int nodeNumber = i + 1; line = string.Format("{0},{1},{2}", nodeNumber, doubleCoord[0], doubleCoord[1]); sw.WriteLine(line); } // 要素番号と要素を構成する節点の全体節点番号の出力 line = string.Format("Elements,{0}", elementCnt); sw.WriteLine(line); foreach (int[] element in elements) { line = ""; foreach (int k in element) { line += string.Format("{0},", k); } line = line.Substring(0, line.Length - 1); // 最後の,を削除 sw.WriteLine(line); } // ポート境界条件節点 int portCounter = 0; line = string.Format("Ports,{0}", portList.Count); sw.WriteLine(line); foreach (IList<int> nodes in portList) { line = string.Format("{0},{1}", ++portCounter, nodes.Count); sw.WriteLine(line); int portNodeNumber = 0; foreach (int nodeNumber in nodes) { line = string.Format("{0},{1}", ++portNodeNumber, nodeNumber); sw.WriteLine(line); } } // 強制境界節点 line = string.Format("Force,{0}", forceBCNodeNumbers.Length); sw.WriteLine(line); foreach (int nodeNumber in forceBCNodeNumbers) { line = string.Format("{0}", nodeNumber); sw.WriteLine(line); } // 周期構造領域内要素番号 System.Diagnostics.Debug.Assert(portCnt == elemNoPeriodicList.Count); for (int portIndex = 0; portIndex < portCnt; portIndex++) { IList<uint> elemNoPeriodic = elemNoPeriodicList[portIndex]; line = string.Format("elemNoPeriodic,{0},{1}", portIndex, elemNoPeriodic.Count); sw.WriteLine(line); for (int i = 0; i < elemNoPeriodic.Count; i++) { line = string.Format("{0}", elemNoPeriodic[i]); sw.WriteLine(line); } } // 周期構造境界節点番号 System.Diagnostics.Debug.Assert(portCnt == nodePeriodicBList.Count); for (int portIndex = 0; portIndex < portCnt; portIndex++) { IList<IList<int>> nodePeriodicB = nodePeriodicBList[portIndex]; for (int boundaryIndex = 0; boundaryIndex < 2; boundaryIndex++) { IList<int> workNodesB = nodePeriodicB[boundaryIndex]; line = string.Format("nodePeriodicB,{0},{1},{2}", portIndex, boundaryIndex, workNodesB.Count); sw.WriteLine(line); for (int i = 0; i < workNodesB.Count; i++) { line = string.Format("{0}", workNodesB[i]); sw.WriteLine(line); } } } // 周期構造領域内欠陥部の節点番号 System.Diagnostics.Debug.Assert(portCnt == defectNodePeriodicList.Count); for (int portIndex = 0; portIndex < portCnt; portIndex++) { IList<int> defectNodePeriodic = defectNodePeriodicList[portIndex]; line = string.Format("defectNodePeriodic,{0},{1}", portIndex, defectNodePeriodic.Count); sw.WriteLine(line); for (int i = 0; i < defectNodePeriodic.Count; i++) { line = string.Format("{0}", defectNodePeriodic[i]); sw.WriteLine(line); } } // 入射ポート番号 line = string.Format("IncidentPortNo,{0}", incidentPortNo); sw.WriteLine(line); // 媒質情報の個数 sw.WriteLine("Medias,{0}", medias.Length); // 媒質情報の書き込み for (int i = 0; i < medias.Length; i++) { MediaInfo media = medias[i]; line = string.Format("{0},", i); double[,] p = media.P; for (int m = 0; m < p.GetLength(0); m++) { for (int n = 0; n < p.GetLength(1); n++) { line += string.Format("{0},", p[m, n]); } } double[,] q = media.Q; for (int m = 0; m < q.GetLength(0); m++) { for (int n = 0; n < q.GetLength(1); n++) { line += string.Format("{0},", q[m, n]); } } line = line.Remove(line.Length - 1); // 最後の,を削除 sw.WriteLine(line); } // 計算対象周波数 sw.WriteLine("WaveLengthRange,{0},{1},{2}", firstWaveLength, lastWaveLength, calcCnt); // 計算対象モード区分 sw.WriteLine("WaveModeDv,{0}", ((waveModeDv == FemSolver.WaveModeDV.TM) ? "TM" : "TE")); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } }
/// <summary> /// 初期化処理 /// </summary> private void init() { CadLgc = new CadLogic(CadPanel); CadLgc.Change += new CadLogic.ChangeDeleagte(CadLgc_Change); Solver = new FemSolver(); PostPro = new FemPostProLogic(); CadModeRadioButtons = new RadioButton[] { radioBtnNone, radioBtnLocation, radioBtnArea, radioBtnPort, radioBtnErase, radioBtnIncidentPort, radioBtnPortNumbering }; // Cadモードをラジオボタンに紐づける CadLogic.CadModeType[] cadModeTypeForRadioButtons = new CadLogic.CadModeType[] { CadLogic.CadModeType.None, CadLogic.CadModeType.Location, CadLogic.CadModeType.Area, CadLogic.CadModeType.Port, CadLogic.CadModeType.Erase, CadLogic.CadModeType.IncidentPort, CadLogic.CadModeType.PortNumbering }; System.Diagnostics.Debug.Assert(CadModeRadioButtons.Length == cadModeTypeForRadioButtons.Length); for (int i = 0; i < CadModeRadioButtons.Length; i++) { CadModeRadioButtons[i].Tag = cadModeTypeForRadioButtons[i]; } // エリア選択描画モードタイプコンボボックスのItemにCadモードを紐づける CellTypeStruct[] cellTypeStructsForImgCBoxCadModeArea = new CellTypeStruct[] { new CellTypeStruct("真空", CadLogic.CellType.Defect), new CellTypeStruct("誘電体ロッド", CadLogic.CellType.Rod), }; // コンボボックスのアイテムをクリア imgcbxCellType.Items.Clear(); foreach (CellTypeStruct cellTypeStruct in cellTypeStructsForImgCBoxCadModeArea) { // コンボボックスにアイテムを追加 imgcbxCellType.Items.Add(cellTypeStruct); if (CadLgc != null) { if (CadLgc.SelectedCellType == cellTypeStruct.CellTypeVal) { imgcbxCellType.SelectedItem = cellTypeStruct; } } } imgcbxCellType.Visible = false; btnLoadCancel.Visible = false; //TEST 4画面表示 FValuePanelIndex = FValuePanelFieldDV_ValueDVPairList.Length; //0; // 等高線図パネルインデックス変更時の処理 changeFValuePanelIndexProc(false); // アプリケーションの終了イベントハンドラを設定する AppDomain.CurrentDomain.ProcessExit += (sender, e) => { System.Diagnostics.Debug.WriteLine("Process exiting"); //System.Diagnostics.Debug.WriteLine("Process exiting"); // フォームの破棄処理を呼び出す this.Dispose(); }; // パネルサイズを記憶する savePanelSize(); //this.DoubleBuffered = true; // ダブルバッファ制御用のプロパティを強制的に取得する System.Reflection.PropertyInfo p; p = typeof(System.Windows.Forms.Control).GetProperty( "DoubleBuffered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); // ダブルバッファを有効にする p.SetValue(CadPanel, true, null); p.SetValue(FValuePanel, true, null); // フォームのタイトルを退避 TitleBaseName = this.Text + " " + MyUtilLib.MyUtil.getAppVersion(); // ファイル名付きフォームタイトルを設定 setFrmTitle(); // GUI初期化 resetGUI(); }
/// <summary> /// Fem入力データをファイルへ書き込み /// </summary> /// <param name="filename">ファイル名(*.fem)</param> /// <param name="nodes">節点リスト</param> /// <param name="elements">要素リスト</param> /// <param name="ports">ポートの節点番号リストのリスト</param> /// <param name="forceBCNodes">強制境界節点番号リスト</param> /// <param name="incidentPortNo">入射ポート番号</param> /// <param name="medias">媒質情報リスト</param> /// <param name="firstWaveLength">計算開始波長</param> /// <param name="lastWaveLength">計算終了波長</param> /// <param name="calcCnt">計算件数</param> /// <param name="waveModeDv">波のモード区分</param> /// <returns></returns> public static void SaveToFile(string filename, IList<FemNode> nodes, IList<FemElement> elements, IList<IList<int>> ports, IList<int> forceBCNodes, IList<IList<uint>> elemNoPeriodicList, IList<IList<IList<int>>> nodePeriodicBList, IList<IList<int>> defectNodePeriodicList, int incidentPortNo, MediaInfo[] medias, double firstWaveLength, double lastWaveLength, int calcCnt, FemSolver.WaveModeDV waveModeDv ) { int nodeCnt = nodes.Count; IList<double[]> doubleCoords = new List<double[]>(); foreach (FemNode femNode in nodes) { doubleCoords.Add(femNode.Coord); } int elementCnt = elements.Count; IList<int[]> in_elements = new List<int[]>(); foreach (FemElement femElement in elements) { int cnt = 2 + femElement.NodeNumbers.Length; int[] in_element = new int[cnt]; in_element[0] = femElement.No; in_element[1] = femElement.MediaIndex; for (int ino = 0; ino < femElement.NodeNumbers.Length; ino++) { in_element[2 + ino] = femElement.NodeNumbers[ino]; } in_elements.Add(in_element); } int portCnt = ports.Count; int[] forceBCNodeNumbers = forceBCNodes.ToArray(); SaveToFileFromCad( filename, nodeCnt, doubleCoords, elementCnt, in_elements, portCnt, ports, forceBCNodeNumbers, elemNoPeriodicList, nodePeriodicBList, defectNodePeriodicList, incidentPortNo, medias, firstWaveLength, lastWaveLength, calcCnt, waveModeDv); }
/// <summary> /// Fem入力データをファイルから読み込み /// </summary> /// <param name="filename">ファイル名(*.fem)</param> /// <param name="nodes">節点リスト</param> /// <param name="elements">要素リスト</param> /// <param name="ports">ポートの節点番号リストのリスト</param> /// <param name="forceBCNodes">強制境界節点番号リスト</param> /// <param name="incidentPortNo">入射ポート番号</param> /// <param name="medias">媒質情報リスト</param> /// <param name="firstWaveLength">計算開始波長</param> /// <param name="lastWaveLength">計算終了波長</param> /// <param name="calcCnt">計算件数</param> /// <param name="wgStructureDv">導波路構造区分</param> /// <param name="waveModeDv">波のモード区分</param> /// <returns></returns> public static bool LoadFromFile( string filename, out IList<FemNode> nodes, out IList<FemElement> elements, out IList<IList<int>> ports, out IList<int> forceBCNodes, out IList<IList<uint>> elemNoPeriodicList, out IList<IList<IList<int>>> nodePeriodicBList, out IList<IList<int>> defectNodePeriodicList, out int incidentPortNo, out MediaInfo[] medias, out double firstWaveLength, out double lastWaveLength, out int calcCnt, out FemSolver.WaveModeDV waveModeDv ) { int eNodeCnt = 0; nodes = new List<FemNode>(); elements = new List<FemElement>(); ports = new List<IList<int>>(); forceBCNodes = new List<int>(); elemNoPeriodicList = new List<IList<uint>>(); nodePeriodicBList = new List<IList<IList<int>>>(); defectNodePeriodicList = new List<IList<int>>(); incidentPortNo = 1; medias = new MediaInfo[Constants.MaxMediaCount]; 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; } firstWaveLength = 0.0; lastWaveLength = 0.0; calcCnt = 0; waveModeDv = Constants.DefWaveModeDv; if (!File.Exists(filename)) { return false; } // 入力データ読み込み try { using (StreamReader sr = new StreamReader(filename)) { const char delimiter = ','; string line; string[] tokens; line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "Nodes") { MessageBox.Show("節点情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int nodeCnt = int.Parse(tokens[1]); for (int i = 0; i < nodeCnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 3) { MessageBox.Show("節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int no = int.Parse(tokens[0]); if (no != i + 1) { MessageBox.Show("節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } FemNode femNode = new FemNode(); femNode.No = no; femNode.Coord = new double[2]; femNode.Coord[0] = double.Parse(tokens[1]); femNode.Coord[1] = double.Parse(tokens[2]); nodes.Add(femNode); } line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "Elements") { MessageBox.Show("要素情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int elementCnt = int.Parse(tokens[1]); for (int i = 0; i < elementCnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if ((tokens.Length != 1 + Constants.TriNodeCnt_SecondOrder) && (tokens.Length != 2 + Constants.TriNodeCnt_SecondOrder) // ver1.1.0.0で媒質インデックスを番号の後に挿入 && (tokens.Length != 2 + Constants.TriNodeCnt_FirstOrder) ) { MessageBox.Show("要素情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int elemNo = int.Parse(tokens[0]); int mediaIndex = 0; int indexOffset = 1; // ver1.0.0.0 int workENodeCnt = Constants.TriNodeCnt_SecondOrder; if (tokens.Length == 1 + Constants.TriNodeCnt_SecondOrder) { // 媒質インデックスのない古い形式(ver1.0.0.0) } else { // ver1.1.0.0で媒質インデックスを追加 mediaIndex = int.Parse(tokens[1]); indexOffset = 2; workENodeCnt = tokens.Length - 2; } if (workENodeCnt <= 0) { MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } if (eNodeCnt == 0) { // 最初の要素の節点数を格納(チェックに利用) eNodeCnt = workENodeCnt; } else { // 要素の節点数が変わった? if (workENodeCnt != eNodeCnt) { MessageBox.Show("要素節点数が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } } //FemElement femElement = new FemElement(); FemElement femElement = FemMeshLogic.CreateFemElementByElementNodeCnt(eNodeCnt); femElement.No = elemNo; femElement.MediaIndex = mediaIndex; femElement.NodeNumbers = new int[eNodeCnt]; for (int n = 0; n < femElement.NodeNumbers.Length; n++) { femElement.NodeNumbers[n] = int.Parse(tokens[n + indexOffset]); } elements.Add(femElement); } line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "Ports") { MessageBox.Show("入出力ポート情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int portCnt = int.Parse(tokens[1]); for (int i = 0; i < portCnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2) { MessageBox.Show("入出力ポート情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int portNo = int.Parse(tokens[0]); int portNodeCnt = int.Parse(tokens[1]); if (portNo != i + 1) { MessageBox.Show("ポート番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } IList<int> portNodes = new List<int>(); for (int n = 0; n < portNodeCnt; n++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2) { MessageBox.Show("ポートの節点情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int portNodeNumber = int.Parse(tokens[0]); int nodeNumber = int.Parse(tokens[1]); if (portNodeNumber != n + 1) { MessageBox.Show("ポートの節点番号が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } portNodes.Add(nodeNumber); } ports.Add(portNodes); } line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "Force") { MessageBox.Show("強制境界情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int forceNodeCnt = int.Parse(tokens[1]); for (int i = 0; i < forceNodeCnt; i++) { line = sr.ReadLine(); int nodeNumber = int.Parse(line); forceBCNodes.Add(nodeNumber); } // 周期構造領域内要素番号 for (int portIndex = 0; portIndex < portCnt; portIndex++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 3 || tokens[0] != "elemNoPeriodic") { MessageBox.Show("周期構造領域要素情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int tmpIndex = int.Parse(tokens[1]); System.Diagnostics.Debug.Assert(tmpIndex == portIndex); int cnt = int.Parse(tokens[2]); IList<uint> elemNoPeriodic = new List<uint>(); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 1) { MessageBox.Show("周期構造領域要素番号情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } uint elemNo = uint.Parse(tokens[0]); elemNoPeriodic.Add(elemNo); } elemNoPeriodicList.Add(elemNoPeriodic); } // 周期構造境界節点番号 for (int portIndex = 0; portIndex < portCnt; portIndex++) { IList<IList<int>> nodePeriodicB = new List<IList<int>>(); for (int boundaryIndex = 0; boundaryIndex < 2; boundaryIndex++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 4 || tokens[0] != "nodePeriodicB") { MessageBox.Show("周期構造境界節点番号情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int tmpIndex1 = int.Parse(tokens[1]); System.Diagnostics.Debug.Assert(tmpIndex1 == portIndex); int tmpIndex2 = int.Parse(tokens[2]); System.Diagnostics.Debug.Assert(tmpIndex2 == boundaryIndex); int cnt = int.Parse(tokens[3]); IList<int> workNodesB = new List<int>(); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 1) { MessageBox.Show("周期構造境界節点番号情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int nodeNumber = int.Parse(tokens[0]); workNodesB.Add(nodeNumber); } nodePeriodicB.Add(workNodesB); } nodePeriodicBList.Add(nodePeriodicB); } // 周期構造領域内要素番号 for (int portIndex = 0; portIndex < portCnt; portIndex++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 3 || tokens[0] != "defectNodePeriodic") { MessageBox.Show("周期構造領域欠陥部節点情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int tmpIndex = int.Parse(tokens[1]); System.Diagnostics.Debug.Assert(tmpIndex == portIndex); int cnt = int.Parse(tokens[2]); IList<int> defectNodePeriodic = new List<int>(); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 1) { MessageBox.Show("周期構造領域欠陥部節点番号情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } int nodeNumber = int.Parse(tokens[0]); defectNodePeriodic.Add(nodeNumber); } defectNodePeriodicList.Add(defectNodePeriodic); } line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "IncidentPortNo") { MessageBox.Show("入射ポート番号がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } incidentPortNo = int.Parse(tokens[1]); line = sr.ReadLine(); if (line == null || line.Length == 0) { // 媒質情報なし } else { // 媒質情報? tokens = line.Split(delimiter); if (tokens[0] != "Medias") { MessageBox.Show("媒質情報がありません"); return false; } int cnt = int.Parse(tokens[1]); if (cnt > Constants.MaxMediaCount) { MessageBox.Show("媒質情報の個数が不正です"); return false; } for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); if (line.Length == 0) { MessageBox.Show("媒質情報が不正です"); return false; } tokens = line.Split(delimiter); if (tokens.Length != 1 + 9 + 9) { MessageBox.Show("媒質情報が不正です"); return false; } int mediaIndex = int.Parse(tokens[0]); System.Diagnostics.Debug.Assert(mediaIndex == i); double[,] p = new double[3, 3]; for (int m = 0; m < p.GetLength(0); m++) { for (int n = 0; n < p.GetLength(1); n++) { p[m, n] = double.Parse(tokens[1 + m * p.GetLength(1) + n]); } } medias[i].SetP(p); double[,] q = new double[3, 3]; for (int m = 0; m < q.GetLength(0); m++) { for (int n = 0; n < q.GetLength(1); n++) { q[m, n] = double.Parse(tokens[1 + 9 + m * q.GetLength(1) + n]); } } medias[i].SetQ(q); } } line = sr.ReadLine(); if (line == null || line.Length == 0) { } else { tokens = line.Split(delimiter); if (tokens.Length != 4 || tokens[0] != "WaveLengthRange") { MessageBox.Show("計算対象周波数情報がありません"); return false; } firstWaveLength = double.Parse(tokens[1]); lastWaveLength = double.Parse(tokens[2]); calcCnt = int.Parse(tokens[3]); } line = sr.ReadLine(); if (line == null || line.Length == 0) { } else { tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "WaveModeDv") { MessageBox.Show("計算対象モード区分情報がありません"); return false; } if (tokens[1] == "TE") { waveModeDv = FemSolver.WaveModeDV.TE; } else if (tokens[1] == "TM") { waveModeDv = FemSolver.WaveModeDV.TM; } else { MessageBox.Show("計算対象モード区分情報が不正です"); return false; } } } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } return true; }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <param name="waveLength">波長</param> /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> /// <param name="element">有限要素</param> /// <param name="Nodes">節点リスト</param> /// <param name="Medias">媒質リスト</param> /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="mat">マージされる全体行列</param> public static void AddElementMat( double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDV WaveModeDv, ref MyComplexMatrix mat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.TriVertexCnt; //3; // 要素内節点数 const int nno = Constants.TriNodeCnt_SecondOrder; //6; // 2次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得 double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WaveModeDv, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //System.Diagnostics.Debug.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // 形状関数の微分の係数を求める // dndxC[ino,n,k] ino節点のn方向微分のLk(k面積座標)の係数 // dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3] double[, ,] dndxC = new double[nno, ndim, vertexCnt + 1] { { {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]}, {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]}, }, { {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]}, {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]}, }, { {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]}, {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]}, }, { {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0}, {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0}, }, { {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0}, {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0}, }, { {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0}, {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0}, }, }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; for (int n = 0; n < ndim; n++) { for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[n, ino, jno] = area / 6.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 1] + dndxC[ino, n, 2] * dndxC[jno, n, 2]) + area / 12.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 1] + dndxC[ino, n, 0] * dndxC[jno, n, 2] + dndxC[ino, n, 1] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 2] + dndxC[ino, n, 2] * dndxC[jno, n, 0] + dndxC[ino, n, 2] * dndxC[jno, n, 1]) + area / 3.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 3] + dndxC[ino, n, 1] * dndxC[jno, n, 3] + dndxC[ino, n, 2] * dndxC[jno, n, 3] + dndxC[ino, n, 3] * dndxC[jno, n, 0] + dndxC[ino, n, 3] * dndxC[jno, n, 1] + dndxC[ino, n, 3] * dndxC[jno, n, 2]) + area * dndxC[ino, n, 3] * dndxC[jno, n, 3]; } } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 6.0 * area / 180.0, -1.0 * area / 180.0, -1.0 * area / 180.0, 0.0, -4.0 * area / 180.0, 0.0}, { -1.0 * area / 180.0, 6.0 * area / 180.0, -1.0 * area / 180.0, 0.0, 0.0, -4.0 * area / 180.0}, { -1.0 * area / 180.0, -1.0 * area / 180.0, 6.0 * area / 180.0, -4.0 * area / 180.0, 0.0, 0.0}, { 0.0, 0.0, -4.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0, 16.0 * area / 180.0}, { -4.0 * area / 180.0, 0.0, 0.0, 16.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0}, { 0.0, -4.0 * area / 180.0, 0.0, 16.0 * area / 180.0, 16.0 * area / 180.0, 32.0 * area / 180.0}, }; // 要素剛性行列を作る double[,] emat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = media_P[0, 0] * integralDNDX[1, ino, jno] + media_P[1, 1] * integralDNDX[0, ino, jno] - k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSorted[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSorted[jNodeNumber]; //mat[inoGlobal, jnoGlobal] += emat[ino, jno]; //mat._body[inoGlobal + jnoGlobal * mat.RowSize] += emat[ino, jno]; // 実数部に加算する //mat._body[inoGlobal + jnoGlobal * mat.RowSize].Real += emat[ino, jno]; // バンドマトリクス対応 mat._body[mat.GetBufferIndex(inoGlobal, jnoGlobal)].Real += emat[ino, jno]; } } }
/// <summary> /// 周期構造導波路固有値問題用FEM行列の追加 /// </summary> /// <param name="isYDirectionPeriodic"></param> /// <param name="waveLength"></param> /// <param name="nodeCntPeriodic"></param> /// <param name="freeNodeCntPeriodic_0"></param> /// <param name="toSortedPeriodic"></param> /// <param name="element"></param> /// <param name="Nodes"></param> /// <param name="Medias"></param> /// <param name="ForceNodeNumberH"></param> /// <param name="WaveModeDv"></param> /// <param name="KMat"></param> public static void AddElementMatPeriodic( bool isYDirectionPeriodic, bool isSVEA, double waveLength, int nodeCntPeriodic, int freeNodeCntPeriodic_0, Dictionary<int, int> toSortedPeriodic, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WaveModeDV WaveModeDv, ref double[] KMat, ref double[] CMat, ref double[] MMat) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 const int vertexCnt = Constants.TriVertexCnt; //3; // 要素内節点数 const int nno = Constants.TriNodeCnt_SecondOrder; //6; // 2次三角形要素 // 座標次元数 const int ndim = Constants.CoordDim2D; //2; int[] nodeNumbers = element.NodeNumbers; int[] no_c = new int[nno]; MediaInfo media = Medias[element.MediaIndex]; // ver1.1.0.0 媒質情報の取得 double[,] media_P = null; double[,] media_Q = null; // ヘルムホルツ方程式のパラメータP,Qを取得する FemSolver.GetHelmholtzMediaPQ( k0, media, WaveModeDv, out media_P, out media_Q); // 節点座標(IFの都合上配列の配列形式の2次元配列を作成) double[][] pp = new double[nno][]; for (int ino = 0; ino < nno; ino++) { int nodeNumber = nodeNumbers[ino]; int nodeIndex = nodeNumber - 1; FemNode node = Nodes[nodeIndex]; no_c[ino] = nodeNumber; pp[ino] = new double[ndim]; for (int n = 0; n < ndim; n++) { pp[ino][n] = node.Coord[n]; } } // 面積を求める double area = KerEMatTri.TriArea(pp[0], pp[1], pp[2]); //System.Diagnostics.Debug.WriteLine("Elem No {0} area: {1}", element.No, area); System.Diagnostics.Debug.Assert(area >= 0.0); // 面積座標の微分を求める // dldx[k, n] k面積座標Lkのn方向微分 double[,] dldx = null; double[] const_term = null; KerEMatTri.TriDlDx(out dldx, out const_term, pp[0], pp[1], pp[2]); // 形状関数の微分の係数を求める // dndxC[ino,n,k] ino節点のn方向微分のLk(k面積座標)の係数 // dNino/dn = dndxC[ino, n, 0] * L0 + dndxC[ino, n, 1] * L1 + dndxC[ino, n, 2] * L2 + dndxC[ino, n, 3] double[, ,] dndxC = new double[nno, ndim, vertexCnt + 1] { { {4.0 * dldx[0, 0], 0.0, 0.0, -1.0 * dldx[0, 0]}, {4.0 * dldx[0, 1], 0.0, 0.0, -1.0 * dldx[0, 1]}, }, { {0.0, 4.0 * dldx[1, 0], 0.0, -1.0 * dldx[1, 0]}, {0.0, 4.0 * dldx[1, 1], 0.0, -1.0 * dldx[1, 1]}, }, { {0.0, 0.0, 4.0 * dldx[2, 0], -1.0 * dldx[2, 0]}, {0.0, 0.0, 4.0 * dldx[2, 1], -1.0 * dldx[2, 1]}, }, { {4.0 * dldx[1, 0], 4.0 * dldx[0, 0], 0.0, 0.0}, {4.0 * dldx[1, 1], 4.0 * dldx[0, 1], 0.0, 0.0}, }, { {0.0, 4.0 * dldx[2, 0], 4.0 * dldx[1, 0], 0.0}, {0.0, 4.0 * dldx[2, 1], 4.0 * dldx[1, 1], 0.0}, }, { {4.0 * dldx[2, 0], 0.0, 4.0 * dldx[0, 0], 0.0}, {4.0 * dldx[2, 1], 0.0, 4.0 * dldx[0, 1], 0.0}, }, }; // ∫dN/dndN/dn dxdy // integralDNDX[n, ino, jno] n = 0 --> ∫dN/dxdN/dx dxdy // n = 1 --> ∫dN/dydN/dy dxdy double[, ,] integralDNDX = new double[ndim, nno, nno]; for (int n = 0; n < ndim; n++) { for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[n, ino, jno] = area / 6.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 1] + dndxC[ino, n, 2] * dndxC[jno, n, 2]) + area / 12.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 1] + dndxC[ino, n, 0] * dndxC[jno, n, 2] + dndxC[ino, n, 1] * dndxC[jno, n, 0] + dndxC[ino, n, 1] * dndxC[jno, n, 2] + dndxC[ino, n, 2] * dndxC[jno, n, 0] + dndxC[ino, n, 2] * dndxC[jno, n, 1]) + area / 3.0 * (dndxC[ino, n, 0] * dndxC[jno, n, 3] + dndxC[ino, n, 1] * dndxC[jno, n, 3] + dndxC[ino, n, 2] * dndxC[jno, n, 3] + dndxC[ino, n, 3] * dndxC[jno, n, 0] + dndxC[ino, n, 3] * dndxC[jno, n, 1] + dndxC[ino, n, 3] * dndxC[jno, n, 2]) + area * dndxC[ino, n, 3] * dndxC[jno, n, 3]; } } } // ∫(dNi/dx)Nj dxdy // ∫(dNi/dy)Nj dxdy double[, ,] integralDNDXL = new double[2, nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int n = 0; n < ndim; n++) { integralDNDXL[n, ino, 0] = (area / 30.0) * dndxC[ino, n, 0] - (area / 60.0) * (dndxC[ino, n, 1] + dndxC[ino, n, 2]); integralDNDXL[n, ino, 1] = (area / 30.0) * dndxC[ino, n, 1] - (area / 60.0) * (dndxC[ino, n, 0] + dndxC[ino, n, 2]); integralDNDXL[n, ino, 2] = (area / 30.0) * dndxC[ino, n, 2] - (area / 60.0) * (dndxC[ino, n, 0] + dndxC[ino, n, 1]); integralDNDXL[n, ino, 3] = (area / 15.0) * (2.0 * dndxC[ino, n, 0] + 2.0 * dndxC[ino, n, 1] + dndxC[ino, n, 2] + 5.0 * dndxC[ino, n, 3]); integralDNDXL[n, ino, 4] = (area / 15.0) * (dndxC[ino, n, 0] + 2.0 * dndxC[ino, n, 1] + 2.0 * dndxC[ino, n, 2] + 5.0 * dndxC[ino, n, 3]); integralDNDXL[n, ino, 5] = (area / 15.0) * (2.0 * dndxC[ino, n, 0] + dndxC[ino, n, 1] + 2.0 * dndxC[ino, n, 2] + 5.0 * dndxC[ino, n, 3]); } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 6.0 * area / 180.0, -1.0 * area / 180.0, -1.0 * area / 180.0, 0.0, -4.0 * area / 180.0, 0.0}, { -1.0 * area / 180.0, 6.0 * area / 180.0, -1.0 * area / 180.0, 0.0, 0.0, -4.0 * area / 180.0}, { -1.0 * area / 180.0, -1.0 * area / 180.0, 6.0 * area / 180.0, -4.0 * area / 180.0, 0.0, 0.0}, { 0.0, 0.0, -4.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0, 16.0 * area / 180.0}, { -4.0 * area / 180.0, 0.0, 0.0, 16.0 * area / 180.0, 32.0 * area / 180.0, 16.0 * area / 180.0}, { 0.0, -4.0 * area / 180.0, 0.0, 16.0 * area / 180.0, 16.0 * area / 180.0, 32.0 * area / 180.0}, }; // 要素剛性行列を作る double[,] eKMat = new double[nno, nno]; double[,] eCMat = new double[nno, nno]; double[,] eMMat = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { eKMat[ino, jno] = -media_P[0, 0] * integralDNDX[1, ino, jno] - media_P[1, 1] * integralDNDX[0, ino, jno] + k0 * k0 * media_Q[2, 2] * integralN[ino, jno]; if (isSVEA) { if (isYDirectionPeriodic) { eCMat[ino, jno] = -media.P[1, 1] * (integralDNDXL[1, ino, jno] - integralDNDXL[1, jno, ino]); } else { eCMat[ino, jno] = -media.P[1, 1] * (integralDNDXL[0, ino, jno] - integralDNDXL[0, jno, ino]); } // 要素質量行列 eMMat[ino, jno] = media.P[1, 1] * integralN[ino, jno]; } } } // 要素剛性行列にマージする for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; int inoGlobal = toSortedPeriodic[iNodeNumber]; for (int jno = 0; jno < nno; jno++) { int jNodeNumber = no_c[jno]; if (ForceNodeNumberH.ContainsKey(jNodeNumber)) continue; int jnoGlobal = toSortedPeriodic[jNodeNumber]; KMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eKMat[ino, jno]; if (isSVEA) { CMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eCMat[ino, jno]; MMat[inoGlobal + freeNodeCntPeriodic_0 * jnoGlobal] += eMMat[ino, jno]; } } } }
/// <summary> /// フィールド値をセットする /// </summary> /// <param name="valuesAll"></param> /// <param name="nodesRegionToIndex"></param> /// <param name="factorForRot">回転に掛ける因子(磁界または電界への変換)</param> public virtual void SetFieldValueFromAllValues(Complex[] valuesAll, Dictionary<int, int> nodesRegionToIndex, Complex factorForRot, double[,] media_Q, FemSolver.WaveModeDV waveModeDv) { _FValues = new Complex[NodeNumbers.Length]; for (int ino = 0; ino < NodeNumbers.Length; ino++) { int nodeNumber = NodeNumbers[ino]; if (nodesRegionToIndex.ContainsKey(nodeNumber)) { int nodeIndex = nodesRegionToIndex[nodeNumber]; //_FValues[ino] = valuesAll[nodeIndex]; _FValues[ino].Real = valuesAll[nodeIndex].Real; _FValues[ino].Imaginary = valuesAll[nodeIndex].Imaginary; } else { // 強制境界とみなす //_FValues[ino] = new Complex(); } } _FactorForRot = factorForRot; for (int i = 0; i < _media_Q.GetLength(0); i++) { for (int j = 0; j < _media_Q.GetLength(1); j++) { _media_Q[i, j] = media_Q[i, j]; } } _WaveModeDv = waveModeDv; // フィールドの回転を求める calcRotField(out _RotXFValues, out _RotYFValues); // 複素共役を格納 //if (_RotXFValues != null && _RotYFValues != null) //{ // int nno = NodeNumbers.Length; // for (int ino = 0; ino < nno; ino++) // { // _RotXFValues[ino] = Complex.Conjugate(_RotXFValues[ino]); // _RotYFValues[ino] = Complex.Conjugate(_RotYFValues[ino]); // } //} // 回転を計算できたら(実装されていたら)、複素ポインティングベクトルを計算する _PoyntingXFValues = null; _PoyntingYFValues = null; if (_RotXFValues != null && _RotYFValues != null) { int nno = NodeNumbers.Length; _PoyntingXFValues = new Complex[nno]; _PoyntingYFValues = new Complex[nno]; for (int ino = 0; ino < nno; ino++) { { if (_WaveModeDv == FemSolver.WaveModeDV.TM) { // F:磁界(Z成分) // G:電界(XY成分) // E x H* = rot x (fz)* = { (fz)*(roty), - (fz)* (rotx) } (rotは_FactorForRotを乗算済み) //_PoyntingXFValues[ino] = -1.0 * Complex.Conjugate(_FValues[ino]) * _RotYFValues[ino]; //_PoyntingYFValues[ino] = Complex.Conjugate(_FValues[ino]) * _RotXFValues[ino]; _PoyntingXFValues[ino] = -1.0 * _FValues[ino] * Complex.Conjugate(_RotYFValues[ino]); _PoyntingYFValues[ino] = _FValues[ino] * Complex.Conjugate(_RotXFValues[ino]); } else { // F:電界(Z成分) // G:磁界(XY成分) // (E x H*) = (fz x (rot)*) = { - fz(roty)*, fz (rotx)* } (rotは_FactorForRotを乗算済み) _PoyntingXFValues[ino] = _FValues[ino] * Complex.Conjugate(_RotYFValues[ino]); //_PoyntingYFValues[ino] = -1.0 * _FValues[ino] * Complex.Conjugate(_RotXFValues[ino]); _PoyntingYFValues[ino] = _FValues[ino] * Complex.Conjugate(_RotXFValues[ino]); } } } } }