/// <summary> /// コピー /// </summary> /// <param name="src"></param> public void CP(FemNode src) { No = src.No; Coord = null; if (src.Coord != null) { Coord = new double[src.Coord.Length]; for (int i = 0; i < src.Coord.Length; i++) { Coord[i] = src.Coord[i]; } } }
/// <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); int y = (int)((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> /// Fem入力データの取得 /// </summary> /// <param name="outNodes">節点リスト</param> /// <param name="outElements">要素リスト</param> /// <param name="outMedias">媒質リスト</param> /// <param name="outPorts">ポート節点番号リストのリスト</param> /// <param name="outForceNodes">強制境界節点番号リスト</param> /// <param name="outIncidentPortNo">入射ポート番号</param> /// <param name="outWaveguideWidth">導波路の幅</param> public void GetFemInputInfo( out FemNode[] outNodes, out FemElement[] outElements, out MediaInfo[] outMedias, out IList<int[]> outPorts, out int[] outForceNodes, out int outIncidentPortNo, out double outWaveguideWidth, out double outLatticeA) { outNodes = null; outElements = null; outMedias = null; outPorts = null; outForceNodes = null; outIncidentPortNo = 1; outWaveguideWidth = DefWaveguideWidth; outLatticeA = 1.0; /* データの判定は取得した側が行う(メッシュ表示で、ポートを指定しないとメッシュが表示されないのを解消するためここで判定するのを止める) if (!isInputDataValid()) { return; } */ int nodeCnt = Nodes.Count; outNodes = new FemNode[nodeCnt]; for (int i = 0; i < nodeCnt; i++) { FemNode femNode = new FemNode(); femNode.CP(Nodes[i]); outNodes[i] = femNode; } int elementCnt = Elements.Count; outElements = new FemElement[elementCnt]; for (int i = 0; i < elementCnt; i++) { //FemElement femElement = new FemElement(); FemElement femElement = FemMeshLogic.CreateFemElementByElementNodeCnt(Elements[i].NodeNumbers.Length); femElement.CP(Elements[i]); outElements[i] = femElement; } if (Medias != null) { outMedias = new MediaInfo[Medias.Length]; for (int i = 0; i < Medias.Length; i++) { outMedias[i] = Medias[i].Clone() as MediaInfo; } } int portCnt = Ports.Count; outPorts = new List<int[]>(); foreach (IList<int> portNodes in Ports) { int[] outPortNodes = new int[portNodes.Count]; for (int inoB = 0; inoB < portNodes.Count; inoB++) { outPortNodes[inoB] = portNodes[inoB]; } outPorts.Add(outPortNodes); } outForceNodes = new int[ForceBCNodes.Count]; for (int i = 0; i < ForceBCNodes.Count; i++) { outForceNodes[i] = ForceBCNodes[i]; } outIncidentPortNo = IncidentPortNo; outWaveguideWidth = WaveguideWidth; outLatticeA = LatticeA; }
/// <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++; } }
/// <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="nodes"></param> public override void SetNodesFromAllNodes(FemNode[] nodes) { // ベースクラスの処理を実行 base.SetNodesFromAllNodes(nodes); // 描画領域を準備する setupDrawRect(out _RectLiList, out _OrginVertexNo); }
/// <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="nodes">節点情報配列(強制境界を含む全節点を節点番号順に格納した配列)</param> public virtual void SetNodesFromAllNodes(FemNode[] nodes) { _Nodes = new FemNode[NodeNumbers.Length]; for (int i = 0; i < NodeNumbers.Length; i++) { int nodeNumber = NodeNumbers[i]; _Nodes[i] = nodes[nodeNumber - 1]; System.Diagnostics.Debug.Assert(nodeNumber == _Nodes[i].No); } }
/// <summary> /// フィールドの回転を取得する /// </summary> /// <param name="rotXFValues"></param> /// <param name="rotYFValues"></param> protected override void calcRotField(out Complex[] rotXFValues, out Complex[] rotYFValues) { base.calcRotField(out rotXFValues, out rotYFValues); rotXFValues = new Complex[NodeNumbers.Length]; rotYFValues = new Complex[NodeNumbers.Length]; const int ndim = Constants.CoordDim2D; //2; // 座標の次元数 const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ) //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6; // 三角形2次要素 int nodeCnt = NodeNumbers.Length; if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder) { return; } // 三角形の頂点を取得 double[][] pp = new double[vertexCnt][]; for (int ino = 0; ino < pp.GetLength(0); ino++) { FemNode node = _Nodes[ino]; System.Diagnostics.Debug.Assert(node.Coord.Length == ndim); pp[ino] = new double[ndim]; pp[ino][0] = node.Coord[0]; pp[ino][1] = node.Coord[1]; } // 面積座標の微分を求める // 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 = null; if (nodeCnt == Constants.TriNodeCnt_FirstOrder) { dndxC = new double[Constants.TriNodeCnt_FirstOrder, ndim, vertexCnt + 1] { { { 0.0, 0.0, 0.0, dldx[0, 0] }, { 0.0, 0.0, 0.0, dldx[0, 1] }, }, { { 0.0, 0.0, 0.0, dldx[1, 0] }, { 0.0, 0.0, 0.0, dldx[1, 1] }, }, { { 0.0, 0.0, 0.0, dldx[2, 0] }, { 0.0, 0.0, 0.0, dldx[2, 1] }, }, }; } else { dndxC = new double[Constants.TriNodeCnt_SecondOrder, 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 }, }, }; } // 節点の面積座標 double[][] n_pts = null; if (nodeCnt == Constants.TriNodeCnt_FirstOrder) { n_pts = new double[Constants.TriNodeCnt_FirstOrder][] { new double[vertexCnt] { 1.0, 0.0, 0.0 }, new double[vertexCnt] { 0.0, 1.0, 0.0 }, new double[vertexCnt] { 0.0, 0.0, 1.0 }, }; } else { n_pts = new double[Constants.TriNodeCnt_SecondOrder][] { new double[vertexCnt] { 1.0, 0.0, 0.0 }, new double[vertexCnt] { 0.0, 1.0, 0.0 }, new double[vertexCnt] { 0.0, 0.0, 1.0 }, new double[vertexCnt] { 0.5, 0.5, 0.0 }, new double[vertexCnt] { 0.0, 0.5, 0.5 }, new double[vertexCnt] { 0.5, 0.0, 0.5 }, }; } for (int ino = 0; ino < nodeCnt; ino++) { double[] L = n_pts[ino]; double[] dNdx = new double[nodeCnt]; double[] dNdy = new double[nodeCnt]; for (int k = 0; k < nodeCnt; k++) { int direction; direction = 0; dNdx[k] = dndxC[k, direction, 0] * L[0] + dndxC[k, direction, 1] * L[1] + dndxC[k, direction, 2] * L[2] + dndxC[k, direction, 3]; direction = 1; dNdy[k] = dndxC[k, direction, 0] * L[0] + dndxC[k, direction, 1] * L[1] + dndxC[k, direction, 2] * L[2] + dndxC[k, direction, 3]; } rotXFValues[ino] = new Complex(); rotYFValues[ino] = new Complex(); for (int k = 0; k < nodeCnt; k++) { // (rot(Ez)x = dEz/dy rotXFValues[ino] += _FValues[k] * dNdy[k]; // (rot(Ez)y = - dEz/dx rotYFValues[ino] += -1.0 * _FValues[k] * dNdx[k]; } // rot(Ez)を磁界の値に変換する rotXFValues[ino] *= _FactorForRot / _media_Q[0, 0]; rotYFValues[ino] *= _FactorForRot / _media_Q[1, 1]; } }
/// <summary> /// フィールド値の回転を描画する /// </summary> /// <param name="g"></param> /// <param name="ofs"></param> /// <param name="delta"></param> /// <param name="regionSize"></param> /// <param name="drawColor"></param> /// <param name="fieldDv"></param> /// <param name="minRotFValue"></param> /// <param name="maxRotFValue"></param> public override void DrawRotField(Graphics g, Size ofs, Size delta, Size regionSize, Color drawColor, FemElement.FieldDV fieldDv, double minRotFValue, double maxRotFValue) { if (_Nodes == null || _FValues == null || _RotXFValues == null || _RotYFValues == null || _PoyntingXFValues == null || _PoyntingYFValues == null) { return; } Complex[] tagtXValues = null; Complex[] tagtYValues = null; if (fieldDv == FemElement.FieldDV.PoyntingXY) { tagtXValues = _PoyntingXFValues; tagtYValues = _PoyntingYFValues; } else if (fieldDv == FemElement.FieldDV.RotXY) { tagtXValues = _RotXFValues; tagtYValues = _RotYFValues; } else { return; } const int ndim = Constants.CoordDim2D; //2; // 座標の次元数 const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ) //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6; // 三角形2次要素 int nodeCnt = NodeNumbers.Length; if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder) { return; } // 三角形の節点座標を取得 double[][] pp = new double[nodeCnt][]; for (int ino = 0; ino < pp.GetLength(0); ino++) { FemNode node = _Nodes[ino]; System.Diagnostics.Debug.Assert(node.Coord.Length == ndim); pp[ino] = new double[ndim]; pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width; //pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height; pp[ino][1] = node.Coord[1] * delta.Height + ofs.Height; } // 表示する位置の面積座標 double[] Li = new double[vertexCnt] { 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0 }; // 表示する位置の形状関数 double[] vNi = null; if (nodeCnt == Constants.TriNodeCnt_FirstOrder) { vNi = new double[] { Li[0], Li[1], Li[2] }; } else { vNi = new double[] { Li[0] * (2.0 * Li[0] - 1.0), Li[1] * (2.0 * Li[1] - 1.0), Li[2] * (2.0 * Li[2] - 1.0), 4.0 * Li[0] * Li[1], 4.0 * Li[1] * Li[2], 4.0 * Li[2] * Li[0], }; } // 表示する位置 double showPosX = 0; double showPosY = 0; for (int k = 0; k < nodeCnt; k++) { showPosX += pp[k][0] * vNi[k]; showPosY += pp[k][1] * vNi[k]; } Complex cvalueX = new Complex(0, 0); Complex cvalueY = new Complex(0, 0); for (int k = 0; k < nodeCnt; k++) { cvalueX += tagtXValues[k] * vNi[k]; cvalueY += tagtYValues[k] * vNi[k]; } try { double showScale = ((double)regionSize.Width / DefPanelWidth) * ArrowLength; // 実数部のベクトル表示 int lenX = 0; int lenY = 0; if (Math.Abs(maxRotFValue) >= Constants.PrecisionLowerLimit) { lenX = (int)((double)(cvalueX.Real / maxRotFValue) * showScale); lenY = (int)((double)(cvalueY.Real / maxRotFValue) * showScale); } if (lenX != 0 || lenY != 0) { // Y方向は表示上逆になる lenY = -lenY; using (Pen pen = new Pen(drawColor, 1)) { //pen.DashStyle = System.Drawing.Drawing2D.DashStyle.Dot; //pen.StartCap = System.Drawing.Drawing2D.LineCap.Round; pen.EndCap = System.Drawing.Drawing2D.LineCap.ArrowAnchor; //pen.CustomEndCap = new System.Drawing.Drawing2D.AdjustableArrowCap(3, 3, false); // 重い g.DrawLine(pen, (int)showPosX, (int)showPosY, (int)(showPosX + lenX), (int)(showPosY + lenY)); } } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); } }
/// <summary> /// 描画領域をセットアップ /// </summary> /// <param name="out_rectLiList"></param> private void setupDrawRect(out IList <double[][]> out_rectLiList, out int orginVertexNo) { orginVertexNo = 2; out_rectLiList = new List <double[][]>(); if (_Nodes == null) { return; } const int ndim = Constants.CoordDim2D; //2; // 座標の次元数 const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ) //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6; // 三角形2次要素 int nodeCnt = NodeNumbers.Length; if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder) { return; } // 三角形の節点座標を取得 double[][] pp = new double[nodeCnt][]; for (int ino = 0; ino < pp.GetLength(0); ino++) { FemNode node = _Nodes[ino]; System.Diagnostics.Debug.Assert(node.Coord.Length == ndim); pp[ino] = new double[ndim]; // 取りあえず規格化した値で計算する pp[ino][0] = node.Coord[0]; pp[ino][1] = -node.Coord[1]; // Y方向は逆にする } // 下記分割ロジックの原点となる頂点 // 頂点0固定で計算していたが、原点の内角が直角のとき長方形メッシュになるので原点を2(頂点を0,1,2としたとき)にする //int orginVertexNo = 2; // 内角が最大の頂点を取得し、その頂点を原点とする(後のロジックは原点が頂点を0,1,2としたとき、2になっている { double minCosth = double.MaxValue; int minCosthVertexNo = 0; for (int ino = 0; ino < vertexCnt; ino++) { const int vecCnt = 2; double[][] vec = new double[vecCnt][] { new double[ndim] { 0, 0 }, new double[ndim] { 0, 0 } }; double[] len = new double[vecCnt]; double costh; { int n1 = ino; int n2 = (ino + 1) % 3; int n3 = (ino + 2) % 3; vec[0][0] = pp[n2][0] - pp[n1][0]; vec[0][1] = pp[n2][1] - pp[n1][1]; vec[1][0] = pp[n3][0] - pp[n1][0]; vec[1][1] = pp[n3][1] - pp[n1][1]; len[0] = FemMeshLogic.GetDistance(pp[n1], pp[n2]); len[1] = FemMeshLogic.GetDistance(pp[n1], pp[n3]); costh = (vec[0][0] * vec[1][0] + vec[0][1] * vec[1][1]) / (len[0] * len[1]); if (costh < minCosth) { minCosth = costh; minCosthVertexNo = ino; } } } orginVertexNo = (minCosthVertexNo + 2) % 3; } // 三角形内部を四角形で分割 // 面積座標L1方向分割数 //int ndiv = 4; //int ndiv = this.IsCoarseFieldMesh ? (Constants.TriDrawFieldMshDivCnt / 2) : Constants.TriDrawFieldMshDivCnt; int ndiv = this.IsCoarseFieldMesh ? 1 : Constants.TriDrawFieldMshDivCnt; double defdL1 = 1.0 / (double)ndiv; double defdL2 = defdL1; for (int i1 = 0; i1 < ndiv; i1++) { double vL1 = i1 * defdL1; double vL1Next = (i1 + 1) * defdL1; if (i1 == ndiv - 1) { vL1Next = 1.0; } double vL2max = 1.0 - vL1; if (vL2max < 0.0) { // ERROR System.Diagnostics.Debug.WriteLine("logic error vL2max = {0}", vL2max); continue; } double fdiv2 = (double)ndiv * vL2max; int ndiv2 = (int)fdiv2; if (fdiv2 - (double)ndiv2 > Constants.PrecisionLowerLimit) { ndiv2++; } for (int i2 = 0; i2 < ndiv2; i2++) { double vL2 = i2 * defdL2; double vL2Next = (i2 + 1) * defdL2; if (i2 == ndiv2 - 1) { vL2Next = vL2max; } double vL3 = 1.0 - vL1 - vL2; if (vL3 < 0.0) { // ERROR System.Diagnostics.Debug.WriteLine("logic error vL3 = {0}", vL3); continue; } // 四角形の頂点 const int rectVCnt = 4; double[][] rectLi = new double[rectVCnt][] { new double[] { vL1, vL2, 0 }, new double[] { vL1Next, vL2, 0 }, new double[] { vL1Next, vL2Next, 0 }, new double[] { vL1, vL2Next, 0 } }; if ((i1 == ndiv - 1) || (i2 == ndiv2 - 1)) { for (int k = 0; k < 3; k++) { rectLi[2][k] = rectLi[3][k]; } } for (int ino = 0; ino < rectVCnt; ino++) { if (rectLi[ino][0] < 0.0) { rectLi[ino][0] = 0.0; System.Diagnostics.Debug.WriteLine("logical error rectLi[{0}][0] = {1}", ino, rectLi[ino][0]); } if (rectLi[ino][0] > 1.0) { rectLi[ino][0] = 1.0; System.Diagnostics.Debug.WriteLine("logical error rectLi[{0}][0] = {1}", ino, rectLi[ino][0]); } if (rectLi[ino][1] < 0.0) { rectLi[ino][1] = 0.0; System.Diagnostics.Debug.WriteLine("logical error rectLi[{0}][1] = {1}", ino, rectLi[ino][1]); } if (rectLi[ino][1] > (1.0 - rectLi[ino][0])) // L2最大値(1 - L1)チェック { rectLi[ino][1] = 1.0 - rectLi[ino][0]; } rectLi[ino][2] = 1.0 - rectLi[ino][0] - rectLi[ino][1]; if (rectLi[ino][2] < 0.0) { System.Diagnostics.Debug.WriteLine("logical error rectLi[{0}][2] = {1}", ino, rectLi[ino][2]); } } /* * double[][] shiftedRectLi = new double[rectVCnt][]; * for (int ino = 0; ino < rectVCnt; ino++) * { * shiftedRectLi[ino] = new double[vertexCnt]; * for (int k = 0; k < vertexCnt; k++) * { * shiftedRectLi[ino][k] = rectLi[ino][(k + orginVertexNo) % vertexCnt]; * } * } * out_rectLiList.Add(shiftedRectLi); */ out_rectLiList.Add(rectLi); } } }
/// <summary> /// 対象のフィールドを描画する /// </summary> /// <param name="g"></param> /// <param name="ofs"></param> /// <param name="delta"></param> /// <param name="regionSize"></param> /// <param name="tagtValues"></param> /// <param name="valueDv"></param> /// <param name="colorMap"></param> public void doDrawField(Graphics g, Size ofs, Size delta, Size regionSize, Complex[] tagtValues, FemElement.ValueDV valueDv, ColorMap colorMap) { const int ndim = Constants.CoordDim2D; //2; // 座標の次元数 const int vertexCnt = Constants.TriVertexCnt; //3; // 三角形の頂点の数(2次要素でも同じ) //const int nodeCnt = Constants.TriNodeCnt_SecondOrder; //6; // 三角形2次要素 int nodeCnt = NodeNumbers.Length; if (nodeCnt != Constants.TriNodeCnt_SecondOrder && nodeCnt != Constants.TriNodeCnt_FirstOrder) { return; } // 三角形の節点座標を取得 double[][] pp = new double[nodeCnt][]; for (int ino = 0; ino < pp.GetLength(0); ino++) { FemNode node = _Nodes[ino]; System.Diagnostics.Debug.Assert(node.Coord.Length == ndim); pp[ino] = new double[ndim]; pp[ino][0] = node.Coord[0] * delta.Width + ofs.Width; //pp[ino][1] = regionSize.Height - node.Coord[1] * delta.Height + ofs.Height; pp[ino][1] = node.Coord[1] * delta.Height + ofs.Height; } // 長方形描画領域のリスト IList <double[][]> rectLiList = _RectLiList; // 描画ロジック上の原点となる頂点 int orginVertexNo = _OrginVertexNo; // 四角形の頂点 const int rectVCnt = 4; foreach (double[][] rectLi in rectLiList) { double[][] rectpp = new double[rectVCnt][]; for (int ino = 0; ino < rectVCnt; ino++) { double[] vLpp = rectLi[ino]; double xx = 0.0; double yy = 0.0; for (int k = 0; k < vertexCnt; k++) { xx += pp[k][0] * vLpp[(k + orginVertexNo) % vertexCnt]; yy += pp[k][1] * vLpp[(k + orginVertexNo) % vertexCnt]; } rectpp[ino] = new double[] { xx, yy }; } // 表示する位置 double[] vLi = new double[] { (rectLi[0][0] + rectLi[1][0]) * 0.5, (rectLi[0][1] + rectLi[3][1]) * 0.5, 0 }; if (vLi[0] < 0.0) { vLi[0] = 0.0; } if (vLi[0] > 1.0) { vLi[0] = 1.0; } if (vLi[1] < 0.0) { vLi[1] = 0.0; } if (vLi[1] > (1.0 - vLi[0])) { vLi[1] = (1.0 - vLi[0]); } vLi[2] = 1.0 - vLi[0] - vLi[1]; if (vLi[2] < 0.0) { System.Diagnostics.Debug.WriteLine("logic error vLi[2] = {0}", vLi[2]); } // 表示する値 Complex cvalue = new Complex(0.0, 0.0); // 表示する位置の形状関数値 double[] vNi = null; double[] shiftedLi = new double[vertexCnt]; for (int i = 0; i < vertexCnt; i++) { shiftedLi[i] = vLi[(i + orginVertexNo) % vertexCnt]; } if (nodeCnt == Constants.TriNodeCnt_FirstOrder) { vNi = new double[] { shiftedLi[0], shiftedLi[1], shiftedLi[2] }; } else { vNi = new double[] { shiftedLi[0] * (2.0 * shiftedLi[0] - 1.0), shiftedLi[1] * (2.0 * shiftedLi[1] - 1.0), shiftedLi[2] * (2.0 * shiftedLi[2] - 1.0), 4.0 * shiftedLi[0] * shiftedLi[1], 4.0 * shiftedLi[1] * shiftedLi[2], 4.0 * shiftedLi[2] * shiftedLi[0], }; } for (int k = 0; k < nodeCnt; k++) { cvalue += tagtValues[k] * vNi[k]; } // 四角形の頂点(描画用) Point[] rectp = new Point[rectVCnt]; for (int ino = 0; ino < rectVCnt; ino++) { rectp[ino] = new Point((int)rectpp[ino][0], (int)rectpp[ino][1]); } try { // 表示する値 double showValue = 0.0; if (valueDv == ValueDV.Real) { showValue = cvalue.Real; } else if (valueDv == ValueDV.Imaginary) { showValue = cvalue.Imaginary; } else { // 既定値は絶対値 showValue = Complex.Abs(cvalue); } // 塗りつぶし色の取得 Color fillColor = colorMap.GetColor(showValue); // 塗りつぶし using (Brush brush = new SolidBrush(fillColor)) { g.FillPolygon(brush, rectp); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); } } }