@@ -14,146 +14,125 @@ function interact!(dv, v_particle_system, u_particle_system,
1414
1515 system_coords = current_coordinates (u_particle_system, particle_system)
1616 neighbor_system_coords = current_coordinates (u_neighbor_system, neighbor_system)
17-
18- # In order to visualize quantities like pressure forces or viscosity forces, uncomment
19- # the following code and the two other lines below that are marked as "debug example".
20- # debug_array = zeros(ndims(particle_system), nparticles(particle_system))
21-
22- # For `distance == 0`, the analytical gradient is zero, but the unsafe gradient
23- # and the density diffusion divide by zero.
24- # To account for rounding errors, we check if `distance` is almost zero.
25- # Since the coordinates are in the order of the smoothing length `h`, `distance^2` is in
26- # the order of `h^2`, so we need to check `distance < sqrt(eps(h^2))`.
27- # Note that `sqrt(eps(h^2)) != eps(h)`.
28- h = initial_smoothing_length (particle_system)
29- almostzero = sqrt (eps (h^ 2 ))
30-
31- # Loop over all pairs of particles and neighbors within the kernel cutoff
32- foreach_point_neighbor (particle_system, neighbor_system,
33- system_coords, neighbor_system_coords, semi;
34- points= each_integrated_particle (particle_system)) do particle,
35- neighbor,
36- pos_diff,
37- distance
38- # Skip neighbors with the same position because the kernel gradient is zero.
39- # Note that `return` only exits the closure, i.e., skips the current neighbor.
40- skip_zero_distance (particle_system) && distance < almostzero && return
41-
42- # Now that we know that `distance` is not zero, we can safely call the unsafe
43- # version of the kernel gradient to avoid redundant zero checks.
44- grad_kernel = smoothing_kernel_grad_unsafe (particle_system, pos_diff,
45- distance, particle)
46-
47- # `foreach_point_neighbor` makes sure that `particle` and `neighbor` are
48- # in bounds of the respective system. For performance reasons, we use `@inbounds`
49- # in this hot loop to avoid bounds checking when extracting particle quantities.
50- rho_a = @inbounds current_density (v_particle_system, particle_system, particle)
51- rho_b = @inbounds current_density (v_neighbor_system, neighbor_system, neighbor)
52- rho_mean = (rho_a + rho_b) / 2
53-
54- v_a = @inbounds current_velocity (v_particle_system, particle_system, particle)
55- v_b = @inbounds current_velocity (v_neighbor_system, neighbor_system, neighbor)
56-
57- # Determine correction factors.
58- # This can be ignored, as these are all 1 when no correction is used.
59- (viscosity_correction, pressure_correction,
60- surface_tension_correction) = free_surface_correction (correction, particle_system,
61- rho_mean)
62-
17+ neighborhood_search = get_neighborhood_search (particle_system, neighbor_system, semi)
18+
19+ # For `distance == 0`, the analytical gradient is zero, but the unsafe gradient divides
20+ # by zero. To account for rounding errors, we check if `distance` is almost zero.
21+ # Since the coordinates are in the order of the compact support `c`, `distance^2` is in
22+ # the order of `c^2`, so we need to check `distance < sqrt(eps(c^2))`.
23+ # Note that `sqrt(eps(c^2)) != eps(c)`.
24+ compact_support_ = compact_support (particle_system, neighbor_system)
25+ almostzero = sqrt (eps (compact_support_^ 2 ))
26+
27+ @threaded semi for particle in each_integrated_particle (particle_system)
28+ # We are looping over the particles of `particle_system`, so it is guaranteed
29+ # that `particle` is in bounds of `particle_system`.
6330 m_a = @inbounds hydrodynamic_mass (particle_system, particle)
64- m_b = @inbounds hydrodynamic_mass (neighbor_system, neighbor )
31+ p_a = @inbounds current_pressure (v_particle_system, particle_system, particle )
6532
6633 v_a = @inbounds current_velocity (v_particle_system, particle_system, particle)
67- v_b = @inbounds current_velocity (v_neighbor_system, neighbor_system, neighbor)
68-
69- # The following call is equivalent to
70- # `p_a = current_pressure(v_particle_system, particle_system, particle)`
71- # `p_b = current_pressure(v_neighbor_system, neighbor_system, neighbor)`
72- # Only when the neighbor system is a `WallBoundarySystem` or a `TotalLagrangianSPHSystem`
73- # with the boundary model `PressureMirroring`, this will return `p_b = p_a`, which is
74- # the pressure of the fluid particle.
75- p_a,
76- p_b = @inbounds particle_neighbor_pressure (v_particle_system,
77- v_neighbor_system,
78- particle_system, neighbor_system,
79- particle, neighbor)
80-
81- dv_pressure = pressure_correction *
82- pressure_acceleration (particle_system, neighbor_system,
83- particle, neighbor,
84- m_a, m_b, p_a, p_b, rho_a, rho_b, pos_diff,
85- distance, grad_kernel, correction)
86-
87- dv_particle = Ref (dv_pressure)
88-
89- # Propagate `@inbounds` to the viscosity function, which accesses particle data
90- @inbounds dv_viscosity! (dv_particle, particle_system, neighbor_system,
91- v_particle_system, v_neighbor_system,
92- particle, neighbor, pos_diff, distance,
93- sound_speed, m_a, m_b, rho_a, rho_b,
94- v_a, v_b, grad_kernel, viscosity_correction)
95-
96- # Extra terms in the momentum equation when using a shifting technique
97- @inbounds dv_shifting! (dv_particle, shifting_technique (particle_system),
98- particle_system, neighbor_system,
99- v_particle_system, v_neighbor_system,
100- particle, neighbor, m_a, m_b, rho_a, rho_b,
101- pos_diff, distance, grad_kernel, correction)
102-
103- @inbounds surface_tension_force! (dv_particle,
104- surface_tension_a, surface_tension_b,
105- particle_system, neighbor_system,
106- particle, neighbor, pos_diff, distance,
107- rho_a, rho_b, grad_kernel,
108- surface_tension_correction)
109-
110- @inbounds adhesion_force! (dv_particle, surface_tension_a, particle_system,
111- neighbor_system,
112- particle, neighbor, pos_diff, distance)
113-
114- for i in 1 : ndims (particle_system)
115- @inbounds dv[i, particle] += dv_particle[][i]
116- # Debug example
117- # debug_array[i, particle] += dv_pressure[i]
118- end
34+ rho_a = @inbounds current_density (v_particle_system, particle_system, particle)
11935
36+ # Accumulate the RHS contributions over all neighbors before writing to `dv`,
37+ # to reduce the number of memory writes.
38+ # Note that we need a `Ref` in order to be able to update these variables
39+ # inside the closure in the `foreach_neighbor` loop.
40+ dv_particle = Ref (zero (v_a))
12041 drho_particle = Ref (zero (rho_a))
12142
122- # TODO If variable smoothing_length is used, this should use the neighbor smoothing length
123- # Propagate `@inbounds` to the continuity equation, which accesses particle data
124- @inbounds continuity_equation! (drho_particle, density_calculator,
125- particle_system, neighbor_system,
126- v_particle_system, v_neighbor_system,
127- particle, neighbor, pos_diff, distance,
128- m_b, rho_a, rho_b, v_a, v_b, grad_kernel)
43+ # Loop over all neighbors within the kernel cutoff
44+ @inbounds PointNeighbors. foreach_neighbor (system_coords, neighbor_system_coords,
45+ neighborhood_search,
46+ particle) do particle, neighbor,
47+ pos_diff, distance
48+ # Skip neighbors with the same position because the kernel gradient is zero.
49+ # Note that `return` only exits the closure, i.e., skips the current neighbor.
50+ skip_zero_distance (particle_system) && distance < almostzero && return
51+
52+ # Now that we know that `distance` is not zero, we can safely call the unsafe
53+ # version of the kernel gradient to avoid redundant zero checks.
54+ grad_kernel = smoothing_kernel_grad_unsafe (particle_system, pos_diff,
55+ distance, particle)
56+
57+ # `foreach_neighbor` makes sure that `neighbor` is in bounds of `neighbor_system`
58+ m_b = @inbounds hydrodynamic_mass (neighbor_system, neighbor)
59+ v_b = @inbounds current_velocity (v_neighbor_system, neighbor_system, neighbor)
60+ rho_b = @inbounds current_density (v_neighbor_system, neighbor_system, neighbor)
61+ rho_mean = (rho_a + rho_b) / 2
62+
63+ # The following call is equivalent to
64+ # `p_b = current_pressure(v_neighbor_system, neighbor_system, neighbor)`
65+ # Only when the neighbor system is a `WallBoundarySystem`
66+ # or a `TotalLagrangianSPHSystem` with the boundary model `PressureMirroring`,
67+ # this will return `p_b = p_a`, which is the pressure of the fluid particle.
68+ p_b = @inbounds neighbor_pressure (v_neighbor_system, neighbor_system,
69+ neighbor, p_a)
70+
71+ # Determine correction factors.
72+ # This can usually be ignored, as these are all 1 when no correction is used.
73+ (viscosity_correction, pressure_correction,
74+ surface_tension_correction) = free_surface_correction (correction,
75+ particle_system,
76+ rho_mean)
77+
78+ # For `ContinuityDensity` without correction, this is equivalent to
79+ # dv_pressure = -m_b * (p_a + p_b) / (rho_a * rho_b) * grad_kernel
80+ dv_pressure = pressure_acceleration (particle_system, neighbor_system,
81+ particle, neighbor,
82+ m_a, m_b, p_a, p_b, rho_a, rho_b, pos_diff,
83+ distance, grad_kernel, correction)
84+ dv_particle[] += dv_pressure * pressure_correction
85+
86+ # Propagate `@inbounds` to the viscosity function, which accesses particle data
87+ @inbounds dv_viscosity! (dv_particle, particle_system, neighbor_system,
88+ v_particle_system, v_neighbor_system,
89+ particle, neighbor, pos_diff, distance,
90+ sound_speed, m_a, m_b, rho_a, rho_b,
91+ v_a, v_b, grad_kernel, viscosity_correction)
92+
93+ # Extra terms in the momentum equation when using a shifting technique
94+ @inbounds dv_shifting! (dv_particle, shifting_technique (particle_system),
95+ particle_system, neighbor_system,
96+ v_particle_system, v_neighbor_system,
97+ particle, neighbor, m_a, m_b, rho_a, rho_b,
98+ pos_diff, distance, grad_kernel, correction)
99+
100+ @inbounds surface_tension_force! (dv_particle,
101+ surface_tension_a, surface_tension_b,
102+ particle_system, neighbor_system,
103+ particle, neighbor, pos_diff, distance,
104+ rho_a, rho_b, grad_kernel,
105+ surface_tension_correction)
106+
107+ @inbounds adhesion_force! (dv_particle, surface_tension_a, particle_system,
108+ neighbor_system,
109+ particle, neighbor, pos_diff, distance)
110+
111+ # TODO If variable smoothing_length is used, this should use the neighbor smoothing length
112+ # Propagate `@inbounds` to the continuity equation, which accesses particle data
113+ @inbounds continuity_equation! (drho_particle, density_calculator,
114+ particle_system, neighbor_system,
115+ v_particle_system, v_neighbor_system,
116+ particle, neighbor, pos_diff, distance,
117+ m_b, rho_a, rho_b, v_a, v_b, grad_kernel)
118+ end
129119
120+ for i in eachindex (dv_particle[])
121+ @inbounds dv[i, particle] += dv_particle[][i]
122+ end
130123 @inbounds write_drho_particle! (dv, density_calculator, drho_particle, particle)
131124 end
132- # Debug example
133- # periodic_box = neighborhood_search.periodic_box
134- # Note: this saves a file in every stage of the integrator
135- # if !@isdefined iter; iter = 0; end
136- # TODO : This call should use public API. This requires some additional changes to simplify the calls.
137- # trixi2vtk(v_particle_system, u_particle_system, -1.0, particle_system, periodic_box, debug=debug_array, prefix="debug", iter=iter += 1)
138125
139126 return dv
140127end
141128
142- @propagate_inbounds function particle_neighbor_pressure (v_particle_system,
143- v_neighbor_system,
144- particle_system, neighbor_system,
145- particle, neighbor)
146- p_a = current_pressure (v_particle_system, particle_system, particle)
147- p_b = current_pressure (v_neighbor_system, neighbor_system, neighbor)
148-
149- return p_a, p_b
129+ @propagate_inbounds function neighbor_pressure (v_neighbor_system, neighbor_system,
130+ neighbor, p_a)
131+ return current_pressure (v_neighbor_system, neighbor_system, neighbor)
150132end
151133
152- @inline function particle_neighbor_pressure (v_particle_system, v_neighbor_system,
153- particle_system,
154- neighbor_system:: WallBoundarySystem{<:BoundaryModelDummyParticles{PressureMirroring}} ,
155- particle, neighbor)
156- p_a = current_pressure (v_particle_system, particle_system, particle)
157-
158- return p_a, p_a
134+ @inline function neighbor_pressure (v_neighbor_system,
135+ neighbor_system:: WallBoundarySystem{<:BoundaryModelDummyParticles{PressureMirroring}} ,
136+ neighbor, p_a)
137+ return p_a
159138end
0 commit comments