ParallelStencil.jl
ParallelStencil.jl copied to clipboard
Creating modules that depend on `ParallelStencil.jl`
Suppose I wanted to create a module that depends on ParallelStencil.jl (e.g. a self-contained finite-difference code). What's the best way to do this?
Normally this is rather straightforward... but the primary source of ambiguity for me is how to best handle the @init_parallel_stencil() macro.
Naively, I might just call that macro at the top of the script which calls the new module, but it gets hairy when you need to access the created Data class inside of your new module (there's a lot of redundant passing that occurs).
Perhaps a more elegant scenario is to call that macro within the module itself (but then you have a chicken-egg problem when trying to specify the parameters of that macro...)?
I'm curious to see how others tackle this.
Not very elegant, this is what I currently do now:
function environment!(model::PS_Setup{T,N}) where {T,N}
gpu = model.device == :gpu ? true : false
# call appropriate FD module
Base.eval(@__MODULE__, Meta.parse("using ParallelStencil.FiniteDifferences$(N)D"))
# start ParallelStencil
if model.device == :gpu
eval(:(@init_parallel_stencil(CUDA, $T, $N)))
Base.eval(Main, Meta.parse("using CUDA"))
else
@eval begin
@init_parallel_stencil(Threads, $T, $N)
end
end
generate_myStruct!(N)
# includes and exports
@eval begin
include("myFile.jl"))
export myfun
# etc
end
and at the top of my script I include:
# setup ParallelStencil.jl environment
model = PS_Setup(:cpu, Float64, 2) # :cpu or :gpu
environment!(model)
I am also curious to know if there's a more elegant wat to handle this.
Great! Thanks, @albert-de-montserrat!
It looks like the current strategy then is to "bootstrap" yourself through the loading process (which I guess is how ParallelStencil.jl itself works...)
I wonder if there's a cleaner (and more flexible) way to do this?
I'm using simply this to automatically decide which version to use:
using CUDA, ParallelStencil, ParallelStencil.FiniteDifferences3D
if CUDA.functional()
@eval @init_parallel_stencil(CUDA, Float32, 3)
else
@eval @init_parallel_stencil(Threads, Float32, 3)
end
The user cannot decide which version to use, however.
In this issue has been fully solved meanwhile: all backend-related dependencies were moved into extensions and init_parallel_stencil is now simply to be called once per module after using ParallelStencil.
The following test project illustrates how to create a package embracing the extensions feature:
https://github.com/omlins/ParallelStencil.jl/tree/main/test/test_projects/Diffusion