-
Notifications
You must be signed in to change notification settings - Fork 19
Expand file tree
/
Copy pathabstract_system.jl
More file actions
189 lines (144 loc) · 7.54 KB
/
abstract_system.jl
File metadata and controls
189 lines (144 loc) · 7.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# Abstract supertype for all system types.
abstract type AbstractSystem{NDIMS} end
@inline Base.ndims(::AbstractSystem{NDIMS}) where {NDIMS} = NDIMS
@inline Base.eltype(system::AbstractSystem) = error("eltype not implemented for system $system")
abstract type AbstractFluidSystem{NDIMS} <: AbstractSystem{NDIMS} end
timer_name(::AbstractFluidSystem) = "fluid"
vtkname(system::AbstractFluidSystem) = "fluid"
abstract type AbstractStructureSystem{NDIMS} <: AbstractSystem{NDIMS} end
timer_name(::AbstractStructureSystem) = "structure"
vtkname(system::AbstractStructureSystem) = "structure"
abstract type AbstractBoundarySystem{NDIMS} <: AbstractSystem{NDIMS} end
timer_name(::AbstractBoundarySystem) = "boundary"
vtkname(system::AbstractBoundarySystem) = "boundary"
# Number of integrated variables in the first component of the ODE system (coordinates)
@inline u_nvariables(system) = ndims(system)
# Number of integrated variables in the second component
# of the ODE system (velocity and sometimes density)
@inline v_nvariables(system) = ndims(system)
# Number of particles in the system
@inline nparticles(system) = length(system.mass)
# Number of particles in the system whose positions are to be integrated
# (corresponds to the size of u and du).
# See comment below for `each_integrated_particle` for more details.
@inline n_integrated_particles(system) = nparticles(system)
# Iterator over all particle indices in the system
@inline eachparticle(system::AbstractSystem) = each_active_particle(system)
@inline eachparticle(initial_condition) = Base.OneTo(nparticles(initial_condition))
# Iterator over all particle indices in the system whose positions are to be integrated
# (corresponds to the size of u and du).
# For most systems, this is the same as `eachparticle`, but for the
# `TotalLagrangianSPHSystem`, the clamped particles are included in `eachparticle`
# but not in `each_integrated_particle`.
@inline each_integrated_particle(system) = each_integrated_particle(system, buffer(system))
@inline function each_integrated_particle(system, ::Nothing)
return Base.OneTo(n_integrated_particles(system))
end
@inline active_coordinates(u, system) = active_coordinates(u, system, buffer(system))
@inline active_coordinates(u, system, ::Nothing) = current_coordinates(u, system)
@inline each_active_particle(system) = each_active_particle(system, buffer(system))
@inline each_active_particle(system, ::Nothing) = Base.OneTo(nparticles(system))
@inline function set_zero!(du)
du .= zero(eltype(du))
return du
end
initialize!(system, semi) = system
# This should not be dispatched by system type. We always expect to get a column of `A`.
@propagate_inbounds function extract_svector(A, system, i)
extract_svector(A, Val(ndims(system)), i)
end
# Return the `i`-th column of the array `A` as an `SVector`.
@inline function extract_svector(A, ::Val{NDIMS}, i) where {NDIMS}
# Explicit bounds check, which can be removed by calling this function with `@inbounds`
@boundscheck checkbounds(A, NDIMS, i)
# Assume inbounds access now
return SVector(ntuple(@inline(dim->@inbounds A[dim, i]), NDIMS))
end
# Return `A[:, :, i]` as an `SMatrix`.
@inline function extract_smatrix(A, system, particle)
@boundscheck checkbounds(A, ndims(system), ndims(system), particle)
# Extract the matrix elements for this particle as a tuple to pass to SMatrix
return SMatrix{ndims(system),
ndims(system)}(ntuple(@inline(i->@inbounds A[mod(i - 1,
ndims(system)) + 1,
div(i - 1,
ndims(system)) + 1,
particle]),
Val(ndims(system)^2)))
end
# Specifically get the current coordinates of a particle for all system types.
@propagate_inbounds function current_coords(u, system, particle)
return extract_svector(current_coordinates(u, system), system, particle)
end
# This can be dispatched by system type, since for some systems, the current coordinates
# are stored in u, for others in the system itself. By default, try to extract them from u.
@inline current_coordinates(u, system) = u
# Specifically get the initial coordinates of a particle for all system types
@propagate_inbounds function initial_coords(system, particle)
return extract_svector(initial_coordinates(system), system, particle)
end
# This can be dispatched by system type
@inline initial_coordinates(system) = system.initial_condition.coordinates
@inline coordinates_eltype(system::AbstractSystem) = eltype(initial_coordinates(system))
@propagate_inbounds function current_velocity(v, system, particle)
return extract_svector(current_velocity(v, system), system, particle)
end
# This can be dispatched by system type, since for some systems, the current velocity
# is stored in `v`, for others it might be stored elsewhere.
# By default, try to extract it from `v`.
@inline current_velocity(v, system) = v
@propagate_inbounds function current_density(v, system::AbstractSystem, particle)
return current_density(v, system)[particle]
end
@propagate_inbounds function current_pressure(v, system::AbstractSystem, particle)
return current_pressure(v, system)[particle]
end
@inline function current_acceleration(system, particle)
# TODO: Return `dv` of solid particles
return zero(SVector{ndims(system), eltype(system)})
end
@inline set_particle_density!(v, system, particle, density) = v
@inline set_particle_pressure!(v, system, particle, pressure) = v
@inline function smoothing_kernel(system, distance, particle)
(; smoothing_kernel) = system
return kernel(smoothing_kernel, distance, smoothing_length(system, particle))
end
@inline function smoothing_kernel_grad(system, pos_diff, distance, particle)
return corrected_kernel_grad(system_smoothing_kernel(system), pos_diff,
distance, smoothing_length(system, particle),
system_correction(system), system, particle)
end
# System updates do nothing by default, but can be dispatched if needed
function update_positions!(system, v, u, v_ode, u_ode, semi, t)
return system
end
function update_quantities!(system, v, u, v_ode, u_ode, semi, t)
return system
end
function update_pressure!(system, v, u, v_ode, u_ode, semi, t)
return system
end
function update_boundary_interpolation!(system, v, u, v_ode, u_ode, semi, t)
return system
end
function update_final!(system, v, u, v_ode, u_ode, semi, t)
return system
end
@inline initial_smoothing_length(system) = smoothing_length(system, nothing)
@inline function smoothing_length(system, particle)
return system.smoothing_length
end
@inline system_smoothing_kernel(system) = system.smoothing_kernel
@inline system_correction(system) = nothing
@inline particle_spacing(system, particle) = system.initial_condition.particle_spacing
# Assuming a constant particle spacing one can calculate the number of neighbors within the
# compact support for an undisturbed particle distribution.
function ideal_neighbor_count(::Val{D}, particle_spacing, compact_support) where {D}
throw(ArgumentError("Unsupported dimension: $D"))
end
@inline function ideal_neighbor_count(::Val{2}, particle_spacing, compact_support)
return floor(Int, pi * compact_support^2 / particle_spacing^2)
end
@inline @fastpow function ideal_neighbor_count(::Val{3}, particle_spacing, compact_support)
return floor(Int, 4 // 3 * pi * compact_support^3 / particle_spacing^3)
end