/// <summary> /// 要素境界を描画する /// </summary> /// <param name="g"></param> /// <param name="panel"></param> public void Draw(Graphics g, Size ofs, Size delta, Size regionSize, bool backFillFlg = false) { //const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ) Constants.FemElementShapeDV elemShapeDv; int order; int vertexCnt; FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(this.NodeNumbers.Length, out elemShapeDv, out order, out vertexCnt); // 三角形(or 四角形)の頂点を取得 Point[] points = new Point[vertexCnt]; for (int ino = 0; ino < vertexCnt; ino++) { FemNode node = _Nodes[ino]; System.Diagnostics.Debug.Assert(node.Coord.Length == 2); int x = (int)((double)node.Coord[0] * delta.Width); int y = (int)(regionSize.Height - (double)node.Coord[1] * delta.Height); points[ino] = new Point(x, y) + ofs; } // 三角形(or 四角形)を描画 if (backFillFlg) { // 要素の背景を塗りつぶす using (Brush brush = new SolidBrush(BackColor)) { g.FillPolygon(brush, points); } } using (Pen selectedPen = new Pen(LineColor, 1)) { // 境界線の描画 //selectedPen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; g.DrawPolygon(selectedPen, points); } }
/// <summary> /// ポート固有値解析 /// </summary> public static void SolvePortWaveguideEigen( FemSolver.WaveModeDV WaveModeDv, double waveLength, int maxModeSpecified, 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, out Complex[] eigenValues, out Complex[,] eigenVecs) { //System.Diagnostics.Debug.WriteLine("solvePortWaveguideEigen: {0},{1}", waveLength, portNo); nodesBoundary = null; ryy_1d = null; eigenValues = null; eigenVecs = 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; GetMatNonzeroPatternForEigen(elements, toSorted, out matPattern); 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; // 固有値、固有ベクトル int maxMode = maxModeSpecified; if (maxMode > nodeCnt) { maxMode = nodeCnt; } eigenValues = new Complex[maxMode]; eigenVecs = new Complex[maxMode, nodeCnt]; // 固有モード解析でのみ使用する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); } } // [A] = [Txx] - k0 * k0 *[Uzz] //メモリ節約 //MyDoubleMatrix matA = new MyDoubleMatrix(nodeCnt, nodeCnt); MyDoubleSymmetricBandMatrix matA = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize); for (int ino = 0; ino < nodeCnt; ino++) { for (int jno = 0; jno < nodeCnt; jno++) { // 対称バンド行列対応 if (matA is MyDoubleSymmetricBandMatrix && ino > jno) { continue; } // 剛性行列 //matA[ino, jno] = txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno]; // 質量行列matBが正定値行列となるように剛性行列matAの方の符号を反転する matA[ino, jno] = -(txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno]); } } // ( [txx] - k0^2[uzz] + β^2[ryy]){Ez} = {0}より // [A]{x} = λ[B]{x}としたとき、λ = β^2 とすると[B] = -[ryy] //MyDoubleMatrix matB = MyMatrixUtil.product(-1.0, ryy_1d); // 質量行列が正定値となるようにするため、上記符号反転を剛性行列の方に反映し、質量行列はryy_1dをそのまま使用する //MyDoubleMatrix matB = new MyDoubleMatrix(ryy_1d); MyDoubleSymmetricBandMatrix matB = new MyDoubleSymmetricBandMatrix((MyDoubleSymmetricBandMatrix)ryy_1d); // 一般化固有値問題を解く Complex[] evals = null; Complex[,] evecs = null; try { // 固有値、固有ベクトルを求める solveEigen(matA, matB, out evals, out evecs); // 固有値のソート Sort1DEigenMode(k0, evals, evecs); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); System.Diagnostics.Debug.Assert(false); } for (int imode = 0; imode < evecs.GetLength(0); imode++) { KrdLab.clapack.Complex phaseShift = 1.0; double maxAbs = double.MinValue; KrdLab.clapack.Complex fValueAtMaxAbs = 0.0; { // 境界上で位相調整する for (int ino = 0; ino < evecs.GetLength(1); ino++) { KrdLab.clapack.Complex cvalue = evecs[imode, ino]; double abs = KrdLab.clapack.Complex.Abs(cvalue); if (abs > maxAbs) { maxAbs = abs; fValueAtMaxAbs = cvalue; } } } if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit) { phaseShift = fValueAtMaxAbs / maxAbs; } //System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi); for (int ino = 0; ino < evecs.GetLength(1); ino++) { evecs[imode, ino] /= phaseShift; } } for (int imode = 0; imode < maxMode; imode++) { eigenValues[imode] = 0; } for (int tagtModeIdx = evals.Length - 1, imode = 0; tagtModeIdx >= 0 && imode < maxMode; tagtModeIdx--) { // 伝搬定数は固有値のsqrt Complex betam = Complex.Sqrt(evals[tagtModeIdx]); // 定式化BUGFIX // 減衰定数は符号がマイナス(β = -jα) bool isConjugateMode = false; if (betam.Imaginary >= 0.0) { betam = new Complex(betam.Real, -betam.Imaginary); isConjugateMode = true; } // 固有ベクトル Complex[] evec = MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIdx); if (isConjugateMode) { evec = MyMatrixUtil.vector_Conjugate(evec); } // 規格化定数を求める // 実数の場合 [ryy]*t = [ryy]t ryyは対称行列より[ryy]t = [ryy] Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec); Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec); { // H面、平行平板 if (WaveModeDv == FemSolver.WaveModeDV.TM) { dm = Complex.Sqrt(omega * eps0 / Complex.Abs(betam) / dm); } else { dm = Complex.Sqrt(omega * mu0 / Complex.Abs(betam) / dm); } } //System.Diagnostics.Debug.WriteLine("dm = " + dm); // 伝搬定数の格納 eigenValues[imode] = betam; // check if (imode < 5) { //System.Diagnostics.Debug.WriteLine("eigenValues [ " + imode + "] = " + betam.Real + " + " + betam.Imaginary + " i " + " tagtModeIdx :" + tagtModeIdx + " " ); System.Diagnostics.Debug.WriteLine("β/k0 [ " + imode + "] = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + " tagtModeIdx :" + tagtModeIdx + " "); } // 固有ベクトルの格納(規格化定数を掛ける) for (int inoSorted = 0; inoSorted < nodeCnt; inoSorted++) { Complex fm = dm * evec[inoSorted]; eigenVecs[imode, inoSorted] = fm; //System.Diagnostics.Debug.WriteLine("eigenVecs [ " + imode + ", " + inoSorted + "] = " + fm.Real + " + " + fm.Imaginary + " i Abs:" + Complex.Abs(fm)); } imode++; } }