ParallelStencil.jl icon indicating copy to clipboard operation
ParallelStencil.jl copied to clipboard

Creating modules that depend on `ParallelStencil.jl`

Open smartalecH opened this issue 2 years ago • 3 comments

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.

smartalecH avatar Oct 27 '22 20:10 smartalecH

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.

albert-de-montserrat avatar Oct 28 '22 06:10 albert-de-montserrat

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?

smartalecH avatar Oct 28 '22 17:10 smartalecH

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.

korbinian90 avatar Apr 18 '23 15:04 korbinian90

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

omlins avatar Jul 30 '24 17:07 omlins