/// <summary>
        /// CPUでの計算プログラムを作成する
        /// </summary>
        /// <param name="maxDt">初期時間刻み</param>
        /// <param name="a">振幅</param>
        /// <param name="omega">角速度</param>
        public ComputerCpu(double maxDt, double a, double omega)
            : base(maxDt, a, omega)
        {
            // 粒子群を初期化
            this.particles = new Particle[0];

            // 準備処理は何もしない
            this.prepare = () => { };

            // 粒子が追加された時に
            base.ParticleAdded += (sender, e) =>
            {
                // 準備処理の時の処理を実装
                this.prepare = () =>
                {
                    // 新しい粒子群配列を生成
                    var newParticles = new Particle[this.particles.Length + this.inputParticles.Count];

                    // 古い粒子群を新しい粒子群に複製
                    this.particles.CopyTo(newParticles, 0);

                    // 入力粒子群を新しい粒子群に複製
                    this.inputParticles.CopyTo(newParticles, this.particles.Length);

                    // 新しい粒子群を今の粒子群とする
                    this.particles = newParticles;

                    // 入力粒子群を空にする
                    this.inputParticles.Clear();

                    // 準備処理は空
                    this.prepare = () => { };
                };
            };
        }
Example #2
0
        /// <summary>
        /// 粒子を追加する
        /// </summary>
        /// <param name="particle">追加する粒子</param>
        public void AddParticle(Particle particle)
        {
            // 入力粒子に追加
            this.inputParticles.Add(particle);

            // 粒子が追加されたことを通知
            this.OnParticleAdded();
        }
        /// <summary>
        /// メインクラスを開始
        /// </summary>
        public SimpleClooMain()
        {
            // 時間刻み
            const double maxDt = 0.01;

            // 粒子の大きさ
            const double diameter = 50e-3;
            const double diameterWall = diameter * 0.8;
            const double length0 = diameter * 1.001;
            const double length0Wall = diameterWall * 0.75;

            // 計算領域
            const double sizeX = 45000e-3;
            const double sizeZ = 2200e-3;
            const double extraSize = diameter;

            // 物性値
            const double rho = 2.7e3;
            const double E = 30e6;
            const double nu = 0.2;

            // 振幅と角速度
            double A = 0.5;
            double omega = 2.0;

            // 計算プログラムを初期化
            var computerCpu = new ComputerCpu(maxDt, A, omega);
            var computerCL = new ComputerCL(maxDt, A, omega);

            // 最上位ウインドウを作成して設定
            MainWindow mainWindow = new MainWindow(computerCpu, computerCL);
            base.MainWindow = mainWindow;

            mainWindow.Log("データ初期化中...");
            // ウインドウ表示
            base.MainWindow.Show();
            mainWindow.LogLine("完了");

            mainWindow.Log("データ作成中...");

            // 材質を生成
            var materials = new []
            {
                // 移動粒子
                new Material(0, rho, E, nu, new Color4( 50,  50, 255, 255)),

                // 壁
                new Material(1, rho, E, nu, new Color4(200, 200, 200, 255))
            };

            // 粒子番号
            ulong particleID = 0;

            // 領域内に
            for(double x = 0; x < sizeX; x += length0)
            {
                for(double z = 0; z < sizeZ; z += length0)
                {
                    // 移動粒子を作成
                    var particle = new Particle(particleID++, diameter * (0.4 + 0.6 * z / sizeZ), materials[0], ParticleType.FreeMovable)
                    {
                        X = new Vector(x, 0, z)
                    };

                    // 追加
                    computerCpu.AddParticle(particle);
                    computerCL.AddParticle(particle);
                }
            }

            // 床の部分に
            for(double x = -extraSize; x < sizeX + extraSize; x += length0Wall)
            {
                // 固定粒子を作成
                var particle = new Particle(particleID++, diameterWall, materials[1], ParticleType.Fixed)
                {
                    X = new Vector(x, 0, -extraSize)
                };

                // 追加
                computerCpu.AddParticle(particle);
                computerCL.AddParticle(particle);
            }

            mainWindow.LogLine("完了");

            // 計算中かどうか
            bool isComputing = false;

            // 計算中かどうかを変更する
            Action<bool> changeIsComputing = (isComputingNow) =>
            {
                // 計算状態を設定
                isComputing = isComputingNow;

                // ウインドウで
                mainWindow.Dispatcher.BeginInvoke((Action)(() =>
                {
                    // 1ステップ計算のボタンの有効化および無効化
                    mainWindow.ComputeOneButton.IsEnabled = !isComputingNow;

                    // 計算状態に合わせて自動実行ボタンの表示を変える
                    mainWindow.ComputeAllButton.Content = (isComputingNow) ? "自動実行を停止" : "自動実行を開始";

                    // 計算開始および終了を通知
                    mainWindow.LogLine((isComputingNow) ? "計算を開始" : "計算を終了");
                }));
            };

            // 1ステップ実行がクリックされたら
            mainWindow.ComputeOneButton.Click += (sender, e) =>
            {
                // 計算中でなければ
                if(!isComputing)
                {
                    // 計算開始
                    changeIsComputing(true);

                    // 1ステップだけ進める
                    mainWindow.computer.Next();

                    // 計算終了
                    changeIsComputing(false);
                }
            };

            // 自動実行がクリックされたら
            mainWindow.ComputeAllButton.Click += (sender, e) =>
            {
                // 計算中でなければ
                if(!isComputing)
                {
                    // 計算開始
                    changeIsComputing(true);

                    // 自動実行スレッド開始
                    new Task(() =>
                    {
                        // 計算中の間
                        while(isComputing)
                        {
                            // 次ステップに進める
                            mainWindow.computer.Next();
                        }

                        // 計算終了
                        changeIsComputing(false);

                    }, TaskCreationOptions.LongRunning).Start();
                }
                // 計算中なら
                else
                {
                    // 計算中断
                    changeIsComputing(false);
                }
            };

            // プログラムが切り替わったら
            System.Windows.RoutedEventHandler stopWhenSwitchWith = (sender, e) =>
            {
                // 計算終了
                changeIsComputing(false);
            };

            // プログラムが切り替わった時の処理
            mainWindow.WithCpuButton.Checked += stopWhenSwitchWith;
            mainWindow.WithCLButton.Checked += stopWhenSwitchWith;

            // アプリケーションの終了時に
            this.Exit += (sender, e) =>
            {
                // 計算終了
                changeIsComputing(false);
            };
        }
        /// <summary>
        /// 現在の粒子を取得する
        /// </summary>
        /// <returns>現在の粒子の複製</returns>
        public override Particle[] GetParticles()
        {
            // 準備が出来ていなかったら
            if(this.bufferX != null)
            {
                // 出力データを確保
                var particlesX = new Vector4[this.particleCount];
                var particlesU = new Vector4[this.particleCount];
                var particlesA = new Vector4[this.particleCount];

                // バッファーから転送
                this.queue.ReadFromBuffer(this.bufferX, ref particlesX, false, null);
                this.queue.ReadFromBuffer(this.bufferU, ref particlesU, false, null);
                this.queue.ReadFromBuffer(this.bufferA, ref particlesA, false, null);

                // 出力粒子を作製
                var particles = new Particle[this.particleCount];

                // ここまで待機
                this.queue.Finish();

                // 全粒子について
                for(ulong i = 0; i < (ulong)this.particleCount; i++)
                {
                    particles[i] = new Particle(i,
                        this.particlesD[i],
                        this.particlesMaterial[i],
                        this.particlesType[i])
                        {
                            X = new Vector(particlesX[i].X, particlesX[i].Y, particlesX[i].Z),
                            U = new Vector(particlesU[i].X, particlesU[i].Y, particlesU[i].Z),
                            A = new Vector(particlesA[i].X, particlesA[i].Y, particlesA[i].Z),
                        };
                };

                // 粒子群を返す
                return particles;
            }

            // 空の配列を返す
            return new Particle[0];
        }
        /// <summary>
        /// 現在の粒子を取得する
        /// </summary>
        /// <returns>現在の粒子の複製</returns>
        public override Particle[] GetParticles()
        {
            // 複製配列を作成して、粒子群を複製
            var clone = new Particle[this.particles.Length];
            this.particles.CopyTo(clone, 0);

            // 複製したものを返す
            return clone;
        }