/// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</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.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); double[,] integralN = new double[nno, nno] { { 4.0 / 30.0 * elen, -1.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { -1.0 / 30.0 * elen, 4.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { 2.0 / 30.0 * elen, 2.0 / 30.0 * elen, 16.0 / 30.0 * elen }, }; double[,] integralDNDY = new double[nno, nno] { { 7.0 / (3.0 * elen), 1.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { 1.0 / (3.0 * elen), 7.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) }, }; for (int ino = 0; ino < nno; ino++) { int inoBoundary = nodeNumbers[ino]; int inoSorted; if (!toSorted.ContainsKey(inoBoundary)) { continue; } inoSorted = toSorted[inoBoundary]; for (int jno = 0; jno < nno; jno++) { int jnoBoundary = nodeNumbers[jno]; int jnoSorted; if (!toSorted.ContainsKey(jnoBoundary)) { continue; } jnoSorted = toSorted[jnoBoundary]; // 対称バンド行列対応 if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted) { continue; } double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno]; double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno]; double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno]; //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno; //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno; //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno; txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno; ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno; uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno; } } }
/// <summary> /// ヘルムホルツ方程式に対する有限要素マトリクス作成 /// </summary> /// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary <int, int> toSorted, FemElement element, IList <FemNode> Nodes, MediaInfo[] Medias, Dictionary <int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_FirstOrder; //4; // 1次セレンディピティ // 座標次元数 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, 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[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ + +2 // | | | // ---+---+---+-->r // | | | // 0+ + +1 // | // double[][] n_pts = { // r, s new double[] { -1.0, -1.0 }, //0 new double[] { 1.0, -1.0 }, //1 new double[] { 1.0, 1.0 }, //2 new double[] { -1.0, 1.0 }, //3 }; // ∫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] { { { 2.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx) }, { -2.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx) }, { -1.0 * ly / (6.0 * lx), 1.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx) }, { 1.0 * ly / (6.0 * lx), -1.0 * ly / (6.0 * lx), -2.0 * ly / (6.0 * lx), 2.0 * ly / (6.0 * lx) }, }, { { 2.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly) }, { 1.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly) }, { -1.0 * lx / (6.0 * ly), -2.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly) }, { -2.0 * lx / (6.0 * ly), -1.0 * lx / (6.0 * ly), 1.0 * lx / (6.0 * ly), 2.0 * lx / (6.0 * ly) }, } }; // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 }, { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) { continue; } uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary <int, int> toSorted, FemElement element, IList <FemNode> Nodes, MediaInfo[] Medias, Dictionary <int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 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_FirstOrder; //3; // 1次三角形要素 // 座標次元数 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, 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]); // ∫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 ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[0, ino, jno] = area * dldx[ino, 0] * dldx[jno, 0]; integralDNDX[1, ino, jno] = area * dldx[ino, 1] * dldx[jno, 1]; } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { area / 6.0, area / 12.0, area / 12.0 }, { area / 12.0, area / 6.0, area / 12.0 }, { area / 12.0, area / 12.0, area / 6.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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) { continue; } uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// <returns></returns> public static bool LoadFromFile( string filename, out string appVersion, out string useUtility, ref CCadObj2D editCad2D, ref IList<CadLogic.Loop> loopList, ref IList<EdgeCollection> edgeCollectionList, out int incidentPortNo, ref MediaInfo[] medias ) { bool success = false; //////////////////////////////////////////////////////// // 出力データの初期化 // アプリケーションのバージョン番号 appVersion = ""; // ユーティリティ名 useUtility = ""; // 図面のクリア editCad2D.Clear(); //// ベースループIDを初期化 //baseLoopId = 0; // ループ情報リストの初期化 loopList.Clear(); // 入射ポートの初期化 incidentPortNo = 1; // ポートのエッジコレクションのリストを初期化 edgeCollectionList.Clear(); // 媒質の比誘電率、比透磁率の逆数の初期化 foreach (MediaInfo media in medias) { // 比透磁率の逆数 media.SetP(new double[,] { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }); // 比誘電率 media.SetQ(new double[,] { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }); } try { // Cadオブジェクトデータファイル string basename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename); string cadObjFilename = basename + Constants.CadObjExt; if (File.Exists(cadObjFilename)) { // Cadオブジェクトデータを外部ファイルから読み込む using (CSerializer fin = new CSerializer(cadObjFilename, true)) { editCad2D.Serialize(fin); } } else { MessageBox.Show("CadObjデータファイルがありません"); return success; } using (StreamReader sr = new StreamReader(filename)) { string line; string[] tokens; const char delimiter = ','; int cnt = 0; // アプリケーションのバージョン番号 line = sr.ReadLine(); if (line == null) { MessageBox.Show("アプリケーションのバージョン情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "AppVersion") { MessageBox.Show("アプリケーションのバージョン情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } appVersion = tokens[1]; // ユーティリティ名 line = sr.ReadLine(); if (line == null) { MessageBox.Show("ユーティリティ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "UseUtility") { MessageBox.Show("ユーティリティ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } useUtility = tokens[1]; if (useUtility != CadLogic.UseUtility) { MessageBox.Show("ユーティリティ情報が本アプリケーションのバージョンのものと一致しません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } // ベースループID //line = sr.ReadLine(); //if (line == null) //{ // MessageBox.Show("ベースループIDがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); // return success; //} //tokens = line.Split(delimiter); //if (tokens.Length != 2 || tokens[0] != "BaseLoopId") //{ // MessageBox.Show("ベースループIDがありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); // return success; //} //baseLoopId = uint.Parse(tokens[1]); // ループのリスト line = sr.ReadLine(); if (line == null) { MessageBox.Show("ループ一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "LoopList") { MessageBox.Show("ループ一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } cnt = int.Parse(tokens[1]); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); if (line == null) { MessageBox.Show("ループ情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length != 4 || tokens[0] != "Loop") { MessageBox.Show("ループ情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } int countNo = int.Parse(tokens[1]); uint loopId = uint.Parse(tokens[2]); int mediaIndex = int.Parse(tokens[3]); System.Diagnostics.Debug.Assert(countNo == i + 1); CadLogic.Loop loop = new CadLogicBase.Loop(loopId, mediaIndex); loopList.Add(loop); } // ポートのエッジコレクションのリスト line = sr.ReadLine(); if (line == null) { MessageBox.Show("ポート一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "EdgeCollectionList") { MessageBox.Show("ポート一覧がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } cnt = int.Parse(tokens[1]); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); if (line == null) { MessageBox.Show("ポート情報がありません", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } tokens = line.Split(delimiter); if (tokens.Length < (4 + 1) || tokens[0] != "EdgeCollection") { MessageBox.Show("ポート情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } int countNo = int.Parse(tokens[1]); int portNo = int.Parse(tokens[2]); int eIdCnt = int.Parse(tokens[3]); System.Diagnostics.Debug.Assert(countNo == i + 1); System.Diagnostics.Debug.Assert(eIdCnt != 0 && eIdCnt == (tokens.Length - 4)); EdgeCollection edgeCollection = new EdgeCollection(); edgeCollection.No = portNo; for (int tokenIndex = 4; tokenIndex < tokens.Length; tokenIndex++) { uint eId = uint.Parse(tokens[tokenIndex]); if (!edgeCollection.ContainsEdgeId(eId)) { bool ret = edgeCollection.AddEdgeId(eId, editCad2D); } } edgeCollectionList.Add(edgeCollection); } // 入射ポート番号 line = sr.ReadLine(); if (line == null) { MessageBox.Show("入射ポート番号がありません"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "IncidentPortNo") { MessageBox.Show("入射ポート番号がありません"); return success; } incidentPortNo = int.Parse(tokens[1]); // 媒質情報 line = sr.ReadLine(); if (line == null) { MessageBox.Show("媒質情報がありません"); return success; } tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "Medias") { MessageBox.Show("媒質情報がありません"); return success; } cnt = int.Parse(tokens[1]); for (int i = 0; i < cnt; i++) { line = sr.ReadLine(); if (line == null) { 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); if (i >= medias.Length) { //読み飛ばす continue; } 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); } } // 番号順に並び替え ((List<EdgeCollection>)edgeCollectionList).Sort(); //////////////////////////////////////////////////////////////////////// // Cadオブジェクトの色をセットする // ループとその辺、頂点の色をセット foreach (CadLogic.Loop loop in loopList) { uint id_l = loop.LoopId; int mediaIndex = loop.MediaIndex; MediaInfo media = medias[mediaIndex]; Color backColor = media.BackColor; CadLogic.SetupColorOfCadObjectsForOneLoop(editCad2D, id_l, backColor); } // ポートの色をセットする CadLogic.SetupColorOfPortEdgeCollection(editCad2D, edgeCollectionList, incidentPortNo); success = true; } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } return success; }
/// <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="wgStructureDv">導波路構造区分</param> /// <param name="waveModeDv">波のモード区分</param> /// <param name="lsEqnSolverDv">線形方程式解法区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</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, int incidentPortNo, MediaInfo[] medias, double firstWaveLength, double lastWaveLength, int calcCnt, FemSolver.WGStructureDV wgStructureDv, FemSolver.WaveModeDV waveModeDv, FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv, double waveguideWidthForEPlane) { ////////////////////////////////////////// // ファイル出力 ////////////////////////////////////////// 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); } // 入射ポート番号 line = string.Format("IncidentPortNo,{0}", incidentPortNo); sw.WriteLine(line); ////////////////////////////////////////// //// 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); } // 計算対象周波数 sw.WriteLine("WaveLengthRange,{0},{1},{2}", firstWaveLength, lastWaveLength, calcCnt); // 線形方程式解法区分 sw.WriteLine("LsEqnSolverDv,{0}", FemSolver.LinearSystemEqnSolverDVToStr(lsEqnSolverDv)); // 計算対象モード区分 sw.WriteLine("WaveModeDv,{0}", ((waveModeDv == FemSolver.WaveModeDV.TM) ? "TM" : "TE")); // 導波路構造区分 sw.WriteLine("WGStructureDv,{0}", FemSolver.WGStructureDVToStr(wgStructureDv)); // 導波路幅(E面解析用) sw.WriteLine("WaveguideWidthForEPlane,{0}", waveguideWidthForEPlane); } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } }
/* 数値積分版 /// <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.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 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; if (WaveModeDv == FemSolver.WaveModeDv.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDv.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(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[] le = new double[4]; //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // ガウスルジャンドルの積分公式 double[][] g_pts = new double[5][] { // ポイント(ξ: [-1 +1]区間)、重み new double[] { -0.90617985, 0.23692689}, new double[] { -0.53846931, 0.47862867}, new double[] {0.0, 0.56888889}, new double[] {0.53846931, 0.47862867}, new double[] {0.90617985, 0.23692689} }; // 要素剛性行列を作る double[,] emat = new Complex[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { emat[ino, jno] = 0.0; double detjsum = 0; //check foreach (double[] s_g_pt in g_pts) { foreach (double[] r_g_pt in g_pts) { // 積分点 double r = r_g_pt[0]; double s = s_g_pt[0]; // 重み(2次元) double weight = r_g_pt[1] * s_g_pt[1]; // 形状関数 double[] N = new double[nno]; // 形状関数のr, s方向微分 double[] dNdr = new double[nno]; double[] dNds = new double[nno]; // 節点0~3 : 四角形の頂点 for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0); // 形状関数のr方向微分 dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s); // 形状関数のs方向微分 dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s); } // 節点4,6 : r方向辺上中点 foreach (int i in new int[]{ 4, 6}) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s); // 形状関数のr方向微分 dNdr[i] = -1.0 * r * (1.0 + si * s); // 形状関数のs方向微分 dNds[i] = 0.5 * si * (1.0 - r * r); } // 節点5,7 : s方向辺上中点 foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; // 形状関数N N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s); // 形状関数のr方向微分 dNdr[i] = 0.5 * ri * (1.0 - s * s); // 形状関数のs方向微分 dNds[i] = -1.0 * s * (1.0 + ri * r); } // ヤコビアン行列 double j11; double j12; double j21; double j22; j11 = 0; j12 = 0; j21 = 0; j22 = 0; //for (int i = 0; i < vertexCnt; i++) //{ // // 頂点の座標の微分 // // 座標の形状関数は一次四角形のものを使用する // // 節点の局所座標 // double ri = n_pts[i][0]; // double si = n_pts[i][1]; // double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s); // double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si; // j11 += dNdr_1stOrder * pp[i][0]; // j12 += dNdr_1stOrder * pp[i][1]; // j21 += dNds_1stOrder * pp[i][0]; // j22 += dNds_1stOrder * pp[i][1]; //} for (int i = 0; i < nno; i++) { j11 += dNdr[i] * pp[i][0]; j12 += dNdr[i] * pp[i][1]; j21 += dNds[i] * pp[i][0]; j22 += dNds[i] * pp[i][1]; } // ヤコビアン double detj = j11 * j22 - j12 * j21; detjsum += detj * weight; //System.Diagnostics.Debug.WriteLine("det:{0}", detj); // gradr[0] : gradrのx成分 grad[1] : gradrのy成分 // grads[0] : gradsのx成分 grads[1] : gradsのy成分 double[] gradr = new double[2]; double[] grads = new double[2]; gradr[0] = j22 / detj; gradr[1] = - j21 / detj; grads[0] = - j12 / detj; grads[1] = j11 / detj; // 形状関数のx, y方向微分 double[,] dNdX = new double[ndim, nno]; for (int i = 0; i < nno; i++) { for (int direction = 0; direction < ndim; direction++) { dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction]; } } // 汎関数 double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno] - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno]; emat[ino, jno] += detj * weight * functional; } } //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum); } } // 要素剛性行列にマージする 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]; } } } */ /// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, 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[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 new double[] { 0, -1.0}, //4 new double[] { 1.0, 0}, //5 new double[] { 0, 1.0}, //6 new double[] {-1.0, 0}, //7 }; // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] Ni_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.25 * ri * ri * si; Ni_a[i, 1] = 0.25 * ri * ri; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.25 * ri * si; Ni_a[i, 4] = 0.25 * ri * si * si; Ni_a[i, 5] = 0.25 * si * si; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = -0.25; } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = -0.5 * si; Ni_a[i, 1] = -0.5; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = 0.0; Ni_a[i, 5] = 0.0; Ni_a[i, 6] = 0.5 * si; Ni_a[i, 7] = 0.5; } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.0; Ni_a[i, 1] = 0.0; Ni_a[i, 2] = 0.5 * ri; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = -0.5 * ri; Ni_a[i, 5] = -0.5; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = 0.5; } // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNidr_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri; // r dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.25 * ri * si * si; // s^2 dNidr_a[i, 6] = 0.25 * ri * si; // s dNidr_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = -1.0; // r dNidr_a[i, 3] = -si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.0; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.0; // 1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.0; // r dNidr_a[i, 3] = 0.0; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = -0.5 * ri; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.5 * ri; // 1 } // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNids_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.25 * ri * ri * si; // r^2 dNids_a[i, 2] = 0.25 * ri * si; // r dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.25 * 2.0 * si * si; // s dNids_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = -0.5 * si; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = 0.0; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.0; // s dNids_a[i, 7] = 0.5 * si; //1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.0; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = -ri; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = -1.0; // s dNids_a[i, 7] = 0.0; //1 } // ∫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]; // ∫N N dxdy double[,] integralN = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralN[ino, jno] = lx * ly / 4.0 * ( // r^4s^2 4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3] + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6]) // r^4 + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1] // r^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4] // s^4 + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5] // s^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7]) // 1 + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7] ); integralDNDX[0, ino, jno] = ly / lx * ( // r^4s^2 4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2] + dNidr_a[ino, 3] * dNidr_a[jno, 3] + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4] // s^4 + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7]) // 1 + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7] ); integralDNDX[1, ino, jno] = lx / ly * ( // r^4s^2 4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2] + dNids_a[ino, 3] * dNids_a[jno, 3] + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4] // s^4 + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7]) // 1 + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7] ); } } // 要素剛性行列を作る 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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// <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">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</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, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_FirstOrder; //4; // 1次セレンディピティ // 座標次元数 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; if (WaveModeDv == FemSolver.WaveModeDV.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(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[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ + +2 // | | | // ---+---+---+-->r // | | | // 0+ + +1 // | // double[][] n_pts = { // r, s new double[] {-1.0, -1.0}, //0 new double[] { 1.0, -1.0}, //1 new double[] { 1.0, 1.0}, //2 new double[] {-1.0, 1.0}, //3 }; // ∫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] { { { 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx) }, { -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx) }, { -1.0 * ly /(6.0 * lx), 1.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx) }, { 1.0 * ly /(6.0 * lx), -1.0 * ly /(6.0 * lx), -2.0 * ly /(6.0 * lx), 2.0 * ly /(6.0 * lx) }, }, { { 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly) }, { 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly) }, { -1.0 * lx /(6.0 * ly), -2.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly) }, { -2.0 * lx /(6.0 * ly), -1.0 * lx /(6.0 * ly), 1.0 * lx /(6.0 * ly), 2.0 * lx /(6.0 * ly) }, } }; // ∫N N dxdy double[,] integralN = new double[nno, nno] { { 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0 }, { 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0 }, { 2.0 * lx * ly / 36.0, 1.0 * lx * ly / 36.0, 2.0 * lx * ly / 36.0, 4.0 * lx * ly / 36.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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// Ver1.2.0.0形式の図面ファイルから読み込み(Ver1.2.0.0→Ver1.3.0.0の変換あり) /// </summary> /// <param name="in_filename"></param> /// <param name="isBackupFile">バックアップファイル?</param> /// <param name="out_cad2d">格納先Cadオブジェクトのリファレンス</param> /// <param name="out_LoopList">ループ情報のリスト</param> /// <param name="out_edgeCollectionList">ポートのエッジコレクションのリスト</param> /// <param name="out_incidentPortNo">入射ポート番号</param> /// <param name="out_medias">媒質情報リストのリファレンス(比誘電率、比透磁率だけセットされる)</param> /// <returns></returns> public static bool LoadFromFile_Ver_1_2( string in_filename, out bool isBackupFile, ref CCadObj2D out_cad2d, ref IList<CadLogic.Loop> out_LoopList, ref IList<EdgeCollection> out_edgeCollectionList, out int out_incidentPortNo, ref MediaInfo[] out_medias ) { bool success = false; //////////////////////////////////////////////////////// // 出力データの初期化 // バックアップファイル? isBackupFile = false; // 図面のクリア out_cad2d.Clear(); // ループ情報リストの初期化 out_LoopList.Clear(); // 入射ポートの初期化 out_incidentPortNo = 1; // ポートのエッジコレクションのリストを初期化 out_edgeCollectionList.Clear(); // 媒質の比誘電率、比透磁率の逆数の初期化 foreach (MediaInfo media in out_medias) { // 比透磁率の逆数 media.SetP(new double[,] { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }); // 比誘電率 media.SetQ(new double[,] { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }); } //////////////////////////////////////////////////////// // バックアップファイルの作成 string filename = ""; if (in_filename.IndexOf(Ver1_2_Backup_Suffix) >= 0) { isBackupFile = true; MessageBox.Show("このファイルはバックアップファイルです。このファイルを上書き保存しないようご注意ください。", "旧データ形式からの変換", MessageBoxButtons.OK, MessageBoxIcon.Information); // 入力ファイル名をそのまま利用 filename = in_filename; } else { // 指定されたCadファイルとその入出力データをリネームする string basename = Path.GetDirectoryName(in_filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(in_filename); string inputfilename = basename + Constants.FemInputExt; string outputfilename = basename + Constants.FemOutputExt; string indexfilename = outputfilename + Constants.FemOutputIndexExt; //ReadOnlyにするのを止める ////FEM入出力データは移動しない(Ver1.2のアプリで再計算すると落ちるので止めます:データ削除でtry catchしていないのが原因だと思われる) //string[] tagtfilenames = { in_filename }; // 全ファイルを移動する string[] tagtfilenames = { in_filename, inputfilename, outputfilename, indexfilename }; foreach (string tagtfilename in tagtfilenames) { string fname = Path.GetFileNameWithoutExtension(tagtfilename); string ext = Path.GetExtension(tagtfilename); if (fname != Path.GetFileNameWithoutExtension(fname)) // .out.idxの場合、ファイル名に.outまで入るので小細工する { string ext2 = Path.GetExtension(fname); string fname2 = Path.GetFileNameWithoutExtension(fname); ext = ext2 + ext; fname = fname2; } string tagtbasename = Path.GetDirectoryName(tagtfilename) + Path.DirectorySeparatorChar + fname; string backupFilename = tagtbasename + Ver1_2_Backup_Suffix + ext; if (File.Exists(tagtfilename)) { if (!File.Exists(backupFilename)) { // 対象ファイルが存在し、かつバックアップファイルが存在しないとき //バックアップファイルの作成 //MyUtilLib.MyUtil.MoveFileWithReadOnly(tagtfilename, backupFilename); try { // そのまま移動(更新時刻等の再設定が面倒なのでコピーでなく移動する) File.Move(tagtfilename, backupFilename); // コピーとして戻す File.Copy(backupFilename, tagtfilename); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } } else { // 対象ファイルは存在し、バックアップが存在するとき // バックアップを作成できない MessageBox.Show("すでに別のバックアップファイルがあるので、バックアップを作成できません。このファイルを上書き保存しないようご注意ください。", "旧データ形式からの変換", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } // バックアップファイルに移動したので、バックアップファイルから読み込む filename = basename + Ver1_2_Backup_Suffix + Constants.CadExt; } // Ver1.2.0.0形式のファイルの読み込み Size maxDiv; bool[,] areaSelection; int[,] areaToMediaIndex; IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList_Ver_1_2; bool[,] yBoundarySelection; bool[,] xBoundarySelection; int incidentPortNo_Ver_1_2; MediaInfo[] medias_Ver_1_2; bool loadSuccess = false; loadSuccess = CadDatFile_Ver_1_2.LoadFromFile_Ver_1_2( filename, out maxDiv, out areaSelection, out areaToMediaIndex, out edgeList_Ver_1_2, out yBoundarySelection, out xBoundarySelection, out incidentPortNo_Ver_1_2, out medias_Ver_1_2 ); if (!loadSuccess) { return success; } ///////////////////////////////////////////////////////////////////////////////// // 本バージョンへのデータ変換 ///////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////// // そのまま使用できる情報 out_incidentPortNo = incidentPortNo_Ver_1_2; ///////////////////////////////////////////////////////////////////////////////// // 変換が必要な情報 // Medias --> インデックスを1加算 // AreaToMediaIndex --> インデックスを1加算 // AreaSelection, AreaToMediaIndex --> loop // EdgeVer1_2 --> EdgeCollection ////////////////////////// // 媒質情報は、Ver1.2→Ver1.3で媒質インデックスが1つずれる(導体が追加されたため) for (int oldMediaIndex = 0; oldMediaIndex < medias_Ver_1_2.Length; oldMediaIndex++) { if (oldMediaIndex + 1 < out_medias.Length) { int mediaIndex = oldMediaIndex + 1; //インデックスを1加算 out_medias[mediaIndex].SetP(medias_Ver_1_2[oldMediaIndex].P); out_medias[mediaIndex].SetQ(medias_Ver_1_2[oldMediaIndex].Q); } } for (int y = 0; y < maxDiv.Height; y++) { for (int x = 0; x < maxDiv.Width; x++) { areaToMediaIndex[y, x]++; //インデックスを1加算 } } /////////////////////////// // 変換準備 /* // 領域選択情報を媒質情報にマージする(非選択の場合もインデックスは0が設定されているがこれを-1に変更) for (int y = 0; y < maxDiv.Height; y++) { for (int x = 0; x < maxDiv.Width; x++) { if (!areaSelection[y, x]) { // エリアが選択されていない areaToMediaIndex[y, x] = -1; // 未指定に設定する } } } */ // 非選択部分は導体媒質を設定する for (int y = 0; y < maxDiv.Height; y++) { for (int x = 0; x < maxDiv.Width; x++) { if (!areaSelection[y, x]) { // エリアが選択されていない areaToMediaIndex[y, x] = CadLogic.MetalMediaIndex; // 導体を指定する } } } // ループの取得 IList<DelFEM4NetCom.Pair<int, IList<Point>>> loopList = getLoopList(maxDiv, areaToMediaIndex); // ループをエッジに変換 IList<IList<CadDatFile_Ver_1_2.Edge_Ver_1_2>> loopEdgeListList = getLoopEdgeList(loopList); // ポート境界のエッジリスト分、エッジコレクションを先に作成する(複数のループにまたがる場合があるため) foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 portEdge in edgeList_Ver_1_2) { EdgeCollection edgeCollection = new EdgeCollection(); edgeCollection.No = portEdge.No; out_edgeCollectionList.Add(edgeCollection); } var newLoopEdgeListList = new List<IList<CadDatFile_Ver_1_2.Edge_Ver_1_2>>(); // ループ数分チェック foreach (IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> loopEdgeList in loopEdgeListList) { // 1つのループ var newLoopEdgeList = new List<CadDatFile_Ver_1_2.Edge_Ver_1_2>(); foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 loopEdge in loopEdgeList) { // 1つのエッジ // ポート境界を含んでいれば分解する // 頂点リスト IList<Point> vertexPts = new List<Point>(); // 頂点にポートが対応していれば、ポート番号を格納 // 既定値は -1 IList<int> toPortNo = new List<int>(); // エッジの最初の頂点を追加 vertexPts.Add(loopEdge.Points[0]); toPortNo.Add(-1); // ポート境界のエッジリストを走査 foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 portEdge in edgeList_Ver_1_2) { // contains? Point minPt; Point maxPt; if (loopEdge.Contains(portEdge, out minPt, out maxPt)) { // ポート境界が含まれていた // ポート境界の頂点を追加 //vertexPts.Add(portEdge.Points[0]); // 始点 //vertexPts.Add(portEdge.Points[1]); // 終点 vertexPts.Add(minPt); // 始点 vertexPts.Add(maxPt); // 終点 // ポート番号を頂点にあわせて追加 toPortNo.Add(portEdge.No); toPortNo.Add(portEdge.No); } else if (loopEdge.GetSimpleSwap().Contains(portEdge, out minPt, out maxPt)) { // ポート境界の頂点を追加 //vertexPts.Add(portEdge.Points[1]); // swap 終点 //vertexPts.Add(portEdge.Points[0]); // swap 始点 vertexPts.Add(maxPt); // swap 終点 vertexPts.Add(minPt); // swap 始点 // ポート番号を頂点にあわせて追加 toPortNo.Add(portEdge.No); toPortNo.Add(portEdge.No); } } // 最後の頂点を追加 vertexPts.Add(loopEdge.Points[1]); toPortNo.Add(-1); // 頂点を元にしてエッジを再構築 for (int ino = 0; ino < vertexPts.Count - 1; ino++) { CadDatFile_Ver_1_2.Edge_Ver_1_2 work = new CadDatFile_Ver_1_2.Edge_Ver_1_2(); // ポート番号があれば格納 if (toPortNo[ino] != -1) { work.No = toPortNo[ino]; } else { work.No = 0; } // 辺の始点、終点 work.Points[0] = vertexPts[ino]; work.Points[1] = vertexPts[ino + 1]; // Deltaの計算&格納 Point p1 = work.Points[0]; Point p2 = work.Points[1]; work.Delta = CadDatFile_Ver_1_2.Edge_Ver_1_2.CalcDelta(p1, p2); // 空チェック if (work.IsEmpty()) { // 空の場合追加しない } else { // 追加 newLoopEdgeList.Add(work); } } // 1つのエッジ再構築終了 } // エッジ // 1つのループのエッジリストをリストに追加 newLoopEdgeListList.Add(newLoopEdgeList); } // ループ /////////////////////////////////////////////////////////////////// // version1.3.0.0のデータ構造に反映する bool errorCCadObj = false; // ループ領域を作成 //uint baseLoopId = 0; for (int loopIndex = 0; loopIndex < loopList.Count; loopIndex++) { System.Diagnostics.Debug.WriteLine("loopIndex: {0}", loopIndex); DelFEM4NetCom.Pair<int, IList<Point>> loop = loopList[loopIndex]; // 媒質インデックス int mediaIndex = loop.First; // ループを構成する頂点 IList<Point> pts = loop.Second; IList<CVector2D> pps = new List<CVector2D>(); /* foreach (Point pt in pts) { double xx = pt.X - maxDiv.Width * 0.5; double yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; pps.Add(new CVector2D(xx, yy)); } */ // このループのエッジリストを取得する IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> loopEdgeList = newLoopEdgeListList[loopIndex]; // エッジのリストインデックス→エッジコレクションのリストのインデックス変換マップ IList<int> loopEdgeIndexToEdgeCollectionIndex = new List<int>(); // OpenGlの頂点リストを作成 for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++) { // エッジ CadDatFile_Ver_1_2.Edge_Ver_1_2 work = loopEdgeList[loopEdgeIndex]; //////////////////////////////// // OpenGlの頂点作成 double xx; double yy; Point pt; pt = work.Points[0]; //始点を追加していく xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; pps.Add(new CVector2D(xx, yy)); System.Diagnostics.Debug.WriteLine("pps[{0}]: {1}, {2}", pps.Count - 1, pps[pps.Count - 1].x, pps[pps.Count - 1].y); // check: 終点は次のエッジの始点のはず if (loopEdgeIndex < loopEdgeList.Count - 1) { CadDatFile_Ver_1_2.Edge_Ver_1_2 next = loopEdgeList[loopEdgeIndex + 1]; System.Diagnostics.Debug.Assert(work.Points[1].Equals(next.Points[0])); } /* ループの最後の点は追加しない if (loopEdgeIndex == loopEdgeList.Count - 1) { // 最後だけ終点を追加 pt = work.Points[1]; xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; pps.Add(new CVector2D(xx, yy)); } */ int edgeCollectionIndex = -1; if (work.No != 0) { //////////////////////////////////////////////////////// // ポート情報がある場合 // check { EdgeCollection edgeCollection = out_edgeCollectionList[work.No - 1]; System.Diagnostics.Debug.Assert(work.No == edgeCollection.No); } // エッジコレクションリストのインデックスをセット edgeCollectionIndex = work.No - 1; } // エッジのリストインデックス→エッジコレクションのリストのインデックス変換マップ(ポートがない場合も-1で追加する) loopEdgeIndexToEdgeCollectionIndex.Add(edgeCollectionIndex); } // loopEdgeIndex uint id_l = 0; // 多角形でループを作成するのを止める //uint id_l = out_cad2d.AddPolygon(pps, baseLoopId).id_l_add; // 自力でループ作成 System.Diagnostics.Debug.WriteLine("makeLoop: loopIndex: {0}", loopIndex); id_l = CadLogic.makeLoop(out_cad2d, pps, out_LoopList, false); if (id_l == 0) { // 領域分割でできた領域は、現状取り込みを実装していません。 MessageBox.Show("領域の追加に失敗しました。"); errorCCadObj = true; } else { ////////////////////////////////////////////////////////////////////// // 辺と頂点を取得 IList<uint> vIdList = null; IList<uint> eIdList = null; CadLogic.GetEdgeVertexListOfLoop(out_cad2d, id_l, out vIdList, out eIdList); // 元々の辺のインデックスに対して生成された辺のIDのリストを要素とするリスト IList<IList<uint>> generatedEIdsList = new List<IList<uint>>(); // ループ作成時に辺が分割された場合も考慮 int eIdIndexOfs = 0; System.Diagnostics.Debug.WriteLine("pps[0]: {0},{1}", pps[0].x, pps[0].y); { Edge_Ver_1_2 loopEdge0 = loopEdgeList[0]; CVector2D loopEdge0_pp_v1; CVector2D loopEdge0_pp_v2; { double xx; double yy; Point pt; pt = loopEdge0.Points[0]; xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; loopEdge0_pp_v1 = new CVector2D(xx, yy); pt = loopEdge0.Points[1]; xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; loopEdge0_pp_v2 = new CVector2D(xx, yy); } System.Diagnostics.Debug.WriteLine("loopEdge0_pp_v1: {0},{1} loopEdge0_pp_v2: {2},{3}", loopEdge0_pp_v1.x, loopEdge0_pp_v1.y, loopEdge0_pp_v2.x, loopEdge0_pp_v2.y); for (int eIdIndexSearch = 0; eIdIndexSearch < eIdList.Count; eIdIndexSearch++) { uint id_e = eIdList[eIdIndexSearch]; bool isIncluding = CadLogic.isEdgeIncludingEdge(out_cad2d, loopEdge0_pp_v1, loopEdge0_pp_v2, id_e); if (isIncluding) { eIdIndexOfs = eIdIndexSearch; break; } } } System.Diagnostics.Debug.WriteLine("eIdIndexOfs:{0}", eIdIndexOfs); for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++) { IList<uint> generatedEIds = new List<uint>(); Edge_Ver_1_2 loopEdge = loopEdgeList[loopEdgeIndex]; CVector2D loopEdge_pp_v1; CVector2D loopEdge_pp_v2; { double xx; double yy; Point pt; pt = loopEdge.Points[0]; xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; loopEdge_pp_v1 = new CVector2D(xx, yy); pt = loopEdge.Points[1]; xx = pt.X - maxDiv.Width * 0.5; yy = maxDiv.Height - pt.Y - maxDiv.Height * 0.5; loopEdge_pp_v2 = new CVector2D(xx, yy); } System.Diagnostics.Debug.WriteLine(" loopEdgeIndex:{0}", loopEdgeIndex); System.Diagnostics.Debug.WriteLine(" loopEdge_pp_v1: {0},{1} loopEdge0_pp_v2: {2},{3}", loopEdge_pp_v1.x, loopEdge_pp_v1.y, loopEdge_pp_v2.x, loopEdge_pp_v2.y); for (int eIdIndex = 0; eIdIndex < eIdList.Count; eIdIndex++) { uint id_e = eIdList[(eIdIndex + eIdIndexOfs) % eIdList.Count]; // 1つずらして取得 //System.Diagnostics.Debug.WriteLine(" {0} id_e:{1}", (eIdIndex + eIdIndexOfs) % eIdList.Count, id_e); bool isIncluding = CadLogic.isEdgeIncludingEdge(out_cad2d, loopEdge_pp_v1, loopEdge_pp_v2, id_e); if (!isIncluding) { continue; } generatedEIds.Add(id_e); // check { uint id_v1 = 0; uint id_v2 = 0; CadLogic.getVertexIdsOfEdgeId(out_cad2d, id_e, out id_v1, out id_v2); CVector2D pp_v1 = out_cad2d.GetVertexCoord(id_v1); CVector2D pp_v2 = out_cad2d.GetVertexCoord(id_v2); System.Diagnostics.Debug.WriteLine(" eId: {0}, pp_v1: {1},{2} pp_v2: {3},{4}", id_e, pp_v1.x, pp_v1.y, pp_v2.x, pp_v2.y); } } generatedEIdsList.Add(generatedEIds); } /////////////////////////////////////////////////////////////////////// // エッジコレクションにポート境界に対応する辺のIDをセットする //IList<EdgeCollection> workEdgeCollectionList = new List<EdgeCollection>(); // ここで辺のIDをセットしたコレクションを辺の色付けのために一時保管する for (int loopEdgeIndex = 0; loopEdgeIndex < loopEdgeList.Count; loopEdgeIndex++) { int edgeCollectionIndex = loopEdgeIndexToEdgeCollectionIndex[loopEdgeIndex]; if (edgeCollectionIndex != -1) { // EdgeCollection edgeCollection = out_edgeCollectionList[edgeCollectionIndex]; IList<uint> generatedEIds = generatedEIdsList[loopEdgeIndex]; foreach (uint id_e in generatedEIds) { // 辺のIDをエッジコレクションにセット // 辺の連続性はここではチェックしない(ばらばらで追加されるので) bool chkFlg = false; if (!edgeCollection.ContainsEdgeId(id_e)) { bool ret = edgeCollection.AddEdgeId(id_e, out_cad2d, chkFlg); } } // 一時保管 //workEdgeCollectionList.Add(edgeCollection); } } //////////////////////////////////////////////////////////////////////// // 最初のループならばそのIdを記録する //if (baseLoopId == 0) //{ // baseLoopId = id_l; //} // ループの情報を追加する out_LoopList.Add(new CadLogic.Loop(id_l, mediaIndex)); // まだ処理が完全でないので下記は処理しない // ループの内側にあるループを子ループに設定する //CadLogic.reconstructLoopsInsideLoopAsChild(out_cad2d, id_l, ref out_LoopList, ref out_edgeCollectionList, out_medias, ref out_incidentPortNo); //////////////////////////////////////////////////////////////////////// // Cadオブジェクトの色をセットする // ループとその辺、頂点の色をセット MediaInfo media = out_medias[mediaIndex]; Color backColor = media.BackColor; CadLogic.SetupColorOfCadObjectsForOneLoop(out_cad2d, id_l, backColor); // ポートの色をセットする //CadLogic.SetupColorOfPortEdgeCollection(out_cad2d, workEdgeCollectionList, incidentPortNo_Ver_1_2); } // if id_l != 0 } // loopIndex // 番号順に並び替え ((List<EdgeCollection>)out_edgeCollectionList).Sort(); // エッジコレクションの辺IDリストをソートする foreach (EdgeCollection workEdgeCollection in out_edgeCollectionList) { bool ret = workEdgeCollection.SortEdgeIds(out_cad2d); } // ポートの色をセットする CadLogic.SetupColorOfPortEdgeCollection(out_cad2d, out_edgeCollectionList, out_incidentPortNo); ///////////////////////////////////////////// // 外側の導体媒質ループ削除処理 // // 外側の導体媒質ループを取得する IList<CadLogic.Loop> delLoopList = new List<CadLogic.Loop>(); foreach (CadLogic.Loop loop in out_LoopList) { if (loop.MediaIndex == CadLogic.MetalMediaIndex) // 導体の場合のみ実行 { // 外側の判定 --->他のループと共有していない辺が存在する IList<uint> vIdList = null; IList<uint> eIdList = null; CadLogic.GetEdgeVertexListOfLoop(out_cad2d, loop.LoopId, out vIdList, out eIdList); bool notSharedEdgeExists = false; foreach (uint eId in eIdList) { if (CadLogic.isEdgeSharedByLoops(out_cad2d, eId)) { // 辺を2つのループで共有している } else { // 辺を共有していない notSharedEdgeExists = true; break; } } if (notSharedEdgeExists) { delLoopList.Add(loop); } } } // 外側の導体媒質ループを削除 foreach (CadLogic.Loop deltarget in delLoopList) { CadLogic.delLoop(out_cad2d, deltarget.LoopId, ref out_LoopList, ref out_edgeCollectionList, out_medias, ref out_incidentPortNo); } if (errorCCadObj) { success = false; } else { success = true; } return success; }
/// <summary> /// Ver1.2.0.0形式のCadファイルフォーマットで図面情報を読み込む /// </summary> /// <param name="filename"></param> /// <param name="maxDiv"></param> /// <param name="areaSelection"></param> /// <param name="areaToMediaIndex"></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> /// <returns></returns> public static bool LoadFromFile_Ver_1_2( string filename, out Size maxDiv, out bool[,] areaSelection, out int[,] areaToMediaIndex, out IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList, out bool[,] yBoundarySelection, out bool[,] xBoundarySelection, out int incidentPortNo, out MediaInfo[] medias ) { bool success = false; // ver1.2.0.0の設定値 int maxMediaCount = 3; maxDiv = new Size(30, 30); // 初期化 areaSelection = new bool[maxDiv.Width, maxDiv.Height]; areaToMediaIndex = new int[maxDiv.Width, maxDiv.Height]; for (int y = 0; y < maxDiv.Height; y++) { for (int x = 0; x < maxDiv.Width; x++) { areaSelection[y, x] = false; areaToMediaIndex[y, x] = 0; } } edgeList = new List<CadDatFile_Ver_1_2.Edge_Ver_1_2>(); yBoundarySelection = new bool[maxDiv.Height, maxDiv.Width + 1]; xBoundarySelection = new bool[maxDiv.Height + 1, maxDiv.Width]; 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; } } incidentPortNo = 1; medias = new MediaInfo[maxMediaCount]; for (int i = 0; i < medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = CadLogic.MediaBackColors[i]; medias[i] = media; } 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 != 2 && tokens.Length != 3) // ver1.1.0.0で媒質インデックス追加 { MessageBox.Show("領域選択情報が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } int x = int.Parse(tokens[0]); int y = int.Parse(tokens[1]); int mediaIndex = 0;//CadLogic.DefMediaIndex; if (tokens.Length == 3) { mediaIndex = int.Parse(tokens[2]); } if ((x >= 0 && x < maxDiv.Width) && (y >= 0 && y < maxDiv.Height)) { areaSelection[y, x] = true; } else { MessageBox.Show("領域選択座標値が不正です", "", MessageBoxButtons.OK, MessageBoxIcon.Error); return success; } // ver1.1.0.0で追加 areaToMediaIndex[y, x] = mediaIndex; } // ポート境界 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; } CadDatFile_Ver_1_2.Edge_Ver_1_2 edge = new CadDatFile_Ver_1_2.Edge_Ver_1_2(); edge.Delta = delta; edge.No = edgeNo; edge.Points[0] = p[0]; edge.Points[1] = p[1]; edgeList.Add(edge); } // 2次的な情報(edgeListから生成される) foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 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]); ////////////////////////////////////////// //// Ver1.1.0.0からの追加情報 ////////////////////////////////////////// line = sr.ReadLine(); if (line == null || line.Length == 0) { // 媒質情報なし // ver1.0.0.0 } else { // 媒質情報? // ver1.1.0.0 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); } } } success = true; } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } return success; }
/// <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="lsEqnSolverDv">線形方程式解法区分</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, int incidentPortNo, MediaInfo[] medias, double firstWaveLength, double lastWaveLength, int calcCnt, FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv) { ////////////////////////////////////////// // ファイル出力 ////////////////////////////////////////// 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); } // 入射ポート番号 line = string.Format("IncidentPortNo,{0}", incidentPortNo); sw.WriteLine(line); ////////////////////////////////////////// //// 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); } // 計算対象周波数 sw.WriteLine("WaveLengthRange,{0},{1},{2}", firstWaveLength, lastWaveLength, calcCnt); // 線形方程式解法区分 sw.WriteLine("LsEqnSolverDv,{0}", FemSolver.LinearSystemEqnSolverDVToStr(lsEqnSolverDv)); } } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } }
/// <summary> /// 1Dヘルムホルツ方程式固有値問題の要素行列を加算する /// </summary> /// <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( 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) { // 1次線要素 const int nno = Constants.LineNodeCnt_FirstOrder; // 2; 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; if (WaveModeDv == FemSolver.WaveModeDV.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } media_P = MyMatrixUtil.matrix_Inverse(media_P); double[,] integralN = new double[nno, nno] { { elen / 3.0, elen / 6.0 }, { elen / 6.0, elen / 3.0 }, }; double[,] integralDNDY = new double[nno, nno] { { 1.0 / elen, -1.0 / elen }, { -1.0 / elen, 1.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> /// 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="lsEqnSolverDv">線形方程式解法区分</param> /// <returns></returns> public static void SaveToFile(string filename, IList<FemNode> nodes, IList<FemElement> elements, IList<IList<int>> ports, IList<int> forceBCNodes, int incidentPortNo, MediaInfo[] medias, double firstWaveLength, double lastWaveLength, int calcCnt, FemSolver.LinearSystemEqnSoverDV lsEqnSolverDv ) { 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, incidentPortNo, medias, firstWaveLength, lastWaveLength, calcCnt, lsEqnSolverDv); }
/// <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> /// <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 int incidentPortNo, out MediaInfo[] medias, out double firstWaveLength, out double lastWaveLength, out int calcCnt, out FemSolver.LinearSystemEqnSoverDV lsEqnSoverDv ) { int eNodeCnt = 0; nodes = new List<FemNode>(); elements = new List<FemElement>(); ports = new List<IList<int>>(); forceBCNodes = new List<int>(); incidentPortNo = 1; medias = new MediaInfo[Constants.MaxMediaCount]; for (int i = 0; i < medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = CadLogic.MediaBackColors[i]; medias[i] = media; } firstWaveLength = 0.0; lastWaveLength = 0.0; calcCnt = 0; lsEqnSoverDv = Constants.DefLsEqnSolverDv; 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.QuadNodeCnt_SecondOrder_Type2) && (tokens.Length != 2 + Constants.TriNodeCnt_FirstOrder) && (tokens.Length != 2 + Constants.QuadNodeCnt_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); } 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]); ////////////////////////////////////////// //// Ver1.1.0.0からの追加情報 ////////////////////////////////////////// line = sr.ReadLine(); if (line == null || line.Length == 0) { // 媒質情報なし // ver1.0.0.0 } else { // 媒質情報? // ver1.1.0.0 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] != "LsEqnSolverDv") { MessageBox.Show("線形方程式解法区分情報がありません"); return false; } string value = tokens[1]; lsEqnSoverDv = FemSolver.StrToLinearSystemEqnSolverDV(value); } } } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } return true; }
/* 数値積分版 * /// <summary> * /// ヘルムホルツ方程式に対する有限要素マトリクス作成 * /// </summary> * /// <param name="waveLength">波長</param> * /// <param name="toSorted">ソートされた節点インデックス( 2D節点番号→ソート済みリストインデックスのマップ)</param> * /// <param name="element">有限要素</param> * /// <param name="Nodes">節点リスト</param> * /// <param name="Medias">媒質リスト</param> * /// <param name="ForceNodeNumberH">強制境界節点ハッシュ</param> * /// <param name="WaveModeDv">計算する波のモード区分</param> * /// <param name="mat">マージされる全体行列</param> * public static void AddElementMat(double waveLength, * Dictionary<int, int> toSorted, * FemElement element, * IList<FemNode> Nodes, * MediaInfo[] Medias, * Dictionary<int, bool> ForceNodeNumberH, * FemSolver.WaveModeDv WaveModeDv, * ref MyComplexMatrix mat) * { * // 定数 * const double pi = Constants.pi; * const double c0 = Constants.c0; * // 波数 * double k0 = 2.0 * pi / waveLength; * // 角周波数 * double omega = k0 * c0; * * // 要素頂点数 * const int vertexCnt = Constants.QuadVertexCnt; //4; * // 要素内節点数 * const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 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; * if (WaveModeDv == FemSolver.WaveModeDv.TE) * { * media_P = media.P; * media_Q = media.Q; * } * else if (WaveModeDv == FemSolver.WaveModeDv.TM) * { * media_P = media.Q; * media_Q = media.P; * } * else * { * System.Diagnostics.Debug.Assert(false); * } * // [p]は逆数をとる * media_P = MyMatrixUtil.matrix_Inverse(media_P); * * // 節点座標(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[] le = new double[4]; * //le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); * //le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); * //le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); * //le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); * * // 要素節点座標( 局所r,s成分 ) * // s * // | * // 3+ 6 +2 * // | | | * // ---7---+---5-->r * // | | | * // 0+ 4 +1 * // | * // * double[][] n_pts = * { * // r, s * new double[] {-1.0, -1.0}, //0 * new double[] { 1.0, -1.0}, //1 * new double[] { 1.0, 1.0}, //2 * new double[] {-1.0, 1.0}, //3 * new double[] { 0, -1.0}, //4 * new double[] { 1.0, 0}, //5 * new double[] { 0, 1.0}, //6 * new double[] {-1.0, 0}, //7 * }; * * * // ガウスルジャンドルの積分公式 * double[][] g_pts = new double[5][] * { * // ポイント(ξ: [-1 +1]区間)、重み * new double[] { -0.90617985, 0.23692689}, * new double[] { -0.53846931, 0.47862867}, * new double[] {0.0, 0.56888889}, * new double[] {0.53846931, 0.47862867}, * new double[] {0.90617985, 0.23692689} * }; * * // 要素剛性行列を作る * double[,] emat = new Complex[nno, nno]; * for (int ino = 0; ino < nno; ino++) * { * for (int jno = 0; jno < nno; jno++) * { * emat[ino, jno] = 0.0; * double detjsum = 0; //check * foreach (double[] s_g_pt in g_pts) * { * foreach (double[] r_g_pt in g_pts) * { * // 積分点 * double r = r_g_pt[0]; * double s = s_g_pt[0]; * // 重み(2次元) * double weight = r_g_pt[1] * s_g_pt[1]; * // 形状関数 * double[] N = new double[nno]; * // 形状関数のr, s方向微分 * double[] dNdr = new double[nno]; * double[] dNds = new double[nno]; * // 節点0~3 : 四角形の頂点 * for (int i = 0; i < 4; i++) * { * // 節点の局所座標 * double ri = n_pts[i][0]; * double si = n_pts[i][1]; * // 形状関数N * N[i] = 0.25 * (1.0 + ri * r) * (1.0 + si * s) * (ri* r + si * s - 1.0); * // 形状関数のr方向微分 * dNdr[i] = 0.25 * ri * (1.0 + si * s) * (2.0 * ri * r + si * s); * // 形状関数のs方向微分 * dNds[i] = 0.25 * si * (1.0 + ri * r) * (ri * r + 2.0 * si * s); * } * // 節点4,6 : r方向辺上中点 * foreach (int i in new int[]{ 4, 6}) * { * // 節点の局所座標 * double ri = n_pts[i][0]; * double si = n_pts[i][1]; * // 形状関数N * N[i] = 0.5 * (1.0 - r * r) * (1.0 + si * s); * // 形状関数のr方向微分 * dNdr[i] = -1.0 * r * (1.0 + si * s); * // 形状関数のs方向微分 * dNds[i] = 0.5 * si * (1.0 - r * r); * } * // 節点5,7 : s方向辺上中点 * foreach (int i in new int[] { 5, 7 }) * { * // 節点の局所座標 * double ri = n_pts[i][0]; * double si = n_pts[i][1]; * // 形状関数N * N[i] = 0.5 * (1.0 + ri * r) * (1.0 - s * s); * // 形状関数のr方向微分 * dNdr[i] = 0.5 * ri * (1.0 - s * s); * // 形状関数のs方向微分 * dNds[i] = -1.0 * s * (1.0 + ri * r); * } * * // ヤコビアン行列 * double j11; * double j12; * double j21; * double j22; * j11 = 0; * j12 = 0; * j21 = 0; * j22 = 0; * * //for (int i = 0; i < vertexCnt; i++) * //{ * // // 頂点の座標の微分 * // // 座標の形状関数は一次四角形のものを使用する * // // 節点の局所座標 * // double ri = n_pts[i][0]; * // double si = n_pts[i][1]; * // double dNdr_1stOrder = 0.25 * ri * (1.0 + si * s); * // double dNds_1stOrder = 0.25 * (1.0 + ri * r) * si; * // j11 += dNdr_1stOrder * pp[i][0]; * // j12 += dNdr_1stOrder * pp[i][1]; * // j21 += dNds_1stOrder * pp[i][0]; * // j22 += dNds_1stOrder * pp[i][1]; * //} * * for (int i = 0; i < nno; i++) * { * j11 += dNdr[i] * pp[i][0]; * j12 += dNdr[i] * pp[i][1]; * j21 += dNds[i] * pp[i][0]; * j22 += dNds[i] * pp[i][1]; * } * // ヤコビアン * double detj = j11 * j22 - j12 * j21; * detjsum += detj * weight; * //System.Diagnostics.Debug.WriteLine("det:{0}", detj); * * // gradr[0] : gradrのx成分 grad[1] : gradrのy成分 * // grads[0] : gradsのx成分 grads[1] : gradsのy成分 * double[] gradr = new double[2]; * double[] grads = new double[2]; * gradr[0] = j22 / detj; * gradr[1] = - j21 / detj; * grads[0] = - j12 / detj; * grads[1] = j11 / detj; * * // 形状関数のx, y方向微分 * double[,] dNdX = new double[ndim, nno]; * for (int i = 0; i < nno; i++) * { * for (int direction = 0; direction < ndim; direction++) * { * dNdX[direction, i] = dNdr[i] * gradr[direction] + dNds[i] * grads[direction]; * } * } * * // 汎関数 * double functional = media_P[0, 0] * dNdX[1, ino] * dNdX[1, jno] + media_P[1, 1] * dNdX[0, ino] * dNdX[0, jno] * - k0 * k0 * media_Q[2, 2] * N[ino] * N[jno]; * emat[ino, jno] += detj * weight * functional; * } * } * //System.Diagnostics.Debug.WriteLine("detsum: {0}", detjsum); * } * } * * // 要素剛性行列にマージする * 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]; * } * } * } */ /// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary <int, int> toSorted, FemElement element, IList <FemNode> Nodes, MediaInfo[] Medias, Dictionary <int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 const double pi = Constants.pi; const double c0 = Constants.c0; // 波数 double k0 = 2.0 * pi / waveLength; // 角周波数 double omega = k0 * c0; // 要素頂点数 //const int vertexCnt = Constants.QuadVertexCnt; //4; // 要素内節点数 const int nno = Constants.QuadNodeCnt_SecondOrder_Type2; //8; // 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, 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[] le = new double[4]; le[0] = FemMeshLogic.GetDistance(pp[0], pp[1]); le[1] = FemMeshLogic.GetDistance(pp[1], pp[2]); le[2] = FemMeshLogic.GetDistance(pp[2], pp[3]); le[3] = FemMeshLogic.GetDistance(pp[3], pp[0]); System.Diagnostics.Debug.Assert(Math.Abs(le[0] - le[2]) < Constants.PrecisionLowerLimit); System.Diagnostics.Debug.Assert(Math.Abs(le[1] - le[3]) < Constants.PrecisionLowerLimit); double lx = le[0]; double ly = le[1]; // 要素節点座標( 局所r,s成分 ) // s // | // 3+ 6 +2 // | | | // ---7---+---5-->r // | | | // 0+ 4 +1 // | // double[][] n_pts = { // r, s new double[] { -1.0, -1.0 }, //0 new double[] { 1.0, -1.0 }, //1 new double[] { 1.0, 1.0 }, //2 new double[] { -1.0, 1.0 }, //3 new double[] { 0, -1.0 }, //4 new double[] { 1.0, 0 }, //5 new double[] { 0, 1.0 }, //6 new double[] { -1.0, 0 }, //7 }; // Ni = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] Ni_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.25 * ri * ri * si; Ni_a[i, 1] = 0.25 * ri * ri; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.25 * ri * si; Ni_a[i, 4] = 0.25 * ri * si * si; Ni_a[i, 5] = 0.25 * si * si; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = -0.25; } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = -0.5 * si; Ni_a[i, 1] = -0.5; Ni_a[i, 2] = 0.0; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = 0.0; Ni_a[i, 5] = 0.0; Ni_a[i, 6] = 0.5 * si; Ni_a[i, 7] = 0.5; } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; Ni_a[i, 0] = 0.0; Ni_a[i, 1] = 0.0; Ni_a[i, 2] = 0.5 * ri; Ni_a[i, 3] = 0.0; Ni_a[i, 4] = -0.5 * ri; Ni_a[i, 5] = -0.5; Ni_a[i, 6] = 0.0; Ni_a[i, 7] = 0.5; } // dNidr = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNidr_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.25 * 2.0 * ri * ri; // r dNidr_a[i, 3] = 0.25 * 2.0 * ri * ri * si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.25 * ri * si * si; // s^2 dNidr_a[i, 6] = 0.25 * ri * si; // s dNidr_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = -1.0; // r dNidr_a[i, 3] = -si; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = 0.0; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.0; // 1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNidr_a[i, 0] = 0.0; dNidr_a[i, 1] = 0.0; // r^2 dNidr_a[i, 2] = 0.0; // r dNidr_a[i, 3] = 0.0; // rs dNidr_a[i, 4] = 0.0; dNidr_a[i, 5] = -0.5 * ri; // s^2 dNidr_a[i, 6] = 0.0; // s dNidr_a[i, 7] = 0.5 * ri; // 1 } // dNids = a0(r^2*s) + a1(r^2) + a2(r) + a3(rs) + a4(rs^2) + a5(s^2) + a6(s) + a7 double[,] dNids_a = new double[nno, 8]; for (int i = 0; i < 4; i++) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.25 * ri * ri * si; // r^2 dNids_a[i, 2] = 0.25 * ri * si; // r dNids_a[i, 3] = 0.25 * 2.0 * ri * si * si; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.25 * 2.0 * si * si; // s dNids_a[i, 7] = 0.0; //1 } foreach (int i in new int[] { 4, 6 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = -0.5 * si; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = 0.0; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = 0.0; // s dNids_a[i, 7] = 0.5 * si; //1 } foreach (int i in new int[] { 5, 7 }) { // 節点の局所座標 double ri = n_pts[i][0]; double si = n_pts[i][1]; dNids_a[i, 0] = 0.0; dNids_a[i, 1] = 0.0; // r^2 dNids_a[i, 2] = 0.0; // r dNids_a[i, 3] = -ri; // rs dNids_a[i, 4] = 0.0; dNids_a[i, 5] = 0.0; // s^2 dNids_a[i, 6] = -1.0; // s dNids_a[i, 7] = 0.0; //1 } // ∫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]; // ∫N N dxdy double[,] integralN = new double[nno, nno]; for (int ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralN[ino, jno] = lx * ly / 4.0 * ( // r^4s^2 4.0 / 15.0 * Ni_a[ino, 0] * Ni_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (Ni_a[ino, 6] * Ni_a[jno, 0] + Ni_a[ino, 5] * Ni_a[jno, 1] + Ni_a[ino, 4] * Ni_a[jno, 2] + Ni_a[ino, 3] * Ni_a[jno, 3] + Ni_a[ino, 2] * Ni_a[jno, 4] + Ni_a[ino, 1] * Ni_a[jno, 5] + Ni_a[ino, 0] * Ni_a[jno, 6]) // r^4 + 4.0 / 5.0 * Ni_a[ino, 1] * Ni_a[jno, 1] // r^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 1] + Ni_a[ino, 2] * Ni_a[jno, 2] + Ni_a[ino, 1] * Ni_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * Ni_a[ino, 4] * Ni_a[jno, 4] // s^4 + 4.0 / 5.0 * Ni_a[ino, 5] * Ni_a[jno, 5] // s^2 + 4.0 / 3.0 * (Ni_a[ino, 7] * Ni_a[jno, 5] + Ni_a[ino, 6] * Ni_a[jno, 6] + Ni_a[ino, 5] * Ni_a[jno, 7]) // 1 + 4.0 * Ni_a[ino, 7] * Ni_a[jno, 7] ); integralDNDX[0, ino, jno] = ly / lx * ( // r^4s^2 4.0 / 15.0 * dNidr_a[ino, 0] * dNidr_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNidr_a[ino, 6] * dNidr_a[jno, 0] + dNidr_a[ino, 5] * dNidr_a[jno, 1] + dNidr_a[ino, 4] * dNidr_a[jno, 2] + dNidr_a[ino, 3] * dNidr_a[jno, 3] + dNidr_a[ino, 2] * dNidr_a[jno, 4] + dNidr_a[ino, 1] * dNidr_a[jno, 5] + dNidr_a[ino, 0] * dNidr_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNidr_a[ino, 1] * dNidr_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 1] + dNidr_a[ino, 2] * dNidr_a[jno, 2] + dNidr_a[ino, 1] * dNidr_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNidr_a[ino, 4] * dNidr_a[jno, 4] // s^4 + 4.0 / 5.0 * dNidr_a[ino, 5] * dNidr_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNidr_a[ino, 7] * dNidr_a[jno, 5] + dNidr_a[ino, 6] * dNidr_a[jno, 6] + dNidr_a[ino, 5] * dNidr_a[jno, 7]) // 1 + 4.0 * dNidr_a[ino, 7] * dNidr_a[jno, 7] ); integralDNDX[1, ino, jno] = lx / ly * ( // r^4s^2 4.0 / 15.0 * dNids_a[ino, 0] * dNids_a[jno, 0] // r^2s^2 + 4.0 / 9.0 * (dNids_a[ino, 6] * dNids_a[jno, 0] + dNids_a[ino, 5] * dNids_a[jno, 1] + dNids_a[ino, 4] * dNids_a[jno, 2] + dNids_a[ino, 3] * dNids_a[jno, 3] + dNids_a[ino, 2] * dNids_a[jno, 4] + dNids_a[ino, 1] * dNids_a[jno, 5] + dNids_a[ino, 0] * dNids_a[jno, 6]) // r^4 + 4.0 / 5.0 * dNids_a[ino, 1] * dNids_a[jno, 1] // r^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 1] + dNids_a[ino, 2] * dNids_a[jno, 2] + dNids_a[ino, 1] * dNids_a[jno, 7]) // r^2s^4 + 4.0 / 15.0 * dNids_a[ino, 4] * dNids_a[jno, 4] // s^4 + 4.0 / 5.0 * dNids_a[ino, 5] * dNids_a[jno, 5] // s^2 + 4.0 / 3.0 * (dNids_a[ino, 7] * dNids_a[jno, 5] + dNids_a[ino, 6] * dNids_a[jno, 6] + dNids_a[ino, 5] * dNids_a[jno, 7]) // 1 + 4.0 * dNids_a[ino, 7] * dNids_a[jno, 7] ); } } // 要素剛性行列を作る 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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary <uint, int> inoGlobalDic = new Dictionary <uint, int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) { continue; } uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray <uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// <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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</param> /// <param name="mat">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</param> public static void AddElementMat(double waveLength, Dictionary<int, int> toSorted, FemElement element, IList<FemNode> Nodes, MediaInfo[] Medias, Dictionary<int, bool> ForceNodeNumberH, FemSolver.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, ref MyComplexMatrix mat, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 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_FirstOrder; //3; // 1次三角形要素 // 座標次元数 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, 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]); // ∫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 ino = 0; ino < nno; ino++) { for (int jno = 0; jno < nno; jno++) { integralDNDX[0, ino, jno] = area * dldx[ino, 0] * dldx[jno, 0]; integralDNDX[1, ino, jno] = area * dldx[ino, 1] * dldx[jno, 1]; } } // ∫N N dxdy double[,] integralN = new double[nno, nno] { { area / 6.0 , area / 12.0, area / 12.0 }, { area / 12.0, area / 6.0, area / 12.0 }, { area / 12.0, area / 12.0, area / 6.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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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> /// Ver1.2.0.0形式のCadファイルフォーマットで図面情報を保存する /// </summary> /// <param name="filename"></param> /// <param name="maxDiv"></param> /// <param name="areaSelection"></param> /// <param name="areaToMediaIndex"></param> /// <param name="edgeList"></param> /// <param name="incidentPortNo"></param> /// <param name="medias"></param> public static void SaveToFile_Ver_1_2( string filename, Size maxDiv, bool[,] areaSelection, int[,] areaToMediaIndex, IList<CadDatFile_Ver_1_2.Edge_Ver_1_2> edgeList, int incidentPortNo, MediaInfo[] medias ) { 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]) { counter++; } } } // 領域: 書き込み sw.WriteLine("AreaSelection,{0}", counter); for (int y = 0; y < maxDiv.Height; y++) { for (int x = 0; x < maxDiv.Width; x++) { if (areaSelection[y, x]) { // ver1.1.0.0から座標の後に媒質インデックスを追加 sw.WriteLine("{0},{1},{2}", x, y, areaToMediaIndex[y, x]); } } } // ポート境界: 書き込み個数の計算 sw.WriteLine("EdgeList,{0}", edgeList.Count); // ポート境界: 書き込み foreach (CadDatFile_Ver_1_2.Edge_Ver_1_2 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); } } } 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="WGStructureDv">導波路構造区分</param> /// <param name="WaveModeDv">計算する波のモード区分</param> /// <param name="waveguideWidthForEPlane">導波路幅(E面解析用)</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.WGStructureDV WGStructureDv, FemSolver.WaveModeDV WaveModeDv, double waveguideWidthForEPlane, 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, WGStructureDv, WaveModeDv, waveguideWidthForEPlane, out media_P, out media_Q); double[,] integralN = new double[nno, nno] { { 4.0 / 30.0 * elen, -1.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { -1.0 / 30.0 * elen, 4.0 / 30.0 * elen, 2.0 / 30.0 * elen }, { 2.0 / 30.0 * elen, 2.0 / 30.0 * elen, 16.0 / 30.0 * elen }, }; double[,] integralDNDY = new double[nno, nno] { { 7.0 / (3.0 * elen), 1.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { 1.0 / (3.0 * elen), 7.0 / (3.0 * elen), -8.0 / (3.0 * elen) }, { -8.0 / (3.0 * elen), -8.0 / (3.0 * elen), 16.0 / (3.0 * elen) }, }; for (int ino = 0; ino < nno; ino++) { int inoBoundary = nodeNumbers[ino]; int inoSorted; if (!toSorted.ContainsKey(inoBoundary)) continue; inoSorted = toSorted[inoBoundary]; for (int jno = 0; jno < nno; jno++) { int jnoBoundary = nodeNumbers[jno]; int jnoSorted; if (!toSorted.ContainsKey(jnoBoundary)) continue; jnoSorted = toSorted[jnoBoundary]; // 対称バンド行列対応 if (ryy_1d is MyDoubleSymmetricBandMatrix && jnoSorted < inoSorted) { continue; } double e_txx_1d_inojno = media_P[0, 0] * integralDNDY[ino, jno]; double e_ryy_1d_inojno = media_P[1, 1] * integralN[ino, jno]; double e_uzz_1d_inojno = media_Q[2, 2] * integralN[ino, jno]; //txx_1d[inoSorted, jnoSorted] += e_txx_1d_inojno; //ryy_1d[inoSorted, jnoSorted] += e_ryy_1d_inojno; //uzz_1d[inoSorted, jnoSorted] += e_uzz_1d_inojno; txx_1d._body[txx_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_txx_1d_inojno; ryy_1d._body[ryy_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_ryy_1d_inojno; uzz_1d._body[uzz_1d.GetBufferIndex(inoSorted, jnoSorted)] += e_uzz_1d_inojno; } } }
/// <summary> /// 初期化処理 /// </summary> protected void init() { _CadMode = CadModeType.None; SerializedCadObjBuff = ""; LoopList.Clear(); EdgeCollectionList.Clear(); //edit EditPts.Clear(); EditVertexIds.Clear(); EditEdgeIds.Clear(); IncidentPortNo = 1; for (int i = 0; i < Medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = MediaBackColors[i]; Medias[i] = media; } }
/// <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">マージされる全体行列(clapack使用時)</param> /// <param name="mat_cc">マージされる全体行列(DelFEM使用時)</param> /// <param name="res_c">マージされる残差ベクトル(DelFEM使用時)</param> /// <param name="tmpBuffer">一時バッファ(DelFEM使用時)</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, ref DelFEM4NetMatVec.CZMatDia_BlkCrs_Ptr mat_cc, ref DelFEM4NetMatVec.CZVector_Blk_Ptr res_c, ref int[] tmpBuffer) { // 定数 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; if (WaveModeDv == FemSolver.WaveModeDV.TE) { media_P = media.P; media_Q = media.Q; } else if (WaveModeDv == FemSolver.WaveModeDV.TM) { media_P = media.Q; media_Q = media.P; } else { System.Diagnostics.Debug.Assert(false); } // [p]は逆数をとる media_P = MyMatrixUtil.matrix_Inverse(media_P); // 節点座標(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]); //Console.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]; } } // 要素剛性行列にマージする if (mat_cc != null) { // 全体節点番号→要素内節点インデックスマップ Dictionary<uint, int> inoGlobalDic = new Dictionary<uint,int>(); for (int ino = 0; ino < nno; ino++) { int iNodeNumber = no_c[ino]; if (ForceNodeNumberH.ContainsKey(iNodeNumber)) continue; uint inoGlobal = (uint)toSorted[iNodeNumber]; inoGlobalDic.Add(inoGlobal, ino); } // マージ用の節点番号リスト uint[] no_c_tmp = inoGlobalDic.Keys.ToArray<uint>(); // マージする節点数("col"と"row"のサイズ) uint ncolrow_tmp = (uint)no_c_tmp.Length; // Note: // 要素の節点がすべて強制境界の場合がある.その場合は、ncolrow_tmpが0 if (ncolrow_tmp > 0) { // マージする要素行列 DelFEM4NetCom.Complex[] ematBuffer = new DelFEM4NetCom.Complex[ncolrow_tmp * ncolrow_tmp]; for (int ino_tmp = 0; ino_tmp < ncolrow_tmp; ino_tmp++) { int ino = inoGlobalDic[no_c_tmp[ino_tmp]]; for (int jno_tmp = 0; jno_tmp < ncolrow_tmp; jno_tmp++) { int jno = inoGlobalDic[no_c_tmp[jno_tmp]]; double value = emat[ino, jno]; DelFEM4NetCom.Complex cvalueDelFEM = new DelFEM4NetCom.Complex(value, 0); // ematBuffer[ino_tmp, jno_tmp] 横ベクトルを先に埋める(clapack方式でないことに注意) ematBuffer[ino_tmp * ncolrow_tmp + jno_tmp] = cvalueDelFEM; } } // 全体行列に要素行列をマージする mat_cc.Mearge(ncolrow_tmp, no_c_tmp, ncolrow_tmp, no_c_tmp, 1, ematBuffer, ref tmpBuffer); } } else if (mat != null) { 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="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> /// <param name="lsEqnSoverDv">線形方程式解法区分</param> /// <param name="waveguideWidthForEPlane">導波管幅(E面解析用)</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 int incidentPortNo, out MediaInfo[] medias, out double firstWaveLength, out double lastWaveLength, out int calcCnt, out FemSolver.WGStructureDV wgStructureDv, out FemSolver.WaveModeDV waveModeDv, out FemSolver.LinearSystemEqnSoverDV lsEqnSoverDv, out double waveguideWidthForEPlane ) { int eNodeCnt = 0; nodes = new List <FemNode>(); elements = new List <FemElement>(); ports = new List <IList <int> >(); forceBCNodes = new List <int>(); incidentPortNo = 1; medias = new MediaInfo[Constants.MaxMediaCount]; for (int i = 0; i < medias.Length; i++) { MediaInfo media = new MediaInfo(); media.BackColor = CadLogic.MediaBackColors[i]; medias[i] = media; } firstWaveLength = 0.0; lastWaveLength = 0.0; calcCnt = 0; wgStructureDv = Constants.DefWGStructureDv; waveModeDv = Constants.DefWaveModeDv; lsEqnSoverDv = Constants.DefLsEqnSolverDv; waveguideWidthForEPlane = 0; 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.QuadNodeCnt_SecondOrder_Type2) && (tokens.Length != 2 + Constants.TriNodeCnt_FirstOrder) && (tokens.Length != 2 + Constants.QuadNodeCnt_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); } 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]); ////////////////////////////////////////// //// Ver1.1.0.0からの追加情報 ////////////////////////////////////////// line = sr.ReadLine(); if (line == null || line.Length == 0) { // 媒質情報なし // ver1.0.0.0 } else { // 媒質情報? // ver1.1.0.0 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] != "LsEqnSolverDv") { MessageBox.Show("線形方程式解法区分情報がありません"); return(false); } string value = tokens[1]; lsEqnSoverDv = FemSolver.StrToLinearSystemEqnSolverDV(value); } 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); } } line = sr.ReadLine(); if (line == null || line.Length == 0) { } else { tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "WGStructureDv") { MessageBox.Show("計算対象導波路構造区分情報がありません"); return(false); } wgStructureDv = FemSolver.StrToWGStructureDV(tokens[1]); } line = sr.ReadLine(); if (line == null || line.Length == 0) { } else { tokens = line.Split(delimiter); if (tokens.Length != 2 || tokens[0] != "WaveguideWidthForEPlane") { MessageBox.Show("E面解析用導波路幅がありません"); return(false); } waveguideWidthForEPlane = double.Parse(tokens[1]); } } } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message, "", MessageBoxButtons.OK, MessageBoxIcon.Error); return(false); } return(true); }
public object Clone() { MediaInfo media = new MediaInfo(this.p, this.q); media.BackColor = this.BackColor; return (object)media; }
///////////////////////////////////////////////////////////////////////////// // 定数 ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // 型 ///////////////////////////////////////////////////////////////////////////// /// <summary> /// 図面情報を保存する /// </summary> /// <param name="filename"></param> /// <param name="editCad2D"></param> /// <param name="loopList"></param> /// <param name="edgeCollectionList"></param> /// <param name="incidentPortNo"></param> /// <param name="medias"></param> public static void SaveToFile( string filename, CCadObj2D editCad2D, IList<CadLogic.Loop> loopList, IList<EdgeCollection> edgeCollectionList, int incidentPortNo, MediaInfo[] medias ) { // 番号順に並び替え ((List<EdgeCollection>)edgeCollectionList).Sort(); try { // Cadオブジェクトデータファイル string basename = Path.GetDirectoryName(filename) + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filename); string cadObjFilename = basename + Constants.CadObjExt; // Cadオブジェクトデータを外部ファイルに書き込み using (CSerializer fout = new CSerializer(cadObjFilename, false)) { editCad2D.Serialize(fout); } // Cadデータの書き込み using (StreamWriter sw = new StreamWriter(filename)) { int counter; string line; // アプリケーションのバージョン番号 sw.WriteLine("AppVersion,{0}", MyUtilLib.MyUtil.getAppVersion()); // CadLogicの使用ユーティリティ名 sw.WriteLine("UseUtility,{0}", CadLogic.UseUtility); //// ベースループID //sw.WriteLine("BaseLoopId,{0}", baseLoopId); // ループのリスト counter = 0; sw.WriteLine("LoopList,{0}", loopList.Count); foreach (CadLogic.Loop loop in loopList) { sw.WriteLine("Loop,{0},{1},{2}", ++counter, loop.LoopId, loop.MediaIndex); } // ポートのエッジコレクションのリスト counter = 0; sw.WriteLine("EdgeCollectionList,{0}", edgeCollectionList.Count); foreach (EdgeCollection edgeCollection in edgeCollectionList) { line = string.Format("EdgeCollection,{0},{1},{2},", ++counter, edgeCollection.No, edgeCollection.EdgeIds.Count); foreach (uint eId in edgeCollection.EdgeIds) { line += string.Format("{0},", eId); } line = line.Remove(line.Length - 1); // 最後の,を削除 sw.WriteLine(line); } // 入射ポート番号 sw.WriteLine("IncidentPortNo,{0}", incidentPortNo); // 媒質情報の個数 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); } } } catch (Exception exception) { Console.WriteLine(exception.Message + " " + exception.StackTrace); MessageBox.Show(exception.Message); } }