-
-
Notifications
You must be signed in to change notification settings - Fork 38
GPU-Accelerated Ensemble Simulation with Randomized Decay Rates #345
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
ChrisRackauckas
merged 8 commits into
SciML:master
from
ParyaRoustaee:add-random-decay-tutorial
Apr 19, 2025
Merged
Changes from 6 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
ee76292
comparing GPU and CPU performance
859ee6b
finalized the code and link to the added tutorial
90208bc
uncommenting
ef12de0
breaking down the code with explnation for better clarity
76730b5
added more description in the link for getting started
964c47a
adding comment to hint which packages to install
3f35615
Update docs/src/getting_started.md
ChrisRackauckas 1c09532
add to building pages
ChrisRackauckas File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,107 @@ | ||
| # GPU Ensemble Simulation with Random Decay Rates | ||
|
|
||
| In this tutorial, we demonstrate how to perform GPU-accelerated ensemble simulations using DiffEqGPU.jl. We model an exponential decay ODE: | ||
| \[ u'(t) = -\lambda \, u(t) \] | ||
| with the twist that each trajectory uses a random decay rate \(\lambda\) sampled uniformly from \([0.5, 1.5]\). | ||
|
|
||
| ## Setup | ||
|
|
||
| We first define the ODE and set up an `EnsembleProblem` that randomizes the decay rate for each trajectory. | ||
|
|
||
| ```julia | ||
| # Make sure you have the necessary packages installed | ||
| # using Pkg | ||
| # Pkg.add(["OrdinaryDiffEq", "DiffEqGPU", "CUDA", "Random", "Statistics", "Plots"]) | ||
| # # Depending on your system, you might need to configure CUDA.jl: | ||
| # # import Pkg; Pkg.build("CUDA") | ||
| using OrdinaryDiffEq, DiffEqGPU, CUDA, Random, Statistics, Plots | ||
|
|
||
| # Set a random seed for reproducibility | ||
| Random.seed!(123) | ||
|
|
||
| # Define the decay ODE: du/dt = -λ * u, with initial value u(0) = 1. | ||
| decay(u, p, t) = -p * u | ||
|
|
||
| # Setup initial condition and time span (using Float32 for GPU efficiency) | ||
| u0 = 1.0f0 | ||
| tspan = (0.0f0, 5.0f0) | ||
| base_param = 1.0f0 | ||
| prob = ODEProblem(decay, u0, tspan, base_param) | ||
|
|
||
| # Define a probability function that randomizes λ for each ensemble member. | ||
| # Each trajectory's λ is sampled uniformly from [0.5, 1.5]. | ||
| prob_func = (prob, i, repeat) -> begin | ||
| new_λ = 0.5f0 + 1.0f0 * rand() | ||
| remake(prob, p = new_λ) | ||
| end | ||
|
|
||
| ensemble_prob = EnsembleProblem(prob, prob_func = prob_func, safetycopy = false) | ||
| ``` | ||
|
|
||
| # Solving on GPU and CPU | ||
|
|
||
| Here we solve the ensemble problem on both GPU and CPU. We use 10,000 trajectories with a fixed time step to facilitate performance comparison. | ||
|
|
||
| ```julia | ||
| # Number of trajectories | ||
| num_trajectories = 10_000 | ||
|
|
||
| # Solve on GPU (check for CUDA availability) | ||
| if CUDA.has_cuda() | ||
| @info "Running GPU simulation..." | ||
| gpu_sol = solve(ensemble_prob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()); | ||
| trajectories = num_trajectories, dt = 0.01f0, adaptive = false) | ||
| else | ||
| @warn "CUDA not available. Skipping GPU simulation." | ||
| gpu_sol = nothing | ||
| end | ||
|
|
||
| # Solve on CPU using multi-threading | ||
| @info "Running CPU simulation..." | ||
| cpu_sol = solve(ensemble_prob, Tsit5(), EnsembleThreads(); | ||
| trajectories = num_trajectories, dt = 0.01f0, adaptive = false) | ||
|
|
||
|
|
||
| ``` | ||
|
|
||
| # Performance Comparison | ||
|
|
||
| We measure the performance of each simulation. (Note: The first run may include compilation time.) | ||
|
|
||
| ```julia | ||
|
|
||
| # Warm-up (first run) for GPU if applicable | ||
| if gpu_sol !== nothing | ||
| @time solve(ensemble_prob, GPUTsit5(), EnsembleGPUKernel(CUDA.CUDABackend()); | ||
| trajectories = num_trajectories, dt = 0.01f0, adaptive = false) | ||
| end | ||
|
|
||
| @time cpu_sol = solve(ensemble_prob, Tsit5(), EnsembleThreads(); | ||
| trajectories = num_trajectories, dt = 0.01f0, adaptive = false) | ||
| ``` | ||
|
|
||
| # Statistical Analysis and Visualization | ||
| We analyze the ensemble by computing the mean and standard deviation of u(t)u(t) across trajectories, and then visualize the results. | ||
|
|
||
| ```julia | ||
|
|
||
| # Assuming all solutions have the same time points (fixed dt & saveat) | ||
| t_vals = cpu_sol[1].t | ||
| num_times = length(t_vals) | ||
| ensemble_vals = reduce(hcat, [sol.u for sol in cpu_sol]) # each column corresponds to one trajectory | ||
|
|
||
| # Compute ensemble statistics | ||
| mean_u = [mean(ensemble_vals[i, :]) for i in 1:num_times] | ||
| std_u = [std(ensemble_vals[i, :]) for i in 1:num_times] | ||
|
|
||
| # Plot the mean trajectory with ±1 standard deviation | ||
| p1 = plot(t_vals, mean_u, ribbon = std_u, xlabel = "Time", ylabel = "u(t)", | ||
| title = "Ensemble Mean and ±1σ", label = "Mean ± σ", legend = :topright) | ||
|
|
||
| # Histogram of final values (u at t=5) | ||
| final_vals = ensemble_vals[end, :] | ||
| p2 = histogram(final_vals, bins = 30, xlabel = "Final u", ylabel = "Frequency", | ||
| title = "Distribution of Final Values", label = "") | ||
| plot(p1, p2, layout = (1,2), size = (900,400)) | ||
|
|
||
|
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.