示例#1
0
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="freqIndex">計算する周波数のインデックス</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="FreqDelta">計算刻み幅</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">波長</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループの値のフィールドID</param>
        /// <param name="FieldForceBcId">強制境界の値のフィールドID</param>
        /// <param name="WgPortInfoList">入出力導波路情報リスト</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsInoutWgSame">同じ入出力導波路?</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="Ls">リニアシステム</param>
        /// <param name="Prec">プリコンディショナ―</param>
        /// <param name="ScatterVecList">散乱係数リスト(ポート毎のモード散乱係数リストのリスト)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int freqIndex,
            double NormalizedFreq1,
            double NormalizedFreq2,
            double FreqDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            IList<WgUtilForPeriodicEigenExt.WgPortInfo> WgPortInfoList,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            bool IsInoutWgSame,
            bool IsShowAbsField,
            ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec,
            ref IList<IList<Complex[]>> ScatterVecList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            // ポート数
            int portCnt = WgPortInfoList.Count;
            // モード電力の合計を出力として表示する
            //bool isShowTotalPortPower = true;
            bool isShowTotalPortPower = false;
            // PC導波路?
            bool isPCWaveguide = false;
            foreach (WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo in WgPortInfoList)
            {
                if (workWgPortInfo.IsPCWaveguide)
                {
                    isPCWaveguide = true;
                    break;
                }
            }
            //// モード追跡する?
            //bool isModeTrace = true;
            //if (!isPCWaveguide)
            //{
            //    isModeTrace = false;
            //}

            // モード追跡用の固有ベクトル格納先の初期化
            if (freqIndex == 0)
            {
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    WgPortInfoList[portIndex].PrevModalVecList = null;
                }
            }
            try
            {

                // 規格化周波数
                double normalizedFreq = getNormalizedFreq(
                    ref freqIndex,
                    NormalizedFreq1,
                    NormalizedFreq2,
                    FreqDelta);
                if (freqIndex == -1)
                {
                    return success;
                }
                // 格子定数
                double latticeA = 0.0;
                double periodicDistance = 0.0;
                if (portCnt > 0)
                {
                    latticeA = WgPortInfoList[0].LatticeA;
                    periodicDistance = WgPortInfoList[0].PeriodicDistance;
                }
                // 波数
                double k0 = 0;
                if (isPCWaveguide)
                {
                    k0 = normalizedFreq * 2.0 * pi / latticeA;
                    System.Diagnostics.Debug.WriteLine("a/λ:{0}", normalizedFreq);
                }
                else
                {
                    k0 = normalizedFreq * pi / WaveguideWidth;
                    System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq);
                }
                // 波長
                double waveLength = 2.0 * pi / k0;

                //------------------------------------------------------------------
                // リニアシステム
                //------------------------------------------------------------------
                Ls.Clear();
                Prec.Clear();
                WgUtil.GC_Collect();

                //------------------------------------------------------------------
                // 界パターン追加
                //------------------------------------------------------------------
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);
                // 領域全体の界パターンを追加
                Ls.AddPattern_Field(FieldValId, World);

                // 上記界パターンでは、隣接する要素以外の剛性行列の値は追加できないようです。境界用に追加パターンを作成
                foreach (WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo in WgPortInfoList)
                {
                    WgUtil.MakeWaveguidePortBCPattern(Ls, World, workWgPortInfo.FieldPortBcId);
                }

                //------------------------------------------------------------------
                // 固定境界条件を設定
                //------------------------------------------------------------------
                if (FieldForceBcId != 0)
                {
                    Ls.SetFixedBoundaryCondition_Field(FieldForceBcId, 0, World); // 固定境界条件を設定
                }
                uint[] fixedBcNodes = null;
                // 強制境界条件を課す節点を取得する
                // 境界の固有モード解析で強制境界を指定する際に使用する(CZLinearSystemのBCFlagを参照できないので)
                Dictionary<uint, uint> tmp_to_no_boundary = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out fixedBcNodes, out tmp_to_no_boundary);
                }

                //------------------------------------------------------------------
                // 剛性行列、残差ベクトルのマージ
                //------------------------------------------------------------------
                Ls.InitializeMarge();

                IList<double[,]> ryy_1d_port_list = new List<double[,]>();
                IList<Complex[]> eigen_values_port_list = new List<Complex[]>();
                IList<Complex[,]> eigen_vecs_port_list = new List<Complex[,]>();
                IList<Complex[,]> eigen_dFdXs_port_list = new List<Complex[,]>();

                // 境界の界に導波路開口条件を追加
                bool retAddPort = false;

                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    WgUtilForPeriodicEigenExt.WgPortInfo workWgPortInfo = WgPortInfoList[portIndex];

                    if (!IsInoutWgSame || (IsInoutWgSame && portIndex == 0))
                    {
                        // 導波路開口1
                        double[,] ryy_1d_port1 = null;
                        Complex[] eigen_values_port1 = null;
                        Complex[,] eigen_vecs_port1 = null;
                        Complex[,] eigen_dFdXs_port1 = null;
                        bool isModeTrace = workWgPortInfo.IsModeTrace;
                        if (!workWgPortInfo.IsPCWaveguide)
                        {
                            isModeTrace = false;
                        }
                        retAddPort = WgUtilForPeriodicEigenExt.GetPortPeriodicWaveguideFemMatAndEigenVec(
                            Ls,
                            waveLength,
                            WaveModeDv,
                            World,
                            workWgPortInfo.FieldInputWgLoopId,
                            workWgPortInfo.FieldPortBcId,
                            workWgPortInfo.FieldInputWgBcId,
                            fixedBcNodes,
                            workWgPortInfo.IsPCWaveguide,
                            workWgPortInfo.LatticeA,
                            workWgPortInfo.PeriodicDistance,
                            workWgPortInfo.PCWaveguidePorts,
                            workWgPortInfo.IncidentModeIndex,
                            workWgPortInfo.IsSolveEigenItr,
                            workWgPortInfo.PropModeCntToSolve,
                            workWgPortInfo.IsSVEA,
                            isModeTrace,
                            ref workWgPortInfo.PrevModalVecList,
                            workWgPortInfo.MinEffN,
                            workWgPortInfo.MaxEffN,
                            workWgPortInfo.MinWaveNum,
                            workWgPortInfo.MaxWaveNum,
                            Medias,
                            workWgPortInfo.InputWgLoopDic,
                            workWgPortInfo.InputWgEdgeDic,
                            (portIndex == 0) ? true : false, // isPortBc2Reverse : 周期構造導波路の外部境界と内部境界の辺の方向が逆かどうかを指定する。
                                                             //                    図面の作成手順より、ポート1の場合true ポート2の場合false
                            out ryy_1d_port1,
                            out eigen_values_port1,
                            out eigen_vecs_port1,
                            out eigen_dFdXs_port1);
                        /*
                        // DEBUG モード確認
                        {
                            //暫定描画処理
                            DrawerAry.Clear();
                            DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                            DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                            // カメラの変換行列初期化
                            DrawerAry.InitTrans(Camera);
                            return true;
                        }
                         */
                        // 格納する
                        ryy_1d_port_list.Add(ryy_1d_port1);
                        eigen_values_port_list.Add(eigen_values_port1);
                        eigen_vecs_port_list.Add(eigen_vecs_port1);
                        eigen_dFdXs_port_list.Add(eigen_dFdXs_port1);

                        // 入射モードチェック
                        if (retAddPort)
                        {
                            if ((workWgPortInfo.IncidentModeIndex >= eigen_values_port_list[portIndex].Length)
                                || (Math.Abs(eigen_values_port_list[portIndex][workWgPortInfo.IncidentModeIndex].Real) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 入射モードが伝搬モードでない
                                )
                            {
                                retAddPort = false;
                            }
                        }
                    }
                    else if (IsInoutWgSame && portIndex != 0)
                    {
                        double[,] ryy_1d_port2 = null;
                        Complex[] eigen_values_port2 = null;
                        Complex[,] eigen_vecs_port2 = null;
                        Complex[,] eigen_dFdXs_port2 = null;

                        //  出力側は入力側と同じ導波路とする
                        double[,] ryy_1d_port1 = ryy_1d_port_list[0];
                        Complex[] eigen_values_port1 = eigen_values_port_list[0];
                        Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[0];
                        Complex[,] eigen_dFdXs_port1 = eigen_dFdXs_port_list[0];
                        ryy_1d_port2 = new double[ryy_1d_port1.GetLength(0), ryy_1d_port1.GetLength(1)];
                        for (int i = 0; i < ryy_1d_port2.GetLength(0); i++)
                        {
                            // 位置を反転
                            for (int j = 0; j < ryy_1d_port2.GetLength(1); j++)
                            {
                                double value = ryy_1d_port1[ryy_1d_port2.GetLength(0) - 1 - i, ryy_1d_port2.GetLength(1) - 1 - j];
                                ryy_1d_port2[i, j] = value;
                            }
                        }
                        eigen_values_port2 = new Complex[eigen_values_port1.Length];
                        eigen_vecs_port2 = new Complex[eigen_vecs_port1.GetLength(0), eigen_vecs_port1.GetLength(1)];
                        eigen_dFdXs_port2 = new Complex[eigen_dFdXs_port1.GetLength(0), eigen_dFdXs_port1.GetLength(1)];
                        for (int i = 0; i < eigen_vecs_port2.GetLength(0); i++)
                        {
                            Complex betam = eigen_values_port1[i];
                            eigen_values_port2[i] = betam;
                            // 位置を反転
                            for (int j = 0; j < eigen_vecs_port2.GetLength(1); j++)
                            {
                                eigen_vecs_port2[i, j] = eigen_vecs_port1[i, eigen_vecs_port2.GetLength(1) - 1 - j];
                                eigen_dFdXs_port2[i, j] = eigen_dFdXs_port1[i, eigen_dFdXs_port2.GetLength(1) - 1 - j];
                            }
                        }

                        // 格納する
                        ryy_1d_port_list.Add(ryy_1d_port2);
                        eigen_values_port_list.Add(eigen_values_port2);
                        eigen_vecs_port_list.Add(eigen_vecs_port2);
                        eigen_dFdXs_port_list.Add(eigen_dFdXs_port2);
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                        retAddPort = false;
                    }
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                                int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                                if (isShowTotalPortPower)
                                {
                                    propModeCnt = 1;
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        {
                            DrawerAry.Clear();
                            Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                            DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                            DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                            // カメラの変換行列初期化
                            DrawerAry.InitTrans(Camera);
                            // 表示位置調整
                            setupPanAndScale(probNo, Camera);
                        }
                        return false;
                    }

                    // 入射振幅を指定する(全モード入射)
                    Complex[] work_amps = null;
                    if (probNo == 13)
                    {
                        if (workWgPortInfo.IsIncidentPort)
                        {
                            /*
                            work_amps = Problem13_2.GetIncidentAmplitude(
                                World,
                                workWgPortInfo.FieldPortBcId,
                                workWgPortInfo.PCWaveguidePorts,
                                eigen_values_port_list[portIndex],
                                eigen_vecs_port_list[portIndex]);
                             */
                            /*
                            work_amps = Problem13_3.GetIncidentAmplitude(
                                World,
                                workWgPortInfo.FieldPortBcId,
                                workWgPortInfo.PCWaveguidePorts,
                                eigen_values_port_list[portIndex],
                                eigen_vecs_port_list[portIndex]);
                             */
                        }
                    }
                    workWgPortInfo.Amps = work_amps;

                    retAddPort = WgUtilForPeriodicEigenExt.AddLinSys_PeriodicWaveguidePortBC(
                        Ls,
                        waveLength,
                        WaveModeDv,
                        workWgPortInfo.PeriodicDistance,
                        World,
                        workWgPortInfo.FieldInputWgLoopId,
                        workWgPortInfo.FieldPortBcId,
                        fixedBcNodes,
                        workWgPortInfo.IsIncidentPort, // isInputPort : true
                        workWgPortInfo.IncidentModeIndex,
                        workWgPortInfo.Amps,
                        false, // isFreeBc: false:モード展開  true:PMLを装荷する場合、Sommerfeld境界条件を適用する場合
                        ryy_1d_port_list[portIndex],
                        eigen_values_port_list[portIndex],
                        eigen_vecs_port_list[portIndex],
                        eigen_dFdXs_port_list[portIndex]);
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                                int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                                if (isShowTotalPortPower)
                                {
                                    propModeCnt = 1;
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        return false;
                    }
                    System.Diagnostics.Debug.WriteLine("port{0} node_cnt: {1}", (portIndex + 1), eigen_vecs_port_list[portIndex].GetLength(1));
                }
                /*
                // TEST Sommerfelt
                CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(Ls, waveLength, World, FieldPortBcId1);
                CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(Ls, waveLength, World, FieldPortBcId2);
                 */
                /*
                //  散乱係数計算用に1のモード分布をセット
                ryy_1d_port2 = ryy_1d_port1;
                eigen_values_port2 = eigen_values_port1;
                eigen_vecs_port2 = eigen_vecs_port1;
                eigen_dFdXs_port2 = eigen_dFdXs_port1;
                */

                // 領域
                WgUtil.AddLinSysHelmholtz(Ls, waveLength, World, FieldLoopId
                    , Medias, LoopDic);

                double res = Ls.FinalizeMarge();
                //System.Diagnostics.Debug.WriteLine("Residual : " + res);

                //------------------------------------------------------------------
                // プリコンディショナ―
                //------------------------------------------------------------------
                // set Preconditioner
                //Prec.SetFillInLevel(1);
                //Prec.SetFillInLevel(int.MaxValue);  // 対称でなくても解けてしまう
                // ILU(0)のパターン初期化
                //Prec.SetLinearSystem(Ls);

                //------------------------------------------------------------------
                // リニアシステムを解く
                //------------------------------------------------------------------
                // メモリを解放する
                WgUtil.GC_Collect();
                /*
                // プリコンディショナに値を設定してILU分解を行う
                Prec.SetValue(Ls);
                double tol = 1.0e-6;
                uint maxIter = 2000;
                uint iter = maxIter;
                CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
                if (iter == maxIter)
                {
                    Console.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                    System.Diagnostics.Debug.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                }
                //System.Diagnostics.Debug.WriteLine("Solved!");

                // 計算結果をワールド座標系に反映する
                Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                 */

                //// 非対称複素行列の連立方程式をclapackで解く
                //solveAsymmetricCompplexMatEqn(Ls, World, FieldValId);

                // 非対称複素帯行列の連立方程式をclapackで解く
                solveAsymmetricComplexBandMatEqn(Ls, World, FieldValId);

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 反射、透過係数
                double totalPower = 0.0;
                int incidentPortNo = getIncidentPortNo(WgPortInfoList);
                IList<Complex[]> portScatterVecList = new List<Complex[]>();
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    Complex[] eigen_values_port1 = eigen_values_port_list[portIndex];
                    double[,] ryy_1d_port1 = ryy_1d_port_list[portIndex];
                    Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[portIndex];
                    Complex[,] eigen_dFdXs_port1 = eigen_dFdXs_port_list[portIndex];
                    WgUtilForPeriodicEigenExt.WgPortInfo wgPortInfo1 = WgPortInfoList[portIndex];
                    int propModeCntToShow = wgPortInfo1.PropModeCntToSolve;
                    if (isShowTotalPortPower)
                    {
                        propModeCntToShow = 1;
                    }
                    Complex[] scatterVec = new Complex[propModeCntToShow];
                    for (int m = 0; m < propModeCntToShow; m++)
                    {
                        scatterVec[m] = 0.0;
                    }

                    for (uint imode = 0; imode < eigen_values_port1.Length; imode++)
                    {
                        if (Math.Abs(eigen_values_port1[imode].Real) >= 1.0e-12 && Math.Abs(eigen_values_port1[imode].Imag) < 1.0e-12)
                        {
                            Complex s11 = 0.0;
                            bool isIncidentMode = (wgPortInfo1.IsIncidentPort && imode == wgPortInfo1.IncidentModeIndex);
                            if (wgPortInfo1.Amps != null)
                            {
                                // 全モード入射の時
                                isIncidentMode = wgPortInfo1.IsIncidentPort;
                            }
                            s11 = WgUtilForPeriodicEigenExt.GetPeriodicWaveguidePortReflectionCoef(
                                Ls,
                                waveLength,
                                WaveModeDv,
                                wgPortInfo1.PeriodicDistance,
                                World,
                                wgPortInfo1.FieldPortBcId,
                                imode,
                                isIncidentMode,
                                wgPortInfo1.Amps,
                                ryy_1d_port1,
                                eigen_values_port1,
                                eigen_vecs_port1,
                                eigen_dFdXs_port1);
                            System.Diagnostics.Debug.WriteLine("    s" + (portIndex + 1) + incidentPortNo + " = (" + s11.Real + "," + s11.Imag + ")" + " |s" + (portIndex + 1) + incidentPortNo + "|^2 = " + Complex.SquaredNorm(s11) + ((imode == wgPortInfo1.IncidentModeIndex) ? "  incident" : ""));
                            if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                            {
                                totalPower += Complex.SquaredNorm(s11);
                            }
                            if (isShowTotalPortPower)
                            {
                                // ポート電力を計算
                                scatterVec[0] += Complex.Norm(s11) * Complex.Norm(s11);
                            }
                            else
                            {
                                if (imode < propModeCntToShow)
                                {
                                    scatterVec[imode] = s11;
                                }
                            }
                        }
                    }
                    portScatterVecList.Add(scatterVec);
                }
                System.Diagnostics.Debug.WriteLine("    totalPower = {0}", totalPower);
                if (isShowTotalPortPower)
                {
                    for (int p = 0; p < portCnt; p++)
                    {
                        // ルート電力に変換
                        Complex[] scatterVec = portScatterVecList[p];
                        double sqrtPower = Math.Sqrt(Complex.Norm(scatterVec[0]));
                        scatterVec[0] = sqrtPower;
                        //portScatterVecList[p] = scatterVec;
                        System.Diagnostics.Debug.WriteLine("port total sqrt power s{0}{1} : {2}", (p + 1), incidentPortNo, sqrtPower);
                    }
                }

                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    ScatterVecList.Add(portScatterVecList);
                }

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                    for (int p = 0; p < portCnt; p++)
                    {
                        WgUtilForPeriodicEigenExt.WgPortInfo tmpWgPortInfo = WgPortInfoList[p];
                        int propModeCnt = tmpWgPortInfo.PropModeCntToSolve;
                        if (isShowTotalPortPower)
                        {
                            propModeCnt = 1;
                        }
                        Complex[] work_scatterVec = new Complex[propModeCnt];
                        for (int imode = 0; imode < propModeCnt; imode++)
                        {
                            work_scatterVec[imode] = 0;
                        }
                        work_portScatterVecList.Add(work_scatterVec);
                    }
                    ScatterVecList.Add(work_portScatterVecList);
                }
                {
                    DrawerAry.Clear();
                    Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);
                    DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                    DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);
                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
            }
            return success;
        }
示例#2
0
        /// <summary>
        /// 問題を解く
        /// </summary>
        /// <param name="probNo">問題番号</param>
        /// <param name="freqIndex">周波数のインデックス</param>
        /// <param name="NormalizedFreq1">開始規格化周波数</param>
        /// <param name="NormalizedFreq2">終了規格化周波数</param>
        /// <param name="FreqDelta">計算刻み幅</param>
        /// <param name="initFlg">カメラ初期化フラグ</param>
        /// <param name="WaveguideWidth">導波路幅</param>
        /// <param name="WaveModeDv">波のモード区分</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldValId">値のフィールドID</param>
        /// <param name="FieldLoopId">ループのフィールドID</param>
        /// <param name="FieldForceBcId">強制境界のフィールドID</param>
        /// <param name="FieldPortBcId1">ポート1境界のフィールドID</param>
        /// <param name="FieldPortBcId2">ポート2境界のフィールドID</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">ループID→ループ情報マップ</param>
        /// <param name="EdgeDic">エッジID→エッジ情報マップ</param>
        /// <param name="IsShowAbsField">絶対値表示する?</param>
        /// <param name="Ls">リニアシステム</param>
        /// <param name="Prec">プリコンディショナ―</param>
        /// <param name="ScatterVecList">散乱係数リスト(ポート毎のモード散乱係数リストのリスト)</param>
        /// <param name="DrawerAry">描画オブジェクトアレイ</param>
        /// <param name="Camera">カメラ</param>
        /// <returns></returns>
        private static bool solveProblem(
            int probNo,
            ref int freqIndex,
            double NormalizedFreq1,
            double NormalizedFreq2,
            double FreqDelta,
            bool initFlg,
            double WaveguideWidth,
            WgUtil.WaveModeDV WaveModeDv,
            ref CFieldWorld World,
            uint FieldValId,
            uint FieldLoopId,
            uint FieldForceBcId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            IList<MediaInfo> Medias,
            Dictionary<uint, World.Loop> LoopDic,
            Dictionary<uint, World.Edge> EdgeDic,
            bool IsShowAbsField,
            ref CZLinearSystem Ls,
            ref CZPreconditioner_ILU Prec,
            ref IList<IList<Complex[]>> ScatterVecList,
            ref CDrawerArrayField DrawerAry,
            CCamera Camera)
        {
            //long memorySize1 = GC.GetTotalMemory(false);
            //Console.WriteLine("    total memory: {0}", memorySize1);

            bool success = false;
            // 入射モードインデックス
            int incidentModeIndex = 0;
            // ポート数
            int portCnt = 2;
            int incidentPortNo = getIncidentPortNo();
            int propModeCnt_port1 = 1;
            int propModeCnt_port2 = 1;
            // モード電力の合計を出力として表示する
            bool isShowTotalPortPower = false;
            if (probNo == 3)
            {
                /*
                // 入力5モード表示
                //propModeCnt_port1 = 5;
                //propModeCnt_port2 = 1;
                // 出力5モード表示
                //propModeCnt_port1 = 1;
                //propModeCnt_port2 = 5;
                propModeCnt_port1 = 3;
                propModeCnt_port2 = 3;
                 */
                //isShowTotalPortPower = true; // モード電力の合計を出力として表示する
            }
            try
            {

                // 規格化周波数
                double normalizedFreq = getNormalizedFreq(
                    ref freqIndex,
                    NormalizedFreq1,
                    NormalizedFreq2,
                    FreqDelta);
                if (freqIndex == -1)
                {
                    return success;
                }
                // 波数
                double k0 = normalizedFreq * pi / WaveguideWidth;
                // 波長
                double waveLength = 2.0 * pi / k0;
                System.Diagnostics.Debug.WriteLine("2W/λ:{0}", normalizedFreq);

                //------------------------------------------------------------------
                // リニアシステム
                //------------------------------------------------------------------
                Ls.Clear();
                Prec.Clear();
                WgUtil.GC_Collect();

                //------------------------------------------------------------------
                // 界パターン追加
                //------------------------------------------------------------------
                // ワールド座標系のフィールド値をクリア
                WgUtil.ClearFieldValues(World, FieldValId);
                // 領域全体の界パターンを追加
                Ls.AddPattern_Field(FieldValId, World);

                // 上記界パターンでは、隣接する要素以外の剛性行列の値は追加できないようです。境界用に追加パターンを作成
                uint[] fieldPortBcId_list = {FieldPortBcId1, FieldPortBcId2};
                System.Diagnostics.Debug.Assert(fieldPortBcId_list.Length == portCnt);
                foreach (uint workFieldPortBcId in fieldPortBcId_list)
                {
                    WgUtil.MakeWaveguidePortBCPattern(Ls, World, workFieldPortBcId);
                }

                //------------------------------------------------------------------
                // 固定境界条件を設定
                //------------------------------------------------------------------
                if (FieldForceBcId != 0)
                {
                    Ls.SetFixedBoundaryCondition_Field(FieldForceBcId, 0, World); // 固定境界条件を設定
                }
                uint[] fixedBcNodes = null;
                // 強制境界条件を課す節点を取得する
                // 境界の固有モード解析で強制境界を指定する際に使用する(CZLinearSystemのBCFlagを参照できないので)
                Dictionary<uint, uint> tmp_to_no_boundary = null;
                if (FieldForceBcId != 0)
                {
                    WgUtil.GetBoundaryNodeList(World, FieldForceBcId, out fixedBcNodes, out tmp_to_no_boundary);
                }
                //------------------------------------------------------------------
                // プリコンディショナ―
                //------------------------------------------------------------------
                // set Preconditioner
                //Prec.SetFillInLevel(1);
                uint fillInLevel = 1;
                if (probNo == 3)
                {
                    // 誘電体スラブ導波路ではILU(1)では収束しないので、フィルインレベルを大きくとる
                    fillInLevel = 15;
                }
                System.Diagnostics.Debug.WriteLine("fillInLevel: {0}", fillInLevel);
                Prec.SetFillInLevel(fillInLevel);

                // ILU(0)のパターン初期化
                Prec.SetLinearSystem(Ls);

                //------------------------------------------------------------------
                // 剛性行列、残差ベクトルのマージ
                //------------------------------------------------------------------
                Ls.InitializeMarge();

                IList<double[,]> ryy_1d_port_list = new List<double[,]>();
                IList<Complex[]> eigen_values_port_list = new List<Complex[]>();
                IList<Complex[,]> eigen_vecs_port_list = new List<Complex[,]>();
                System.Diagnostics.Debug.Assert(incidentPortNo == 1);

                // 境界の界に導波路開口条件を追加
                bool retAddPort = false;

                // 境界の界に導波路開口条件を追加
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    uint workFieldPortBcId = fieldPortBcId_list[portIndex];
                    double[,] ryy_1d_port1 = null;
                    Complex[] eigen_values_port1 = null;
                    Complex[,] eigen_vecs_port1 = null;
                    retAddPort = WgUtil.AddLinSys_WaveguidePortBC(
                        Ls,
                        waveLength,
                        WaveModeDv,
                        World,
                        workFieldPortBcId,
                        fixedBcNodes,
                        (portIndex == (incidentPortNo - 1)),
                        incidentModeIndex,
                        Medias,
                        EdgeDic,
                        out ryy_1d_port1,
                        out eigen_values_port1,
                        out eigen_vecs_port1);
                    // 格納する
                    ryy_1d_port_list.Add(ryy_1d_port1);
                    eigen_values_port_list.Add(eigen_values_port1);
                    eigen_vecs_port_list.Add(eigen_vecs_port1);
                    if (!retAddPort)
                    {
                        System.Diagnostics.Debug.WriteLine("failed addPort (port{0})", (portIndex + 1));
                        // 表示用にデータを格納する
                        if (freqIndex == 0)
                        {
                            ScatterVecList.Clear();
                        }
                        {
                            IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                            for (int p = 0; p < portCnt; p++)
                            {
                                int propModeCnt = 0;
                                if (p == 0)
                                {
                                    propModeCnt = propModeCnt_port1;
                                }
                                else if (p == 1)
                                {
                                    propModeCnt = propModeCnt_port2;
                                }
                                else
                                {
                                    System.Diagnostics.Debug.Assert(false);
                                }
                                Complex[] work_scatterVec = new Complex[propModeCnt];
                                for (int imode = 0; imode < propModeCnt; imode++)
                                {
                                    work_scatterVec[imode] = 0;
                                }
                                work_portScatterVecList.Add(work_scatterVec);
                            }
                            ScatterVecList.Add(work_portScatterVecList);
                        }
                        return false;
                    }
                    System.Diagnostics.Debug.WriteLine("port{0} node_cnt: {1}", (portIndex + 1), eigen_vecs_port_list[portIndex].GetLength(1));
                }

                // 領域
                WgUtil.AddLinSysHelmholtz(Ls, waveLength, World, FieldLoopId, Medias, LoopDic);

                double res = Ls.FinalizeMarge();
                //System.Diagnostics.Debug.WriteLine("Residual : " + res);

                //------------------------------------------------------------------
                // リニアシステムを解く
                //------------------------------------------------------------------
                // プリコンディショナに値を設定してILU分解を行う
                Prec.SetValue(Ls);
                double tol = 1.0e-6;
                uint maxIter = 2000;
                uint iter = maxIter;
                CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
                if (iter == maxIter)
                {
                    Console.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                    System.Diagnostics.Debug.WriteLine("Not converged at 2W/λ = {0}", normalizedFreq);
                }
                //System.Diagnostics.Debug.WriteLine("Solved!");

                // 計算結果をワールド座標系に反映する
                Ls.UpdateValueOfField(FieldValId, World, FIELD_DERIVATION_TYPE.VALUE);

                //------------------------------------------------------------------
                // 計算結果の後処理
                //------------------------------------------------------------------
                // 反射、透過係数
                double totalPower = 0.0;
                IList<Complex[]> portScatterVecList = new List<Complex[]>();
                for (int portIndex = 0; portIndex < portCnt; portIndex++)
                {
                    Complex[] eigen_values_port1 = eigen_values_port_list[portIndex];
                    double[,] ryy_1d_port1 = ryy_1d_port_list[portIndex];
                    Complex[,] eigen_vecs_port1 = eigen_vecs_port_list[portIndex];
                    int propModeCnt = 0;
                    if (portIndex == 0)
                    {
                        propModeCnt = propModeCnt_port1;
                    }
                    else if (portIndex == 1)
                    {
                        propModeCnt = propModeCnt_port2;
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(false);
                    }
                    Complex[] scatterVec = new Complex[propModeCnt];
                    for (int m = 0; m < propModeCnt; m++)
                    {
                        scatterVec[m] = 0.0;
                    }

                    uint workFieldPortBcId = fieldPortBcId_list[portIndex];
                    for (uint imode = 0; imode < eigen_values_port1.Length; imode++)
                    {
                        Complex s11 = WgUtil.GetWaveguidePortReflectionCoef(
                            Ls,
                            waveLength,
                            WaveModeDv,
                            World,
                            workFieldPortBcId,
                            imode,
                            ((portIndex == (incidentPortNo - 1)) && imode == incidentModeIndex),
                            ryy_1d_port1,
                            eigen_values_port1,
                            eigen_vecs_port1);
                        if (imode < propModeCnt || Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                        {
                            System.Diagnostics.Debug.WriteLine("    s" + (portIndex + 1) + incidentPortNo + " = (" + s11.Real + "," + s11.Imag + ")" + " |s" + (portIndex + 1) + incidentPortNo + "|^2 = " + Complex.SquaredNorm(s11) + ((imode == 0) ? "  incident" : ""));
                        }
                        if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                            && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                        {
                            totalPower += Complex.SquaredNorm(s11);
                        }
                        if (isShowTotalPortPower)
                        {
                            if (Math.Abs(eigen_values_port1[imode].Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit
                                && Math.Abs(eigen_values_port1[imode].Imag) < MyUtilLib.Matrix.Constants.PrecisionLowerLimit) // 伝搬モード
                            {
                                // ポート電力を計算
                                scatterVec[0] += Complex.Norm(s11) * Complex.Norm(s11);
                            }
                        }
                        else
                        {
                            if (imode < propModeCnt)
                            {
                                scatterVec[imode] = s11;
                            }
                        }
                    }
                    portScatterVecList.Add(scatterVec);
                }
                System.Diagnostics.Debug.WriteLine("    totalPower = {0}", totalPower);
                if (isShowTotalPortPower)
                {
                    for (int p = 0; p < portCnt; p++)
                    {
                        // ルート電力に変換
                        Complex[] scatterVec = portScatterVecList[p];
                        double sqrtPower = Math.Sqrt(Complex.Norm(scatterVec[0]));
                        scatterVec[0] = sqrtPower;
                        //portScatterVecList[p] = scatterVec;
                        System.Diagnostics.Debug.WriteLine("port total sqrt power s{0}{1} : {2}", (p + 1), incidentPortNo, sqrtPower);
                    }
                }

                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    ScatterVecList.Add(portScatterVecList);
                }

                // 描画する界の値を加工して置き換える
                //    そのまま描画オブジェクトにフィールドを渡すと、複素数で格納されているフィールド値の実数部が表示されます。
                //    絶対値を表示したかったので、下記処理を追加しています。
                if (IsShowAbsField)
                {
                    WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                }
                // DEBUG
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId); // 絶対値表示
                //WgUtil.ReplaceFieldValueForDisplay(World, FieldValId, 1); // 虚数部表示

                //------------------------------------------------------------------
                // 描画する界の追加
                //------------------------------------------------------------------
                DrawerAry.Clear();
                DrawerAry.PushBack(new CDrawerFace(FieldValId, true, World, FieldValId));
                DrawerAry.PushBack(new CDrawerEdge(FieldValId, true, World));
                if (initFlg)
                {
                    // カメラの変換行列初期化
                    DrawerAry.InitTrans(Camera);

                    // 表示位置調整
                    setupPanAndScale(probNo, Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
                System.Diagnostics.Debug.WriteLine(exception.Message + " " + exception.StackTrace);
                // 表示用にデータを格納する
                if (freqIndex == 0)
                {
                    ScatterVecList.Clear();
                }
                {
                    IList<Complex[]> work_portScatterVecList = new List<Complex[]>();
                    for (int p = 0; p < portCnt; p++)
                    {
                        int propModeCnt = 0;
                        if (p == 0)
                        {
                            propModeCnt = propModeCnt_port1;
                        }
                        else if (p == 1)
                        {
                            propModeCnt = propModeCnt_port2;
                        }
                        else
                        {
                            System.Diagnostics.Debug.Assert(false);
                        }
                        Complex[] work_scatterVec = new Complex[propModeCnt];
                        for (int imode = 0; imode < propModeCnt; imode++)
                        {
                            work_scatterVec[imode] = 0;
                        }
                        work_portScatterVecList.Add(work_scatterVec);
                    }
                    ScatterVecList.Add(work_portScatterVecList);
                }
            }
            return success;
        }