Hi all,
I am interested in evaluating a volume integral of a vector-valued function. So the integral has the following form:
I already tried to use nested quadgk and hcubature. Both methods give me the correct results, but also result in a high number of allocations.
Here is my code for using nested quadgk.
function f(r_accent_x, r_accent_y, r_accent_z, r::SVector, M, inside_cube)
r_accent = @SVector[r_accent_x, r_accent_y, r_accent_z]
teller = cross(M, r - r_accent)
noemer = norm(r - r_accent)^3
#Add 0..00001 to avoid singularity
if inside_cube
noemer += 0.00001
result = teller/noemer
return @SVector[result[1], result[2], result[3]]
else
result = teller/noemer
return @SVector[result[1], result[2], result[3]]
end
end
# Function to check if r is inside the cube
function is_inside_cube(r, cube_vertices)
min_coords = minimum([vec[i] for vec in cube_vertices for i in 1:3])
max_coords = maximum([vec[i] for vec in cube_vertices for i in 1:3])
all(r .>= min_coords) && all(r .<= max_coords)
end
function evaluate_integral_nested_QuadGK(r::SVector, M, source_vertices)
x_vals = [v[1] for v in source_vertices]
y_vals = [v[2] for v in source_vertices]
z_vals = [v[3] for v in source_vertices]
min_x = minimum(x_vals)
max_x = maximum(x_vals)
min_y = minimum(y_vals)
max_y = maximum(y_vals)
min_z = minimum(z_vals)
max_z = maximum(z_vals)
y_middle_edge = (source_vertices[1][2] + source_vertices[3][2])/2
count_smaller = count(y -> y < y_middle_edge, y_vals)
inside_cube = is_inside_cube(r, source_vertices)
g(r_accent_x, r_accent_y, r, M) = quadgk(r_accent_z -> f(r_accent_x, r_accent_y, r_accent_z, r, M, inside_cube), min_z, max_z)[1]
function h_varies(count_smaller, r_accent_x, r, M)
if count_smaller >= 4
return quadgk(u -> g(r_accent_x, u*(r_accent_x - min_x - min_y) + min_y , r, M) * (r_accent_x - min_x - min_y), 0, 1)[1]
else
return quadgk(u -> g(r_accent_x, -u*(max_y - (r_accent_x - min_x)) + max_y, r, M) * (max_y - (r_accent_x - min_x)), 0, 1)[1]
end
end
h(r_accent_x, r, M) = h_varies(count_smaller, r_accent_x, r, M)
l(r, M) = quadgk_count(r_accent_x -> h(r_accent_x, r, M) , min_x, max_x)[1]
return l(r,M)
end
@btime evaluate_integral_nested_QuadGK(center_vertices, [1, 0, 0], source_vertices)
# 125.739 ms (2686730 allocations: 209.38 MiB)
Both center_vertices as source_vertices are StaticArrays.
Is there a method or an existing Julia package for solving this integral that is more efficient?
Thanks!