/// <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> /// 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; } } }
public object Clone() { MediaInfo media = new MediaInfo(this.p, this.q); media.BackColor = this.BackColor; return (object)media; }
/// <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> /// ポート境界の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> /// 散乱行列の計算 /// </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> /// 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="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> /// <param name="filename"></param> /// <param name="AreaSelection"></param> /// <param name="EdgeList"></param> /// <param name="IncidentPortNo"></param> /// <param name="Medias"></param> /// <param name="ndivForOneLattice"></param> /// <param name="rodRadiusRatio"></param> /// <param name="rodCircleDiv"></param> /// <param name="rodRadiusDiv"></param> public static void SaveToFile( string filename, CadLogic.CellType[,] AreaSelection, IList<Edge> EdgeList, int IncidentPortNo, MediaInfo[] Medias, int ndivForOneLattice, double rodRadiusRatio, int rodCircleDiv, int rodRadiusDiv ) { Size MaxDiv = Constants.MaxDiv; try { using (StreamWriter sw = new StreamWriter(filename)) { int counter; string line; // 領域: 書き込む個数の計算 counter = 0; for (int y = 0; y < MaxDiv.Height; y++) { for (int x = 0; x < MaxDiv.Width; x++) { if (AreaSelection[y, x] != CadLogic.CellType.Empty) { counter++; } } } // 領域: 書き込み sw.WriteLine("AreaSelection,{0}", counter); for (int y = 0; y < MaxDiv.Height; y++) { for (int x = 0; x < MaxDiv.Width; x++) { CadLogic.CellType cellType = AreaSelection[y, x]; if (cellType != CadLogic.CellType.Empty) { string cellTypeStr = CadLogic.GetCellTypeStr(cellType); sw.WriteLine("{0},{1},{2}", x, y, cellTypeStr); } } } // ポート境界: 書き込み個数の計算 sw.WriteLine("EdgeList,{0}", EdgeList.Count); // ポート境界: 書き込み foreach (Edge edge in EdgeList) { sw.WriteLine("{0},{1},{2},{3},{4}", edge.No, edge.Points[0].X, edge.Points[0].Y, edge.Points[1].X, edge.Points[1].Y); } // 入射ポート番号 sw.WriteLine("IncidentPortNo,{0}", IncidentPortNo); ////////////////////////////////////////// //// Ver1.1.0.0からの追加情報 ////////////////////////////////////////// // 媒質情報の個数 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); } // 格子1辺の分割数 sw.WriteLine("ndivForOneLattice,{0}", ndivForOneLattice); // ロッドの半径の割合 sw.WriteLine("rodRadiusRatio,{0}", rodRadiusRatio); // ロッドの円周方向分割数 sw.WriteLine("rodCircleDiv,{0}", rodCircleDiv); // ロッドの半径方向分割数 sw.WriteLine("rodRadiusDiv,{0}", rodRadiusDiv); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } }
/// <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="filename"></param> /// <param name="areaSelection"></param> /// <param name="edgeList"></param> /// <param name="yBoundarySelection">2次的な情報(edgeListから生成される)</param> /// <param name="xBoundarySelection">2次的な情報(edgeListから生成される)</param> /// <param name="incidentPortNo"></param> /// <param name="medias"></param> /// <param name="ndivForOneLattice"></param> /// <param name="rodRadiusRatio"></param> /// <param name="rodCircleDiv"></param> /// <param name="rodRadiusDiv"></param> /// <returns></returns> public static bool LoadFromFile( string filename, ref CadLogic.CellType[,] AreaSelection, ref IList<Edge> EdgeList, ref bool[,] YBoundarySelection, ref bool[,] XBoundarySelection, ref int IncidentPortNo, ref MediaInfo[] Medias, ref int ndivForOneLattice, ref double rodRadiusRatio, ref int rodCircleDiv, ref int rodRadiusDiv ) { bool success = false; Size MaxDiv = Constants.MaxDiv; int MaxMediaCount = Medias.Length; for (int y = 0; y < AreaSelection.GetLength(0); y++) { for (int x = 0; x < AreaSelection.GetLength(1); x++) { AreaSelection[y, x] = CadLogic.CellType.Empty; } } try { using (StreamReader sr = new StreamReader(filename)) { string line; string[] tokens; const char delimiter = ','; int cnt = 0; // 領域選択 line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens[0] != "AreaSelection") { MessageBox.Show("領域選択情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } cnt = int.Parse(tokens[1]); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 3) { MessageBox.Show("領域選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } int x = int.Parse(tokens[0]); int y = int.Parse(tokens[1]); CadLogic.CellType cellType = CadLogic.GetCellTypeFromStr(tokens[2]); if ((x >= 0 && x < MaxDiv.Width) && (y >= 0 && y < MaxDiv.Height)) { AreaSelection[y, x] = cellType; } else { MessageBox.Show("領域選択座標値が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } } // ポート境界 line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens[0] != "EdgeList") { MessageBox.Show("境界選択情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } cnt = int.Parse(tokens[1]); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 5) { MessageBox.Show("境界選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } int edgeNo = int.Parse(tokens[0]); Point[] p = new Point[2]; for (int k = 0; k < p.Length; k++) { p[k] = new Point(); p[k].X = int.Parse(tokens[1 + k * 2]); p[k].Y = int.Parse(tokens[1 + k * 2 + 1]); } Size delta = new Size(0, 0); if (p[0].X == p[1].X) { // Y方向境界 delta = new Size(0, 1); } else if (p[0].Y == p[1].Y) { // X方向境界 delta = new Size(1, 0); } else { MessageBox.Show("境界選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } Edge edge = new Edge(delta); edge.No = edgeNo; edge.Set(p[0], p[1]); EdgeList.Add(edge); } foreach (Edge edge in EdgeList) { if (edge.Delta.Width == 0) { // Y方向境界 int x = edge.Points[0].X; int sty = edge.Points[0].Y; int edy = edge.Points[1].Y; for (int y = sty; y < edy; y++) { YBoundarySelection[y, x] = true; } } else if (edge.Delta.Height == 0) { // X方向境界 int y = edge.Points[0].Y; int stx = edge.Points[0].X; int edx = edge.Points[1].X; for (int x = stx; x < edx; x++) { XBoundarySelection[y, x] = true; } } else { MessageBox.Show("Not implemented"); } } line = sr.ReadLine(); if (line.Length == 0) { MessageBox.Show("入射ポート番号がありません"); return success; } tokens = line.Split(delimiter); if (tokens[0] != "IncidentPortNo") { MessageBox.Show("入射ポート番号がありません"); return success; } IncidentPortNo = int.Parse(tokens[1]); line = sr.ReadLine(); // 媒質情報? tokens = line.Split(delimiter); if (tokens[0] != "Medias") { MessageBox.Show("媒質情報がありません"); return success; } cnt = int.Parse(tokens[1]); if (cnt > MaxMediaCount) { MessageBox.Show("媒質情報の個数が不正です"); return success; } for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); if (line.Length == 0) { MessageBox.Show("媒質情報が不正です"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 1 + 9 + 9) { MessageBox.Show("媒質情報が不正です"); return success; } 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) { MessageBox.Show("格子1辺の分割数がありません"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "ndivForOneLattice") { MessageBox.Show("格子1辺の分割数がありません"); return success; } ndivForOneLattice = int.Parse(tokens[1]); line = sr.ReadLine(); if (line == null) { MessageBox.Show("ロッドの半径がありません"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "rodRadiusRatio") { MessageBox.Show("ロッドの半径がありません"); return success; } rodRadiusRatio = double.Parse(tokens[1]); line = sr.ReadLine(); if (line == null) { MessageBox.Show("ロッドの円周方向の分割数がありません"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "rodCircleDiv") { MessageBox.Show("ロッドの円周方向の分割数がありません"); return success; } rodCircleDiv = int.Parse(tokens[1]); line = sr.ReadLine(); tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "rodRadiusDiv") { MessageBox.Show("ロッドの半径方向の分割数がありません"); return success; } rodRadiusDiv = int.Parse(tokens[1]); } success = true; } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } return success; }
/// <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> private void init() { IsCalcAborted = false; Nodes.Clear(); Elements.Clear(); foreach (IList<int> portNodes in Ports) { portNodes.Clear(); } Ports.Clear(); ForceBCNodes.Clear(); ForceNodeNumberH.Clear(); ElemNoPeriodicList.Clear(); NodePeriodicBList.Clear(); DefectNodePeriodicList.Clear(); IncidentPortNo = 1; Color[] workColorList = { CadLogic.VacumnBackColor, CadLogic.RodBackColor }; for (int i = 0; i < Medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = workColorList[i]; Medias[i] = media; } EdgeToElementNoH.Clear(); //WaveguideWidth = 0.0; WaveguideWidth = DefWaveguideWidth; // 規格化周波数が定義できるように初期値を設定 FirstWaveLength = 0.0; LastWaveLength = 0.0; CalcFreqCnt = 0; WaveModeDv = Constants.DefWaveModeDv; BoundaryDv = BoundaryDV.ElectricWall; ElemShapeDvToBeSet = Constants.DefElemShapeDv; ElemOrderToBeSet = Constants.DefElementOrder; }
/// <summary> /// Fem入力データファイルへ保存 /// 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> /// ヘルムホルツ方程式のパラメータP,Qを取得する /// </summary> /// <param name="k0">波数</param> /// <param name="media">媒質</param> /// <param name="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">波のモード区分</param> /// <param name="media_P">ヘルムホルツ方程式のパラメータP</param> /// <param name="media_Q">ヘルムホルツ方程式のパラメータQ</param> public static void GetHelmholtzMediaPQ( double k0, MediaInfo media, WaveModeDV WaveModeDv, out double[,] media_P, out double[,] media_Q) { media_P = null; media_Q = null; double[,] erMat = media.Q; double[,] urMat = media.P; // 平行平板導波路の場合 if (WaveModeDv == FemSolver.WaveModeDV.TE) { // TEモード(H面) // 界方程式: Ez(H面に垂直な電界) // p = (μr)-1 // q = εr //media_P = urMat; //media_Q = erMat; //// [p]は逆数をとる //media_P = MyMatrixUtil.matrix_Inverse(media_P); // 比透磁率の逆数 media_P = new double[3, 3]; media_P[0, 0] = 1.0 / urMat[0, 0]; media_P[1, 1] = 1.0 / urMat[1, 1]; media_P[2, 2] = 1.0 / urMat[2, 2]; // 比誘電率 media_Q = new double[3, 3]; media_Q[0, 0] = erMat[0, 0]; media_Q[1, 1] = erMat[1, 1]; media_Q[2, 2] = erMat[2, 2]; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { // TMモード(TEMモードを含む)(H面) // 界方程式: Hz(H面に垂直な磁界) // p = (εr)-1 // q = μr //media_P = erMat; //media_Q = urMat; //// [p]は逆数をとる //media_P = MyMatrixUtil.matrix_Inverse(media_P); // 比誘電率の逆数 media_P = new double[3, 3]; media_P[0, 0] = 1.0 / erMat[0, 0]; media_P[1, 1] = 1.0 / erMat[1, 1]; media_P[2, 2] = 1.0 / erMat[2, 2]; // 比透磁率 media_Q = new double[3, 3]; media_Q[0, 0] = urMat[0, 0]; media_Q[1, 1] = urMat[1, 1]; media_Q[2, 2] = urMat[2, 2]; } else { System.Diagnostics.Debug.Assert(false); } }
/// <summary> /// 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> /// 界の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> /// 周期構造導波路固有値問題用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="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> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </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> /// ポート固有値解析 /// </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> protected void init() { _CadMode = CadModeType.None; for (int y = 0; y < MaxDiv.Height; y++) { for (int x = 0; x < MaxDiv.Width; x++) { AreaSelection[y, x] = CellType.Empty; } } for (int x = 0; x < MaxDiv.Width + 1; x++) { for (int y = 0; y < MaxDiv.Height; y++) { YBoundarySelection[y, x] = false; } } for (int y = 0; y < MaxDiv.Height + 1; y++) { for (int x = 0; x < MaxDiv.Width; x++) { XBoundarySelection[y, x] = false; } } EdgeList.Clear(); IncidentPortNo = 1; System.Diagnostics.Debug.Assert(Medias.Length == 2); Color[] workBackColorList = { VacumnBackColor, RodBackColor }; double[] workEpsList = { 1.0, Constants.DefRodEps }; for (int i = 0; i < Medias.Length; i++) { MediaInfo media = new MediaInfo(); double eps = workEpsList[i]; media.BackColor = workBackColorList[i]; media.SetP(new double[3,3] { {1.0 / 1.0, 0.0, 0.0}, {0.0, 1.0 / 1.0, 0.0}, {0.0, 0.0, 1.0 / 1.0}, } ); media.SetQ(new double[3, 3] { {eps, 0.0, 0.0}, {0.0, eps, 0.0}, {0.0, 0.0, eps}, }); Medias[i] = media; } _NdivForOneLattice = Constants.DefNDivForOneLattice; _RodRadiusRatio = Constants.DefRodRadiusRatio; _RodCircleDiv = Constants.DefRodCircleDiv; _RodRadiusDiv = Constants.DefRodRadiusDiv; }