Skip to content

Commit 7a9026f

Browse files
authored
Merge pull request #280 from WaterLily-jl/refactor_measure
Refactor measure
2 parents f539311 + 8352e45 commit 7a9026f

6 files changed

Lines changed: 32 additions & 28 deletions

File tree

src/AutoBody.jl

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,13 @@ The velocity is determined _solely_ from the optional `map` function.
2828
Skips the `n,V` calculation when `d²>fastd²`.
2929
"""
3030
function measure(body::AutoBody,x,t;fastd²=Inf)
31-
# eval d=f(x,t), and n̂ = ∇f
3231
d = sdf(body,x,t)
33-
d^2>fastd² && return (d,zero(x),zero(x)) # skip n,V
34-
n = ForwardDiff.gradient(x->sdf(body,x,t), x)
35-
any(isnan.(n)) && return (d,zero(x),zero(x))
36-
37-
# correct general implicit fnc f(x₀)=0 to be a pseudo-sdf
38-
# f(x) = f(x₀)+d|∇f|+O(d²) ∴ d ≈ f(x)/|∇f|
39-
m = sum(abs2,n); d /= m; n /= m
40-
41-
# The velocity depends on the material change of ξ=m(x,t):
42-
# Dm/Dt=0 → ṁ + (dm/dx)ẋ = 0 ∴ ẋ =-(dm/dx)\ṁ
43-
J = ForwardDiff.jacobian(x->body.map(x,t), x)
44-
dot = ForwardDiff.derivative(t->body.map(x,t), t)
45-
return (d,n,-J\dot)
32+
d^2>fastd² && return (d,zero(x),zero(x))
33+
n = ForwardDiff.gradient->body.sdf(ξ,t), body.map(x,t)) # body-frame only
34+
any(isnan, n) && return (d,zero(x),zero(x)) # handle non-diff'able points
35+
J = ForwardDiff.jacobian(x->body.map(x,t), x) # for mapping n,V to x-frame
36+
n = J'n; m = sum(abs2,n); d /= m; n /= m # chain rule then normalise
37+
return (d, n, -J\ForwardDiff.derivative(t->body.map(x,t), t))
4638
end
4739

4840
using LinearAlgebra: tr

src/Body.jl

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@ Queries the body geometry to fill the arrays:
2020
- `flow.μ₁`, First kernel moment scaled by the body normal
2121
- `flow.V`, Body velocity
2222
23-
at time `t` using an immersion kernel of size `ϵ`.
23+
at time `t` using an immersion kernel of size `ϵ`. The velocity is only filled within a narrow band
24+
of size `2+ϵ` around the body. This function also fills `flow.σ` with the signed distance function.
2425
2526
See Maertens & Weymouth, doi:[10.1016/j.cma.2014.09.007](https://doi.org/10.1016/j.cma.2014.09.007).
2627
"""
2728
function measure!(a::Flow{N,T},body::AbstractBody;t=zero(T),ϵ=1) where {N,T}
28-
a.V .= zero(T); a.μ₀ .= one(T); a.μ₁ .= zero(T); d²=(2+ϵ)^2
29+
a.V .= zero(T); a.μ₀ .= one(T); a.μ₁ .= zero(T); d²=T(2+ϵ)^2
30+
measure_sdf!(a.σ, body, t; fastd²=d²) # measure separately to allow specialization
2931
@fastmath @inline function fill!(μ₀,μ₁,V,d,I)
30-
d[I] = sdf(body,loc(0,I,T),t,fastd²=d²)
3132
if d[I]^2<
3233
for i 1:N
3334
dᵢ,nᵢ,Vᵢ = measure(body,loc(i,I,T),t,fastd²=d²)
35+
dᵢ = abs(dᵢ) 0.5 ? dᵢ : copysign(dᵢ,d[I]) # enforce sign consistency
3436
V[I,i] = Vᵢ[i]
3537
μ₀[I,i] = WaterLily.μ₀(dᵢ,ϵ)
3638
for j 1:N
@@ -99,7 +101,7 @@ Base.:-(a::AbstractBody) = SetBody(-,a,NoBody())
99101
Base.:-(a::AbstractBody, b::AbstractBody) = a (-b)
100102

101103
# Measurements
102-
function measure(body::SetBody,x,t;fastd²=Inf)
104+
function measure(body::SetBody,x::AbstractVector{T},t;fastd²=T(Inf)) where T
103105
body.op(measure(body.a,x,t;fastd²),measure(body.b,x,t;fastd²)) # can't mapreduce within GPU kernel
104106
end
105-
measure(body::SetBody{typeof(-)},x,t;fastd²=Inf) = ((d,n,V) = measure(body.a,x,t;fastd²); (-d,-n,V))
107+
measure(body::SetBody{typeof(-)},x::AbstractVector{T},t;fastd²=T(Inf)) where T = ((d,n,V) = measure(body.a,x,t;fastd²); (-d,-n,V))

src/Metrics.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ end
8888
8989
BDIM-masked surface normal.
9090
"""
91-
@inline function nds(body,x,t)
92-
d,n,_ = measure(body,x,t,fastd²=1)
91+
@inline function nds(body,x::AbstractVector{T},t) where T
92+
d,n,_ = measure(body,x,t,fastd²=one(T))
9393
n*WaterLily.kern(clamp(d,-1,1))
9494
end
9595

src/MultiLevelPoisson.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@ function restrictML(b::Poisson)
2323
restrictL!(aL,b.L,perdir=b.perdir)
2424
Poisson(ax,aL,copy(ax);b.perdir)
2525
end
26-
function restrictL!(a::AbstractArray{T},b;perdir=()) where T
26+
function restrictL!(a::AbstractArray{T,M},b;perdir=()) where {T,M}
2727
Na,n = size_u(a)
2828
for i 1:n
2929
@loop a[I,i] = restrictL(I,i,b) over I CartesianIndices(map(n->2:n-1,Na))
3030
end
31-
BC!(a,zeros(SVector{n,T}),false,perdir) # correct μ₀ @ boundaries
31+
BC!(a,zero(SVector{M-1,T}),false,perdir) # correct μ₀ @ boundaries
3232
end
3333
restrict!(a,b) = @inside a[I] = restrict(I,b)
3434
prolongate!(a,b) = @inside a[I] = b[down(I)]

src/RigidMap.jl

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,21 @@ for n in 1:10
2525
end
2626
```
2727
"""
28-
struct RigidMap{A<:AbstractVector,R} <: Function
28+
struct RigidMap{A<:AbstractVector,R,M} <: Function
2929
x₀ :: A # center of translation
3030
θ :: R # rotation (angle in 2D, euler angles in 3D)
3131
xₚ :: A # rotation offset
3232
V :: A # linear velocity of the center
3333
ω :: R # angular velocity (scalar in 2D, vector in 3D)
34+
:: M # rotation matrix (precomputed for efficiency)
3435
end
35-
RigidMap(x₀::SVector,θ;xₚ=zero(x₀),V=zero(x₀),ω=zero(θ)) = RigidMap(x₀, θ, xₚ, V, ω)
36+
RigidMap(x₀::SVector,θ;xₚ=zero(x₀),V=zero(x₀),ω=zero(θ)) = RigidMap(x₀, θ, xₚ, V, ω, rotation(θ))
3637

3738
# this is the function map(x,t) AND derivative(t->map(x,t),t)
38-
(map::RigidMap)(x::SVector,t=0) = rotation(map.θ)*(x-map.x₀-map.xₚ)+map.xₚ
39-
(map::RigidMap)(x::SVector,::ForwardDiff.Dual{Tag}) where Tag = Dual{Tag}.(map(x),-rotation(map.θ)*(map.V+map.ω×(x-map.x₀-map.xₚ)))
39+
(m::RigidMap)(x::SVector,t=0) = m.*(x-m.x₀-m.xₚ)+m.xₚ
40+
(m::RigidMap)(x::SVector,t::ForwardDiff.Dual{Tag}) where Tag = Dual{Tag}.(m(x),map_velocity(m, x, t))
41+
map_jacobian(m::RigidMap, x, t) = m.
42+
map_velocity(m::RigidMap, x, t) = -m.*(m.V + m.ω×(x-m.x₀-m.xₚ))
4043

4144
# cross product in 2D and rotation matrix in 2D and 3D
4245
import WaterLily: ×
@@ -45,7 +48,9 @@ rotation(θ::T) where T = SA{T}[cos(θ) sin(θ); -sin(θ) cos(θ)]
4548
rotation::SVector{3,T}) where T = SA{T}[cos(θ[3])*cos(θ[2]) cos(θ[3])*sin(θ[2])*sin(θ[1])+sin(θ[3])*cos(θ[1]) -cos(θ[3])*sin(θ[2])*cos(θ[1])+sin(θ[3])*sin(θ[1]);
4649
-sin(θ[3])*cos(θ[2]) -sin(θ[3])*sin(θ[2])*sin(θ[1])+cos(θ[3])*cos(θ[1]) sin(θ[3])*sin(θ[2])*cos(θ[1])+cos(θ[3])*sin(θ[1]);
4750
sin(θ[2]) -cos(θ[2])*sin(θ[1]) cos(θ[2])*cos(θ[1])]
48-
import ConstructionBase: setproperties
51+
52+
import ConstructionBase: setproperties, constructorof
53+
constructorof(::Type{<:RigidMap}) = (x₀,θ,xₚ,V,ω,_) -> RigidMap(x₀,θ;xₚ,V,ω) # force precomputation of R̂
4954
setmap(body::AbstractBody; kwargs...) = setproperties(body,map=setproperties(body.map; kwargs...))
5055
setmap(body::SetBody; kwargs...) = SetBody(body.op,setmap(body.a; kwargs...),setmap(body.b; kwargs...))
5156
setmap(body::NoBody; kwargs...) = NoBody()

test/alloctest.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,9 @@ backend != "SIMD" && throw(ArgumentError("KernelAbstractions backend not allowed
3333
r = run(b)
3434
println("▶ Allocated "*@sprintf("%.0f", r.memory/1e3)*" KiB")
3535
@test r.memory < 50000 # less than 50 KiB allocated on the best mom_step! run (commit f721343 ≈ 8 KiB)
36+
37+
b = @benchmarkable measure!($sim) samples=100; tune!(b) # check 100 times
38+
r = run(b)
39+
println("▶ Allocated "*@sprintf("%.0f", r.memory/1e3)*" KiB")
40+
@test r.memory < 50000 # less than 50 KiB allocated on the best mom_step! run (commit f721343 ≈ 8 KiB)
3641
end

0 commit comments

Comments
 (0)