コード例 #1
0
ファイル: FemSolverPort.cs プロジェクト: lulzzz/PhCFem
        /// <summary>
        /// ポート固有値解析
        /// </summary>
        public static void SolvePortWaveguideEigen(
            FemSolver.WaveModeDV WaveModeDv,
            double waveLength,
            int maxModeSpecified,
            IList <FemNode> Nodes,
            Dictionary <string, IList <int> > EdgeToElementNoH,
            IList <FemElement> Elements,
            MediaInfo[] Medias,
            Dictionary <int, bool> ForceNodeNumberH,
            IList <int> portNodes,
            out int[] nodesBoundary,
            out MyDoubleMatrix ryy_1d,
            out Complex[] eigenValues,
            out Complex[,] eigenVecs)
        {
            //System.Diagnostics.Debug.WriteLine("solvePortWaveguideEigen: {0},{1}", waveLength, portNo);
            nodesBoundary = null;
            ryy_1d        = null;
            eigenValues   = null;
            eigenVecs     = null;


            // 2D次元数
            const int ndim2d = Constants.CoordDim2D; //2;
            // 波数
            double k0 = 2.0 * pi / waveLength;
            // 角周波数
            double omega = k0 * c0;

            // 節点番号リスト(要素インデックス: 1D節点番号 - 1 要素:2D節点番号)
            IList <int> nodes = portNodes;
            // 2D→1D節点番号マップ
            Dictionary <int, int> to1dNodes = new Dictionary <int, int>();
            // 節点座標リスト
            IList <double> coords = new List <double>();
            // 要素リスト
            IList <FemLineElement> elements = new List <FemLineElement>();
            // 1D節点番号リスト(ソート済み)
            IList <int> sortedNodes = new List <int>();
            // 1D節点番号→ソート済みリストインデックスのマップ
            Dictionary <int, int> toSorted = new Dictionary <int, int>();

            // 2Dの要素から次数を取得する
            Constants.FemElementShapeDV elemShapeDv2d;
            int order;
            int vertexCnt2d;

            FemMeshLogic.GetElementShapeDvAndOrderByElemNodeCnt(Elements[0].NodeNumbers.Length, out elemShapeDv2d, out order, out vertexCnt2d);

            // 2D→1D節点番号マップ作成
            for (int i = 0; i < nodes.Count; i++)
            {
                int nodeNumber2d = nodes[i];
                if (!to1dNodes.ContainsKey(nodeNumber2d))
                {
                    to1dNodes.Add(nodeNumber2d, i + 1);
                }
            }
            // 原点
            int     nodeNumber0 = nodes[0];
            int     nodeIndex0  = nodeNumber0 - 1;
            FemNode node0       = Nodes[nodeIndex0];

            double[] coord0 = new double[ndim2d];
            coord0[0] = node0.Coord[0];
            coord0[1] = node0.Coord[1];
            // 座標リスト作成
            double[] coord = new double[ndim2d];
            foreach (int nodeNumber in nodes)
            {
                int     nodeIndex = nodeNumber - 1;
                FemNode node      = Nodes[nodeIndex];
                coord[0] = node.Coord[0];
                coord[1] = node.Coord[1];
                double x = FemMeshLogic.GetDistance(coord, coord0);
                //System.Diagnostics.Debug.WriteLine("{0},{1},{2},{3}", nodeIndex, coord[0], coord[1], x);
                coords.Add(x);
            }

            // 線要素を作成する
            if (order == Constants.FirstOrder)
            {
                // 1次線要素
                FemMat_Line_First.MkElements(
                    nodes,
                    EdgeToElementNoH,
                    Elements,
                    ref elements);
            }
            else
            {
                // 2次線要素
                FemMat_Line_Second.MkElements(
                    nodes,
                    EdgeToElementNoH,
                    Elements,
                    ref elements);
            }

            // 強制境界節点と内部領域節点を分離
            foreach (int nodeNumber2d in nodes)
            {
                int nodeNumber = to1dNodes[nodeNumber2d];
                if (ForceNodeNumberH.ContainsKey(nodeNumber2d))
                {
                    System.Diagnostics.Debug.WriteLine("{0}:    {1}    {2}", nodeNumber, Nodes[nodeNumber2d - 1].Coord[0], Nodes[nodeNumber2d - 1].Coord[1]);
                }
                else
                {
                    sortedNodes.Add(nodeNumber);
                    toSorted.Add(nodeNumber, sortedNodes.Count - 1);
                }
            }
            // 対称バンド行列のパラメータを取得する
            int rowcolSize   = 0;
            int subdiaSize   = 0;
            int superdiaSize = 0;

            {
                bool[,] matPattern = null;
                GetMatNonzeroPatternForEigen(elements, toSorted, out matPattern);
                GetBandMatrixSubDiaSizeAndSuperDiaSizeForEigen(matPattern, out rowcolSize, out subdiaSize, out superdiaSize);
            }
            // ソート済み1D節点インデックス→2D節点番号マップ
            nodesBoundary = new int[sortedNodes.Count];
            for (int i = 0; i < sortedNodes.Count; i++)
            {
                int nodeNumber   = sortedNodes[i];
                int nodeIndex    = nodeNumber - 1;
                int nodeNumber2d = nodes[nodeIndex];
                nodesBoundary[i] = nodeNumber2d;
            }

            // 節点数
            int nodeCnt = sortedNodes.Count;
            // 固有値、固有ベクトル
            int maxMode = maxModeSpecified;

            if (maxMode > nodeCnt)
            {
                maxMode = nodeCnt;
            }
            eigenValues = new Complex[maxMode];
            eigenVecs   = new Complex[maxMode, nodeCnt];
            // 固有モード解析でのみ使用するuzz_1d, txx_1d
            MyDoubleMatrix txx_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);
            MyDoubleMatrix uzz_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            // ryy_1dマトリクス (線要素)
            ryy_1d = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            for (int elemIndex = 0; elemIndex < elements.Count; elemIndex++)
            {
                // 線要素
                FemLineElement element = elements[elemIndex];

                // 1Dヘルムホルツ方程式固有値問題の要素行列を加算する
                if (order == Constants.FirstOrder)
                {
                    // 1次線要素
                    FemMat_Line_First.AddElementMatOf1dEigenValueProblem(
                        waveLength, // E面の場合のみ使用
                        element,
                        coords,
                        toSorted,
                        Medias,
                        WaveModeDv,
                        ref txx_1d, ref ryy_1d, ref uzz_1d);
                }
                else
                {
                    // 2次線要素
                    FemMat_Line_Second.AddElementMatOf1dEigenValueProblem(
                        waveLength, // E面の場合のみ使用
                        element,
                        coords,
                        toSorted,
                        Medias,
                        WaveModeDv,
                        ref txx_1d, ref ryy_1d, ref uzz_1d);
                }
            }

            // [A] = [Txx] - k0 * k0 *[Uzz]
            //メモリ節約
            //MyDoubleMatrix matA = new MyDoubleMatrix(nodeCnt, nodeCnt);
            MyDoubleSymmetricBandMatrix matA = new MyDoubleSymmetricBandMatrix(nodeCnt, subdiaSize, superdiaSize);

            for (int ino = 0; ino < nodeCnt; ino++)
            {
                for (int jno = 0; jno < nodeCnt; jno++)
                {
                    // 対称バンド行列対応
                    if (matA is MyDoubleSymmetricBandMatrix && ino > jno)
                    {
                        continue;
                    }
                    // 剛性行列
                    //matA[ino, jno] = txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno];
                    //  質量行列matBが正定値行列となるように剛性行列matAの方の符号を反転する
                    matA[ino, jno] = -(txx_1d[ino, jno] - (k0 * k0) * uzz_1d[ino, jno]);
                }
            }

            // ( [txx] - k0^2[uzz] + β^2[ryy]){Ez} = {0}より
            // [A]{x} = λ[B]{x}としたとき、λ = β^2 とすると[B] = -[ryy]
            //MyDoubleMatrix matB = MyMatrixUtil.product(-1.0, ryy_1d);
            // 質量行列が正定値となるようにするため、上記符号反転を剛性行列の方に反映し、質量行列はryy_1dをそのまま使用する
            //MyDoubleMatrix matB = new MyDoubleMatrix(ryy_1d);
            MyDoubleSymmetricBandMatrix matB = new MyDoubleSymmetricBandMatrix((MyDoubleSymmetricBandMatrix)ryy_1d);

            // 一般化固有値問題を解く
            Complex[] evals = null;
            Complex[,] evecs = null;
            try
            {
                // 固有値、固有ベクトルを求める
                solveEigen(matA, matB, out evals, out evecs);
                // 固有値のソート
                Sort1DEigenMode(k0, evals, evecs);
            }
            catch (Exception exception)
            {
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.Assert(false);
            }
            for (int imode = 0; imode < evecs.GetLength(0); imode++)
            {
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    // 境界上で位相調整する
                    for (int ino = 0; ino < evecs.GetLength(1); ino++)
                    {
                        KrdLab.clapack.Complex cvalue = evecs[imode, ino];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs         = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                }
                if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    phaseShift = fValueAtMaxAbs / maxAbs;
                }
                //System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi);
                for (int ino = 0; ino < evecs.GetLength(1); ino++)
                {
                    evecs[imode, ino] /= phaseShift;
                }
            }

            for (int imode = 0; imode < maxMode; imode++)
            {
                eigenValues[imode] = 0;
            }
            for (int tagtModeIdx = evals.Length - 1, imode = 0; tagtModeIdx >= 0 && imode < maxMode; tagtModeIdx--)
            {
                // 伝搬定数は固有値のsqrt
                Complex betam = Complex.Sqrt(evals[tagtModeIdx]);
                // 定式化BUGFIX
                //   減衰定数は符号がマイナス(β = -jα)
                bool isConjugateMode = false;
                if (betam.Imaginary >= 0.0)
                {
                    betam           = new Complex(betam.Real, -betam.Imaginary);
                    isConjugateMode = true;
                }
                // 固有ベクトル
                Complex[] evec = MyMatrixUtil.matrix_GetRowVec(evecs, tagtModeIdx);
                if (isConjugateMode)
                {
                    evec = MyMatrixUtil.vector_Conjugate(evec);
                }
                // 規格化定数を求める
                // 実数の場合 [ryy]*t = [ryy]t ryyは対称行列より[ryy]t = [ryy]
                Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec);
                Complex   dm      = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec);
                {
                    // H面、平行平板
                    if (WaveModeDv == FemSolver.WaveModeDV.TM)
                    {
                        dm = Complex.Sqrt(omega * eps0 / Complex.Abs(betam) / dm);
                    }
                    else
                    {
                        dm = Complex.Sqrt(omega * mu0 / Complex.Abs(betam) / dm);
                    }
                }
                //System.Diagnostics.Debug.WriteLine("dm = " + dm);

                // 伝搬定数の格納
                eigenValues[imode] = betam;
                // check
                if (imode < 5)
                {
                    //System.Diagnostics.Debug.WriteLine("eigenValues [ " + imode + "] = " + betam.Real + " + " + betam.Imaginary + " i " + " tagtModeIdx :" + tagtModeIdx + " " );
                    System.Diagnostics.Debug.WriteLine("β/k0 [ " + imode + "] = " + betam.Real / k0 + " + " + betam.Imaginary / k0 + " i " + " tagtModeIdx :" + tagtModeIdx + " ");
                }
                // 固有ベクトルの格納(規格化定数を掛ける)
                for (int inoSorted = 0; inoSorted < nodeCnt; inoSorted++)
                {
                    Complex fm = dm * evec[inoSorted];
                    eigenVecs[imode, inoSorted] = fm;
                    //System.Diagnostics.Debug.WriteLine("eigenVecs [ " + imode + ", " + inoSorted + "] = " + fm.Real + " + " + fm.Imaginary + " i  Abs:" + Complex.Abs(fm));
                }
                imode++;
            }
        }
コード例 #2
0
ファイル: FemSolverPort.cs プロジェクト: lulzzz/PhCFem
        /// <summary>
        /// 散乱行列の計算
        /// </summary>
        /// <param name="waveLength"></param>
        /// <param name="iMode"></param>
        /// <param name="isIncidentMode"></param>
        /// <param name="nodesBoundary"></param>
        /// <param name="ryy_1d"></param>
        /// <param name="eigenValues"></param>
        /// <param name="eigenVecs"></param>
        /// <param name="nodesRegion"></param>
        /// <param name="valuesAll"></param>
        /// <returns></returns>
        public static Complex GetWaveguidePortReflectionCoef(
            FemSolver.WaveModeDV WaveModeDv,
            double waveLength,
            int iMode,
            bool isIncidentMode,
            int[] nodesBoundary,
            MyDoubleMatrix ryy_1d,
            Complex[] eigenValues,
            Complex[,] eigenVecs,
            int[] nodesRegion,
            IList <FemElement> Elements,
            MediaInfo[] Medias,
            Complex[] valuesAll)
        {
            // 2D節点番号→ソート済みリストインデックスのマップ
            Dictionary <int, int> toSorted = new Dictionary <int, int>();

            // 2D節点番号→ソート済みリストインデックスのマップ作成
            for (int i = 0; i < nodesRegion.Length; i++)
            {
                int nodeNumber = nodesRegion[i];
                if (!toSorted.ContainsKey(nodeNumber))
                {
                    toSorted.Add(nodeNumber, i);
                }
            }

            // ポート上の界を取得する
            int nodeCnt = nodesBoundary.Length;

            Complex[] valuesB = new Complex[nodeCnt];
            for (int ino = 0; ino < nodeCnt; ino++)
            {
                int nodeNumber = nodesBoundary[ino];
                int inoGlobal  = toSorted[nodeNumber];
                valuesB[ino] = valuesAll[inoGlobal];
            }

            double k0    = 2.0 * pi / waveLength;
            double omega = k0 * c0;

            Complex s11 = new Complex(0.0, 0.0);

            int maxMode = eigenValues.Length;

            // {tmp_vec}*t = {fm}*t[ryy]*t
            // {tmp_vec}* = [ryy]* {fm}*
            //   ([ryy]*)t = [ryy]*
            //    [ryy]が実数のときは、[ryy]* -->[ryy]
            Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigenVecs, iMode);
            // ryyが実数のとき
            Complex[] tmp_vec = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec));

            // s11 = {tmp_vec}t {value_all}
            s11 = MyMatrixUtil.vector_Dot(tmp_vec, valuesB);
            Complex betam = eigenValues[iMode];

            {
                // H面、平行平板
                if (WaveModeDv == FemSolver.WaveModeDV.TM)
                {
                    s11 *= (Complex.Abs(betam) / (omega * eps0));
                    if (isIncidentMode)
                    {
                        s11 += -1.0;
                    }
                }
                else
                {
                    s11 *= (Complex.Abs(betam) / (omega * mu0));
                    if (isIncidentMode)
                    {
                        s11 += -1.0;
                    }
                }
            }

            return(s11);
        }