/// <summary> /// 最上位ウインドウを作成 /// </summary> /// <param name="computer">CPU計算</param> /// <param name="computerCL">OpenCL計算</param> public MainWindow(ComputerCpu computerCpu, ComputerCL computerCL) { // 既定ではCPUで計算 this.computer = computerCpu; // コンポーネント初期化 InitializeComponent(); // 初期化中通知 this.Log("ウインドウを初期化中..."); // ポイントスプライトプログラムを作成 this.programPoint = new Program( this.Viewport, Properties.Resources.point_vertex, Properties.Resources.point_geometry, Properties.Resources.point_fragment); // ビューポートにプログラムを追加 this.Viewport.Programs.Add(this.programPoint); // 点の大きさを変更可能に設定 this.programPoint.Enable(EnableCap.ProgramPointSize); // ポイントスプライト用 this.programPoint.Enable(EnableCap.PointSprite); // パラメーター再設定 Action setParameters = () => { // 視野変換および投影変換行列を設定 this.programPoint.SetUniform("view", this.Viewport.View); this.programPoint.SetUniform("projection", this.Viewport.Projection); // 表示する大きさ(拡大率)を設定 this.programPoint.SetUniform("size", (float)this.Viewport.Camera.R); // カメラの位置を設定 this.programPoint.SetUniform("cameraPosition", this.Viewport.Camera.Position); }; // ウインドウが読みこまれたら this.Loaded += (sender, e) => { // 真上からの平行光線を設定 this.programPoint.SetUniform("sunLight", new Vector3(0, 0, -0.6f)); // 環境光強度を割り当て this.programPoint.SetUniform("ambient", 0.1f); // カメラからの光源の強度を割り当て this.programPoint.SetUniform("cameraLight", 0.3f); }; // 再描画時に this.Viewport.Invalidated += (sender, e) => { // パラメーター再設定 setParameters(); }; // カメラが動いたら this.Viewport.Camera.Changed += (sender, e) => { // パラメーター再設定 setParameters(); }; // 終了時に this.Closed += (sender, e) => { // プログラムを削除 this.programPoint.Dispose(); }; // 描画中かどうか bool isRendering = false; // 出力用粒子配列を初期化 var outputParticles = new OutputParticle[0]; // 描画処理 Timer renderer = new Timer((TimerCallback)((state) => { // 描画中でなければ if(!isRendering) { // 描画開始 isRendering = true; // 計算空間画面に this.Viewport.Dispatcher.BeginInvoke((Action)(() => { // 現在の粒子を取得 var thisParticles = this.computer.GetParticles(); // 出力用と粒子数が違えば if((this.particlesBuffer == null)||(outputParticles.Length != thisParticles.Length)) { // 出力用粒子群を再生成 outputParticles = new OutputParticle[thisParticles.Length]; // 動的バッファーを作成 this.particlesBuffer = Buffer.CreateDynamic<OutputParticle>( this.Viewport, BeginMode.Points, outputParticles.Length, MainWindow.CreatePointsIndices(outputParticles.Length)); // バッファーを全除去 this.programPoint.ClearBuffer(); // ポイントスプライトプログラムにバッファーを割り当て this.programPoint.AttachBuffer(this.particlesBuffer, new[] { new VertexAttribution("particleX", VertexAttribPointerType.Float, 3, 0), new VertexAttribution("particleD", VertexAttribPointerType.Float, 1, Vector3.SizeInBytes), new VertexAttribution("particleColor", VertexAttribPointerType.Float, 4, Vector3.SizeInBytes + sizeof(float)), }); } // すべての粒子を int i = 0; foreach(var particle in thisParticles) { // 出力用粒子に変換 outputParticles[i++] = new OutputParticle((OpenTK.Vector3)particle.X, (float)particle.D, particle.Material.Color); } // 出力粒子を書き込み this.particlesBuffer.WriteData(outputParticles); // 再描画 this.Viewport.Invalidate(); // 処理完了 isRendering = false; })); } // 時刻表示パネルに this.TimePanel.Dispatcher.BeginInvoke((Action)(() => { // 時刻・タイムステップ数・時間刻みを表示 this.TBox.Text = this.computer.T.ToString("G5"); this.StepsBox.Text = this.computer.TimeStep.ToString(); this.DtBox.Text = this.computer.Dt.ToString("e"); // 粒子数を表示 this.ParticleCountBox.Text = this.computer.ParticleCount.ToString(); })); })); // 描画を開始 renderer.Change(0, fps); // 前の時刻と時間ステップ double oldT = 0; double oldTimeStep = 0; var oldRealT = DateTime.Now; var initialT = DateTime.Now; // 速度計測 Timer speedMeasure = new Timer((TimerCallback)((state) => { // 速度表示パネルに this.TimePanel.Dispatcher.BeginInvoke((Action)(() => { // 時間ステップを取得 var thisTimeStep = this.computer.TimeStep; var thisRealT = DateTime.Now; // 時間ステップが進んでいれば if(thisTimeStep != oldTimeStep) { // 時刻を取得 var thisT = this.computer.T; // 経過時間を秒で計算 double interval = (double)(thisRealT - oldRealT).TotalSeconds; // 各データを表示 this.StepPerRealBox.Text = (interval / (thisTimeStep - oldTimeStep)).ToString("G5"); this.StepPerRealPerParticleBox.Text = (interval / (thisTimeStep - oldTimeStep) / this.computer.ParticleCount).ToString("G5"); this.ComputationalPerRealBox.Text = (interval / (thisT - oldT)).ToString("G5"); // 前の時刻と時間ステップを設定 oldT = thisT; oldTimeStep = thisTimeStep; oldRealT = thisRealT; } // 現在時刻を表示 this.RealTimeBox.Text = (thisRealT - initialT).ToString(@"d\.hh\:mm\:ss"); })); })); // 1秒感覚で速度計測を開始 speedMeasure.Change(0, 1000); // OS名 this.OSNameBox.Text = System.Environment.OSVersion.ToString(); // CPUの foreach(var processor in new System.Management.ManagementClass("Win32_Processor").GetInstances()) { // データを表示 this.CpuNameBox.Text = string.Format("{0}", processor["Name"]); this.CpuVenderBox.Text = string.Format("{0}", processor["Manufacturer"]); this.CpuMaxClockBox.Text = string.Format("{0:0.00}", double.Parse(processor["MaxClockSpeed"].ToString()) / 1024); this.CpuCoreBox.Text = string.Format("{0}", processor["NumberOfCores"]); } foreach(var os in new System.Management.ManagementClass("Win32_OperatingSystem").GetInstances()) { // メモリを表示 this.CpuMemoryBox.Text = string.Format("{0:0.00}", double.Parse(os["MaxProcessMemorySize"].ToString()) / 1024 / 1024); } // プラットフォームデータを表示 this.PlatformNameBox.Text = computerCL.Platform.Name; this.PlatformVenderBox.Text = computerCL.Platform.Vendor; this.PlatformVersionBox.Text = computerCL.Platform.Version; this.PlatformProfileBox.Text = computerCL.Platform.Profile; // デバイスデータを表示 this.DeviceNameBox.ItemsSource = computerCL.Devices; this.DeviceNameBox.SelectionChanged += (sender, e) => { var device = this.DeviceNameBox.SelectedItem as Cloo.ComputeDevice; this.DeviceVenderBox.Text = device.Vendor; this.DeviceDriverVersionBox.Text = device.DriverVersion; this.DeviceOpenCLVersionBox.Text = device.OpenCLCVersionString; this.DeviceCUBox.Text = string.Format("{0}", device.MaxComputeUnits); this.DeviceGlobalMemoryBox.Text = string.Format("{0}", device.GlobalMemorySize); this.DeviceLocalMemoryBox.Text = string.Format("{0}", device.LocalMemorySize); }; this.DeviceNameBox.SelectedIndex = 0; // 前の時刻を初期化する Action resetOldTime = () => { oldT = this.computer.T; oldTimeStep = this.computer.TimeStep; }; // CPUで計算する場合は this.WithCpuButton.Checked += (sender, e) => { // 計算プログラムをCpuに設定 this.computer = computerCpu; // 前の時刻を初期化 resetOldTime(); }; // OpenCLで計算する場合は this.WithCLButton.Checked += (sender, e) => { // 計算プログラムをOpenCLに設定 this.computer = computerCL; // 前の時刻を初期化 resetOldTime(); }; // 前の時刻を初期化 resetOldTime(); // 初期化完了 this.LogLine("完了"); }
/// <summary> /// 最上位ウインドウを作成 /// </summary> /// <param name="computer">CPU計算</param> /// <param name="computerCL">OpenCL計算</param> public MainWindow(ComputerCpu computerCpu, ComputerCL computerCL) { // 既定ではCPUで計算 this.computer = computerCpu; // コンポーネント初期化 InitializeComponent(); // 初期化中通知 this.Log("ウインドウを初期化中..."); // ポイントスプライトプログラムを作成 this.programPoint = new Program( this.Viewport, Properties.Resources.point_vertex, Properties.Resources.point_geometry, Properties.Resources.point_fragment); // ビューポートにプログラムを追加 this.Viewport.Programs.Add(this.programPoint); // 点の大きさを変更可能に設定 this.programPoint.Enable(EnableCap.ProgramPointSize); // ポイントスプライト用 this.programPoint.Enable(EnableCap.PointSprite); // パラメーター再設定 Action setParameters = () => { // 視野変換および投影変換行列を設定 this.programPoint.SetUniform("view", this.Viewport.View); this.programPoint.SetUniform("projection", this.Viewport.Projection); // 表示する大きさ(拡大率)を設定 this.programPoint.SetUniform("size", (float)this.Viewport.Camera.R); // カメラの位置を設定 this.programPoint.SetUniform("cameraPosition", this.Viewport.Camera.Position); }; // ウインドウが読みこまれたら this.Loaded += (sender, e) => { // 真上からの平行光線を設定 this.programPoint.SetUniform("sunLight", new Vector3(0, 0, -0.6f)); // 環境光強度を割り当て this.programPoint.SetUniform("ambient", 0.1f); // カメラからの光源の強度を割り当て this.programPoint.SetUniform("cameraLight", 0.3f); }; // 再描画時に this.Viewport.Invalidated += (sender, e) => { // パラメーター再設定 setParameters(); }; // カメラが動いたら this.Viewport.Camera.Changed += (sender, e) => { // パラメーター再設定 setParameters(); }; // 終了時に this.Closed += (sender, e) => { // プログラムを削除 this.programPoint.Dispose(); }; // 描画中かどうか bool isRendering = false; // 出力用粒子配列を初期化 var outputParticles = new OutputParticle[0]; // 描画処理 Timer renderer = new Timer((TimerCallback)((state) => { // 描画中でなければ if (!isRendering) { // 描画開始 isRendering = true; // 計算空間画面に this.Viewport.Dispatcher.BeginInvoke((Action)(() => { // 現在の粒子を取得 var thisParticles = this.computer.GetParticles(); // 出力用と粒子数が違えば if ((this.particlesBuffer == null) || (outputParticles.Length != thisParticles.Length)) { // 出力用粒子群を再生成 outputParticles = new OutputParticle[thisParticles.Length]; // 動的バッファーを作成 this.particlesBuffer = Buffer.CreateDynamic <OutputParticle>( this.Viewport, BeginMode.Points, outputParticles.Length, MainWindow.CreatePointsIndices(outputParticles.Length)); // バッファーを全除去 this.programPoint.ClearBuffer(); // ポイントスプライトプログラムにバッファーを割り当て this.programPoint.AttachBuffer(this.particlesBuffer, new[] { new VertexAttribution("particleX", VertexAttribPointerType.Float, 3, 0), new VertexAttribution("particleD", VertexAttribPointerType.Float, 1, Vector3.SizeInBytes), new VertexAttribution("particleColor", VertexAttribPointerType.Float, 4, Vector3.SizeInBytes + sizeof(float)), }); } // すべての粒子を int i = 0; foreach (var particle in thisParticles) { // 出力用粒子に変換 outputParticles[i++] = new OutputParticle((OpenTK.Vector3)particle.X, (float)particle.D, particle.Material.Color); } // 出力粒子を書き込み this.particlesBuffer.WriteData(outputParticles); // 再描画 this.Viewport.Invalidate(); // 処理完了 isRendering = false; })); } // 時刻表示パネルに this.TimePanel.Dispatcher.BeginInvoke((Action)(() => { // 時刻・タイムステップ数・時間刻みを表示 this.TBox.Text = this.computer.T.ToString("G5"); this.StepsBox.Text = this.computer.TimeStep.ToString(); this.DtBox.Text = this.computer.Dt.ToString("e"); // 粒子数を表示 this.ParticleCountBox.Text = this.computer.ParticleCount.ToString(); })); })); // 描画を開始 renderer.Change(0, fps); // 前の時刻と時間ステップ double oldT = 0; double oldTimeStep = 0; var oldRealT = DateTime.Now; var initialT = DateTime.Now; // 速度計測 Timer speedMeasure = new Timer((TimerCallback)((state) => { // 速度表示パネルに this.TimePanel.Dispatcher.BeginInvoke((Action)(() => { // 時間ステップを取得 var thisTimeStep = this.computer.TimeStep; var thisRealT = DateTime.Now; // 時間ステップが進んでいれば if (thisTimeStep != oldTimeStep) { // 時刻を取得 var thisT = this.computer.T; // 経過時間を秒で計算 double interval = (double)(thisRealT - oldRealT).TotalSeconds; // 各データを表示 this.StepPerRealBox.Text = (interval / (thisTimeStep - oldTimeStep)).ToString("G5"); this.StepPerRealPerParticleBox.Text = (interval / (thisTimeStep - oldTimeStep) / this.computer.ParticleCount).ToString("G5"); this.ComputationalPerRealBox.Text = (interval / (thisT - oldT)).ToString("G5"); // 前の時刻と時間ステップを設定 oldT = thisT; oldTimeStep = thisTimeStep; oldRealT = thisRealT; } // 現在時刻を表示 this.RealTimeBox.Text = (thisRealT - initialT).ToString(@"d\.hh\:mm\:ss"); })); })); // 1秒感覚で速度計測を開始 speedMeasure.Change(0, 1000); // OS名 this.OSNameBox.Text = System.Environment.OSVersion.ToString(); // CPUの foreach (var processor in new System.Management.ManagementClass("Win32_Processor").GetInstances()) { // データを表示 this.CpuNameBox.Text = string.Format("{0}", processor["Name"]); this.CpuVenderBox.Text = string.Format("{0}", processor["Manufacturer"]); this.CpuMaxClockBox.Text = string.Format("{0:0.00}", double.Parse(processor["MaxClockSpeed"].ToString()) / 1024); this.CpuCoreBox.Text = string.Format("{0}", processor["NumberOfCores"]); } foreach (var os in new System.Management.ManagementClass("Win32_OperatingSystem").GetInstances()) { // メモリを表示 this.CpuMemoryBox.Text = string.Format("{0:0.00}", double.Parse(os["MaxProcessMemorySize"].ToString()) / 1024 / 1024); } // プラットフォームデータを表示 this.PlatformNameBox.Text = computerCL.Platform.Name; this.PlatformVenderBox.Text = computerCL.Platform.Vendor; this.PlatformVersionBox.Text = computerCL.Platform.Version; this.PlatformProfileBox.Text = computerCL.Platform.Profile; // デバイスデータを表示 this.DeviceNameBox.ItemsSource = computerCL.Devices; this.DeviceNameBox.SelectionChanged += (sender, e) => { var device = this.DeviceNameBox.SelectedItem as Cloo.ComputeDevice; this.DeviceVenderBox.Text = device.Vendor; this.DeviceDriverVersionBox.Text = device.DriverVersion; this.DeviceOpenCLVersionBox.Text = device.OpenCLCVersionString; this.DeviceCUBox.Text = string.Format("{0}", device.MaxComputeUnits); this.DeviceGlobalMemoryBox.Text = string.Format("{0}", device.GlobalMemorySize); this.DeviceLocalMemoryBox.Text = string.Format("{0}", device.LocalMemorySize); }; this.DeviceNameBox.SelectedIndex = 0; // 前の時刻を初期化する Action resetOldTime = () => { oldT = this.computer.T; oldTimeStep = this.computer.TimeStep; }; // CPUで計算する場合は this.WithCpuButton.Checked += (sender, e) => { // 計算プログラムをCpuに設定 this.computer = computerCpu; // 前の時刻を初期化 resetOldTime(); }; // OpenCLで計算する場合は this.WithCLButton.Checked += (sender, e) => { // 計算プログラムをOpenCLに設定 this.computer = computerCL; // 前の時刻を初期化 resetOldTime(); }; // 前の時刻を初期化 resetOldTime(); // 初期化完了 this.LogLine("完了"); }
/// <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> 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); }; }