@@ -4,39 +4,31 @@ const TrixiParticlesODESolution = ODESolution{<:Any, <:Any, <:Any, <:Any, <:Any,
44 <: ODEProblem {<: Any , <: Any , <: Any ,
55 <: Semidiscretization }}
66
7+ # This is the main recipe
78RecipesBase. @recipe function f (sol:: TrixiParticlesODESolution )
89 # Redirect everything to the next recipe
910 return sol. u[end ]. x... , sol. prob. p
1011end
1112
1213# GPU version
13- RecipesBase. @recipe function f (sol :: TrixiParticlesODESolution , semi:: Semidiscretization )
14+ RecipesBase. @recipe function f (v_ode :: AbstractGPUArray , u_ode , semi:: Semidiscretization )
1415 # Move GPU data to the CPU
15- v_ode = Array (sol . u[ end ] . x[ 1 ] )
16- u_ode = Array (sol . u[ end ] . x[ 2 ] )
17- semi_ = Adapt. adapt (Array, sol . prob . p )
16+ v_ode_ = Array (v_ode )
17+ u_ode_ = Array (u_ode )
18+ semi_ = Adapt. adapt (Array, semi )
1819
1920 # Redirect everything to the next recipe
20- return v_ode, u_ode, semi_, particle_spacings (semi)
21- end
22-
23- RecipesBase. @recipe function f (v_ode:: AbstractGPUArray , u_ode, semi:: Semidiscretization ;
24- particle_spacings= nothing ,
25- size= (600 , 400 ), # Default size
26- xlims= (- Inf , Inf ), ylims= (- Inf , Inf ))
27- throw (ArgumentError (" to plot GPU data, use `plot(sol, semi)`" ))
21+ return v_ode_, u_ode_, semi_
2822end
2923
3024RecipesBase. @recipe function f (v_ode, u_ode, semi:: Semidiscretization ;
3125 particle_spacings= TrixiParticles. particle_spacings (semi),
3226 size= (600 , 400 ), # Default size
3327 xlims= (- Inf , Inf ), ylims= (- Inf , Inf ))
34- return v_ode, u_ode, semi, particle_spacings
35- end
36-
37- RecipesBase. @recipe function f (v_ode, u_ode, semi:: Semidiscretization , particle_spacings;
38- size= (600 , 400 ), # Default size
39- xlims= (- Inf , Inf ), ylims= (- Inf , Inf ))
28+ # We need to split this in two recipes in order to find the minimum and maximum
29+ # coordinates across all systems.
30+ # In this first recipe, we collect the data for each system,
31+ # and then pass it to the next recipe.
4032 systems_data = map (enumerate (semi. systems)) do (i, system)
4133 u = wrap_u (u_ode, system, semi)
4234 periodic_box = get_neighborhood_search (system, semi). periodic_box
@@ -54,27 +46,20 @@ RecipesBase.@recipe function f(v_ode, u_ode, semi::Semidiscretization, particle_
5446 x_min, y_min = minimum (coordinates, dims= 2 ) .- 0.5 particle_spacing
5547 x_max, y_max = maximum (coordinates, dims= 2 ) .+ 0.5 particle_spacing
5648
57- # `x_min`, `x_max`, etc. are used to automatically set the marker size.
58- # When `xlims` or `ylims` are passed explicitly, we have to update these to get the correct marker size.
59- isfinite (first (xlims)) && (x_min = xlims[1 ])
60- isfinite (last (xlims)) && (x_max = xlims[2 ])
61-
62- isfinite (first (ylims)) && (y_min = ylims[1 ])
63- isfinite (last (ylims)) && (y_max = ylims[2 ])
64-
6549 return (; x, y, x_min, x_max, y_min, y_max, particle_spacing,
6650 label= timer_name (system))
6751 end
6852
53+ # Pass the semidiscretization and the collected data to the next recipe
6954 return (semi, systems_data... )
7055end
7156
7257function particle_spacings (semi:: Semidiscretization )
7358 return [system. initial_condition. particle_spacing for system in semi. systems]
7459end
7560
76- RecipesBase. @recipe function f (( initial_conditions:: InitialCondition ) . .. ;
77- xlims = ( Inf , Inf ), ylims = ( Inf , Inf ))
61+ RecipesBase. @recipe function f (initial_conditions:: InitialCondition... )
62+ # This recipe is similar to the one above for the semidiscretization
7863 idx = 0
7964 ics = map (initial_conditions) do ic
8065 x = collect (ic. coordinates[1 , :])
@@ -88,34 +73,32 @@ RecipesBase.@recipe function f((initial_conditions::InitialCondition)...;
8873 x_min, y_min = minimum (ic. coordinates, dims= 2 ) .- 0.5 particle_spacing
8974 x_max, y_max = maximum (ic. coordinates, dims= 2 ) .+ 0.5 particle_spacing
9075
91- # `x_min`, `x_max`, etc. are used to automatically set the marker size.
92- # When `xlims` or `ylims` are passed explicitly, we have to update these to get the correct marker size.
93- isfinite (first (xlims)) && (x_min = xlims[1 ])
94- isfinite (last (xlims)) && (x_max = xlims[2 ])
95-
96- isfinite (first (ylims)) && (y_min = ylims[1 ])
97- isfinite (last (ylims)) && (y_max = ylims[2 ])
98-
9976 idx += 1
10077
10178 return (; x, y, x_min, x_max, y_min, y_max, particle_spacing,
10279 label= " initial condition " * " $idx " )
10380 end
10481
82+ # Pass the first initial condition and the collected data to the next recipe
10583 return (first (initial_conditions), ics... )
10684end
10785
10886RecipesBase. @recipe function f (:: Union{InitialCondition, Semidiscretization} ,
109- data... ; zcolor= nothing , size= (600 , 400 ), colorbar_title= " " ,
110- xlims= (Inf , Inf ), ylims= (Inf , Inf ))
87+ data... ; size= (600 , 400 ), xlims= (Inf , Inf ), ylims= (Inf , Inf ))
88+ # `data` is a tuple of named tuples, passed from the recipe above.
89+ # Each named tuple contains coordinates and metadata for a system or initial condition.
90+ #
91+ # First find the minimum and maximum coordinates across all systems.
11192 x_min = minimum (obj. x_min for obj in data)
11293 x_max = maximum (obj. x_max for obj in data)
11394
11495 y_min = minimum (obj. y_min for obj in data)
11596 y_max = maximum (obj. y_max for obj in data)
11697
11798 # `x_min`, `x_max`, etc. are used to automatically set the marker size.
118- # When `xlims` or `ylims` are passed explicitly, we have to update these to get the correct marker size.
99+ # So they need to be the minimum and maximum coordinates of the plot area.
100+ # When `xlims` or `ylims` are passed explicitly, we have to update these
101+ # to get the correct marker size.
119102 isfinite (first (xlims)) && (x_min = xlims[1 ])
120103 isfinite (last (xlims)) && (x_max = xlims[2 ])
121104
@@ -130,14 +113,21 @@ RecipesBase.@recipe function f(::Union{InitialCondition, Semidiscretization},
130113
131114 xlims --> (x_min, x_max)
132115 ylims --> (y_min, y_max)
133- aspect_ratio --> :equal
134116
117+ # Just having the kwargs `xlims` and `ylims` (without setting them)
118+ # is enough to make `widen = :auto` fall back to no widening.
119+ # When no explicit limits are passed, we overwrite this.
120+ if all (! isfinite, xlims) && all (! isfinite, ylims)
121+ widen --> true
122+ end
123+
124+ aspect_ratio --> :equal
135125 seriestype --> :scatter
126+ # No border around the markers
136127 markerstrokewidth --> 0
137128 grid --> false
138- colorbar_title --> colorbar_title
139- zcolor --> zcolor
140129
130+ # Now plot all systems or initial conditions
141131 for obj in data
142132 @series begin
143133 if obj. particle_spacing < eps ()
0 commit comments