Skip to content

Commit 6b4be52

Browse files
Finite splitter wall (#202)
* Add FiniteSplitterWall to obstacles. * Add FiniteSplitterWall to exports. * Fix FiniteSplitterWall typo. * Make FiniteSplitterWall mutable. * Fix FiniteSplitterWall color. * Make FiniteSplitterWalls render dashed. * Fix FiniteSplitterWall normal function. * Impement distance_init for FiniteSplitterWalls. * Add finite collisions to FiniteSplitterWalls. * Add FiniteSplitterWall test. * Update Project.toml and CHANGELOG.md. * Add FiniteSplitterWall to docs. Co-authored-by: owend <[email protected]>
1 parent 46696a6 commit 6b4be52

File tree

8 files changed

+93
-9
lines changed

8 files changed

+93
-9
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# 3.12.0
2+
* New `FiniteSplitterWall` structure.
13
# 3.11.0
24
* `particlebeam` and `randominside_xyφ` functions.
35
# 3.10.0

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "DynamicalBilliards"
22
uuid = "4986ee89-4ee5-5cef-b6b8-e49ba721d7a5"
33
repo = "https://github.com/JuliaDynamics/DynamicalBilliards.jl.git"
4-
version = "3.11.4"
4+
version = "3.12.0"
55

66
[deps]
77
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"

docs/src/ray-splitting.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ them using a simple example in this documentation page.
66
## 1. Ray-Splitting Obstacles
77
The first step is that an [`Obstacle`](@ref) that supports ray-splitting is required to be present in your billiard table. The only new feature these obstacles have is an additional Boolean field called `pflag` (propagation flag). This field notes on which side of the obstacle the particle is currently propagating.
88

9-
The normal vector as well as the distance from boundary change sign depending on the value of `pflag`. The obstacles [`Antidot`](@ref) and [`SplitterWall`](@ref) are the equivalents of disk and wall for ray-splitting.
9+
The normal vector as well as the distance from boundary change sign depending on the value of `pflag`. The obstacles [`Antidot`](@ref), [`SplitterWall`](@ref) and [`FiniteSplitterWall`](@ref) are the equivalents of disk, wall and finite-wall for ray-splitting.
1010

1111
Let's create a billiard with a bunch of ray-splitting obstacles!
1212
```@example ray

docs/src/tutorials/billiard_table.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ evolution:
101101
means that during collision time estimation, if the collision point that was
102102
calculated lies *outside* of the boundaries of the `FiniteWall`, then the
103103
returned collision time is `Inf` (no collision). `FiniteWall` is slower
104-
than `InfiniteWall` for that reason.
104+
than `InfiniteWall` for that reason. [`FiniteSplitterWall`](@ref) behaves like a `FiniteWall` during evolution.
105105

106106

107107
If you wish to create a billiard table that you know will be convex, you should
@@ -133,6 +133,7 @@ RandomWall
133133
PeriodicWall
134134
SplitterWall
135135
FiniteWall
136+
FiniteSplitterWall
136137
```
137138

138139
---

src/billiards/obstacles.jl

+50-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
export Obstacle, Disk, Antidot, RandomDisk, Wall, Circular,
22
InfiniteWall, PeriodicWall, RandomWall, SplitterWall, FiniteWall,
3-
Semicircle, Ellipse
3+
FiniteSplitterWall, Semicircle, Ellipse
44
export translate
55

66
using InteractiveUtils
@@ -314,6 +314,52 @@ function SplitterWall(sp::AbstractVector, ep::AbstractVector,
314314
end
315315
SplitterWall(sp, ep, n, name::String = "Splitter wall") =
316316
SplitterWall(sp, ep, n, true, name)
317+
318+
"""
319+
FiniteSplitterWall{T<:AbstractFloat} <: Wall{T}
320+
Finite wall obstacle allowing fow ray-splitting (mutable type).
321+
### Fields:
322+
* `sp::SVector{2,T}` : Starting point of the Wall.
323+
* `ep::SVector{2,T}` : Ending point of the Wall.
324+
* `normal::SVector{2,T}` : Normal vector to the wall, pointing to where the
325+
particle *will come from before a collision* (pointing towards the inside of the
326+
billiard). The size of the vector is irrelevant
327+
since it is internally normalized.
328+
* `isdoor::Bool` : Flag of whether this `FiniteSplitterWall` instance is a "Door".
329+
Defaults to `false`.
330+
* `pflag::Bool` : Flag that keeps track of where the particle is currently
331+
propagating (`pflag` = propagation flag).
332+
`true` is associated with the `normal` vector the wall is
333+
instantiated with. Defaults to `true`.
334+
* `name::String` : Name of the obstacle, given for user convenience.
335+
Defaults to "Finite Splitter Wall".
336+
"""
337+
mutable struct FiniteSplitterWall{T<:AbstractFloat} <: Wall{T}
338+
sp::SVector{2,T}
339+
ep::SVector{2,T}
340+
normal::SVector{2,T}
341+
width::T
342+
center::SVector{2,T}
343+
isdoor::Bool
344+
pflag::Bool
345+
name::String
346+
end
347+
function FiniteSplitterWall(sp::AbstractVector, ep::AbstractVector,
348+
n::AbstractVector, isdoor::Bool = false, pflag::Bool = true, name::String = "Finite Splitter Wall")
349+
T = eltype(sp)
350+
n = normalize(n)
351+
d = dot(n, ep-sp)
352+
if abs(d) > 10eps(T)
353+
error("Normal vector is not actually normal to the wall: dot = $d")
354+
end
355+
T = eltype(sp) <: Integer ? Float64 : eltype(sp)
356+
w = norm(ep - sp)
357+
center = @. (ep+sp)/2
358+
return FiniteSplitterWall{T}(SVector{2,T}(sp), SVector{2,T}(ep), SVector{2,T}(n),
359+
w, SVector{2,T}(center), isdoor, pflag, name)
360+
end
361+
FiniteSplitterWall(a, b, c, n::String) = FiniteSplitterWall(a, b, c, false, true, n)
362+
317363
#pretty print:
318364
show(io::IO, w::Wall{T}) where {T} = print(io, "$(w.name) {$T}\n",
319365
"start point: $(w.sp)\nend point: $(w.ep)\nnormal vector: $(w.normal)")
@@ -410,6 +456,7 @@ assumed to be very close to the obstacle's boundary).
410456
@inline normalvec(wall::Wall, pos) = wall.normal
411457
@inline normalvec(w::PeriodicWall, pos) = normalize(w.normal)
412458
@inline normalvec(w::SplitterWall, pos) = w.pflag ? w.normal : -w.normal
459+
@inline normalvec(w::FiniteSplitterWall, pos) = w.pflag ? w.normal : -w.normal
413460
@inline normalvec(disk::Circular, pos) = normalize(pos - disk.c)
414461
@inline normalvec(a::Antidot, pos) =
415462
a.pflag ? normalize(pos - a.c) : -normalize(pos - a.c)
@@ -494,11 +541,11 @@ function distance(pos::SV, e::Ellipse{T})::T where {T}
494541
end
495542

496543
# The entire functionality of `distance_init` is necessary only for
497-
# FiniteWall !!!
544+
# FiniteWall and FiniteSplitterWall !!!
498545
distance_init(p::AbstractParticle, a::Obstacle) = distance_init(p.pos, a)
499546
distance_init(pos::SVector, a::Obstacle) = distance(pos, a)
500547

501-
function distance_init(pos::SVector{2,T}, w::FiniteWall{T})::T where {T}
548+
function distance_init(pos::SVector{2,T}, w::Union{FiniteWall{T}, FiniteSplitterWall{T}})::T where {T}
502549

503550
n = normalvec(w, pos)
504551
posdot = dot(w.sp .- pos, n)

src/plotting/obstacles.jl

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
obcolor(::Obstacle) = (0,0.6,0)
22
obcolor(::Union{RandomWall, RandomDisk}) = (149/255, 88/255, 178/255)
3-
obcolor(::Union{SplitterWall, Antidot, Ellipse}) = (0.8,0.0,0)
3+
obcolor(::Union{FiniteSplitterWall, SplitterWall, Antidot, Ellipse}) = (0.8,0.0,0)
44
obcolor(::PeriodicWall) = (0.8,0.8,0)
55
obalpha(::Obstacle) = 0.5
66
obalpha(::Union{Antidot, Ellipse}) = 0.1
77
obls(::Obstacle) = "solid"
8-
obls(::Union{SplitterWall, Antidot, Ellipse}) = "dashed"
8+
obls(::Union{FiniteSplitterWall, SplitterWall, Antidot, Ellipse}) = "dashed"
99
obls(::PeriodicWall) = "dotted"
1010

1111
"""

src/timeevolution/collisions.jl

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function collision(p::Particle{T}, w::Wall{T}) where {T}
4040
end
4141
end
4242

43-
function collision(p::Particle{T}, w::FiniteWall{T}) where {T}
43+
function collision(p::Particle{T}, w::Union{FiniteWall{T}, FiniteSplitterWall{T}}) where {T}
4444
n = normalvec(w, p.pos)
4545
denom = dot(p.vel, n)
4646
# case of velocity pointing away of wall:

test/raysplt_tests.jl

+34
Original file line numberDiff line numberDiff line change
@@ -125,3 +125,37 @@ function inside_antidot(args...)
125125
end
126126

127127
billiards_testset("RAY Stays inside", identity; caller = inside_antidot)
128+
129+
@testset "FiniteSplitterWall" begin
130+
bdr = billiard_rectangle(1.0, 1.0)
131+
splitter = FiniteSplitterWall([0.5,0.0], [0.5,1.0], [-1.0,0.0])
132+
bd = Billiard(splitter, bdr...)
133+
134+
refraction(ϕ, pflag, ω) = pflag ? 0.5ϕ : 2.0ϕ
135+
transmission(ϕ, pflag, ω) = begin
136+
if pflag
137+
0.5*exp(-(ϕ)^2/2/8)^2)
138+
else
139+
abs(ϕ) < π/4 ? 0.5*exp(-(ϕ)^2/2/4)^2) : 0.0
140+
end
141+
end
142+
143+
N = 500
144+
rs = (RaySplitter([1], transmission, refraction),)
145+
ps = particlebeam(0.01, 0.5, 0, N, 0)
146+
positions = []
147+
148+
for p in ps
149+
ct, pos, vel = evolve!(p, bd, 2, rs)
150+
push!(positions, pos[end][1])
151+
reset_billiard!(bd)
152+
end
153+
154+
particles_on_left = length(filter(x ->x < 0.4, positions))
155+
particles_on_right = length(filter(x -> x > 0.6, positions))
156+
particles_in_middle = length(filter(x -> 0.4 <= x <= 0.6, positions))
157+
158+
@test 0.3N < particles_on_left < 0.7N
159+
@test 0.3N < particles_on_right < 0.7N
160+
@test particles_in_middle == 0
161+
end

0 commit comments

Comments
 (0)