I have a type which looks like this:
mutable struct FQCTDipole{T<:Function} <: AbstractForceField
terms::Vector{T}
storage::FQCTDipoleStorage
results::ForceFieldResults
end
The only part of this that matters if the Vector{Function}
which is currently being evaluated (with simplified arguments) as follows:
function evaluate!(coords::Vector{MVector{3, Float64}}, ff::AbstractForceField)
for i in eachindex(ff.terms)
ff.terms[i](coords, ff)
end
end
Importantly, this is designed in such a way that all the arguments to each term
will be identical. Also, none of the functions return anything and instead mutate some buffers.
What I have learned, and seen some mention of since, is that the evaluate!
function above will spend a huge amount of time compiling every time it is called . I guess this is because some piece of information is opaque to the compiler and hence it cannot guarantee the same functions will be called each time we loop through the terms
array.
I can verify that the code gets dramatically faster and doesn’t recompile if I just make a function like this:
function composite_func(coords::Vector{MVector{3, Float64}}, ff::AbstractForceField)
term_a!(coords, ff)
term_b!(coords, ff)
term_c!(coords, ff)
end
where term_a!
would have been the first element of ff.terms
. I am open to adding a field to my struct which contains this composite function and then changing evaluate!
to just call this.
The problem is, I would like to be able to potentially change the functions which make up this composite function at runtime. I am aware that this will require recompiling the new composite function every time it changes and that’s fine.
This seems like a great use for generated functions, if I understand how they actually work, but I don’t really know how to go about doing this… I’ve tried various things that don’t seem to work.
Any help or suggestions would be greatly appreciated!