I’m new to Julia and writing a particle simulation. Each System of Particles should have a set of functions that update the forces acting on the system/particles. These functions should be user definable. I don’t know how to solve this problem properly. Currently I’m using a tuple that contains the functions that should be called:
mutable struct System
ps::Vector{Particle}
forces::Tuple
end
and then calling them like:
function updateForces!(s::System)
for force in s.forces
force(s)
end
end
This however is slow compared to calling the functions directly. @benchmark reports 350ns with 0 allocations vs 430ns with 0 allocations when using 2 custom functions for s.forces.
Looping over functulns tend to be slow because the compiler often cannot devirtualize the call. People usually use GitHub - yuyichao/FunctionWrappers.jl to work around that (although I have heard it is slower than needed due to some julia issue).
Note that this overhead you are observing will be probably irrelevant relative to the cost of computing the functions themselves (it is probably a case of premature optimization).
Take a look at the packages of JuliaMolSim and at CellListMap.jl, probably there is useful stuff there to you.
I don’t fully understand the {} syntax jet, but as far as I understand it specifies types. Does forces::Tuple{F, F} mean that the tuple forces contains 2 objects of type F?
When I try to implement this, I get errors as forces contains different functions, e.g. harmonic! and f_d!:
julia> System([Particle([0.,0.]) for i in 1:3], (harmonic!, f_d!))
ERROR: MethodError: no method matching System(::Vector{Particle}, ::Tuple{typeof(harmonic!), typeof(f_d!)})
Closest candidates are:
System(::Vector{P}, ::Tuple{F, F}) where {P, F} at REPL[5]:2
Aren’t you fighting multiple dispatch a bit here by trying to privately define a set of functions for a struct in a classic object oriented design approach?
What’s preventing you from having the system struct separate to a list of methods that can operate on system structs? You could even define them in a separate module?
I want to have multiple systems where each of them has a different list of forces that act on the system.
How would I do such a thing with multiple dispatch?
Ok - difficult to discern the need - are you trying to allow users to create their own functions for a particular set of forces? If so, are the System structs not actually structs that inherit from the System Abstract struct?
Then you can have any number of methods to act on a concrete system struct and add them to a collection to do as you first posted.
Do you mean, that there should be specific structs that inherit from an abstract struct and specify the functions/forces that should act on the special struct?
Yes, basically. I’m on my phone but that sounds like that pattern you’re describing: you differentiate the action by the properties of the struct.
This is multiple dispatch if inverted from your original design i.e. they are not all actually “system” structs; they are particular types of system struct
What differentiates the different particles? Can that be encoded in the type(s), for example as type parameters, or must each particle instance get an arbitrary list of functions?
If you can design it as the former, you definitely should leverage dispatch instead of the current design.
So the user would define a custom “system” e.g. MySystem and a custom function updateForces!(s::MySystem) that calls the forces-function the user wants.
Then multiple dispatch chooses the appropriate updateForces!.
Do I understand this correctly?
I see your point, however the same kind of particles can be trapped in different kinds of traps e.g harmonic or sinusoidal, so there has to be the possibility to have different forces acting in different systems with the same type of particles in it.