コード例 #1
0
 /// <summary>
 /// ヘルムホルツの方程式 剛性行列 残差ベクトルの追加
 /// </summary>
 /// <param name="ls"></param>
 /// <param name="waveLength"></param>
 /// <param name="world"></param>
 /// <param name="fieldValId"></param>
 /// <returns></returns>
 public static bool AddLinSysHelmholtz(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId)
 {
     if (!world.IsIdField(fieldValId))
     {
         return false;
     }
     CField valField = world.GetField(fieldValId);
     if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR)
     {
         return false;
     }
     IList<uint> aIdEA = valField.GetAryIdEA();
     foreach (uint eaId in aIdEA)
     {
         if (valField.GetInterpolationType(eaId, world) == INTERPOLATION_TYPE.TRI11)
         {
             uint ntmp = ls.GetTmpBufferSize();
             int[] tmpBuffer = new int[ntmp];
             for (int i = 0; i < ntmp; i++)
             {
                 tmpBuffer[i] = -1;
             }
             bool res = AddLinSysHelmholtz_EachElementAry(ls, waveLength, world, fieldValId, eaId, tmpBuffer);
             if (!res)
             {
                 return false;
             }
         }
     }
     return true;
 }
コード例 #2
0
        /// <summary>
        /// リニアシステム初期化(マージ開始までの処理)
        /// </summary>
        /// <param name="matPattern">行列の非0要素パターン</param>
        /// <param name="Ls"></param>
        /// <param name="Prec"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        public static void SetupLinearSystem(
            bool[,] matPattern,
            out CFieldWorld World, out uint FieldValId,
            out CZLinearSystem Ls, out CZPreconditioner_ILU Prec, out int[] tmpBuffer)
        {
            World = new CFieldWorld();
            Ls = new CZLinearSystem();
            Prec = new CZPreconditioner_ILU();
            tmpBuffer = null;

            int matLen = matPattern.GetLength(0);

            //------------------------------------------------------------------
            // ワールド座標系を生成
            //------------------------------------------------------------------
            uint baseId = 0;
            setupWorld((uint)matLen, ref World, out baseId);

            // 界の値を扱うバッファ?を生成する。
            // フィールド値IDが返却される。
            //    要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点
            FieldValId = World.MakeField_FieldElemDim(baseId, 0,
                FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER);

            //------------------------------------------------------------------
            // 界パターン追加
            //------------------------------------------------------------------
            Ls.AddPattern_Field(FieldValId, World);
            //  POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない

            // 非対角要素のパターンの追加
            {
                uint node_cnt = (uint)matLen;
                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                // パターンを追加
                using (CIndexedArray crs = new CIndexedArray())
                {
                    crs.InitializeSize(mat_cc.NBlkMatCol());

                    //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow());
                    using (UIntVectorIndexer index = crs.index)
                    using (UIntVectorIndexer ary = crs.array)
                    {
                        //BUGFIX
                        //for (int iblk = 0; iblk < (int)crs.Size(); iblk++)
                        // indexのサイズは crs.Size() + 1 (crs.Size() > 0のとき)
                        for (int iblk = 0; iblk < index.Count; iblk++)
                        {
                            index[iblk] = 0;
                        }
                        for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                        {
                            // 現在のマトリクスのインデックス設定をコピーする
                            uint npsup = 0;
                            ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                            foreach (uint row_index in cur_rows)
                            {
                                ary.Add(row_index);
                            }
                            index[iblk + 1] = (uint)ary.Count;
                            //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup);
                            // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0)

                            // すべての節点に関して列を追加
                            int ino_global = iblk;
                            int col = iblk;
                            if (col != -1 && ino_global != -1)
                            {
                                // 関連付けられていない節点をその行の列データの最後に追加
                                //int last_index = (int)index[col + 1] - 1;
                                //System.Diagnostics.Debug.Assert(last_index == ary.Count - 1);
                                int add_cnt = 0;
                                for (int jno_global = 0; jno_global < node_cnt; jno_global++)
                                {
                                    if (!matPattern[ino_global, jno_global])
                                    {
                                        continue;
                                    }
                                    uint row = (uint)jno_global;
                                    //if (ino_global != jno_global)  // 対角要素は除く
                                    if (col != row)  // 対角要素は除く
                                    {
                                        if (!cur_rows.Contains(row))
                                        {
                                            //ary.Insert(last_index + 1 + add_cnt, row);
                                            ary.Add(row);
                                            add_cnt++;
                                            //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row);
                                        }
                                    }
                                }
                                if (add_cnt > 0)
                                {
                                    index[col + 1] = (uint)ary.Count;
                                }
                            }
                        }
                    }
                    crs.Sort();
                    System.Diagnostics.Debug.Assert(crs.CheckValid());
                    // パターンを削除する
                    mat_cc.DeletePattern();
                    // パターンを追加する
                    mat_cc.AddPattern(crs);
                }
            }

            //------------------------------------------------------------------
            // プリコンディショナ―
            //------------------------------------------------------------------
            // set Preconditioner
            //Prec.SetFillInLevel(1);
            // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した
            //Prec.SetFillInLevel(0);
            // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする
            //Prec.SetFillInLevel((uint)mat.RowSize);
            //   完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い
            //Prec.SetFillInLevel(3);
            //   誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある
            //以上から
            //メインの導波管の計算時間を短くしたいのでフィルインなしにする
            //Prec.SetFillInLevel(0);
            //    導波管だとこれで十分
            // フィルインレベルの設定(既定値)
            Prec.SetFillInLevel(DefFillInLevel);
            // ILU(0)のパターン初期化
            Prec.SetLinearSystem(Ls);

            //------------------------------------------------------------------
            // 剛性行列、残差ベクトルのマージ開始
            //------------------------------------------------------------------
            Ls.InitializeMarge();
            uint ntmp = Ls.GetTmpBufferSize();
            tmpBuffer = new int[ntmp];
            for (int i = 0; i < ntmp; i++)
            {
                tmpBuffer[i] = -1;
            }
        }
コード例 #3
0
        ////////////////////////////////////////////////////////////////////////////////////////////////
        // DekFEMの処理を隠ぺいした簡易版
        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// PCOCGで線形方程式を解く
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged)
        public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            int matLen = mat.RowSize;

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 1");
            //------------------------------------------------------------------
            // ワールド座標系を生成
            //------------------------------------------------------------------
            uint baseId = 0;
            CFieldWorld World = new CFieldWorld();
            setupWorld((uint)matLen, ref World, out baseId);

            // 界の値を扱うバッファ?を生成する。
            // フィールド値IDが返却される。
            //    要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点
            uint FieldValId = World.MakeField_FieldElemDim(baseId, 0,
                FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER);

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 2");
            //------------------------------------------------------------------
            // リニアシステム
            //------------------------------------------------------------------
            CZLinearSystem Ls = new CZLinearSystem();
            CZPreconditioner_ILU Prec = new CZPreconditioner_ILU();

            //------------------------------------------------------------------
            // 界パターン追加
            //------------------------------------------------------------------
            Ls.AddPattern_Field(FieldValId, World);
            //  POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない

            // 非対角要素のパターンの追加
            {
                uint node_cnt = (uint)matLen;
                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                // パターンを追加
                using (CIndexedArray crs = new CIndexedArray())
                {
                    crs.InitializeSize(mat_cc.NBlkMatCol());

                    //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow());
                    using (UIntVectorIndexer index = crs.index)
                    using (UIntVectorIndexer ary = crs.array)
                    {
                        for (int iblk = 0; iblk < (int)crs.Size(); iblk++)
                        {
                            index[iblk] = 0;
                        }
                        for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                        {
                            // 現在のマトリクスのインデックス設定をコピーする
                            uint npsup = 0;
                            ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                            foreach (uint row_index in cur_rows)
                            {
                                ary.Add(row_index);
                            }
                            index[iblk + 1] = (uint)ary.Count;
                            //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup);
                            // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0)

                            // すべての節点に関して列を追加
                            int ino_global = iblk;
                            int col = iblk;
                            if (col != -1 && ino_global != -1)
                            {
                                // 関連付けられていない節点をその行の列データの最後に追加
                                int last_index = (int)index[col + 1] - 1;
                                int add_cnt = 0;
                                for (int jno_global = 0; jno_global < node_cnt; jno_global++)
                                {
                                    // 行列の0要素を除く
                                    //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit)
                                    //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15)
                                    //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                                    KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                    if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                                    {
                                        continue;
                                    }
                                    uint row = (uint)jno_global;
                                    if (ino_global != jno_global)  // 対角要素は除く
                                    {
                                        if (!cur_rows.Contains(row))
                                        {
                                            ary.Insert(last_index + 1 + add_cnt, row);
                                            add_cnt++;
                                            //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row);
                                        }
                                    }
                                }
                                if (add_cnt > 0)
                                {
                                    index[col + 1] = (uint)ary.Count;
                                }
                            }
                        }
                    }
                    crs.Sort();
                    System.Diagnostics.Debug.Assert(crs.CheckValid());
                    // パターンを削除する
                    mat_cc.DeletePattern();
                    // パターンを追加する
                    mat_cc.AddPattern(crs);
                }
            }

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 3");
            //------------------------------------------------------------------
            // プリコンディショナ―
            //------------------------------------------------------------------
            // set Preconditioner
            //Prec.SetFillInLevel(1);
            // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した
            //Prec.SetFillInLevel(0);
            // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする
            //Prec.SetFillInLevel((uint)mat.RowSize);
            //   完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い
            //Prec.SetFillInLevel(3);
            //   誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある
            //以上から
            //メインの導波管の計算時間を短くしたいのでフィルインなしにする
            //Prec.SetFillInLevel(0);
            //    導波管だとこれで十分
            // フィルインレベルの設定(既定値)
            Prec.SetFillInLevel(DefFillInLevel);
            // ILU(0)のパターン初期化
            Prec.SetLinearSystem(Ls);
            System.Diagnostics.Debug.WriteLine("SolvePCOCG 4");

            //------------------------------------------------------------------
            // 剛性行列、残差ベクトルのマージ
            //------------------------------------------------------------------
            Ls.InitializeMarge();
            {
                uint ntmp = Ls.GetTmpBufferSize();
                int[] tmpBuffer = new int[ntmp];
                for (int i = 0; i < ntmp; i++)
                {
                    tmpBuffer[i] = -1;
                }

                uint node_cnt = (uint)matLen;

                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                bool[,] add_flg = new bool[node_cnt, node_cnt];
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        add_flg[i, j] = false;
                        // 0要素はマージ対象でないので最初から除外する
                        //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit)
                        //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                        KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize];
                        if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                        {
                            add_flg[i, j] = true;
                        }
                    }
                }
                for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                {
                    // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応)
                    uint npsup = 0;
                    ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                    uint colcnt = 1;
                    uint rowcnt = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する
                    Complex[] emattmp = new Complex[colcnt * rowcnt];
                    uint[] no_c_tmp_col = new uint[colcnt];
                    uint[] no_c_tmp_row = new uint[rowcnt];
                    no_c_tmp_col[0] = (uint)iblk;
                    no_c_tmp_row[0] = (uint)iblk;
                    for (int irow = 0; irow < cur_rows.Count; irow++)
                    {
                        no_c_tmp_row[irow + 1] = cur_rows[irow];
                    }
                    {
                        uint ino = 0;
                        uint ino_global = no_c_tmp_col[ino];
                        for (int jno = 0; jno < rowcnt; jno++)
                        {
                            uint jno_global = no_c_tmp_row[jno];
                            //emat[ino, jno]
                            if (!add_flg[ino_global, jno_global])
                            {
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global];
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize];
                                KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                emattmp[ino * rowcnt + jno] = new Complex(cvalue.Real, cvalue.Imaginary);
                                add_flg[ino_global, jno_global] = true;
                            }
                            else
                            {
                                // ここにはこない
                                System.Diagnostics.Debug.Assert(false);
                                emattmp[ino * rowcnt + jno] = new Complex(0, 0);
                            }
                        }
                    }
                    // マージ!
                    mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer);
                }
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] );
                        System.Diagnostics.Debug.Assert(add_flg[i, j]);
                    }
                }

                // 残差ベクトルにマージ
                for (uint ino_global = 0; ino_global < node_cnt; ino_global++)
                {
                    // 残差ベクトルにマージする
                    uint no_tmp = ino_global;
                    //System.Numerics.Complex cvalue = resVec[ino_global];
                    KrdLab.clapack.Complex cvalue = resVec[ino_global];
                    Complex val = new Complex(cvalue.Real, cvalue.Imaginary);
                    res_c.AddValue(no_tmp, 0, val);
                }
            }
            double res = Ls.FinalizeMarge();
            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList<uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry ea = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint ino_global = no_c[ino];
                            Complex cvalue = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Prec.Clear();
            Prec.Dispose();
            World.Clear();
            World.Dispose();
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return success;
        }
コード例 #4
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="Ls"></param>
        /// <param name="Prec"></param>
        /// <param name="tmpBuffer"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        public static bool SolvePCOCG(
            ref CFieldWorld World, ref uint FieldValId,
            ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer,
            ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            //------------------------------------------------------------------
            // マージの終了
            //------------------------------------------------------------------
            double res = Ls.FinalizeMarge();
            tmpBuffer = null;

            // マトリクスサイズの取得
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            // マトリクスのサイズ
            int matLen = (int)mat_cc.NBlkMatCol();

            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);
            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList<uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry ea = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint ino_global = no_c[ino];
                            Complex cvalue = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Ls = null;
            Prec.Clear();
            Prec.Dispose();
            Prec = null;
            World.Clear();
            World.Dispose();
            World = null;
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return success;
        }
コード例 #5
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
 /// <summary>
 /// 使用中のリソースをすべてクリーンアップします。
 /// </summary>
 /// <param name="disposing">マネージ リソースが破棄される場合 true、破棄されない場合は false です。</param>
 protected virtual void Dispose(bool disposing)
 {
     if (Disposed)
     {
         return;
     }
     Disposed = true;
     MyTimer.Enabled = false;
     if (DrawerAry != null)
     {
         DrawerAry.Clear();
         DrawerAry.Dispose();
         DrawerAry = null;
     }
     if (Camera != null)
     {
         Camera.Dispose();
         Camera = null;
     }
     if (World != null)
     {
         World.Clear();
         World.Dispose();
         World = null;
     }
     //if (FieldValueSetter != null)
     //{
     //    FieldValueSetter.Clear();
     //    FieldValueSetter.Dispose();
     //    FieldValueSetter = null;
     //}
     if (Ls != null)
     {
         Ls.Clear();
         Ls.Dispose();
         Ls = null;
     }
     if (Prec != null)
     {
         Prec.Clear();
         Prec.Dispose();
         Prec = null;
     }
     if (CadDrawerAry != null)
     {
         CadDrawerAry.Clear();
         CadDrawerAry.Dispose();
         CadDrawerAry = null;
     }
 }
コード例 #6
0
        /// <summary>
        /// 周期構造導波路の固有モード取得
        /// </summary>
        /// <param name="ls">リニアシステム</param>
        /// <param name="waveLength">波長</param>
        /// <param name="isYDirectionPeriodic">Y方向周期構造?</param>
        /// <param name="World">ワールド座標系</param>
        /// <param name="FieldLoopId">フィールド値ID(周期構造領域のループ)</param>
        /// <param name="FieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param>
        /// <param name="FieldPortBcId2">フィールド値ID(周期構造領域の境界2=内部側境界)</param>
        /// <param name="fixedBcNodes">強制境界節点配列</param>
        /// <param name="IsPCWaveguide">フォトニック結晶導波路?</param>
        /// <param name="PCWaveguidePorts">フォトニック結晶導波路のポート(ロッド欠陥部分)の節点のリスト</param>
        /// <param name="propModeCntToSolve">解く伝搬モードの数(固有値解法の選択基準に用いる)</param>
        /// <param name="max_mode">固有モードの考慮数</param>
        /// <param name="Medias">媒質リスト</param>
        /// <param name="LoopDic">周期構造領域のワールド座標系ループ→ループ情報マップ</param>
        /// <param name="EdgeDic">周期構造領域のワールド座標系辺→辺情報マップ</param>
        /// <param name="isPortBc2Reverse">境界2の方向が境界1と逆方向?</param>
        /// <param name="ryy_1d">[ryy]FEM行列</param>
        /// <param name="eigen_values">固有値配列</param>
        /// <param name="eigen_vecs_Bc1">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="eigen_dFdXs_Bc1">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param>
        /// <returns></returns>
        private static bool solvePortPeriodicWaveguideEigen(
            CZLinearSystem ls,
            double waveLength,
            WaveModeDV waveModeDv,
            bool isYDirectionPeriodic,
            double rotAngle,
            double[] rotOrigin,
            CFieldWorld World,
            uint FieldLoopId,
            uint FieldPortBcId1,
            uint FieldPortBcId2,
            uint[] fixedBcNodes,
            bool IsPCWaveguide,
            double latticeA,
            double periodicDistance,
            IList<IList<uint>> PCWaveguidePorts,
            int incidentModeIndex,
            bool isSolveEigenItr,
            int propModeCntToSolve,
            bool isSVEA,
            uint max_mode,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[][] PrevModalVecList,
            double minEffN,
            double maxEffN,
            double minWaveNum,
            double maxWaveNum,
            IList<MediaInfo> Medias,
            Dictionary<uint, wg2d.World.Loop> LoopDic,
            Dictionary<uint, wg2d.World.Edge> EdgeDic,
            bool isPortBc2Reverse,
            double[,] ryy_1d,
            out Complex[] eigen_values,
            out Complex[,] eigen_vecs_Bc1,
            out Complex[,] eigen_dFdXs_Bc1)
        {
            double k0 = 2.0 * pi / waveLength;
            double omega = k0 * c0;

            eigen_values = null;
            eigen_vecs_Bc1 = null;
            eigen_dFdXs_Bc1 = null;
            //System.Diagnostics.Debug.Assert(max_mode == 1);

            double minBeta = minEffN;
            double maxBeta = maxEffN;

            //////////////////////////////////////////////////////////////////////////////////////
            // 周期構造導波路の固有値解析

            // 全節点数を取得する
            uint node_cnt = 0;
            //node_cnt = WgUtilForPeriodicEigen.GetNodeCnt(world, fieldLoopId);
            //uint[] no_c_all = null;
            //Dictionary<uint, uint> to_no_all = new Dictionary<uint, uint>();
            //WgUtilForPeriodicEigen.GetNodeList(World, FieldLoopId, out no_c_all);
            //node_cnt = (uint)no_c_all.Length;
            //for (int i = 0; i < node_cnt; i++)
            //{
            //    uint nodeNumber = no_c_all[i];
            //    to_no_all.Add(nodeNumber, (uint)i);
            //}
            uint[] no_c_all = null;
            Dictionary<uint, uint> to_no_all = null;
            double[][] coord_c_all = null;
            WgUtil.GetLoopCoordList(World, FieldLoopId, rotAngle, rotOrigin, out no_c_all, out to_no_all, out coord_c_all);
            node_cnt = (uint)no_c_all.Length;

            System.Diagnostics.Debug.WriteLine("solvePortPeriodicWaveguideEigen node_cnt: {0}", node_cnt);

            // 境界の節点リストを取得する
            uint[] no_boundary_fieldForceBcId = null;
            Dictionary<uint, uint> to_no_boundary_fieldForceBcId = null;
            if (fixedBcNodes != null)
            {
                to_no_boundary_fieldForceBcId = new Dictionary<uint, uint>();
                IList<uint> fixedBcNodesInLoop = new List<uint>();
                foreach (uint nodeNumber in fixedBcNodes)
                {
                    if (to_no_all.ContainsKey(nodeNumber))
                    {
                        fixedBcNodesInLoop.Add(nodeNumber);
                        to_no_boundary_fieldForceBcId.Add(nodeNumber, (uint)(fixedBcNodesInLoop.Count - 1));
                    }
                }
                no_boundary_fieldForceBcId = fixedBcNodesInLoop.ToArray();
            }
            uint[] no_c_all_fieldPortBcId1 = null;
            Dictionary<uint, uint> to_no_boundary_fieldPortBcId1 = null;
            WgUtil.GetBoundaryNodeList(World, FieldPortBcId1, out no_c_all_fieldPortBcId1, out to_no_boundary_fieldPortBcId1);
            uint[] no_c_all_fieldPortBcId2 = null;
            Dictionary<uint, uint> to_no_boundary_fieldPortBcId2 = null;
            WgUtil.GetBoundaryNodeList(World, FieldPortBcId2, out no_c_all_fieldPortBcId2, out to_no_boundary_fieldPortBcId2);

            // 節点のソート
            IList<uint> sortedNodes = new List<uint>();
            Dictionary<uint, int> toSorted = new Dictionary<uint, int>();
            //   境界1と境界2は周期構造条件より同じ界の値をとる
            // ポート境界1
            for (int i = 0; i < no_c_all_fieldPortBcId1.Length; i++)
            {
                // 境界1の節点を追加
                uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[i];
                if (fixedBcNodes != null)
                {
                    // 強制境界を除く
                    if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc1)) continue;
                }
                sortedNodes.Add(nodeNumberPortBc1);
                int nodeIndex = sortedNodes.Count - 1;
                toSorted.Add(nodeNumberPortBc1, nodeIndex);
            }
            uint boundary_node_cnt = (uint)sortedNodes.Count; // 境界1
            // 内部領域
            for (int i = 0; i < node_cnt; i++)
            {
                uint nodeNumber = no_c_all[i];
                // 追加済み節点はスキップ
                //if (toSorted.ContainsKey(nodeNumber)) continue;
                // 境界1は除く
                if (to_no_boundary_fieldPortBcId1.ContainsKey(nodeNumber)) continue;
                // 境界2は除く
                if (to_no_boundary_fieldPortBcId2.ContainsKey(nodeNumber)) continue;
                if (fixedBcNodes != null)
                {
                    // 強制境界を除く
                    if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumber)) continue;
                }
                sortedNodes.Add(nodeNumber);
                toSorted.Add(nodeNumber, sortedNodes.Count - 1);
            }
            uint free_node_cnt = (uint)sortedNodes.Count;  // 境界1 + 内部領域
            for (int i = 0; i < no_c_all_fieldPortBcId2.Length; i++)
            {
                // 境界2の節点を追加
                uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[i];
                if (fixedBcNodes != null)
                {
                    // 強制境界を除く
                    if (to_no_boundary_fieldForceBcId.ContainsKey(nodeNumberPortBc2)) continue;
                }
                sortedNodes.Add(nodeNumberPortBc2);
                int nodeIndex = sortedNodes.Count - 1;
                toSorted.Add(nodeNumberPortBc2, nodeIndex);
            }
            uint free_node_cnt0 = (uint)sortedNodes.Count;  // 境界1 + 内部領域 + 境界2

            // 剛性行列、質量行列を作成
            double[] KMat0 = null;
            double[] CMat0 = null;
            double[] MMat0 = null;
            WgUtilForPeriodicEigen.MkPeriodicHelmholtzMat(
                waveLength,
                isYDirectionPeriodic,
                rotAngle,
                rotOrigin,
                World,
                FieldLoopId,
                Medias,
                LoopDic,
                node_cnt,
                free_node_cnt0,
                toSorted,
                out KMat0,
                out CMat0,
                out MMat0);

            // 緩慢変化包絡線近似?
            //bool isSVEA = true;  // 緩慢変化包絡線近似 Φ = φ(x, y) exp(-jβx) と置く方法
            //bool isSVEA = false; // Φを直接解く方法(exp(-jβd)を固有値として扱う)
            System.Diagnostics.Debug.WriteLine("isSVEA: {0}", isSVEA);
            System.Diagnostics.Debug.WriteLine("isModeTrace: {0}, isSolveEigenItr: {1}, propModeCntToSolve: {2}", isModeTrace, isSolveEigenItr, propModeCntToSolve);
            // 逆行列を使う?
            //bool isUseInvMat = false; // 逆行列を使用しない
            bool isUseInvMat = true; // 逆行列を使用する
            System.Diagnostics.Debug.WriteLine("isUseInvMat: {0}", isUseInvMat);

            /*
            // 反復計算のときはモード追跡をOFFにする(うまくいかないときがあるので)
            if (isSolveEigenItr && isModeTrace)
            {
                isModeTrace = false;
                System.Diagnostics.Debug.WriteLine("isModeTrace force to false.(isSolveEigenItr == true)");
            }
             */

            // 境界2の節点は境界1の節点と同一とみなす
            //   境界上の分割が同じであることが前提条件
            double[] KMat = null;
            double[] CMat = null;
            double[] MMat = null;
            if (isSVEA)
            {
                KMat = new double[free_node_cnt * free_node_cnt];
                CMat = new double[free_node_cnt * free_node_cnt];
                MMat = new double[free_node_cnt * free_node_cnt];
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        KMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j];
                        CMat[i + free_node_cnt * j] = CMat0[i + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] = MMat0[i + free_node_cnt0 * j];
                    }
                }
                for (int i = 0; i < free_node_cnt; i++)
                {
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j);
                        KMat[i + free_node_cnt * j] += KMat0[i + free_node_cnt0 * jno_B2];
                        CMat[i + free_node_cnt * j] += CMat0[i + free_node_cnt0 * jno_B2];
                        MMat[i + free_node_cnt * j] += MMat0[i + free_node_cnt0 * jno_B2];
                    }
                }
                for (int i = 0; i < boundary_node_cnt; i++)
                {
                    for (int j = 0; j < free_node_cnt; j++)
                    {
                        int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i);
                        KMat[i + free_node_cnt * j] += KMat0[ino_B2 + free_node_cnt0 * j];
                        CMat[i + free_node_cnt * j] += CMat0[ino_B2 + free_node_cnt0 * j];
                        MMat[i + free_node_cnt * j] += MMat0[ino_B2 + free_node_cnt0 * j];
                    }
                    for (int j = 0; j < boundary_node_cnt; j++)
                    {
                        int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i);
                        int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j);
                        KMat[i + free_node_cnt * j] += KMat0[ino_B2 + free_node_cnt0 * jno_B2];
                        CMat[i + free_node_cnt * j] += CMat0[ino_B2 + free_node_cnt0 * jno_B2];
                        MMat[i + free_node_cnt * j] += MMat0[ino_B2 + free_node_cnt0 * jno_B2];
                    }
                }
                // 行列要素check
                {
                    for (int i = 0; i < free_node_cnt; i++)
                    {
                        for (int j = i; j < free_node_cnt; j++)
                        {
                            // [K]は対称行列
                            System.Diagnostics.Debug.Assert(Math.Abs(KMat[i + free_node_cnt * j] - KMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                            // [M]は対称行列
                            System.Diagnostics.Debug.Assert(Math.Abs(MMat[i + free_node_cnt * j] - MMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                            // [C]は反対称行列
                            System.Diagnostics.Debug.Assert(Math.Abs((-CMat[i + free_node_cnt * j]) - CMat[j + free_node_cnt * i]) < Constants.PrecisionLowerLimit);
                        }
                    }
                }
            }
            else
            {
                if (!isUseInvMat)
                {
                    KMat = new double[free_node_cnt * free_node_cnt];
                    CMat = new double[free_node_cnt * free_node_cnt];
                    MMat = new double[free_node_cnt * free_node_cnt];

                    CMat0 = null;
                    MMat0 = null;
                    uint inner_node_cnt = free_node_cnt - boundary_node_cnt;
                    for (int i = 0; i < boundary_node_cnt; i++)
                    {
                        int ino_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - i) : (int)(free_node_cnt + i);
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j);
                            // [K21]
                            KMat[i + free_node_cnt * j] = KMat0[ino_B2 + free_node_cnt0 * j];
                            // [K11] + [K22]
                            CMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * j] + KMat0[ino_B2 + free_node_cnt0 * jno_B2];
                            // [K12]
                            MMat[i + free_node_cnt * j] = KMat0[i + free_node_cnt0 * jno_B2];
                        }
                        for (int j = 0; j < inner_node_cnt; j++)
                        {
                            // [K20]
                            KMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[ino_B2 + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [K10]
                            CMat[i + free_node_cnt * (j + boundary_node_cnt)] = KMat0[i + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [0]
                            MMat[i + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                        }
                    }
                    for (int i = 0; i < inner_node_cnt; i++)
                    {
                        for (int j = 0; j < boundary_node_cnt; j++)
                        {
                            int jno_B2 = isPortBc2Reverse ? (int)(free_node_cnt + boundary_node_cnt - 1 - j) : (int)(free_node_cnt + j);
                            // [0]
                            KMat[(i + boundary_node_cnt) + free_node_cnt * j] = 0.0;
                            // [K01]
                            CMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * j];
                            // [K02]
                            MMat[(i + boundary_node_cnt) + free_node_cnt * j] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * jno_B2];
                        }
                        for (int j = 0; j < inner_node_cnt; j++)
                        {
                            // [0]
                            KMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                            // [K00]
                            CMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = KMat0[(i + boundary_node_cnt) + free_node_cnt0 * (j + boundary_node_cnt)];
                            // [0]
                            MMat[(i + boundary_node_cnt) + free_node_cnt * (j + boundary_node_cnt)] = 0.0;
                        }
                    }
                }
                else
                {
                    KMat = null;
                    CMat = null;
                    MMat = null;
                }
            }

            // 伝搬定数
            KrdLab.clapack.Complex[] betamToSolveList = null;
            // 界ベクトルは全節点分作成
            KrdLab.clapack.Complex[][] resVecList = null;
            // PC導波路の場合は、波数が[0, π]の領域から探索する
            if (IsPCWaveguide)
            {
                //minBeta = 0.0;
                //maxBeta = 0.5 * (2.0 * pi / periodicDistance) / k0;
                //minBeta = minWaveNum * (2.0 * pi / periodicDistance) / k0;
                //maxBeta = maxWaveNum * (2.0 * pi / periodicDistance) / k0;
                double minBeta_BZ = minWaveNum * (2.0 * pi / periodicDistance) / k0;
                double maxBeta_BZ = maxWaveNum * (2.0 * pi / periodicDistance) / k0;
                if (minBeta_BZ > minBeta)
                {
                    minBeta = minBeta_BZ;
                }
                if (maxBeta_BZ < maxBeta)
                {
                    maxBeta = maxBeta_BZ;
                }
                System.Diagnostics.Debug.WriteLine("minWaveNum:{0}, maxWaveNum: {1}", minWaveNum, maxWaveNum);
                System.Diagnostics.Debug.WriteLine("minBeta: {0}, maxBeta: {1}", minBeta, maxBeta);
            }

            // 緩慢変化包絡線近似でない場合は反復計算しない方法を使用する
            if (!isSolveEigenItr || propModeCntToSolve >= 3 || !isSVEA)
            {
                KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null;
                if (isModeTrace && PrevModalVecList != null)
                {
                    // 前回の固有モードベクトルを取得する
                    //   現状1つだけ
                    if (PrevModalVecList.Length >= 0)
                    {
                        tmpPrevModalVec_1stMode = PrevModalVecList[0];
                    }
                }
                /*
                // マルチモードの場合
                // 周期構造導波路固有値問題を2次一般化固有値問題として解く
                solveAsQuadraticGeneralizedEigen(
                    k0,
                    KMat,
                    CMat,
                    MMat,
                    node_cnt,
                    free_node_cnt,
                    boundary_node_cnt,
                    sortedNodes,
                    toSorted,
                    to_no_all,
                    to_no_boundary_fieldPortBcId1,
                    isModeTrace,
                    ref PrevModalVec,
                    IsPCWaveguide,
                    PCWaveguidePorts,
                    out betamToSolveList,
                    out resVecList);
                 */

                if (!isUseInvMat)
                {
                    // マルチモードの場合
                    // 周期構造導波路固有値問題を2次一般化固有値問題として解く(実行列として解く)
                    solveAsQuadraticGeneralizedEigenWithRealMat(
                        incidentModeIndex,
                        isSVEA,
                        periodicDistance,
                        k0,
                        KMat,
                        CMat,
                        MMat,
                        node_cnt,
                        free_node_cnt,
                        boundary_node_cnt,
                        sortedNodes,
                        toSorted,
                        to_no_all,
                        to_no_boundary_fieldPortBcId1,
                        isYDirectionPeriodic,
                        coord_c_all,
                        IsPCWaveguide,
                        PCWaveguidePorts,
                        isModeTrace,
                        ref tmpPrevModalVec_1stMode,
                        minBeta,
                        maxBeta,
                        (2.0 * pi / periodicDistance), //k0, //1.0,
                        out betamToSolveList,
                        out resVecList);
                }
                else
                {
                    // 逆行列を使用する方法
                    if (isSVEA)
                    {
                        // マルチモードの場合
                        // 周期構造導波路固有値問題を2次一般化固有値問題→標準固有値問題として解く(実行列として解く)(緩慢変化包絡線近似用)
                        System.Diagnostics.Debug.Assert(isSVEA == true);
                        solveAsQuadraticGeneralizedEigenToStandardWithRealMat(
                            incidentModeIndex,
                            k0,
                            KMat,
                            CMat,
                            MMat,
                            node_cnt,
                            free_node_cnt,
                            boundary_node_cnt,
                            sortedNodes,
                            toSorted,
                            to_no_all,
                            to_no_boundary_fieldPortBcId1,
                            IsPCWaveguide,
                            PCWaveguidePorts,
                            isModeTrace,
                            ref tmpPrevModalVec_1stMode,
                            minBeta,
                            maxBeta,
                            k0, //(2.0 * pi / periodicDistance), //k0, //1.0,
                            out betamToSolveList,
                            out resVecList);
                    }
                    else
                    {
                        System.Diagnostics.Debug.Assert(isSVEA == false);
                        solveNonSVEAModeAsQuadraticGeneralizedEigenWithRealMat(
                            incidentModeIndex,
                            periodicDistance,
                            k0,
                            KMat0,
                            isPortBc2Reverse,
                            node_cnt,
                            free_node_cnt0,
                            free_node_cnt,
                            boundary_node_cnt,
                            sortedNodes,
                            toSorted,
                            to_no_all,
                            to_no_boundary_fieldPortBcId1,
                            isYDirectionPeriodic,
                            coord_c_all,
                            IsPCWaveguide,
                            PCWaveguidePorts,
                            isModeTrace,
                            ref tmpPrevModalVec_1stMode,
                            minBeta,
                            maxBeta,
                            (2.0 * pi / periodicDistance), //k0, //1.0,
                            out betamToSolveList,
                            out resVecList);
                    }
                }

                if (isModeTrace && tmpPrevModalVec_1stMode != null)
                {
                    PrevModalVecList = new KrdLab.clapack.Complex[1][];
                    PrevModalVecList[0] = tmpPrevModalVec_1stMode;
                }
            }
            else if (isSolveEigenItr && propModeCntToSolve == 2)
            {
                // 2次の固有値問題として解くより、シングルモードのルーチンで
                // 基本モードと高次モードを計算した方が速い
                // 基本モード
                // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く
                KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null;
                KrdLab.clapack.Complex[] tmpPrevModalVec_2ndMode = null;
                if (isModeTrace && PrevModalVecList != null)
                {
                    // 前回の固有モードベクトルを後ろから順に取得する
                    if (PrevModalVecList.Length >= 1)
                    {
                        tmpPrevModalVec_1stMode = PrevModalVecList[PrevModalVecList.Length - 1];
                    }
                    if (PrevModalVecList.Length >= 2)
                    {
                        tmpPrevModalVec_2ndMode = PrevModalVecList[PrevModalVecList.Length - 2];
                    }
                }
                System.Diagnostics.Debug.Assert(isSVEA == true);
                solveItrAsLinearGeneralizedEigen(
                    k0,
                    KMat,
                    CMat,
                    MMat,
                    node_cnt,
                    free_node_cnt,
                    boundary_node_cnt,
                    sortedNodes,
                    toSorted,
                    to_no_all,
                    to_no_boundary_fieldPortBcId1,
                    IsPCWaveguide,
                    PCWaveguidePorts,
                    false, // isCalcSecondMode: false
                    isModeTrace,
                    ref tmpPrevModalVec_1stMode,
                    minBeta,
                    maxBeta,
                    out betamToSolveList,
                    out resVecList);
                if (isModeTrace && tmpPrevModalVec_1stMode != null)
                {
                    PrevModalVecList = new KrdLab.clapack.Complex[1][];
                    PrevModalVecList[0] = tmpPrevModalVec_1stMode;
                }
                if (betamToSolveList != null)
                {
                    // 基本モードの解を退避
                    KrdLab.clapack.Complex[] betamToSolveList_1stMode = betamToSolveList;
                    KrdLab.clapack.Complex[][] resVecList_1stMode = resVecList;
                    // 高次モード
                    KrdLab.clapack.Complex[] betamToSolveList_2ndMode = null;
                    KrdLab.clapack.Complex[][] resVecList_2ndMode = null;
                    // 高次モードを反復計算で解く
                    // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く
                    System.Diagnostics.Debug.Assert(isSVEA == true);
                    solveItrAsLinearGeneralizedEigen(
                        k0,
                        KMat,
                        CMat,
                        MMat,
                        node_cnt,
                        free_node_cnt,
                        boundary_node_cnt,
                        sortedNodes,
                        toSorted,
                        to_no_all,
                        to_no_boundary_fieldPortBcId1,
                        IsPCWaveguide,
                        PCWaveguidePorts,
                        true, // isCalcSecondMode: true
                        isModeTrace,
                        ref tmpPrevModalVec_2ndMode,
                        minBeta,
                        maxBeta,
                        out betamToSolveList_2ndMode,
                        out resVecList_2ndMode);
                    if (betamToSolveList_2ndMode != null)
                    {
                        // betamToSolveListは伝搬定数の実部の昇順で並べる
                        // したがって、基本モードは最後に格納
                        betamToSolveList = new KrdLab.clapack.Complex[2];
                        resVecList = new KrdLab.clapack.Complex[2][];
                        // 2nd mode
                        betamToSolveList[0] = betamToSolveList_2ndMode[0];
                        resVecList[0] = resVecList_2ndMode[0];
                        // 1st mode
                        betamToSolveList[1] = betamToSolveList_1stMode[0];
                        resVecList[1] = resVecList_1stMode[0];

                        if (isModeTrace)
                        {
                            PrevModalVecList = new KrdLab.clapack.Complex[2][];
                            // 2nd mode
                            PrevModalVecList[0] = tmpPrevModalVec_2ndMode;
                            // 1st mode
                            PrevModalVecList[1] = tmpPrevModalVec_1stMode;
                        }
                    }
                }
            }
            else if (isSolveEigenItr && propModeCntToSolve == 1)
            {
                KrdLab.clapack.Complex[] tmpPrevModalVec_1stMode = null;
                if (isModeTrace && PrevModalVecList != null)
                {
                    // 前回の固有モードベクトルを後ろから順に取得する
                    if (PrevModalVecList.Length >= 1)
                    {
                        tmpPrevModalVec_1stMode = PrevModalVecList[PrevModalVecList.Length - 1];
                    }
                }
                // シングルモードの場合
                // 周期構造導波路固有値問題を一般化固有値問題の反復計算で解く
                System.Diagnostics.Debug.Assert(isSVEA == true);
                solveItrAsLinearGeneralizedEigen(
                    k0,
                    KMat,
                    CMat,
                    MMat,
                    node_cnt,
                    free_node_cnt,
                    boundary_node_cnt,
                    sortedNodes,
                    toSorted,
                    to_no_all,
                    to_no_boundary_fieldPortBcId1,
                    IsPCWaveguide,
                    PCWaveguidePorts,
                    false, // isCalcSecondMode: false
                    isModeTrace,
                    ref tmpPrevModalVec_1stMode,
                    minBeta,
                    maxBeta,
                    out betamToSolveList,
                    out resVecList);
                if (isModeTrace && tmpPrevModalVec_1stMode != null)
                {
                    PrevModalVecList = new KrdLab.clapack.Complex[1][];
                    PrevModalVecList[0] = tmpPrevModalVec_1stMode;
                }
            }
            else
            {
                System.Diagnostics.Debug.Assert(false);
                return false;
            }

            // 固有値が1つでも取得できているかチェック
            if (betamToSolveList == null)
            {
                return false;
            }
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex betam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                // ポート境界1の節点の値を境界2にも格納する
                for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                    uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1];
                    // 境界1の節点の界の値を取得
                    KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1];

                    // 境界2の節点
                    int ino_B2 = isPortBc2Reverse ? (int)(no_c_all_fieldPortBcId2.Length - 1 - ino) : (int)ino;
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[ino_B2];

                    uint ino_InLoop_PortBc2 = to_no_all[nodeNumberPortBc2];
                    if (isSVEA)
                    {
                        // 緩慢変化包絡線近似の場合は、Φ2 = Φ1
                        resVec[ino_InLoop_PortBc2] = cvalue;
                    }
                    else
                    {
                        // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1
                        KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance);
                        resVec[ino_InLoop_PortBc2] = expA * cvalue; // 直接Bloch境界条件を指定する場合
                    }
                }
            }

            /////////////////////////////////////////////////////////////////////////////////////
            // 位相調整

            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex phaseShift = 1.0;
                double maxAbs = double.MinValue;
                KrdLab.clapack.Complex fValueAtMaxAbs = 0.0;
                {
                    /*
                    // 境界上で位相調整する
                    for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++)
                    {
                        uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                        uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1];
                        KrdLab.clapack.Complex cvalue = resVec[ino_InLoop_PortBc1];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                     */
                    // 領域全体で位相調整する
                    for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++)
                    {
                        KrdLab.clapack.Complex cvalue = resVec[ino_InLoop];
                        double abs = KrdLab.clapack.Complex.Abs(cvalue);
                        if (abs > maxAbs)
                        {
                            maxAbs = abs;
                            fValueAtMaxAbs = cvalue;
                        }
                    }
                }
                if (maxAbs >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                {
                    phaseShift = fValueAtMaxAbs / maxAbs;
                }
                System.Diagnostics.Debug.WriteLine("phaseShift: {0} (°)", Math.Atan2(phaseShift.Imaginary, phaseShift.Real) * 180.0 / pi);
                for (int i = 0; i < resVec.Length; i++)
                {
                    resVec[i] /= phaseShift;
                }
            }

            /////////////////////////////////////////////////////////////////////////////////////
            // X方向の微分値を取得する
            KrdLab.clapack.Complex[][] resDFDXVecList = new KrdLab.clapack.Complex[betamToSolveList.Length][];
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = null;
                KrdLab.clapack.Complex[] resDFDYVec = null;
                getDFDXValues(World, FieldLoopId, to_no_all, Medias, LoopDic, rotAngle, rotOrigin, resVec, out resDFDXVec, out resDFDYVec);
                if (isYDirectionPeriodic)
                {
                    // Y方向周期構造の場合
                    resDFDXVecList[imode] = resDFDYVec;
                }
                else
                {
                    // X方向周期構造の場合
                    resDFDXVecList[imode] = resDFDXVec;
                }
            }
            // 境界1と境界2の節点の微分値は同じという条件を弱形式で課している為、微分値は同じにならない。
            // 加えて、getDFDXValuesは内部節点からの寄与を片側のみしか計算していない。
            // →境界の両側からの寄与を考慮する為に境界1の微分値と境界2の微分値を平均してみる
            for (int imode = 0; imode < betamToSolveList.Length; imode++)
            {
                KrdLab.clapack.Complex betam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];
                // ポート境界1の節点の微分値、ポート境界2の微分値は、両者の平均をとる
                for (int ino = 0; ino < no_c_all_fieldPortBcId1.Length; ino++)
                {
                    // 境界1の節点
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                    uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1];
                    // 境界1の節点の界の微分値値を取得
                    KrdLab.clapack.Complex cdFdXValue1 = resDFDXVec[ino_InLoop_PortBc1];

                    // 境界2の節点
                    int ino_B2 = isPortBc2Reverse ? (int)(no_c_all_fieldPortBcId2.Length - 1 - ino) : (int)ino;
                    uint nodeNumberPortBc2 = no_c_all_fieldPortBcId2[ino_B2];
                    uint ino_InLoop_PortBc2 = to_no_all[nodeNumberPortBc2];
                    // 境界2の節点の界の微分値値を取得
                    KrdLab.clapack.Complex cdFdXValue2 = resDFDXVec[ino_InLoop_PortBc2];

                    // 平均値を計算し、境界の微分値として再格納する
                    if (isSVEA)
                    {
                        KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2) * 0.5;
                        resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue;
                        resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue;
                    }
                    else
                    {
                        // 緩慢変化包絡線近似でない場合は、Φ2 = expA * Φ1
                        KrdLab.clapack.Complex expA = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * periodicDistance);
                        // Φ2から逆算でΦ1を求め、平均をとる
                        KrdLab.clapack.Complex cdFdXValue = (cdFdXValue1 + cdFdXValue2 / expA) * 0.5;
                        resDFDXVec[ino_InLoop_PortBc1] = cdFdXValue;
                        resDFDXVec[ino_InLoop_PortBc2] = cdFdXValue * expA;
                    }
                }
            }

            //////////////////////////////////////////////////////////////////////////////////////
            if (!isSVEA)
            {
                // 緩慢変化包絡線近似でない場合は、緩慢変化包絡線近似の分布に変換する
                for (int imode = 0; imode < betamToSolveList.Length; imode++)
                {
                    KrdLab.clapack.Complex betam = betamToSolveList[imode];
                    KrdLab.clapack.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                    KrdLab.clapack.Complex[] resVec = resVecList[imode];
                    KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];
                    System.Diagnostics.Debug.Assert(resVec.Length == coord_c_all.Length);
                    uint nodeNumber1st = sortedNodes[0];
                    uint ino_InLoop_1st = to_no_all[nodeNumber1st];
                    double[] coord1st = coord_c_all[ino_InLoop_1st];
                    for (int ino_InLoop = 0; ino_InLoop < resVec.Length; ino_InLoop++)
                    {
                        // 節点の界の値
                        KrdLab.clapack.Complex fieldVal = resVec[ino_InLoop];
                        // 節点の界の微分値
                        KrdLab.clapack.Complex dFdXVal = resDFDXVec[ino_InLoop];
                        // 節点の座標
                        double[] coord = coord_c_all[ino_InLoop];
                        double x_pt = 0.0;
                        if (isYDirectionPeriodic)
                        {
                            x_pt = (coord[1] - coord1st[1]);
                        }
                        else
                        {
                            x_pt = (coord[0] - coord1st[0]);
                        }
                        //KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam * x_pt);
                        KrdLab.clapack.Complex expX = KrdLab.clapack.Complex.Exp(-1.0 * KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * x_pt);

                        // ΦのSVEA(φ)
                        KrdLab.clapack.Complex fieldVal_SVEA = fieldVal / expX;
                        resVec[ino_InLoop] = fieldVal_SVEA;

                        // SVEAの微分( exp(-jβx)dφ/dx = dΦ/dx + jβφexp(-jβx))
                        //resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam * fieldVal_SVEA;
                        resDFDXVec[ino_InLoop] = dFdXVal / expX + KrdLab.clapack.Complex.ImaginaryOne * betam_periodic * fieldVal_SVEA;
                    }
                }
            }

            //////////////////////////////////////////////////////////////////////////////////////
            // 固有値、固有ベクトル
            // モード数の修正
            if (max_mode > betamToSolveList.Length)
            {
                max_mode = (uint)betamToSolveList.Length;
            }
            // 格納
            uint node_cnt_Bc1 = (uint)no_c_all_fieldPortBcId1.Length;
            eigen_values = new DelFEM4NetCom.Complex[max_mode];
            eigen_vecs_Bc1 = new DelFEM4NetCom.Complex[max_mode, node_cnt_Bc1];
            eigen_dFdXs_Bc1 = new DelFEM4NetCom.Complex[max_mode, node_cnt_Bc1];
            for (int imode = 0; imode < max_mode; imode++)
            {
                eigen_values[imode] = new DelFEM4NetCom.Complex(0, 0);
                for (int ino = 0; ino < node_cnt_Bc1; ino++)
                {
                    eigen_vecs_Bc1[imode, ino] = new DelFEM4NetCom.Complex(0, 0);
                    eigen_dFdXs_Bc1[imode, ino] = new DelFEM4NetCom.Complex(0, 0);
                }
            }
            for (int imode = betamToSolveList.Length - 1, tagtModeIndex = 0; imode >= 0 && tagtModeIndex < max_mode; imode--, tagtModeIndex++)
            {
                KrdLab.clapack.Complex workBetam = betamToSolveList[imode];
                KrdLab.clapack.Complex[] resVec = resVecList[imode];
                KrdLab.clapack.Complex[] resDFDXVec = resDFDXVecList[imode];

                DelFEM4NetCom.Complex betam = new DelFEM4NetCom.Complex(workBetam.Real, workBetam.Imaginary);
                bool isComplexConjugateMode = false;
                //   減衰定数は符号がマイナス(β = -jα)
                if (betam.Imag > 0.0 && Math.Abs(betam.Real) <= 1.0e-12)
                {
                    betam = new Complex(betam.Real, -betam.Imag);
                    isComplexConjugateMode = true;
                }
                DelFEM4NetCom.Complex[] evec = new DelFEM4NetCom.Complex[node_cnt_Bc1];
                DelFEM4NetCom.Complex[] evec_dFdX = new DelFEM4NetCom.Complex[node_cnt_Bc1];
                for (int ino = 0; ino < node_cnt_Bc1; ino++)
                {
                    uint nodeNumberPortBc1 = no_c_all_fieldPortBcId1[ino];
                    uint ino_InLoop_PortBc1 = to_no_all[nodeNumberPortBc1];
                    DelFEM4NetCom.Complex cvalue = new DelFEM4NetCom.Complex(resVec[ino_InLoop_PortBc1].Real, resVec[ino_InLoop_PortBc1].Imaginary);
                    DelFEM4NetCom.Complex dFdXValue = new DelFEM4NetCom.Complex(resDFDXVec[ino_InLoop_PortBc1].Real, resDFDXVec[ino_InLoop_PortBc1].Imaginary);
                    if (isComplexConjugateMode)
                    {
                        cvalue = DelFEM4NetCom.Complex.Conjugate(cvalue);
                        dFdXValue = DelFEM4NetCom.Complex.Conjugate(dFdXValue);
                    }
                    evec[ino] = cvalue;
                    evec_dFdX[ino] = dFdXValue;
                    if (tagtModeIndex == incidentModeIndex)
                    {
                        //System.Diagnostics.Debug.WriteLine("phase: {0} evec {1} evec_dFdX {2}", ino, Math.Atan2(cvalue.Imag, cvalue.Real) * 180 / pi, Math.Atan2(dFdXValue.Imag, dFdXValue.Real) * 180 / pi);
                    }
                }
                // 規格化定数を求める
                DelFEM4NetCom.Complex[] workVec = MyMatrixUtil.product(ryy_1d, evec);
                DelFEM4NetCom.Complex[] evec_Modify = new DelFEM4NetCom.Complex[node_cnt_Bc1];
                DelFEM4NetCom.Complex imagOne = new DelFEM4NetCom.Complex(0.0, 1.0);
                DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                for (int ino = 0; ino < node_cnt_Bc1; ino++)
                {
                    //evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam);
                    evec_Modify[ino] = evec[ino] - evec_dFdX[ino] / (imagOne * betam_periodic);
                }
                //Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec), workVec);
                Complex dm = MyMatrixUtil.vector_Dot(MyMatrixUtil.vector_Conjugate(evec_Modify), workVec);
                if (waveModeDv == WaveModeDV.TM)
                {
                    // TMモード
                    //dm = MyMatrixUtil.complex_Sqrt(omega * eps0 / Complex.Norm(betam) / dm);
                    dm = MyMatrixUtil.complex_Sqrt(omega * eps0 * Complex.Conjugate(betam) / (Complex.Norm(betam) * Complex.Conjugate(betam_periodic)) / dm);
                }
                else
                {
                    // TEモード
                    //dm = MyMatrixUtil.complex_Sqrt(omega * myu0 / Complex.Norm(betam) / dm);
                    dm = MyMatrixUtil.complex_Sqrt(omega * myu0 * Complex.Conjugate(betam) / (Complex.Norm(betam) * Complex.Conjugate(betam_periodic)) / dm);
                }

                // 伝搬定数の格納
                eigen_values[tagtModeIndex] = betam;
                if (tagtModeIndex < 10)
                {
                    System.Diagnostics.Debug.WriteLine("β/k0  ( " + tagtModeIndex + " ) = " + betam.Real / k0 + " + " + betam.Imag / k0 + " i " + ((incidentModeIndex == tagtModeIndex) ? " incident" : ""));
                }
                // 固有ベクトルの格納(規格化定数を掛ける)
                for (int ino = 0; ino < evec.Length; ino++)
                {
                    DelFEM4NetCom.Complex fm = dm * evec[ino];
                    DelFEM4NetCom.Complex dfmdx = dm * evec_dFdX[ino];
                    eigen_vecs_Bc1[tagtModeIndex, ino] = fm;
                    eigen_dFdXs_Bc1[tagtModeIndex, ino] = dfmdx;
                    //System.Diagnostics.Debug.WriteLine("eigen_vecs_Bc1({0}, {1}) = {2} + {3} i", imode, ino, fm.Real, fm.Imag);
                }
                /*
                //DEBUG モード確認
                if (tagtModeIndex == incidentModeIndex)
                {
                    DelFEM4NetCom.Complex[] values_all = new DelFEM4NetCom.Complex[resVec.Length];
                    for (int ino = 0; ino < values_all.Length; ino++)
                    {
                        KrdLab.clapack.Complex cval = resVec[ino];
                        //KrdLab.clapack.Complex cval = resDFDXVec[ino];
                        values_all[ino] = new DelFEM4NetCom.Complex(cval.Real, cval.Imaginary);
                        //values_all[ino] = Complex.Norm(values_all[ino]);
                    }
                    WgUtil.SetFieldValueForDisplay(World, FieldLoopId, values_all, to_no_all);
                }
                 */
            }
            return true;
        }
コード例 #7
0
        /// <summary>
        /// ヘルムホルツの方程式 Sommerfelt放射条件(要素アレイ単位)
        /// </summary>
        /// <param name="ls"></param>
        /// <param name="waveLength"></param>
        /// <param name="world"></param>
        /// <param name="fieldValId"></param>
        /// <param name="eaId"></param>
        /// <param name="tmpBuffer"></param>
        /// <returns></returns>
        private static bool AddLinSys_SommerfeltRadiationBC_EachElementAry(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId, uint eaId, int[] tmpBuffer)
        {
            System.Diagnostics.Debug.Assert(world.IsIdEA(eaId));
            CElemAry ea = world.GetEA(eaId);
            System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE);
            if (!world.IsIdField(fieldValId))
            {
                return false;
            }
            CField valField = world.GetField(fieldValId);
            CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world);
            CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world);

            // 線要素の節点数
            uint nno = 2;
            // 座標の次元
            uint ndim = 2;
            // 要素節点の全体節点番号
            uint[] no_c = new uint[nno];
            // 要素節点の値
            Complex[] value_c = new Complex[nno];
            // 要素節点の座標
            double[][] coord_c = new double[nno][];
            for (int inoes = 0; inoes < nno; inoes++)
            {
                coord_c[inoes] = new double[ndim];
            }
            // 要素剛性行列 (i, j) --> (i * RowSize + j)
            Complex[] ematBuffer = new Complex[nno * nno];
            // 要素節点等価内力、外力、残差ベクトル
            Complex[] eres_c = new Complex[nno];
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world);
            // 要素残差ベクトル(コーナー)
            CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world);

            CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, world);
            CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world);

            for (uint ielem = 0; ielem < ea.Size(); ielem++)
            {
                // 要素配列から要素セグメントの節点番号を取り出す
                es_c_co.GetNodes(ielem, no_c);

                // 座標を取得
                for (uint inoes = 0; inoes < nno; inoes++)
                {
                    double[] tmpval = null;
                    ns_c_co.GetValue(no_c[inoes], out tmpval);
                    System.Diagnostics.Debug.Assert(tmpval.Length == ndim);
                    for (int i = 0; i < tmpval.Length; i++)
                    {
                        coord_c[inoes][i] = tmpval[i];
                    }
                }

                // 節点の値を取って来る
                es_c_va.GetNodes(ielem, no_c);
                for (uint inoes = 0; inoes < nno; inoes++)
                {
                    Complex[] tmpval = null;
                    ns_c_val.GetValue(no_c[inoes], out tmpval);
                    System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                    value_c[inoes] = tmpval[0];
                }
                double elen = Math.Sqrt((coord_c[0][0] - coord_c[1][0]) * (coord_c[0][0] - coord_c[1][0]) + (coord_c[0][1] - coord_c[1][1]) * (coord_c[0][1] - coord_c[1][1]));

                double k = 2.0 * pi / waveLength;
                Complex tmp_val1 = (k / 6.0 * elen) * (new Complex(0, 1));
                Complex tmp_val2 = -1 / (2.0 * elen * k) * (new Complex(0, 1));
                //emat[0, 0]
                ematBuffer[0] = tmp_val1 * 2 + tmp_val2;
                //emat[0, 1]
                ematBuffer[1] = tmp_val1 - tmp_val2;
                //emat[1, 0]
                ematBuffer[nno] = tmp_val1 - tmp_val2;
                //emat[1, 1]
                ematBuffer[nno + 1] = tmp_val1 * 2 + tmp_val2;

                // 要素節点等価内力ベクトルを求める
                for (int ino = 0; ino < nno; ino++)
                {
                    eres_c[ino] = new Complex(0.0);
                    for (int jno = 0; jno < nno; jno++)
                    {
                        eres_c[ino] -= ematBuffer[ino * nno + jno] * value_c[jno];
                    }
                }

                // 要素剛性行列にマージする
                mat_cc.Mearge(nno, no_c, nno, no_c, 1, ematBuffer, ref tmpBuffer);

                // 残差ベクトルにマージする
                for (int inoes = 0; inoes < nno; inoes++)
                {
                    res_c.AddValue(no_c[inoes], 0, eres_c[inoes]);
                }
            }
            return true;
        }
コード例 #8
0
        /// <summary>
        /// リニアシステム初期化(マージ開始までの処理)
        /// </summary>
        /// <param name="matPattern">行列の非0要素パターン</param>
        /// <param name="Ls"></param>
        /// <param name="Prec"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        public static void SetupLinearSystem(
            bool[,] matPattern,
            out CFieldWorld World, out uint FieldValId,
            out CZLinearSystem Ls, out CZPreconditioner_ILU Prec, out int[] tmpBuffer)
        {
            World     = new CFieldWorld();
            Ls        = new CZLinearSystem();
            Prec      = new CZPreconditioner_ILU();
            tmpBuffer = null;

            int matLen = matPattern.GetLength(0);

            //------------------------------------------------------------------
            // ワールド座標系を生成
            //------------------------------------------------------------------
            uint baseId = 0;

            setupWorld((uint)matLen, ref World, out baseId);

            // 界の値を扱うバッファ?を生成する。
            // フィールド値IDが返却される。
            //    要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点
            FieldValId = World.MakeField_FieldElemDim(baseId, 0,
                                                      FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER);

            //------------------------------------------------------------------
            // 界パターン追加
            //------------------------------------------------------------------
            Ls.AddPattern_Field(FieldValId, World);
            //  POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない

            // 非対角要素のパターンの追加
            {
                uint node_cnt = (uint)matLen;
                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                // パターンを追加
                using (CIndexedArray crs = new CIndexedArray())
                {
                    crs.InitializeSize(mat_cc.NBlkMatCol());

                    //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow());
                    using (UIntVectorIndexer index = crs.index)
                        using (UIntVectorIndexer ary = crs.array)
                        {
                            //BUGFIX
                            //for (int iblk = 0; iblk < (int)crs.Size(); iblk++)
                            // indexのサイズは crs.Size() + 1 (crs.Size() > 0のとき)
                            for (int iblk = 0; iblk < index.Count; iblk++)
                            {
                                index[iblk] = 0;
                            }
                            for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                            {
                                // 現在のマトリクスのインデックス設定をコピーする
                                uint npsup = 0;
                                ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                                foreach (uint row_index in cur_rows)
                                {
                                    ary.Add(row_index);
                                }
                                index[iblk + 1] = (uint)ary.Count;
                                //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup);
                                // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0)

                                // すべての節点に関して列を追加
                                int ino_global = iblk;
                                int col        = iblk;
                                if (col != -1 && ino_global != -1)
                                {
                                    // 関連付けられていない節点をその行の列データの最後に追加
                                    //int last_index = (int)index[col + 1] - 1;
                                    //System.Diagnostics.Debug.Assert(last_index == ary.Count - 1);
                                    int add_cnt = 0;
                                    for (int jno_global = 0; jno_global < node_cnt; jno_global++)
                                    {
                                        if (!matPattern[ino_global, jno_global])
                                        {
                                            continue;
                                        }
                                        uint row = (uint)jno_global;
                                        //if (ino_global != jno_global)  // 対角要素は除く
                                        if (col != row) // 対角要素は除く
                                        {
                                            if (!cur_rows.Contains(row))
                                            {
                                                //ary.Insert(last_index + 1 + add_cnt, row);
                                                ary.Add(row);
                                                add_cnt++;
                                                //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row);
                                            }
                                        }
                                    }
                                    if (add_cnt > 0)
                                    {
                                        index[col + 1] = (uint)ary.Count;
                                    }
                                }
                            }
                        }
                    crs.Sort();
                    System.Diagnostics.Debug.Assert(crs.CheckValid());
                    // パターンを削除する
                    mat_cc.DeletePattern();
                    // パターンを追加する
                    mat_cc.AddPattern(crs);
                }
            }

            //------------------------------------------------------------------
            // プリコンディショナ―
            //------------------------------------------------------------------
            // set Preconditioner
            //Prec.SetFillInLevel(1);
            // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した
            //Prec.SetFillInLevel(0);
            // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする
            //Prec.SetFillInLevel((uint)mat.RowSize);
            //   完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い
            //Prec.SetFillInLevel(3);
            //   誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある
            //以上から
            //メインの導波管の計算時間を短くしたいのでフィルインなしにする
            //Prec.SetFillInLevel(0);
            //    導波管だとこれで十分
            // フィルインレベルの設定(既定値)
            Prec.SetFillInLevel(DefFillInLevel);
            // ILU(0)のパターン初期化
            Prec.SetLinearSystem(Ls);

            //------------------------------------------------------------------
            // 剛性行列、残差ベクトルのマージ開始
            //------------------------------------------------------------------
            Ls.InitializeMarge();
            uint ntmp = Ls.GetTmpBufferSize();

            tmpBuffer = new int[ntmp];
            for (int i = 0; i < ntmp; i++)
            {
                tmpBuffer[i] = -1;
            }
        }
コード例 #9
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 非対称複素帯行列の連立方程式をclapackで解く
        /// </summary>
        /// <param name="Ls"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        private static void solveAsymmetricComplexBandMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId)
        {
            // エルミート帯行列の連立方程式をLisys(clapack)で解く
            CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            uint nblk = femMat.NBlkMatCol();
            Complex[] A = new Complex[nblk * nblk]; // ポインタを格納

            System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow());
            for (uint iblk = 0; iblk < nblk; iblk++)
            {
                ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk);
                System.Diagnostics.Debug.Assert(ptr.Count == 1);
                A[iblk + nblk * iblk] = new Complex(ptr[0].Real, ptr[0].Imag);
                //Console.WriteLine("    ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i");

                uint npsup = 0;
                ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup);
                ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup);
                System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count);
                for (int i = 0; i < ptrVal.Count; i++)
                {
                    A[iblk + nblk * ptrInd[i]] = new Complex(ptrVal[i].Real, ptrVal[i].Imag);
                    //Console.WriteLine("    ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i");
                }
            }
            // 残差ベクトル
            CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen());
            System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen());
            KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk];
            for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++)
            {
                Complex cvalue = resPtr.GetValue(iblk, 0);
                B[iblk].Real = cvalue.Real;
                B[iblk].Imaginary = cvalue.Imag;
                //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0));
            }
            // 対称行列チェック
            bool isSymmetrix = true;
            for (int i = 0; i < nblk; i++)
            {
                for (int j = i; j < nblk; j++)
                {
                    Complex aij = A[i + nblk * j];
                    Complex aji = A[j + nblk * i];
                    if (null == aij && null != aji)
                    {
                        isSymmetrix = false;
                        break;
                    }
                    else if (null != aij && null == aji)
                    {
                        isSymmetrix = false;
                        break;
                    }
                    else if (null != aij && null != aji)
                    {
                        if (Math.Abs(aij.Real - aji.Real) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                        {
                            isSymmetrix = false;
                            break;
                        }
                        else if (Math.Abs(aij.Imag - aji.Imag) >= MyUtilLib.Matrix.Constants.PrecisionLowerLimit)
                        {
                            isSymmetrix = false;
                            break;
                        }
                    }
                }
                if (!isSymmetrix)
                {
                    break;
                }
            }
            if (!isSymmetrix)
            {
                System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!");
                //System.Diagnostics.Debug.Assert(false);
            }

            // 複素バンド行列の線形方程式を解く
            KrdLab.clapack.Complex[] X = null;
            {
                // 非0パターンを作成
                bool[,] patternA = new bool[nblk, nblk];
                for (int i = 0; i < nblk; i++)
                {
                    for (int j = 0; j < nblk; j++)
                    {
                        Complex aij = A[i + nblk * j];
                        patternA[i, j] = (aij != null);
                    }
                }
                // バンド行列のバンド幅を縮小する
                bool[,] optPatternA = new bool[nblk, nblk];
                IList<int> optNodesA = null;
                Dictionary<int, int> toOptNodesA = null;
                // [A]のバンド幅を縮小する
                {
                    WgUtilForPeriodicEigenExt.GetOptBandMatNodes(patternA, out optNodesA, out toOptNodesA);

                    for (int i = 0; i < nblk; i++)
                    {
                        int ino_optA = toOptNodesA[i];
                        for (int j = 0; j < nblk; j++)
                        {
                            int jno_optA = toOptNodesA[j];
                            optPatternA[ino_optA, jno_optA] = patternA[i, j];
                        }
                    }
                }
                patternA = null;

                // バンド行列のサイズ取得
                int a_rowcolSize;
                int a_subdiaSize;
                int a_superdiaSize;
                WgUtilForPeriodicEigenExt.GetBandMatrixSubDiaSizeAndSuperDiaSize(optPatternA, out a_rowcolSize, out a_subdiaSize, out a_superdiaSize);
                // 扱っている問題ではsubdiagonalとsuperdiagonalは同じサイズ
                System.Diagnostics.Debug.Assert(a_subdiaSize == a_superdiaSize);
                // バンド行列作成
                int _a_rsize = a_subdiaSize * 2 + a_superdiaSize + 1;
                int _a_csize = a_rowcolSize;
                KrdLab.clapack.Complex[] AB = new KrdLab.clapack.Complex[_a_rsize * _a_csize];
                // [A]の値を[AB]にコピーする
                //   [A]はバンド幅最適化前の並び、[AB]は最適化後の並び
                for (int c = 0; c < a_rowcolSize; c++)
                {
                    int c_org = optNodesA[c];
                    // 対角成分
                    Complex a_c_org_c_org = A[c_org + c_org * a_rowcolSize];
                    if (a_c_org_c_org != null)
                    {
                        AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_c_org_c_org.Real;
                        AB[a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_c_org_c_org.Imag;
                    }

                    // subdiagonal成分
                    if (c < a_rowcolSize - 1)
                    {
                        for (int r = c + 1; r <= c + a_subdiaSize && r < a_rowcolSize; r++)
                        {
                            int r_org = optNodesA[r];
                            System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize);
                            System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize));
                            Complex a_r_c = A[r_org + c_org * a_rowcolSize];
                            if (a_r_c != null)
                            {
                                AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real;
                                AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag;
                            }
                        }
                    }
                    if (c > 0)
                    {
                        for (int r = c - 1; r >= c - a_superdiaSize && r >= 0; r--)
                        {
                            int r_org = optNodesA[r];
                            System.Diagnostics.Debug.Assert(r >= 0 && r < a_rowcolSize && c >= 0 && c < a_rowcolSize);
                            System.Diagnostics.Debug.Assert((r >= c - a_superdiaSize && r <= c + a_subdiaSize));
                            Complex a_r_c = A[r_org + c_org * a_rowcolSize];
                            if (a_r_c != null)
                            {
                                AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Real = a_r_c.Real;
                                AB[(r - c) + a_subdiaSize + a_superdiaSize + c * _a_rsize].Imaginary = a_r_c.Imag;
                            }
                        }
                    }
                }
                // 残差ベクトル{B}をoptAにあわせて並び替える
                KrdLab.clapack.Complex[] optB = new KrdLab.clapack.Complex[nblk];
                for (int i = 0; i < nblk; i++)
                {
                    int ino_optA = toOptNodesA[i];
                    optB[ino_optA].Real = B[i].Real;
                    optB[ino_optA].Imaginary = B[i].Imaginary;
                }
                A = null;
                B = null;

                // 解ベクトル
                KrdLab.clapack.Complex[] optX = null;
                // 連立方程式[AB]{X} = {B}を解く
                int x_row = (int)nblk;
                int x_col = 1;
                int a_row = a_rowcolSize;
                int a_col = a_rowcolSize;
                int kl = a_subdiaSize;
                int ku = a_superdiaSize;
                int b_row = (int)nblk;
                int b_col = 1;
                System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgbsv");
                KrdLab.clapack.FunctionExt.zgbsv(ref optX, ref x_row, ref x_col, AB, a_row, a_col, kl, ku, optB, b_row, b_col);
                // 解ベクトルを元の並びに戻す
                X = new KrdLab.clapack.Complex[nblk];
                for (int i = 0; i < nblk; i++)
                {
                    int inoGlobal = optNodesA[i];
                    X[inoGlobal].Real = optX[i].Real;
                    X[inoGlobal].Imaginary = optX[i].Imaginary;
                }
                optX = null;
            }

            // 解ベクトルをワールド座標系にセット
            Complex[] valuesAll = new Complex[nblk];
            Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>();
            for (uint i = 0; i < nblk; i++)
            {
                valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary);
                toNodeIndex.Add(i, i);
            }
            WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex);
        }
コード例 #10
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <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;
        }
コード例 #11
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 問題を設定する
        /// </summary>
        /// <returns></returns>
        private bool setNewProblem()
        {
            bool success = false;
            try
            {
                if (ProbNo == 0 || ProbNo == 1)
                {
                    ////////////////
                    // 波源の頂点
                    uint id_v = 0;
                    // ワールド座標系のベースID
                    uint id_base = 0;
                    using (CCadObj2D cad2d = new CCadObj2D())
                    {    // define shape
                        IList<CVector2D> pts = new List<CVector2D>();
                        pts.Add(new CVector2D(0.0, 0.0));  // 頂点1
                        pts.Add(new CVector2D(2.0, 0.0));  // 頂点2
                        pts.Add(new CVector2D(2.0, 2.0));  // 頂点3
                        pts.Add(new CVector2D(0.0, 2.0));  // 頂点4
                        uint id_l = cad2d.AddPolygon(pts).id_l_add;
                        id_v = cad2d.AddVertex(CAD_ELEM_TYPE.LOOP, id_l, new CVector2D(0.5, 0.05)).id_v_add;
                        World.Clear();
                        id_base = World.AddMesh(new CMesher2D(cad2d, 0.04));
                    }
                    // CADのIDからワールド座標系のIDへ変換するコンバーターを取得
                    CIDConvEAMshCad conv = World.GetIDConverter(id_base);

                    // フィールドを作成する
                    //   図形の次元2次元、値、コーナー(要素の角頂点)
                    uint id_field_val = World.MakeField_FieldElemDim(
                        id_base,
                        2,
                        FIELD_TYPE.ZSCALAR,
                        FIELD_DERIVATION_TYPE.VALUE,
                        ELSEG_TYPE.CORNER);
                    //uint id_field_bc0 = World.GetPartialField(id_field_val,conv.GetIdEA_fromCad(2, 1));
                    uint id_field_bc1 = 0;
                    {
                        IList<uint> aEA = new List<uint>();
                        aEA.Add(conv.GetIdEA_fromCad(1, CAD_ELEM_TYPE.EDGE));
                        aEA.Add(conv.GetIdEA_fromCad(2, CAD_ELEM_TYPE.EDGE));
                        aEA.Add(conv.GetIdEA_fromCad(3, CAD_ELEM_TYPE.EDGE));
                        aEA.Add(conv.GetIdEA_fromCad(4, CAD_ELEM_TYPE.EDGE));
                        id_field_bc1 = World.GetPartialField(id_field_val, aEA);
                    }
                    CFieldValueSetter.SetFieldValue_Constant(id_field_bc1, 0, FIELD_DERIVATION_TYPE.VALUE, World, 0);

                    using (CZLinearSystem ls = new CZLinearSystem())
                    using (CZPreconditioner_ILU prec = new CZPreconditioner_ILU())
                    {
                        // 場のパターンをリニアシステムに追加する
                        ls.AddPattern_Field(id_field_val, World);

                        // 境界条件
                        //ls.SetFixedBoundaryCondition_Field(id_field_bc0,World);
                        //ls.SetFixedBoundaryCondition_Field(id_field_bc1,World);

                        // プリコンディショナ―フィルインあり
                        prec.SetFillInLevel(1);
                        // プリコンディショナ―にリニアシステムをセットする
                        prec.SetLinearSystem(ls);

                        // 波長
                        double wave_length = 0.4;

                        // 全体行列の作成
                        ls.InitializeMarge();

                        if (ProbNo == 0)
                        {
                            Console.WriteLine("///// DelFEM4NetFem.Eqn.CEqnHelmholtz");
                            // DelFEMのライブラリを使用
                            CEqnHelmholz.AddLinSys_Helmholtz(ls, wave_length, World, id_field_val);
                            CEqnHelmholz.AddLinSys_SommerfeltRadiationBC(ls, wave_length, World, id_field_bc1);
                        }
                        else
                        {
                            Console.WriteLine("///// CEqnHelmholtz_ForCSharp");
                            // C#で記述した関数を使用(TEST)
                            System.Diagnostics.Debug.Assert(ProbNo == 1);
                            CEqnHelmholtz_ForCSharp.AddLinSysHelmholtz(ls, wave_length, World, id_field_val);
                            CEqnHelmholtz_ForCSharp.AddLinSys_SommerfeltRadiationBC(ls, wave_length, World, id_field_bc1);
                        }
                        double res = ls.FinalizeMarge();

                        // リニアシステムのマトリクスの値をセットしてILU分解を行う
                        prec.SetValue(ls);

                        // 励振:波源を設定する
                        {
                            // 波源の頂点IDからワールド座標系の要素アレイIDを取得する
                            uint id_ea_v = conv.GetIdEA_fromCad(id_v, CAD_ELEM_TYPE.VERTEX);
                            Console.WriteLine(id_ea_v);
                            // 要素アレイを取得する
                            CElemAry ea = World.GetEA(id_ea_v);
                            // 要素セグメントを取得する
                            CElemAry.CElemSeg es = ea.GetSeg(1);  // セグメントID: 1
                            System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.POINT);
                            // 最初の要素の節点番号を取り出す
                            uint[] noes = new uint[1];
                            es.GetNodes(0, noes); // 要素インデックス: 0
                            Console.WriteLine(noes[0]);

                            // 残差ベクトルのポインタを取得
                            using (CZVector_Blk_Ptr residualPtr = ls.GetResidualPtr(id_field_val, ELSEG_TYPE.CORNER, World))
                            {
                                // 節点番号noes[0]の0番目の自由度に値を加算する
                                residualPtr.AddValue(noes[0], 0, new Complex(1, 0));
                            }
                        }
                        Console.WriteLine("Residual : " + res);
                        {
                            double tol = 1.0e-6;
                            uint iter = 2000;
                            //CZSolverLsIter.Solve_CG(ref tol, ref iter, ls);
                            //CZSolverLsIter.Solve_PCG(ref tol, ref iter,ls, prec);
                            CZSolverLsIter.Solve_PCOCG(ref tol,ref iter,ls, prec);
                            //CZSolverLsIter.Solve_CGNR(ref tol,ref iter, ls);
                            //CZSolverLsIter.Solve_BiCGSTAB(ref tol,ref iter,ls);
                            //CZSolverLsIter.Solve_BiCGStabP(ref tol, ref iter,ls, prec);
                            Console.WriteLine(iter + " " + tol);
                        }
                        ls.UpdateValueOfField(id_field_val, World, FIELD_DERIVATION_TYPE.VALUE);
                    }

                    // 描画オブジェクトアレイの追加
                    DrawerAry.Clear();
                    DrawerAry.PushBack(new CDrawerFace(id_field_val, true, World, id_field_val, -0.05, 0.05));
                    //DrawerAry.PushBack( new CDrawerFaceContour(id_field_ val, World) );
                    DrawerAry.PushBack(new CDrawerEdge(id_field_val, true, World));
                    DrawerAry.InitTrans(Camera);
                }
                success = true;
            }
            catch (Exception exception)
            {
                Console.WriteLine(exception.Message + " " + exception.StackTrace);
            }

            ProbNo++;
            if (ProbNo == ProbCnt) ProbNo = 0;
            return success;
        }
コード例 #12
0
        private const bool DefIsSVEA = true; // Φ = φ(x, y) exp(-jβx) と置く方法

        #endregion Fields

        #region Methods

        /// <summary>
        /// 周期構造導波路開口境界条件
        /// </summary>
        /// <param name="ls">リニアシステム</param>
        /// <param name="waveLength">波長</param>
        /// <param name="world">ワールド座標系</param>
        /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param>
        /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param>
        /// <param name="fixedBcNodes">強制境界節点配列</param>
        /// <param name="isInputPort">入射ポート?</param>
        /// <param name="incidentModeIndex">入射モードのインデックス</param>
        /// <param name="isFreeBc">境界条件を課さない?</param>
        /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param>
        /// <param name="eigen_values">固有値配列</param>
        /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param>
        /// <returns></returns>
        public static bool AddLinSys_PeriodicWaveguidePortBC(
            CZLinearSystem ls,
            double waveLength,
            WaveModeDV waveModeDv,
            double periodicDistance,
            CFieldWorld world,
            uint fieldInputWgLoopId,
            uint fieldPortBcId1,
            uint[] fixedBcNodes,
            bool isInputPort,
            int incidentModeIndex,
            Complex[] amps,
            bool isFreeBc,
            double[,] ryy_1d,
            Complex[] eigen_values,
            Complex[,] eigen_vecs,
            Complex[,] eigen_dFdXs)
        {
            if (!world.IsIdField(fieldInputWgLoopId))
            {
                return false;
            }
            // フィールドを取得
            CField valField = world.GetField(fieldInputWgLoopId);
            if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR)
            {
                return false;
            }

            bool res;

            //境界節点番号→全体節点番号変換テーブル(no_c_all)
            uint[] no_c_all = null;
            // 全体節点番号→境界節点番号変換テーブル(to_no_boundary
            Dictionary<uint, uint> to_no_boundary = null;

            // 境界上のすべての節点番号を取り出す
            res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary);
            if (!res)
            {
                return false;
            }

            // 境界条件をリニアシステムに設定する
            uint ntmp = ls.GetTmpBufferSize();
            int[] tmpBuffer = new int[ntmp];
            for (int i = 0; i < ntmp; i++)
            {
                tmpBuffer[i] = -1;
            }
            res = addLinSys_PeriodicWaveguidePortBC_Core(
                ls,
                waveLength,
                waveModeDv,
                periodicDistance,
                world,
                fieldPortBcId1,
                isInputPort,
                incidentModeIndex,
                amps,
                isFreeBc,
                ryy_1d,
                eigen_values,
                eigen_vecs,
                eigen_dFdXs,
                no_c_all,
                ref tmpBuffer);
            if (!res)
            {
                return false;
            }

            return true;
        }
コード例 #13
0
        /// <summary>
        /// 周期構造導波路開口固有値解析(FEM行列と固有モードの取得)
        /// </summary>
        /// <param name="ls">リニアシステム</param>
        /// <param name="waveLength">波長</param>
        /// <param name="world">ワールド座標系</param>
        /// <param name="fieldInputWgLoopId">フィールド値ID(周期構造領域のループ)</param>
        /// <param name="fieldPortBcId1">フィールド値ID(周期構造領域の境界1)</param>
        /// <param name="fieldInputWgBcId1">フィールド値ID(周期構造領域の境界2=内部側境界)</param>
        /// <param name="fixedBcNodes">強制境界節点配列</param>
        /// <param name="IsPCWaveguide">フォトニック結晶導波路?</param>
        /// <param name="PCWaveguidePorts">フォトニック結晶導波路のポート(ロッド欠陥部分)の節点のリスト</param>
        /// <param name="medias">媒質リスト</param>
        /// <param name="inputWgLoopDic1">周期構造領域のワールド座標系ループ→ループ情報マップ</param>
        /// <param name="inputWgEdgeDic1">周期構造領域のワールド座標系辺→辺情報マップ</param>
        /// <param name="isPortBc2Reverse">境界2の方向が境界1と逆方向?</param>
        /// <param name="ryy_1d">1次元有限要素法[ryy]配列</param>
        /// <param name="eigen_values">固有値配列</param>
        /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param>
        /// <returns></returns>
        public static bool GetPortPeriodicWaveguideFemMatAndEigenVec(
            CZLinearSystem ls,
            double waveLength,
            WaveModeDV waveModeDv,
            CFieldWorld world,
            uint fieldInputWgLoopId,
            uint fieldPortBcId1,
            uint fieldInputWgBcId1,
            uint[] fixedBcNodes,
            bool IsPCWaveguide,
            double latticeA,
            double periodicDistance,
            IList<IList<uint>> PCWaveguidePorts,
            int incidentModeIndex,
            bool isSolveEigenItr,
            int propModeCntToSolve,
            bool isSVEA,
            bool isModeTrace,
            ref KrdLab.clapack.Complex[][] PrevModalVecList,
            double minBeta,
            double maxBeta,
            double minWaveNum,
            double maxWaveNum,
            IList<MediaInfo> medias,
            Dictionary<uint, wg2d.World.Loop> inputWgLoopDic1,
            Dictionary<uint, World.Edge> inputWgEdgeDic1,
            bool isPortBc2Reverse,
            out double[,] ryy_1d,
            out Complex[] eigen_values,
            out Complex[,] eigen_vecs,
            out Complex[,] eigen_dFdXs)
        {
            ryy_1d = null;
            eigen_values = null;
            eigen_vecs = null;
            eigen_dFdXs = null;

            if (!world.IsIdField(fieldInputWgLoopId))
            {
                return false;
            }
            // フィールドを取得
            CField valField = world.GetField(fieldInputWgLoopId);
            if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR)
            {
                return false;
            }

            bool res;

            //境界節点番号→全体節点番号変換テーブル(no_c_all)
            uint[] no_c_all = null;
            // 全体節点番号→境界節点番号変換テーブル(to_no_boundary
            Dictionary<uint, uint> to_no_boundary = null;
            // 節点座標
            double[,] coord_c_all = null;

            // 導波管の幅取得
            double[] coord_c_first = null;
            double[] coord_c_last = null;
            double waveguideWidth = 0;
            res = WgUtil.getRectangleWaveguideStructInfo(world, fieldPortBcId1, out coord_c_first, out coord_c_last, out waveguideWidth);
            if (!res)
            {
                return false;
            }
            // Y方向に周期構造?
            bool isYDirectionPeriodic = false;
            if (Math.Abs(coord_c_first[1] - coord_c_last[1]) < 1.0e-12)
            {
                isYDirectionPeriodic = true;
            }
            // 回転移動
            double[] rotOrigin = null;
            double rotAngle = 0.0; // ラジアン
            if (!isYDirectionPeriodic)
            {
                // 境界の傾きから回転角度を算出する
                if (Math.Abs(coord_c_first[0] - coord_c_last[0]) >= 1.0e-12)
                {
                    // X軸からの回転角
                    rotAngle = Math.Atan2((coord_c_last[1] - coord_c_first[1]), (coord_c_last[0] - coord_c_first[0]));
                    // Y軸からの回転角に変換 (境界はY軸に平行、X方向周期構造)
                    rotAngle = rotAngle - 0.5 * pi;
                    rotOrigin = coord_c_first;
                    System.Diagnostics.Debug.WriteLine("rotAngle: {0} rotOrigin:{1} {2}", rotAngle * 180.0 / pi, rotOrigin[0], rotOrigin[1]);
                }
            }

            // 境界上のすべての節点番号を取り出す
            res = WgUtil.GetBoundaryNodeList(world, fieldPortBcId1, out no_c_all, out to_no_boundary);
            if (!res)
            {
                return false;
            }

            // 境界積分用ryy_1dを取得する
            //   周期境界1について取得する
            res = getPortWaveguideFemMat(
                waveLength,
                world,
                fieldPortBcId1,
                fixedBcNodes,
                coord_c_first,
                waveguideWidth,
                no_c_all,
                to_no_boundary,
                medias,
                inputWgEdgeDic1,
                out ryy_1d,
                out coord_c_all);
            if (!res)
            {
                return false;
            }

            // 周期構造導波路の固有値、固有ベクトルを取得する
            //   固有ベクトルは境界上のみを取得する
            //uint max_mode = 1;
            uint max_mode = int.MaxValue;
            res = solvePortPeriodicWaveguideEigen(
                ls,
                waveLength,
                waveModeDv,
                isYDirectionPeriodic,
                rotAngle,
                rotOrigin,
                world,
                fieldInputWgLoopId,
                fieldPortBcId1,
                fieldInputWgBcId1,
                fixedBcNodes,
                IsPCWaveguide,
                latticeA,
                periodicDistance,
                PCWaveguidePorts,
                incidentModeIndex,
                isSolveEigenItr,
                propModeCntToSolve,
                isSVEA,
                max_mode,
                isModeTrace,
                ref PrevModalVecList,
                minBeta,
                maxBeta,
                minWaveNum,
                maxWaveNum,
                medias,
                inputWgLoopDic1,
                inputWgEdgeDic1,
                isPortBc2Reverse,
                ryy_1d,
                out eigen_values,
                out eigen_vecs,
                out eigen_dFdXs);
            if (!res)
            {
                return false;
            }

            return true;
        }
コード例 #14
0
        /// <summary>
        /// 矩形導波管開口反射(透過)係数
        ///    ※要素アレイは1つに限定しています。
        ///     ポート境界を指定するときに複数の辺をリストで境界条件設定することでこの条件をクリアできます。
        /// </summary>
        /// <param name="ls">リニアシステム</param>
        /// <param name="waveLength">波長</param>
        /// <param name="fieldValId">フィールド値のID</param>
        /// <param name="imode">固有モードのモード次数</param>
        /// <param name="isIncidentMode">入射モード?</param>
        /// <param name="ryy_1d">[ryy]FEM行列</param>
        /// <param name="eigen_values">固有値配列</param>
        /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param>
        /// <returns>散乱係数</returns>
        public static Complex GetPeriodicWaveguidePortReflectionCoef(
            CZLinearSystem ls,
            double waveLength,
            WaveModeDV waveModeDv,
            double periodicDistance,
            CFieldWorld world,
            uint fieldValId,
            uint imode,
            bool isIncidentMode,
            Complex[] amps,
            double[,] ryy_1d,
            Complex[] eigen_values,
            Complex[,] eigen_vecs,
            Complex[,] eigen_dFdXs)
        {
            Complex s11 = new Complex(0.0, 0.0);
            if (ryy_1d == null || eigen_values == null || eigen_vecs == null)
            {
                return s11;
            }
            if (!world.IsIdField(fieldValId))
            {
                return s11;
            }
            CField valField = world.GetField(fieldValId);
            if (valField.GetFieldType() != FIELD_TYPE.ZSCALAR)
            {
                return s11;
            }

            bool res;

            //境界節点番号→全体節点番号変換テーブル(no_c_all)
            uint[] no_c_all = null;
            // 全体節点番号→境界節点番号変換テーブル(to_no_boundary
            Dictionary<uint, uint> to_no_boundary = null;

            // 境界上のすべての節点番号を取り出す
            res = GetBoundaryNodeList(world, fieldValId, out no_c_all, out to_no_boundary);
            if (!res)
            {
                return s11;
            }

            // 境界上のすべての節点の界の値を取り出す
            Complex[] value_c_all = null;
            res = WgUtil.GetBoundaryFieldValueList(world, fieldValId, no_c_all, to_no_boundary, out value_c_all);
            if (!res)
            {
                return s11;
            }

            uint node_cnt = (uint)no_c_all.Length;
            System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(0));
            System.Diagnostics.Debug.Assert(node_cnt == ryy_1d.GetLength(1));
            System.Diagnostics.Debug.Assert(node_cnt == eigen_vecs.GetLength(1));
            s11 = getPeriodicWaveguidePortReflectionCoef_Core(
                waveLength,
                waveModeDv,
                periodicDistance,
                imode,
                isIncidentMode,
                amps,
                no_c_all,
                to_no_boundary,
                value_c_all,
                ryy_1d,
                eigen_values,
                eigen_vecs,
                eigen_dFdXs);

            return s11;
        }
コード例 #15
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        /// <param name="Ls"></param>
        /// <param name="Prec"></param>
        /// <param name="tmpBuffer"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        public static bool SolvePCOCG(
            ref CFieldWorld World, ref uint FieldValId,
            ref CZLinearSystem Ls, ref CZPreconditioner_ILU Prec, ref int[] tmpBuffer,
            ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            //------------------------------------------------------------------
            // マージの終了
            //------------------------------------------------------------------
            double res = Ls.FinalizeMarge();

            tmpBuffer = null;

            // マトリクスサイズの取得
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            // マトリクスのサイズ
            int matLen = (int)mat_cc.NBlkMatCol();

            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG : CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret  = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);

            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG solved");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList <uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry          ea      = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint    ino_global = no_c[ino];
                            Complex cvalue     = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real      = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Ls = null;
            Prec.Clear();
            Prec.Dispose();
            Prec = null;
            World.Clear();
            World.Dispose();
            World = null;
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return(success);
        }
コード例 #16
0
        ////////////////////////////////////////////////////////////////////////////////////////////////
        // DekFEMの処理を隠ぺいした簡易版
        ////////////////////////////////////////////////////////////////////////////////////////////////
        /// <summary>
        /// PCOCGで線形方程式を解く
        /// </summary>
        /// <param name="mat"></param>
        /// <param name="resVec"></param>
        /// <param name="value_c_all"></param>
        /// <param name="isConverged"></param>
        /// <returns></returns>
        //public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref System.Numerics.Complex[] resVec, out System.Numerics.Complex[] value_c_all, out bool isConverged)
        public static bool SolvePCOCG(ref MyUtilLib.Matrix.MyComplexMatrix mat, ref KrdLab.clapack.Complex[] resVec, out KrdLab.clapack.Complex[] value_c_all, out bool isConverged)
        {
            bool success = false;

            int matLen = mat.RowSize;

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 1");
            //------------------------------------------------------------------
            // ワールド座標系を生成
            //------------------------------------------------------------------
            uint        baseId = 0;
            CFieldWorld World  = new CFieldWorld();

            setupWorld((uint)matLen, ref World, out baseId);

            // 界の値を扱うバッファ?を生成する。
            // フィールド値IDが返却される。
            //    要素の次元: 2次元-->ポイントにしたので0次元? 界: 複素数スカラー 微分タイプ: 値 要素セグメント: 角節点
            uint FieldValId = World.MakeField_FieldElemDim(baseId, 0,
                                                           FIELD_TYPE.ZSCALAR, FIELD_DERIVATION_TYPE.VALUE, ELSEG_TYPE.CORNER);

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 2");
            //------------------------------------------------------------------
            // リニアシステム
            //------------------------------------------------------------------
            CZLinearSystem       Ls   = new CZLinearSystem();
            CZPreconditioner_ILU Prec = new CZPreconditioner_ILU();

            //------------------------------------------------------------------
            // 界パターン追加
            //------------------------------------------------------------------
            Ls.AddPattern_Field(FieldValId, World);
            //  POINTのフィールドなので対角要素のパターンのみ追加される。非対角要素のパターンは追加されない

            // 非対角要素のパターンの追加
            {
                uint node_cnt = (uint)matLen;
                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                // パターンを追加
                using (CIndexedArray crs = new CIndexedArray())
                {
                    crs.InitializeSize(mat_cc.NBlkMatCol());

                    //crs.Fill(mat_cc.NBlkMatCol(), mat_cc.NBlkMatRow());
                    using (UIntVectorIndexer index = crs.index)
                        using (UIntVectorIndexer ary = crs.array)
                        {
                            for (int iblk = 0; iblk < (int)crs.Size(); iblk++)
                            {
                                index[iblk] = 0;
                            }
                            for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                            {
                                // 現在のマトリクスのインデックス設定をコピーする
                                uint npsup = 0;
                                ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                                foreach (uint row_index in cur_rows)
                                {
                                    ary.Add(row_index);
                                }
                                index[iblk + 1] = (uint)ary.Count;
                                //System.Diagnostics.Debug.WriteLine("chk:{0} {1}", iblk, npsup);
                                // Note: インデックス設定はされていないので常にnpsup == 0 (cur_rows.Count == 0)

                                // すべての節点に関して列を追加
                                int ino_global = iblk;
                                int col        = iblk;
                                if (col != -1 && ino_global != -1)
                                {
                                    // 関連付けられていない節点をその行の列データの最後に追加
                                    int last_index = (int)index[col + 1] - 1;
                                    int add_cnt    = 0;
                                    for (int jno_global = 0; jno_global < node_cnt; jno_global++)
                                    {
                                        // 行列の0要素を除く
                                        //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < Constants.PrecisionLowerLimit)
                                        //if (System.Numerics.Complex.Abs(mat[(int)ino_global, (int)jno_global]) < 1.0e-15)
                                        //if (mat._body[ino_global + jno_global * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                                        KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                        if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                                        {
                                            continue;
                                        }
                                        uint row = (uint)jno_global;
                                        if (ino_global != jno_global) // 対角要素は除く
                                        {
                                            if (!cur_rows.Contains(row))
                                            {
                                                ary.Insert(last_index + 1 + add_cnt, row);
                                                add_cnt++;
                                                //System.Diagnostics.Debug.WriteLine("added:" + col + " " + row);
                                            }
                                        }
                                    }
                                    if (add_cnt > 0)
                                    {
                                        index[col + 1] = (uint)ary.Count;
                                    }
                                }
                            }
                        }
                    crs.Sort();
                    System.Diagnostics.Debug.Assert(crs.CheckValid());
                    // パターンを削除する
                    mat_cc.DeletePattern();
                    // パターンを追加する
                    mat_cc.AddPattern(crs);
                }
            }

            System.Diagnostics.Debug.WriteLine("SolvePCOCG 3");
            //------------------------------------------------------------------
            // プリコンディショナ―
            //------------------------------------------------------------------
            // set Preconditioner
            //Prec.SetFillInLevel(1);
            // フィルインなしで不完全LU分解した方が収束が早く、また解もそれなりの結果だったので0に設定した
            //Prec.SetFillInLevel(0);
            // フィルインなしでは、収束しない場合がある。フィルインレベルを最大にする
            //Prec.SetFillInLevel((uint)mat.RowSize);
            //   完全LU分解(だと思われる) Prec.SetLinearSystemの処理が遅い
            //Prec.SetFillInLevel(3);
            //   誘電体スラブ導波路だと最低このレベル。これでも収束しない場合がある
            //以上から
            //メインの導波管の計算時間を短くしたいのでフィルインなしにする
            //Prec.SetFillInLevel(0);
            //    導波管だとこれで十分
            // フィルインレベルの設定(既定値)
            Prec.SetFillInLevel(DefFillInLevel);
            // ILU(0)のパターン初期化
            Prec.SetLinearSystem(Ls);
            System.Diagnostics.Debug.WriteLine("SolvePCOCG 4");

            //------------------------------------------------------------------
            // 剛性行列、残差ベクトルのマージ
            //------------------------------------------------------------------
            Ls.InitializeMarge();
            {
                uint  ntmp      = Ls.GetTmpBufferSize();
                int[] tmpBuffer = new int[ntmp];
                for (int i = 0; i < ntmp; i++)
                {
                    tmpBuffer[i] = -1;
                }

                uint node_cnt = (uint)matLen;

                // 要素剛性行列(コーナ-コーナー)
                CZMatDia_BlkCrs_Ptr mat_cc = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
                // 要素残差ベクトル(コーナー)
                CZVector_Blk_Ptr res_c = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);

                bool[,] add_flg = new bool[node_cnt, node_cnt];
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        add_flg[i, j] = false;
                        // 0要素はマージ対象でないので最初から除外する
                        //if (System.Numerics.Complex.Abs(mat[i, j]) < Constants.PrecisionLowerLimit)
                        //if (mat._body[i + j * mat.RowSize].Magnitude < Constants.PrecisionLowerLimit)
                        KrdLab.clapack.Complex cvalue = mat._body[i + j * mat.RowSize];
                        if (cvalue.Real == 0 && cvalue.Imaginary == 0)
                        {
                            add_flg[i, j] = true;
                        }
                    }
                }
                for (int iblk = 0; iblk < mat_cc.NBlkMatCol(); iblk++)
                {
                    // 自分及び自分自身と関連のある"row"の要素をマージする( 1 x rowcntのベクトル : 行列の横ベクトルに対応)
                    uint npsup = 0;
                    ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                    uint      colcnt       = 1;
                    uint      rowcnt       = (uint)cur_rows.Count + 1; // cur_rowsには自分自身は含まれないので+1する
                    Complex[] emattmp      = new Complex[colcnt * rowcnt];
                    uint[]    no_c_tmp_col = new uint[colcnt];
                    uint[]    no_c_tmp_row = new uint[rowcnt];
                    no_c_tmp_col[0] = (uint)iblk;
                    no_c_tmp_row[0] = (uint)iblk;
                    for (int irow = 0; irow < cur_rows.Count; irow++)
                    {
                        no_c_tmp_row[irow + 1] = cur_rows[irow];
                    }
                    {
                        uint ino        = 0;
                        uint ino_global = no_c_tmp_col[ino];
                        for (int jno = 0; jno < rowcnt; jno++)
                        {
                            uint jno_global = no_c_tmp_row[jno];
                            //emat[ino, jno]
                            if (!add_flg[ino_global, jno_global])
                            {
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat[ino_global, jno_global];
                                //System.Numerics.Complex cvalue = (System.Numerics.Complex)mat._body[ino_global + jno_global * mat.RowSize];
                                KrdLab.clapack.Complex cvalue = mat._body[ino_global + jno_global * mat.RowSize];
                                emattmp[ino * rowcnt + jno]     = new Complex(cvalue.Real, cvalue.Imaginary);
                                add_flg[ino_global, jno_global] = true;
                            }
                            else
                            {
                                // ここにはこない
                                System.Diagnostics.Debug.Assert(false);
                                emattmp[ino * rowcnt + jno] = new Complex(0, 0);
                            }
                        }
                    }
                    // マージ!
                    mat_cc.Mearge(1, no_c_tmp_col, rowcnt, no_c_tmp_row, 1, emattmp, ref tmpBuffer);
                }
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] );
                        System.Diagnostics.Debug.Assert(add_flg[i, j]);
                    }
                }

                // 残差ベクトルにマージ
                for (uint ino_global = 0; ino_global < node_cnt; ino_global++)
                {
                    // 残差ベクトルにマージする
                    uint no_tmp = ino_global;
                    //System.Numerics.Complex cvalue = resVec[ino_global];
                    KrdLab.clapack.Complex cvalue = resVec[ino_global];
                    Complex val = new Complex(cvalue.Real, cvalue.Imaginary);
                    res_c.AddValue(no_tmp, 0, val);
                }
            }
            double res = Ls.FinalizeMarge();

            //------------------------------------------------------------------
            // リニアシステムを解く
            //------------------------------------------------------------------
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 5: CZSolverLsIter.Solve_PCOCG");
            // プリコンディショナに値を設定してILU分解を行う
            Prec.SetValue(Ls);
            //double tol = 1.0e-1;
            //double tol = 1.0e-2;
            //double tol = 0.5e-3;
            //double tol = 1.0e-4;
            double tol = 1.0e-6;
            //uint maxIter = 500;
            //uint maxIter = 1000;
            //uint maxIter = 2000;
            //uint maxIter = 5000;
            //uint maxIter = 10000;
            uint maxIter = 20000;
            //uint maxIter = uint.MaxValue;
            uint iter = maxIter;
            bool ret  = CZSolverLsIter.Solve_PCOCG(ref tol, ref iter, Ls, Prec);

            System.Diagnostics.Debug.WriteLine("iter : " + iter + " Res : " + tol + " ret : " + ret);
            if (iter == maxIter)
            {
                System.Diagnostics.Debug.WriteLine("Not converged");
                isConverged = false;
            }
            else
            {
                isConverged = true;
            }
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG 6");

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

            {
                uint node_cnt = (uint)matLen;
                //value_c_all = new System.Numerics.Complex[node_cnt]; // コーナーの値
                value_c_all = new KrdLab.clapack.Complex[node_cnt]; // コーナーの値

                CField valField = World.GetField(FieldValId);
                // 要素アレイIDのリストを取得
                IList <uint> aIdEA = valField.GetAryIdEA();
                // 要素アレイを走査
                foreach (uint eaId in aIdEA)
                {
                    CElemAry          ea      = World.GetEA(eaId);
                    CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, World);
                    CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, World);
                    // 要素の節点数
                    uint nno = 1; //点
                    // 要素節点の全体節点番号
                    uint[] no_c = new uint[nno];
                    // 要素節点の値
                    Complex[] value_c = new Complex[nno];
                    // 節点の値の節点セグメント
                    CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, World);
                    for (uint ielem = 0; ielem < ea.Size(); ielem++)
                    {
                        // 要素配列から要素セグメントの節点番号を取り出す
                        es_c_co.GetNodes(ielem, no_c);

                        // 節点の値を取って来る
                        es_c_va.GetNodes(ielem, no_c);
                        for (uint inoes = 0; inoes < nno; inoes++)
                        {
                            Complex[] tmpval = null;
                            ns_c_val.GetValue(no_c[inoes], out tmpval);
                            System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                            value_c[inoes] = tmpval[0];
                            //System.Diagnostics.Debug.Write( "(" + value_c[inoes].Real + "," + value_c[inoes].Imag + ")" );
                        }

                        for (uint ino = 0; ino < nno; ino++)
                        {
                            //DelFEMの節点番号は0開始
                            //uint ino_global = no_c[ino] - 1;
                            uint    ino_global = no_c[ino];
                            Complex cvalue     = value_c[ino];
                            //value_c_all[ino_global] = new KrdLab.clapack.Complex(cvalue.Real, cvalue.Imag);
                            value_c_all[ino_global].Real      = cvalue.Real;
                            value_c_all[ino_global].Imaginary = cvalue.Imag;
                        }
                    }
                }
            }

            Ls.Clear();
            Ls.Dispose();
            Prec.Clear();
            Prec.Dispose();
            World.Clear();
            World.Dispose();
            System.Diagnostics.Debug.WriteLine("Solve_PCOCG End");
            return(success);
        }
コード例 #17
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// 非対称複素行列の連立方程式をLisys(clapack)で解く
        /// </summary>
        /// <param name="Ls"></param>
        /// <param name="World"></param>
        /// <param name="FieldValId"></param>
        private static void solveAsymmetricCompplexMatEqn(CZLinearSystem Ls, CFieldWorld World, uint FieldValId)
        {
            // 非対称複素行列の連立方程式をLisys(clapack)で解く
            CZMatDia_BlkCrs_Ptr femMat = Ls.GetMatrixPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            uint nblk = femMat.NBlkMatCol();
            KrdLab.clapack.Complex[] A = new KrdLab.clapack.Complex[nblk * nblk];

            System.Diagnostics.Debug.Assert(nblk == femMat.NBlkMatRow());
            for (uint iblk = 0; iblk < nblk; iblk++)
            {
                ComplexArrayIndexer ptr = femMat.GetPtrValDia(iblk);
                System.Diagnostics.Debug.Assert(ptr.Count == 1);
                A[iblk + nblk * iblk].Real = ptr[0].Real;
                A[iblk + nblk * iblk].Imaginary = ptr[0].Imag;
                //Console.WriteLine("    ( " + iblk + " ) = " + ptr[0].Real + " + " + ptr[0].Imag + " i");

                uint npsup = 0;
                ConstUIntArrayIndexer ptrInd = femMat.GetPtrIndPSuP(iblk, out npsup);
                ComplexArrayIndexer ptrVal = femMat.GetPtrValPSuP(iblk, out npsup);
                System.Diagnostics.Debug.Assert(ptrInd.Count == ptrVal.Count);
                for (int i = 0; i < ptrVal.Count; i++)
                {
                    A[iblk + nblk * ptrInd[i]].Real = ptrVal[i].Real;
                    A[iblk + nblk * ptrInd[i]].Imaginary = ptrVal[i].Imag;
                    //Console.WriteLine("    ( " + iblk + ", " + ptrInd[i] + " ) = " + ptrVal[i].Real + " + " + ptrVal[i].Imag + " i");
                }
            }
            // 残差ベクトル
            CZVector_Blk_Ptr resPtr = Ls.GetResidualPtr(FieldValId, ELSEG_TYPE.CORNER, World);
            System.Diagnostics.Debug.Assert(nblk == resPtr.BlkVecLen());
            System.Diagnostics.Debug.Assert(1 == resPtr.BlkLen());
            KrdLab.clapack.Complex[] B = new KrdLab.clapack.Complex[nblk];
            for (uint iblk = 0; iblk < resPtr.BlkVecLen(); iblk++)
            {
                Complex cvalue = resPtr.GetValue(iblk, 0);
                B[iblk].Real = cvalue.Real;
                B[iblk].Imaginary = cvalue.Imag;
                //System.Console.WriteLine("res( " + iblk + " ) = " + resPtr.GetValue(iblk, 0));
            }
            // 対称行列チェック
            bool isSymmetrix = true;
            for (int i = 0; i < nblk; i++)
            {
                for (int j = i; j < nblk; j++)
                {
                    KrdLab.clapack.Complex aij = A[i + nblk * j];
                    KrdLab.clapack.Complex aji = A[j + nblk * i];
                    if (Math.Abs(aij.Real - aji.Real) >= 1.0e-12)
                    {
                        isSymmetrix = false;
                        break;
                        //System.Diagnostics.Debug.Assert(false);
                    }
                    if (Math.Abs(aij.Imaginary - aji.Imaginary) >= 1.0e-12)
                    {
                        isSymmetrix = false;
                        break;
                        //System.Diagnostics.Debug.Assert(false);
                    }
                }
                if (!isSymmetrix)
                {
                    break;
                }
            }
            if (!isSymmetrix)
            {
                System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix A is NOT symmetric!!!!!!!!!!!!!!");
                //System.Diagnostics.Debug.Assert(false);
            }

            // 非対称行列の線形方程式を解く
            // 解ベクトル
            KrdLab.clapack.Complex[] X = null;
            // 連立方程式AX = Bを解く
            int x_row = (int)nblk;
            int x_col = 1;
            int a_row = (int)nblk;
            int a_col = (int)nblk;
            int b_row = (int)nblk;
            int b_col = 1;
            System.Diagnostics.Debug.WriteLine("solve : KrdLab.clapack.FunctionExt.zgesv");
            KrdLab.clapack.FunctionExt.zgesv(ref X, ref x_row, ref x_col, A, a_row, a_col, B, b_row, b_col);

            // 解ベクトルをワールド座標系にセット
            Complex[] valuesAll = new Complex[nblk];
            Dictionary<uint, uint> toNodeIndex = new Dictionary<uint, uint>();
            for (uint i = 0; i < nblk; i++)
            {
                valuesAll[i] = new Complex(X[i].Real, X[i].Imaginary);
                toNodeIndex.Add(i, i);
            }
            WgUtil.SetFieldValueForDisplay(World, FieldValId, valuesAll, toNodeIndex);
        }
コード例 #18
0
        /// <summary>
        /// ヘルムホルツの方程式 剛性行列 残差ベクトルの追加(要素アレイ単位)
        /// </summary>
        /// <param name="ls"></param>
        /// <param name="waveLength"></param>
        /// <param name="world"></param>
        /// <param name="fieldValId"></param>
        /// <param name="eaId"></param>
        /// <param name="tmpBuffer"></param>
        /// <returns></returns>
        private static bool AddLinSysHelmholtz_EachElementAry(CZLinearSystem ls, double waveLength, CFieldWorld world, uint fieldValId, uint eaId, int[] tmpBuffer)
        {
            System.Diagnostics.Debug.Assert(world.IsIdEA(eaId));
            CElemAry ea = world.GetEA(eaId);
            System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.TRI);
            if (!world.IsIdField(fieldValId))
            {
                return false;
            }
            CField valField = world.GetField(fieldValId);
            CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world);
            CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world);

            // 三角形要素の節点数
            uint nno = 3;
            // 座標の次元
            uint ndim = 2;
            // 要素節点の全体節点番号
            uint[] no_c = new uint[nno];
            // 要素節点の値
            Complex[] value_c = new Complex[nno];
            // 要素節点の座標
            double[][] coord_c = new double[nno][];
            for (int inoes = 0; inoes < nno; inoes++)
            {
                coord_c[inoes] = new double[ndim];
            }
            // 要素剛性行列のバッファ (i, j) --> (i * rowSize + j)
            Complex[] ematBuffer = new Complex[nno * nno];
            // 要素節点等価内力、外力、残差ベクトル
            Complex[] eres_c = new Complex[nno];
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world);
            // 要素残差ベクトル(コーナー)
            CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world);

            CNodeAry.CNodeSeg ns_c_val = valField.GetNodeSeg(ELSEG_TYPE.CORNER, true, world);
            CNodeAry.CNodeSeg ns_c_co = valField.GetNodeSeg(ELSEG_TYPE.CORNER, false, world);

            for (uint ielem = 0; ielem < ea.Size(); ielem++)
            {
                // 要素配列から要素セグメントの節点番号を取り出す
                es_c_co.GetNodes(ielem, no_c);
                // 座標を取得
                for (uint inoes = 0; inoes < nno; inoes++)
                {
                    double[] tmpval = null;
                    ns_c_co.GetValue(no_c[inoes], out tmpval);
                    System.Diagnostics.Debug.Assert(tmpval.Length == ndim);

                    for (int i = 0; i < tmpval.Length; i++)
                    {
                        coord_c[inoes][i] = tmpval[i];
                    }
                    //Console.WriteLine("coord_c [" + no_c[inoes] + " ] = " + coord_c[inoes, 0] + " " +  coord_c[inoes, 1]);
                }
                // 節点の値を取って来る
                es_c_va.GetNodes(ielem, no_c);
                for (uint inoes = 0; inoes < nno; inoes++)
                {
                    Complex[] tmpval = null;
                    ns_c_val.GetValue(no_c[inoes], out tmpval);
                    System.Diagnostics.Debug.Assert(tmpval.Length == 1);
                    value_c[inoes] = tmpval[0];
                    //Console.WriteLine("value_c [" + no_c[inoes] + " ] = " + tmpval[0].Real + " " +  tmpval[0].Imag);
                }

                // 節点座標
                double[] p1 = coord_c[0];
                double[] p2 = coord_c[1];
                double[] p3 = coord_c[2];
                // 面積を求める
                double area = CKerEMatTri.TriArea(p1, p2, p3);

                // 形状関数の微分を求める
                double[,] dldx = null;
                double[] const_term = null;
                CKerEMatTri.TriDlDx(out dldx, out const_term, p1, p2, p3);

                // 要素剛性行列を作る
                for (int ino = 0; ino < nno; ino++)
                {
                    for (int jno = 0; jno < nno; jno++)
                    {
                        //emat[ino, jno]
                        ematBuffer[ino * nno + jno] = area * (dldx[ino, 0] * dldx[jno, 0] + dldx[ino, 1] * dldx[jno, 1]);
                    }
                }
                double k0 = 2 * pi / waveLength;
                double tmp_val = k0 * k0 * area / 12.0;
                for (int ino = 0; ino < nno; ino++)
                {
                    //emat[ino, ino]
                    ematBuffer[ino * nno + ino] -= new Complex(tmp_val);
                    for (int jno = 0; jno < nno; jno++)
                    {
                        //emat[ino, jno]
                        ematBuffer[ino * nno + jno] -= new Complex(tmp_val);
                    }
                }
                // 要素節点等価内力ベクトルを求める
                for (int ino = 0; ino < nno; ino++)
                {
                    eres_c[ino] = new Complex(0.0);
                    for (int jno = 0; jno < nno; jno++)
                    {
                        eres_c[ino] -= ematBuffer[ino * nno + jno] * value_c[jno];
                    }
                }
                // 要素剛性行列にマージする
                mat_cc.Mearge(nno, no_c, nno, no_c, 1, ematBuffer, ref tmpBuffer);

                // 残差ベクトルにマージする
                for (int inoes = 0; inoes < nno; inoes++)
                {
                    res_c.AddValue(no_c[inoes], 0, eres_c[inoes]);
                }
            }

            return true;
        }
コード例 #19
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <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;
        }
コード例 #20
0
ファイル: MainLogic.cs プロジェクト: ryujimiya/delfem4net
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainLogic()
        {
            Disposed = false;
            Camera = new CCamera();
            DrawerAry = new CDrawerArrayField();
            World = new CFieldWorld();
            //FieldValueSetter = new CFieldValueSetter();
            Ls = new CZLinearSystem();
            Prec = new CZPreconditioner_ILU();
            ScatterVecList = new List<IList<Complex[]>>();
            CadDrawerAry = new CDrawerArray();
            IsInitedCamera = true;

            // Glutのアイドル時処理でなく、タイマーで再描画イベントを発生させる
            MyTimer.Tick += (sender, e) =>
            {
                if (IsTimerProcRun)
                {
                    return;
                }
                IsTimerProcRun = true;
                if (IsAnimation && FreqIndex != -1 && !IsCadShow)
                {
                    // 問題を解く
                    bool ret = solveProblem(
                        (IsInitedCamera? false : true)
                        );
                    if (FreqIndex != -1)
                    {
                        FreqIndex++;
                    }
                    if (ret)
                    {
                        if (!IsInitedCamera)
                        {
                            IsInitedCamera = true;
                        }
                    }
                    //DEBUG
                    //Glut.glutPostRedisplay();
                    {
                        // POSTだとメッセージが1つにまとめられる場合がある?
                        // 直接描画する
                        int[] viewport = new int[4];
                        Gl.glGetIntegerv(Gl.GL_VIEWPORT, viewport);
                        int winW = viewport[2];
                        int winH = viewport[3];
                        Camera.SetWindowAspect((double)winW / winH);
                        Gl.glViewport(0, 0, winW, winH);
                        Gl.glMatrixMode(Gl.GL_PROJECTION);
                        Gl.glLoadIdentity();
                        DelFEM4NetCom.View.DrawerGlUtility.SetProjectionTransform(Camera);
                        myGlutDisplay();
                    }
                }
                IsTimerProcRun = false;
            };
            //MyTimer.Interval = 1000 / 60;
            MyTimer.Interval = 1000 / 10;
            //MyTimer.Interval = 2000;
        }
コード例 #21
0
        /// <summary>
        /// 矩形導波管開口境界条件(要素アレイ単位)
        /// Note: 境界の要素はy = 0からy = waveguideWidth へ順番に要素アレイに格納され、節点2は次の要素の節点1となっていることが前提
        /// </summary>
        /// <param name="ls">リニアシステム</param>
        /// <param name="waveLength">波長</param>
        /// <param name="world">ワールド座標系</param>
        /// <param name="fieldValId">フィールド値ID</param>
        /// <param name="isInputPort">入射ポート?</param>
        /// <param name="incidentModeIndex">入射モードのインデックス</param>
        /// <param name="isFreeBc">境界条件を課さない?</param>
        /// <param name="ryy_1d">FEM[ryy]行列</param>
        /// <param name="eigen_values">固有値配列</param>
        /// <param name="eigen_vecs">固有ベクトル行列{f}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="eigen_dFdXs">固有ベクトル行列{df/dx}(i,j: i:固有値インデックス j:節点)</param>
        /// <param name="no_c_all">節点番号配列</param>
        /// <param name="tmpBuffer">一時バッファ</param>
        /// <returns></returns>
        private static bool addLinSys_PeriodicWaveguidePortBC_Core(
            CZLinearSystem ls,
            double waveLength,
            WaveModeDV waveModeDv,
            double periodicDistance,
            CFieldWorld world,
            uint fieldValId,
            bool isInputPort,
            int incidentModeIndex,
            Complex[] amps,
            bool isFreeBc,
            double[,] ryy_1d,
            Complex[] eigen_values,
            Complex[,] eigen_vecs,
            Complex[,] eigen_dFdXs,
            uint[] no_c_all,
            ref int[] tmpBuffer)
        {
            double k0 = 2.0 * pi / waveLength;
            double omega = k0 / Math.Sqrt(myu0 * eps0);

            //System.Diagnostics.Debug.Assert(world.IsIdEA(eaId));
            //CElemAry ea = world.GetEA(eaId);
            //System.Diagnostics.Debug.Assert(ea.ElemType() == ELEM_TYPE.LINE);
            if (!world.IsIdField(fieldValId))
            {
                return false;
            }
            CField valField = world.GetField(fieldValId);
            //CElemAry.CElemSeg es_c_va = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, true, world);
            //CElemAry.CElemSeg es_c_co = valField.GetElemSeg(eaId, ELSEG_TYPE.CORNER, false, world);

            // 境界上の節点数(1次線要素を想定)
            uint node_cnt = (uint)ryy_1d.GetLength(0);
            // 考慮するモード数
            uint max_mode = (uint)eigen_values.Length;

            // 全体剛性行列の作成
            Complex[,] mat_all = new Complex[node_cnt, node_cnt];
            for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
            {
                for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++)
                {
                    mat_all[ino_boundary, jno_boundary] = new Complex(0.0, 0.0);
                }
            }
            if (!isFreeBc)
            {
                for (uint imode = 0; imode < max_mode; imode++)
                {
                    Complex betam = eigen_values[imode];

                    Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode);
                    Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode);
                    Complex[] fmVec_Modify = new Complex[fmVec.Length];
                    Complex imagOne = new Complex(0.0, 1.0);
                    DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                    for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                    {
                        //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam);
                        fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic);
                    }
                    //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec);
                    //Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec));
                    Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify);
                    Complex[] vecj = MyMatrixUtil.product(ryy_1d, MyMatrixUtil.vector_Conjugate(fmVec_Modify));
                    for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                    {
                        for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++)
                        {
                            Complex cvalue = 0.0;
                            if (waveModeDv == WaveModeDV.TM)
                            {
                                // TMモード
                                //cvalue = (imagOne / (omega * eps0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary];
                                cvalue = (imagOne / (omega * eps0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary];
                            }
                            else
                            {
                                // TEモード
                                //cvalue = (imagOne / (omega * myu0)) * betam * Complex.Norm(betam) * veci[ino_boundary] * vecj[jno_boundary];
                                cvalue = (imagOne / (omega * myu0)) * (Complex.Norm(betam) * betam_periodic * Complex.Conjugate(betam_periodic) / Complex.Conjugate(betam)) * veci[ino_boundary] * vecj[jno_boundary];
                            }
                            mat_all[ino_boundary, jno_boundary] += cvalue;
                        }
                    }
                }
                // check 対称行列
                bool isSymmetrix = true;
                for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                {
                    for (uint jno_boundary = ino_boundary; jno_boundary < node_cnt; jno_boundary++)
                    {
                        if (Math.Abs(mat_all[ino_boundary, jno_boundary].Real - mat_all[jno_boundary, ino_boundary].Real) >= 1.0e-12)
                        {
                            isSymmetrix = false;
                            break;
                            //System.Diagnostics.Debug.Assert(false);
                        }
                        if (Math.Abs(mat_all[ino_boundary, jno_boundary].Imag - mat_all[jno_boundary, ino_boundary].Imag) >= 1.0e-12)
                        {
                            isSymmetrix = false;
                            break;
                            //System.Diagnostics.Debug.Assert(false);
                        }
                    }
                    if (!isSymmetrix)
                    {
                        break;
                    }
                }
                if (!isSymmetrix)
                {
                    System.Diagnostics.Debug.WriteLine("!!!!!!!!!!matrix is NOT symmetric!!!!!!!!!!!!!!");
                    //System.Diagnostics.Debug.Assert(false);
                }
                //MyMatrixUtil.printMatrix("emat_all", emat_all);
            }

            // 残差ベクトルの作成
            Complex[] res_c_all = new Complex[node_cnt];
            for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
            {
                res_c_all[ino_boundary] = 0.0;
            }
            if (isInputPort && incidentModeIndex < eigen_values.Length)
            {
                if (amps != null)
                {
                    // 全モードを入射させる
                    for (uint imode = 0; imode < max_mode; imode++)
                    {
                        Complex betam = eigen_values[imode];
                        Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode);
                        Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode);
                        Complex[] fmVec_Modify = new Complex[fmVec.Length];
                        Complex imagOne = new Complex(0.0, 1.0);
                        DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                        for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                        {
                            //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam);
                            fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic);
                        }
                        //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec);
                        Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify);
                        for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                        {
                            // TEモード、TMモード共通
                            //Complex cvalue = 2.0 * imagOne * betam * veci[ino_boundary] * amList[imode];
                            Complex cvalue = 2.0 * imagOne * betam_periodic * veci[ino_boundary] * amps[imode];
                            res_c_all[ino_boundary] += cvalue;
                        }
                    }
                }
                else
                {
                    uint imode = (uint)incidentModeIndex;
                    Complex betam = eigen_values[imode];
                    Complex[] fmVec = MyMatrixUtil.matrix_GetRowVec(eigen_vecs, (int)imode);
                    Complex[] dfmdxVec = MyMatrixUtil.matrix_GetRowVec(eigen_dFdXs, (int)imode);
                    Complex[] fmVec_Modify = new Complex[fmVec.Length];
                    Complex imagOne = new Complex(0.0, 1.0);
                    DelFEM4NetCom.Complex betam_periodic = ToBetaPeriodic(betam, periodicDistance);
                    for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                    {
                        //fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam);
                        fmVec_Modify[ino_boundary] = fmVec[ino_boundary] - dfmdxVec[ino_boundary] / (imagOne * betam_periodic);
                    }
                    //Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec);
                    Complex[] veci = MyMatrixUtil.product(ryy_1d, fmVec_Modify);
                    for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                    {
                        // TEモード、TMモード共通
                        //res_c_all[ino_boundary] = 2.0 * imagOne * betam * veci[ino_boundary];
                        res_c_all[ino_boundary] = 2.0 * imagOne * betam_periodic * veci[ino_boundary];
                    }
                }
            }
            //MyMatrixUtil.printVec("eres_c_all", eres_c_all);

            // 線要素の節点数
            uint nno = 2;
            // 座標の次元
            //uint ndim = 2;
            // 要素節点の全体節点番号
            uint[] no_c = new uint[nno];
            // 要素剛性行列(コーナ-コーナー)
            CZMatDia_BlkCrs_Ptr mat_cc = ls.GetMatrixPtr(fieldValId, ELSEG_TYPE.CORNER, world);
            // 要素残差ベクトル(コーナー)
            CZVector_Blk_Ptr res_c = ls.GetResidualPtr(fieldValId, ELSEG_TYPE.CORNER, world);

            //System.Diagnostics.Debug.WriteLine("fieldValId: {0}", fieldValId);
            //System.Diagnostics.Debug.WriteLine("NBlkMatCol:" + mat_cc.NBlkMatCol()); // (境界でなく領域の総節点数と同じ?)

            if (!isFreeBc)
            {
                // 要素剛性行列にマージ
                //   この定式化では行列のスパース性は失われている(隣接していない要素の節点間にも関連がある)
                // 要素剛性行列にマージする
                bool[,] add_flg = new bool[node_cnt, node_cnt];
                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        add_flg[i, j] = false;
                    }
                }
                // このケースではmat_ccへのマージは対角行列でマージしなければならないようです。
                // 1 x node_cntの横ベクトルでマージしようとするとassertに引っかかります。
                // 境界上の節点に関しては非0要素はないので、境界上の節点に関する
                //  node_cnt x node_cntの行列を一括でマージできます。
                // col, rowの全体節点番号ベクトル
                uint[] no_c_tmp = new uint[node_cnt];
                // 要素行列(ここでは境界の剛性行列を一括でマージします)
                Complex[] emattmp = new Complex[node_cnt * node_cnt];
                for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
                {
                    // colブロックのインデックス(全体行列の節点番号)
                    uint iblk = no_c_all[ino_boundary];
                    uint npsup = 0;
                    ConstUIntArrayIndexer cur_rows = mat_cc.GetPtrIndPSuP((uint)iblk, out npsup);
                    //System.Diagnostics.Debug.WriteLine("chk3:{0} {1}", iblk, npsup);
                    for (uint jno_boundary = 0; jno_boundary < node_cnt; jno_boundary++)
                    {
                        if (ino_boundary != jno_boundary)
                        {
                            uint rowno = no_c_all[jno_boundary];
                            if (cur_rows.IndexOf(rowno) == -1)
                            {
                                System.Diagnostics.Debug.Assert(false);
                                return false;
                            }
                        }
                        if (!add_flg[ino_boundary, jno_boundary])
                        {
                            // 要素行列を作成
                            Complex cvalue = mat_all[ino_boundary, jno_boundary];
                            //emattmp[ino_boundary, jno_boundary]
                            emattmp[ino_boundary * node_cnt + jno_boundary] = cvalue;
                            add_flg[ino_boundary, jno_boundary] = true;
                        }
                        else
                        {
                            // ここにはこない
                            System.Diagnostics.Debug.Assert(false);
                            //emattmp[ino_boundary, jno_boundary]
                            emattmp[ino_boundary * node_cnt + jno_boundary] = new Complex(0, 0);
                        }
                    }
                    no_c_tmp[ino_boundary] = iblk;
                }
                // 一括マージ
                mat_cc.Mearge(node_cnt, no_c_tmp, node_cnt, no_c_tmp, 1, emattmp, ref tmpBuffer);

                for (int i = 0; i < node_cnt; i++)
                {
                    for (int j = 0; j < node_cnt; j++)
                    {
                        //System.Diagnostics.Debug.WriteLine( i + " " + j + " " + add_flg[i, j] );
                        System.Diagnostics.Debug.Assert(add_flg[i, j]);
                    }
                }
            }

            // 残差ベクトルにマージ
            for (uint ino_boundary = 0; ino_boundary < node_cnt; ino_boundary++)
            {
                // 残差ベクトルにマージする
                uint no_tmp = no_c_all[ino_boundary];
                Complex val = res_c_all[ino_boundary];

                res_c.AddValue(no_tmp, 0, val);
            }

            return true;
        }