Beispiel #1
0
        private void cbed_DoWork(object sender, DoWorkEventArgs e)
        {
            //波数を計算
            var kvac = UniversalConstants.Convert.EnergyToElectronWaveNumber(AccVoltage);
            //U0を計算
            var u0 = getU(AccVoltage, (0, 0, 0), 0).Real.Real;
            //k0ベクトルを計算
            var vecK0 = getVecK0(kvac, u0);

            //計算対象のg-Vectorsを決める。indexが小さく、かつsg(励起誤差)の小さいg-vectorを抽出する
            Beams = Find_gVectors(BaseRotation, vecK0);

            //入射面での波動関数を定義
            var psi0 = DVec.OfArray(Enumerable.Range(0, Beams.Length).ToList().Select(g => g == 0 ? One : 0).ToArray());

            //ポテンシャルマトリックスを取得
            uDictionary = new Dictionary <int, (Complex, Complex)>();
            var factorMatrix = getPotentialMatrix(Beams);
            //有効なRotationだけを選択
            var beamRotationsValid = new List <Matrix3D>();

            for (int i = 0; i < BeamRotations.Length; i++)
            {
                if (BeamRotations[i] != null)
                {
                    beamRotationsValid.Add(BeamRotations[i]);
                }
            }
            RotationArrayValidLength = beamRotationsValid.Count;
            //rotationsValidに対応するdiskValidを定義
            var diskValid = new List <Complex[][]>();
            //進捗状況報告用の各種定数を初期化
            int count = 0, total = beamRotationsValid.Count;
            var sw   = new Stopwatch();
            var bLen = Beams.Length;

            //ローカル関数. RotationsValid(の一部)を対象にdisks[t][g]を計算し、diskValidに追加し、最後にかかった時間を返す
            long func(Solver solver, int thread, bool speedTest = true)
            {
                if (solver == Solver.MKL)
                {
                    MathNet.Numerics.Control.TryUseNativeMKL();
                }
                else if (solver == Solver.Managed)
                {
                    MathNet.Numerics.Control.UseManaged();
                }

                var reportString   = (solver == Solver.MKL ? "MKL" : "EIG") + thread.ToString();
                var beamRotationsP = beamRotationsValid.AsParallel().WithDegreeOfParallelism(thread);

                if (speedTest)//スピードテストのとき
                {
                    var n = Math.Min(bLen < 64 ? 512 : bLen < 128 ? 256 : bLen < 256 ? 128 : bLen < 512 ? 64 : 32, beamRotationsValid.Count);
                    if (n == 0)
                    {
                        return(0);
                    }
                    beamRotationsP = beamRotationsValid.Take(n).ToArray().AsParallel().WithDegreeOfParallelism(thread);
                    beamRotationsValid.RemoveRange(0, n);
                }
                sw.Restart();
                //disks[t][g]を計算.
                var disk = beamRotationsP.Select(beamRotation =>
                {
                    if (bwCBED.CancellationPending)
                    {
                        return(null);
                    }
                    var rotZ  = beamRotation * zNorm;
                    var coeff = 1.0 / rotZ.Z; // = 1/cosTau

                    var vecK0 = getVecK0(kvac, u0, beamRotation);

                    var beams           = reset_gVectors(Beams, BaseRotation, vecK0); //BeamsのPやQをリセット
                    var potentialMatrix = getEigenProblemMatrix(beams, factorMatrix); //ポテンシャル行列をセット
                    Complex[][] result;

                    //ポテンシャル行列の固有値、固有ベクトルを取得し、resultに格納
                    if (solver == Solver.Eigen)
                    {
                        result = NativeWrapper.CBEDSolver(potentialMatrix, psi0.ToArray(), Thicknesses, coeff);
                    }
                    else
                    {
                        var evd   = DMat.OfArray(potentialMatrix).Evd(Symmetricity.Unknown);
                        var alpha = evd.EigenVectors.Inverse() * psi0;
                        result    = Thicknesses.Select(t =>
                        {
                            //ガンマの対称行列×アルファを作成
                            var gammmaAlpha = DVec.OfArray(evd.EigenValues.Select((ev, i) => Exp(TwoPiI * ev * t * coeff) * alpha[i]).ToArray());
                            //深さtにおけるψを求める
                            return((evd.EigenVectors * gammmaAlpha).ToArray());
                        }).ToArray();
                    }
                    bwCBED.ReportProgress(Interlocked.Increment(ref count), reportString); //進捗状況を報告
                    return(result);
                }).ToArray();

                diskValid.AddRange(disk); //diskをdiskValidに加える
                return(sw.ElapsedTicks);  //経過時間を返す
            }

            //ここからチューニング&本番

            if ((Solver)((object[])e.Argument)[0] == Solver.Auto)
            {
                if (EigenEnabled && bLen < 512 && func(Solver.Eigen, Environment.ProcessorCount) < func(Solver.MKL, 8))//eigenの方が早い場合
                {
                    func(Solver.Eigen, Environment.ProcessorCount, false);
                }
                else if (Environment.ProcessorCount <= 4)//MKLでコア数が4以下の場合
                {
                    func(Solver.MKL, Environment.ProcessorCount, false);
                }
                else//コア数4,6,8,10,12,14,16を試して最速のもので
                {
                    var list = new SortedList <long, int>();
                    foreach (var t in new[] { 4, 6, 8, 10, 12, 14, 16 })
                    {
                        if (t <= Environment.ProcessorCount)
                        {
                            list.Add(func(Solver.MKL, t), t);
                        }
                    }
                    func(Solver.MKL, list.Values[0], false);
                }
            }
            else
            {
                func((Solver)((object[])e.Argument)[0], (int)((object[])e.Argument)[1], false);
            }


            //無効なRotationも考慮してdisk[RotationIndex][Z_index][G_index]を構築
            var disk = new List <Complex[][]>();

            for (int i = 0, j = 0; i < BeamRotations.Length; i++)
            {
                disk.Add(BeamRotations[i] != null ? diskValid[j++] : null);
            }

            //diskをコンパイルする
            Disks = new CBED_Disk[Thicknesses.Length][];
            Parallel.For(0, Thicknesses.Length, t =>
            {
                Disks[t] = new CBED_Disk[Beams.Length];
                for (int g = 0; g < Beams.Length; g++)
                {
                    var intensity = new double[BeamRotations.Length];
                    for (int r = 0; r < BeamRotations.Length; r++)
                    {
                        if (disk[r] != null)
                        {
                            intensity[r] = disk[r][t][g].Magnitude2();
                        }
                    }

                    Disks[t][g] = new CBED_Disk(new[] { Beams[g].H, Beams[g].K, Beams[g].L }, Beams[g].Vec, Thicknesses[t], intensity);
                }
            });

            if (bwCBED.CancellationPending)
            {
                e.Cancel = true;
            }
        }
Beispiel #2
0
        /// <summary>
        /// 平行ビームの電子回折計算
        /// </summary>
        /// <param name="maxNumOfBloch"></param>
        /// <param name="voltage"></param>
        /// <param name="rotation"></param>
        /// <param name="thickness"></param>
        /// <returns></returns>
        public Beam[] GetDifractedBeamAmpriltudes(int maxNumOfBloch, double voltage, Matrix3D rotation, double thickness)
        {
            var useEigen = !MathNet.Numerics.Control.TryUseNativeMKL();

            if (AccVoltage != voltage)
            {
                uDictionary = new Dictionary <int, (Complex, Complex)>();
            }

            //波数を計算
            var k_vac = UniversalConstants.Convert.EnergyToElectronWaveNumber(voltage);
            //U0を計算
            var u0    = getU(voltage, (0, 0, 0), 0).Real.Real;
            var vecK0 = getVecK0(k_vac, u0);

            if (MaxNumOfBloch != maxNumOfBloch || AccVoltage != voltage || EigenValues == null || EigenVectors == null || !rotation.Equals(BaseRotation))
            {
                MaxNumOfBloch = maxNumOfBloch;
                AccVoltage    = voltage;
                BaseRotation  = new Matrix3D(rotation);
                Thickness     = thickness;

                //計算対象のg-Vectorsを決める。
                Beams = Find_gVectors(BaseRotation, vecK0);

                if (Beams == null || Beams.Length == 0)
                {
                    return(new Beam[0]);
                }

                var potentialMatrix = getEigenProblemMatrix(Beams);

                //A行列に関する固有値、固有ベクトルを取得
                if (useEigen)
                {
                    (EigenValues, EigenVectors) = NativeWrapper.EigenSolver(potentialMatrix);
                }
                else
                {
                    var evd = DMat.OfArray(potentialMatrix).Evd(Symmetricity.Asymmetric);
                    EigenValues  = evd.EigenValues.AsArray();
                    EigenVectors = (DMat)evd.EigenVectors;
                }

                //(EigenVectors, EigenValues) = RefineEigenProblem(DMat.OfArray(potentialMatrix), (DMat)evd.EigenVectors, evd.EigenValues.ToArray());
            }
            int len = EigenValues.Count();

            var psi0 = DVec.OfArray(new Complex[len]);//入射面での波動関数を定義

            psi0[0] = 1;

            var alpha = EigenVectors.Inverse() * psi0;//アルファベクトルを求める

            //ガンマの対称行列×アルファを作成
            var gamma_alpha = new DVec(Enumerable.Range(0, len).Select(n => Exp(TwoPiI * EigenValues[n] * thickness) * alpha[n]).ToArray());

            //出射面での境界条件を考慮した位相にするため、以下の1行を追加 (20190827)
            var p = new DiagonalMatrix(len, len, Beams.Select(b => Exp(PiI * (b.P - 2 * k_vac * Surface.Z) * thickness)).ToArray());
            //var p = new DiagonalMatrix(len, len, Beams.Select(b => new Complex(1, 0)).ToArray());

            //深さZにおけるψを求める
            var psi_atZ = p * EigenVectors * gamma_alpha;

            for (int i = 0; i < Beams.Length && i < len; i++)
            {
                Beams[i].Psi = psi_atZ[i];
            }

            return(Beams);
        }
 /// <summary>
 /// Clone the given vector.
 /// </summary>
 public static DenseVector Clone(DenseVector vector)
 {
     return(DenseVector.OfArray((Complex[])vector));
 }