Skip to content

Commit

Permalink
update names for leaf_size and multipole_threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
rymanderson committed May 18, 2024
1 parent 393c80c commit 97b8bbc
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 180 deletions.
6 changes: 3 additions & 3 deletions scripts/benchmark.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ if !isdir(joinpath(scripts_dir, save_dir))
mkdir(joinpath(scripts_dir, save_dir))
end

function benchmark_fmm(ns_fmm, is_direct; expansion_order = 2, n_per_branch=50, multipole_acceptance_criterion=4)
function benchmark_fmm(ns_fmm, is_direct; expansion_order = 2, leaf_size=50, multipole_threshold=4)
times_fmm = zeros(length(ns_fmm))
times_direct = zeros(length(ns_fmm)) .* NaN
# max_errs = zeros(length(orders))
Expand All @@ -23,7 +23,7 @@ function benchmark_fmm(ns_fmm, is_direct; expansion_order = 2, n_per_branch=50,
ms = rand(n)
xs = rand(n,3)
masses = [Mass(xs[i,:],[ms[i]],zeros(1),zeros(3)) for i in 1:length(ms)]
@elapsed fmm.fmm!(masses, derivatives, expansion_order, n_per_branch, multipole_acceptance_criterion)
@elapsed fmm.fmm!(masses, derivatives, expansion_order, leaf_size, multipole_threshold)
@elapsed fmm.direct!(masses; reflex=false)

println("\nBegin Benchmark Test:")
Expand All @@ -38,7 +38,7 @@ function benchmark_fmm(ns_fmm, is_direct; expansion_order = 2, n_per_branch=50,
# fmm
# println("\t\tBuilding Tree...")
println("\t\tComputing FMM...")
times_fmm[i] = @elapsed tree = fmm.fmm!(masses, expansion_order, n_per_branch, multipole_acceptance_criterion, B2M!, P2P!)
times_fmm[i] = @elapsed tree = fmm.fmm!(masses, expansion_order, leaf_size, multipole_threshold, B2M!, P2P!)
println("\t\tFMM time: $(times_fmm[i]) seconds")
for ii in 1:n
potentials_fmm[ii] = masses[ii].potential[1]
Expand Down
15 changes: 15 additions & 0 deletions scripts/optimize.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using FastMultipole, Random

include("../test/gravitational.jl")

function optimize(n_bodies; seed = 123, radius_factor=0.1, p_bounds=(1,15), theta_bounds=(0.0,0.1,1.0), ncrit_bound=(0,500))
# generate system
Random.seed!(seed)
bodies = rand(8,n_bodies)
bodies[4,:] ./= (n_bodies^(1/3)*2)
bodies[4,:] .*= radius_factor
bodies[5,:] ./= (n_bodies^(1/3)*2) # attempt to preserve similar potential at each body, rather than a constant total strength
system = Gravitational(bodies)

#
end
148 changes: 74 additions & 74 deletions scripts/simple_gravitational.jl

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/containers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ struct MultiTree{TF,N,TB,P} <: Tree{TF,P}
inverse_sort_index_list::NTuple{N,Vector{Int}}
buffers::TB
expansion_order::Val{P}
n_per_branch::Int64 # max number of bodies in a leaf
leaf_size::Int64 # max number of bodies in a leaf
# cost_parameters::MultiCostParameters{N}
# cost_parameters::SVector{N,Float64}
end
Expand All @@ -256,7 +256,7 @@ struct SingleTree{TF,TB,P} <: Tree{TF,P}
inverse_sort_index::Vector{Int64}
buffer::TB
expansion_order::Val{P}
n_per_branch::Int64 # max number of bodies in a leaf
leaf_size::Int64 # max number of bodies in a leaf
# cost_parameters::SingleCostParameters
# cost_parameters::Float64
end
Expand Down
22 changes: 11 additions & 11 deletions src/estimate_cost.jl
Original file line number Diff line number Diff line change
Expand Up @@ -438,32 +438,32 @@ function DummySystem(n_bodies, TF)
return DummySystem(bodies, potential, vector_potential, velocity, gradient)
end

function direct_cost_estimate(system, n_per_branch; n_iter=10)
function direct_cost_estimate(system, leaf_size; n_iter=10)
# create dummy system
# target_system = DummySystem(n_per_branch, eltype(system[1,POSITION]))
# target_system = DummySystem(leaf_size, eltype(system[1,POSITION]))

# # benchmark
# t = 0.0
# for i in 1:n_iter+1 # one for precompilation
# i > 1 && (t += @elapsed direct!(target_system, 1:n_per_branch, system, 1:n_per_branch))
# i > 1 && (t += @elapsed direct!(target_system, 1:leaf_size, system, 1:leaf_size))
# end
# t /= n_iter # mean time per iteration
# t /= n_per_branch^2 # mean time per interaction
# t /= leaf_size^2 # mean time per interaction

# return t
return dummy_direct_cost_estimate(system, n_per_branch)
return dummy_direct_cost_estimate(system, leaf_size)
end

function dummy_direct_cost_estimate(system, n_per_branch)
function dummy_direct_cost_estimate(system, leaf_size)
return NaN
end

function direct_cost_estimate(systems::Tuple, n_per_branch; n_iter=10)
# return SVector{length(systems),Float64}(direct_cost_estimate(system, n_per_branch; n_iter=n_iter) for system in systems)
return dummy_direct_cost_estimate(systems, n_per_branch)
function direct_cost_estimate(systems::Tuple, leaf_size; n_iter=10)
# return SVector{length(systems),Float64}(direct_cost_estimate(system, leaf_size; n_iter=n_iter) for system in systems)
return dummy_direct_cost_estimate(systems, leaf_size)
end

function dummy_direct_cost_estimate(systems::Tuple, n_per_branch)
return SVector{length(systems),Float64}(dummy_direct_cost_estimate(system, n_per_branch) for system in systems)
function dummy_direct_cost_estimate(systems::Tuple, leaf_size)
return SVector{length(systems),Float64}(dummy_direct_cost_estimate(system, leaf_size) for system in systems)
end

48 changes: 24 additions & 24 deletions src/fmm.jl
Original file line number Diff line number Diff line change
Expand Up @@ -458,32 +458,32 @@ end
#####
##### create interaction lists
#####
function build_interaction_lists(target_branches, source_branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
function build_interaction_lists(target_branches, source_branches, multipole_threshold, farfield, nearfield, self_induced)
m2l_list = Vector{SVector{2,Int32}}(undef,0)
direct_list = Vector{SVector{2,Int32}}(undef,0)
build_interaction_lists!(m2l_list, direct_list, 1, 1, target_branches, source_branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
build_interaction_lists!(m2l_list, direct_list, 1, 1, target_branches, source_branches, multipole_threshold, farfield, nearfield, self_induced)
return m2l_list, direct_list
end

function build_interaction_lists!(m2l_list, direct_list, i_target, j_source, target_branches, source_branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
function build_interaction_lists!(m2l_list, direct_list, i_target, j_source, target_branches, source_branches, multipole_threshold, farfield, nearfield, self_induced)
source_branch = source_branches[j_source]
target_branch = target_branches[i_target]

spacing = source_branch.center - target_branch.center
center_spacing_squared = spacing[1]*spacing[1] + spacing[2]*spacing[2] + spacing[3]*spacing[3]
summed_radii_squared = target_branch.radius + source_branch.radius
summed_radii_squared *= summed_radii_squared
if center_spacing_squared * multipole_acceptance_criterion * multipole_acceptance_criterion >= summed_radii_squared && farfield # meet M2L criteria
if center_spacing_squared * multipole_threshold * multipole_threshold >= summed_radii_squared && farfield # meet M2L criteria
push!(m2l_list, SVector{2}(i_target, j_source))
elseif source_branch.n_branches == target_branch.n_branches == 0 && nearfield && (i_target!=j_source || self_induced) # both leaves
push!(direct_list, SVector{2}(i_target, j_source))
elseif source_branch.n_branches == 0 || (target_branch.radius >= source_branch.radius && target_branch.n_branches != 0) # source is a leaf OR target is not a leaf and is bigger or the same size
for i_child in target_branch.branch_index
build_interaction_lists!(m2l_list, direct_list, i_child, j_source, target_branches, source_branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
build_interaction_lists!(m2l_list, direct_list, i_child, j_source, target_branches, source_branches, multipole_threshold, farfield, nearfield, self_induced)
end
else # source is not a leaf AND target is a leaf or is smaller
for j_child in source_branch.branch_index
build_interaction_lists!(m2l_list, direct_list, i_target, j_child, target_branches, source_branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
build_interaction_lists!(m2l_list, direct_list, i_target, j_child, target_branches, source_branches, multipole_threshold, farfield, nearfield, self_induced)
end
end
end
Expand Down Expand Up @@ -512,9 +512,9 @@ Apply all interactions of `source_systems` acting on `target_systems` using the
# Optional Arguments
- `expansion_order::Int`: the expansion order to be used
- `n_per_branch_source::Int`: maximum number of bodies from `source_systems` allowed in a leaf-level branch
- `n_per_branch_target::Int`: maximum number of bodies from `target_systems` allowed in a leaf-level branch
- `multipole_acceptance_criterion::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `leaf_size_source::Int`: maximum number of bodies from `source_systems` allowed in a leaf-level branch
- `leaf_size_target::Int`: maximum number of bodies from `target_systems` allowed in a leaf-level branch
- `multipole_threshold::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `scalar_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a scalar potential from `source_systems`
- `vector_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a vector potential from `source_systems`
- `velocity::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a velocity from `source_systems`
Expand All @@ -532,7 +532,7 @@ Apply all interactions of `source_systems` acting on `target_systems` using the
"""
function fmm!(target_systems, source_systems;
scalar_potential=true, vector_potential=true, velocity=true, velocity_gradient=true,
expansion_order=5, n_per_branch_source=50, n_per_branch_target=50, multipole_acceptance_criterion=0.4,
expansion_order=5, leaf_size_source=50, leaf_size_target=50, multipole_threshold=0.4,
nearfield=true, farfield=true, self_induced=true,
unsort_source_bodies=true, unsort_target_bodies=true,
source_shrink_recenter=true, target_shrink_recenter=true,
Expand All @@ -542,13 +542,13 @@ function fmm!(target_systems, source_systems;
target_systems = wrap_duplicates(target_systems, source_systems)

# create trees
source_tree = Tree(source_systems; expansion_order, n_per_branch=n_per_branch_source, shrink_recenter=source_shrink_recenter)
target_tree = Tree(target_systems; expansion_order, n_per_branch=n_per_branch_target, shrink_recenter=target_shrink_recenter)
source_tree = Tree(source_systems; expansion_order, leaf_size=leaf_size_source, shrink_recenter=source_shrink_recenter)
target_tree = Tree(target_systems; expansion_order, leaf_size=leaf_size_target, shrink_recenter=target_shrink_recenter)

# perform fmm
fmm!(target_tree, target_systems, source_tree, source_systems;
scalar_potential, vector_potential, velocity, velocity_gradient,
multipole_acceptance_criterion,
multipole_threshold,
reset_source_tree=false, reset_target_tree=false,
nearfield, farfield, self_induced,
unsort_source_bodies, unsort_target_bodies
Expand All @@ -575,8 +575,8 @@ Apply all interactions of `systems` acting on itself using the fast multipole me
# Optional Arguments
- `expansion_order::Int`: the expansion order to be used
- `n_per_branch::Int`: maximum number of bodies from `systems` allowed in a leaf-level branch
- `multipole_acceptance_criterion::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `leaf_size::Int`: maximum number of bodies from `systems` allowed in a leaf-level branch
- `multipole_threshold::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `scalar_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a scalar potential from `source_systems`
- `vector_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a vector potential from `source_systems`
- `velocity::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a velocity from `source_systems`
Expand All @@ -592,18 +592,18 @@ Apply all interactions of `systems` acting on itself using the fast multipole me
"""
function fmm!(systems;
scalar_potential=true, vector_potential=true, velocity=true, velocity_gradient=true,
expansion_order=5, n_per_branch=50, multipole_acceptance_criterion=0.4,
expansion_order=5, leaf_size=50, multipole_threshold=0.4,
nearfield=true, farfield=true, self_induced=true,
unsort_bodies=true, shrink_recenter=true,
save_tree=false, save_name="tree"
)
# create tree
tree = Tree(systems; expansion_order, n_per_branch, shrink_recenter)
tree = Tree(systems; expansion_order, leaf_size, shrink_recenter)

# perform fmm
fmm!(tree, systems;
scalar_potential, vector_potential, velocity, velocity_gradient,
multipole_acceptance_criterion, reset_tree=false,
multipole_threshold, reset_tree=false,
nearfield, farfield, self_induced,
unsort_bodies
)
Expand All @@ -629,7 +629,7 @@ Dispatches `fmm!` using an existing `::Tree`.
# Optional Arguments
- `multipole_acceptance_criterion::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `multipole_threshold::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `scalar_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a scalar potential from `source_systems`
- `vector_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a vector potential from `source_systems`
- `velocity::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(systems)` indicating whether each system should receive a velocity from `source_systems`
Expand All @@ -642,13 +642,13 @@ Dispatches `fmm!` using an existing `::Tree`.
"""
function fmm!(tree::Tree, systems;
scalar_potential=true, vector_potential=true, velocity=true, velocity_gradient=true,
multipole_acceptance_criterion=0.4, reset_tree=true,
multipole_threshold=0.4, reset_tree=true,
nearfield=true, farfield=true, self_induced=true,
unsort_bodies=true
)
fmm!(tree, systems, tree, systems;
scalar_potential, vector_potential, velocity, velocity_gradient,
multipole_acceptance_criterion, reset_source_tree=reset_tree, reset_target_tree=false,
multipole_threshold, reset_source_tree=reset_tree, reset_target_tree=false,
nearfield, farfield, self_induced,
unsort_source_bodies=unsort_bodies, unsort_target_bodies=false
)
Expand Down Expand Up @@ -676,7 +676,7 @@ Dispatches `fmm!` using existing `::Tree` objects.
# Optional Arguments
- `multipole_acceptance_criterion::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `multipole_threshold::Float64`: number between 0 and 1 (often denoted theta in [0,1]) controls the accuracy by determining the non-dimensional distance after which multipoles are used; 0 means an infinite distance (no error, high cost), and 1 means barely convergent (high error, low cost)
- `scalar_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a scalar potential from `source_systems`
- `vector_potential::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a vector potential from `source_systems`
- `velocity::Bool`: either a `::Bool` or a `::AbstractVector{Bool}` of length `length(target_systems)` indicating whether each system should receive a velocity from `source_systems`
Expand All @@ -690,7 +690,7 @@ Dispatches `fmm!` using existing `::Tree` objects.
"""
function fmm!(target_tree::Tree, target_systems, source_tree::Tree, source_systems;
scalar_potential=true, vector_potential=true, velocity=true, velocity_gradient=true,
multipole_acceptance_criterion=0.4,
multipole_threshold=0.4,
reset_source_tree=true, reset_target_tree=true,
nearfield=true, farfield=true, self_induced=true,
unsort_source_bodies=true, unsort_target_bodies=true
Expand All @@ -706,7 +706,7 @@ function fmm!(target_tree::Tree, target_systems, source_tree::Tree, source_syste
reset_source_tree && (reset_expansions!(source_tree))

# create interaction lists
m2l_list, direct_list = build_interaction_lists(target_tree.branches, source_tree.branches, multipole_acceptance_criterion, farfield, nearfield, self_induced)
m2l_list, direct_list = build_interaction_lists(target_tree.branches, source_tree.branches, multipole_threshold, farfield, nearfield, self_induced)

# assemble derivatives switch
derivatives_switch = DerivativesSwitch(scalar_potential, vector_potential, velocity, velocity_gradient, target_systems)
Expand Down
Loading

0 comments on commit 97b8bbc

Please sign in to comment.