From f038f265dde59c771506cabb47fffe5706875257 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 30 Sep 2024 21:50:25 +0200 Subject: [PATCH 01/13] Add Metal support --- Project.toml | 5 ++++- ext/ChmyMetalExt/ChmyMetalExt.jl | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 ext/ChmyMetalExt/ChmyMetalExt.jl diff --git a/Project.toml b/Project.toml index 509ba7ee..d50b7017 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Chmy" uuid = "33a72cf0-4690-46d7-b987-06506c2248b9" authors = ["Ivan Utkin , Ludovic Raess , and contributors"] -version = "0.1.19" +version = "0.1.20" [deps] Adapt = "79e6a3ab-5dfb-504d-930d-738a2a938a0e" @@ -13,10 +13,12 @@ MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" [weakdeps] AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +Metal = "dde4c033-4e86-420c-a63e-0dd931031962" [extensions] ChmyAMDGPUExt = "AMDGPU" ChmyCUDAExt = "CUDA" +ChmyMetalExt = "Metal" [compat] AMDGPU = "0.8, 0.9, 1" @@ -25,4 +27,5 @@ CUDA = "5" KernelAbstractions = "0.9" MPI = "0.20" MacroTools = "0.5" +Metal = "1" julia = "1.9" diff --git a/ext/ChmyMetalExt/ChmyMetalExt.jl b/ext/ChmyMetalExt/ChmyMetalExt.jl new file mode 100644 index 00000000..ed780c43 --- /dev/null +++ b/ext/ChmyMetalExt/ChmyMetalExt.jl @@ -0,0 +1,19 @@ +module ChmyMetalExt + +using Metal, KernelAbstractions + +import Chmy.Architectures: heuristic_groupsize, set_device!, get_device, pointertype + +Base.unsafe_wrap(::MetalBackend, ptr::Metal.MtlPtr, dims) = unsafe_wrap(MtlArray, ptr, dims) + +pointertype(::MetalBackend, T::DataType) = Metal.MtlPtr{T} + +set_device!(dev::Metal.MTL.MTLDeviceInstance) = Metal.device!(dev) + +get_device(::MetalBackend, id::Integer) = Metal.MTL.MTLDevice(id) + +heuristic_groupsize(::MetalBackend, ::Val{1}) = (256,) +heuristic_groupsize(::MetalBackend, ::Val{2}) = (32, 8) +heuristic_groupsize(::MetalBackend, ::Val{3}) = (32, 8, 1) + +end From 71cd67e380d788416da5f90b44029a5a0bcbf707 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Mon, 30 Sep 2024 21:50:38 +0200 Subject: [PATCH 02/13] Cleanup --- ext/ChmyAMDGPUExt/ChmyAMDGPUExt.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ChmyAMDGPUExt/ChmyAMDGPUExt.jl b/ext/ChmyAMDGPUExt/ChmyAMDGPUExt.jl index ae8361e3..951527ca 100644 --- a/ext/ChmyAMDGPUExt/ChmyAMDGPUExt.jl +++ b/ext/ChmyAMDGPUExt/ChmyAMDGPUExt.jl @@ -1,6 +1,6 @@ module ChmyAMDGPUExt -using AMDGPU, KernelAbstractions, Chmy +using AMDGPU, KernelAbstractions import Chmy.Architectures: heuristic_groupsize, set_device!, get_device, pointertype From 3f349d004e9cf4dfcb044b90481a993ab9b5be47 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Tue, 1 Oct 2024 18:07:15 +0200 Subject: [PATCH 03/13] Rework tests and add Metal --- .buildkite/run_tests.yml | 32 +++ test/Project.toml | 2 + test/common.jl | 22 +- test/runtests.jl | 3 + test/test_boundary_conditions.jl | 398 ++++++++++++++++--------------- test/test_boundary_functions.jl | 177 +++++++------- test/test_fields.jl | 142 +++++------ test/test_grids.jl | 308 ++++++++++++------------ test/test_interpolations.jl | 122 +++++----- 9 files changed, 642 insertions(+), 564 deletions(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index d3b52e63..3a844505 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -25,6 +25,8 @@ steps: timeout_in_minutes: 120 soft_fail: - exit_status: 3 + env: + JULIA_NUM_THREADS: 4 - label: "AMDGPU Julia {{matrix.version}}" matrix: @@ -54,5 +56,35 @@ steps: - exit_status: 3 env: JULIA_NUM_THREADS: 4 + + - label: "Metal Julia {{matrix.julia}}" + matrix: + setup: + version: + - "1.10" + - "1.11" + plugins: + - JuliaCI/julia#v1: + version: "{{matrix.version}}" + - JuliaCI/julia-coverage#v1: + codecov: true + command: | + julia -e 'println("--- :julia: Instantiating project") + using Pkg + Pkg.develop(; path=pwd())' || exit 3 + + julia -e 'println("+++ :julia: Running tests") + using Pkg + Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=true)' + agents: + queue: "juliaecosystem" + os: "macos" + arch: "aarch64" + timeout_in_minutes: 60 + soft_fail: + - exit_status: 3 + env: + JULIA_NUM_THREADS: 4 + env: SECRET_CODECOV_TOKEN: "D2H/GglFTcK7SKyfuO/Fy34xrVWHzXbtGTGQXAA3wpEPNAATGhHO/mIm0ILLzhMZSI1LplJBxJ7nV5WVsky0e/01nbSnW5iB0QqFHK8rD+lXUr4ls4zMlyUa0Lvsl/HixFyhwBtFhy8ruwUsqN8AbJNSJSiF9x4jXhzTgIvlO25/HqQObcfJa6qwcw0m9uMa3K26w1xrPhdE7F4mdUUREjB1W8dzfkKF+vZUeMqYFKgit21uQ9QsRjDJl0ExOEw0SC910rtGHtDO0bpIe+D1nEGQsQr8VEN3o0hOCgTJrya8MFitBqkKeVBV/NUImu4UtxlNb7r0ZrjTawiFle2tfg==;U2FsdGVkX1+sdgrm8OBTX9elIdJMwLMpOvXFFtHrG9lj5J8qDBdbjJDva3XMXkbF6I4PCh9G9NW0pEcF9ghb7g==" diff --git a/test/Project.toml b/test/Project.toml index c785276b..e9553275 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -8,9 +8,11 @@ Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [weakdeps] AMDGPU = "21141c5a-9bdb-4563-92ae-f87d6854732e" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" +Metal = "dde4c033-4e86-420c-a63e-0dd931031962" [compat] AMDGPU = "0.8, 0.9, 1" CUDA = "5" KernelAbstractions = "0.9" MPI = "0.20" +Metal = "1" diff --git a/test/common.jl b/test/common.jl index dcb18a4a..978ad460 100644 --- a/test/common.jl +++ b/test/common.jl @@ -3,13 +3,31 @@ using Chmy using KernelAbstractions +# testing for various floating point arithmetic precisions +precisions = [Float32, Float64] + # add KA backends backends = KernelAbstractions.Backend[CPU()] +# do not test Float64 on Metal.jl +skip_Float64 = [false] + if get(ENV, "JULIA_CHMY_BACKEND", "") == "AMDGPU" using AMDGPU - AMDGPU.functional() && push!(backends, ROCBackend()) + if AMDGPU.functional() + push!(backends, ROCBackend()) + push!(skip_Float64, false) + end elseif get(ENV, "JULIA_CHMY_BACKEND", "") == "CUDA" using CUDA - CUDA.functional() && push!(backends, CUDABackend()) + if CUDA.functional() + push!(backends, CUDABackend()) + push!(skip_Float64, false) + end +elseif get(ENV, "JULIA_CHMY_BACKEND", "") == "Metal" + using Metal + if Metal.functional() + push!(backends, MetalBackend()) + push!(skip_Float64, true) + end end diff --git a/test/runtests.jl b/test/runtests.jl index 78be7944..2f368cf2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -67,6 +67,9 @@ _, backend_name = parse_flags!(ARGS, "--backend"; default="CPU", typ=String) elseif backend_name == "CUDA" Pkg.add("CUDA") ENV["JULIA_CHMY_BACKEND"] = "CUDA" +elseif backend_name == "Metal" + Pkg.add("Metal") + ENV["JULIA_CHMY_BACKEND"] = "Metal" end exit(runtests()) diff --git a/test/test_boundary_conditions.jl b/test/test_boundary_conditions.jl index 18f68f68..2354b63e 100644 --- a/test/test_boundary_conditions.jl +++ b/test/test_boundary_conditions.jl @@ -5,203 +5,207 @@ using Chmy.Fields using Chmy.Grids using Chmy.BoundaryConditions -for backend in backends - @testset "$(basename(@__FILE__)) (backend: $backend)" begin - arch = Arch(backend) - - @testset "1D Cartesian Center()" begin - nx = 8 - grid = UniformGrid(arch; origin=(-π,), extent=(2π,), dims=(nx,)) - field = Field(arch, grid, Center()) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ .-field_i[2]) - @test all(field_i[end] .≈ .-field_i[end-1]) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ field_i[2]) - @test all(field_i[end] .≈ field_i[end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = 2.0 - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ .-field_i[2] .+ 2v) - @test all(field_i[end] .≈ .-field_i[end-1] .+ 2v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = 2.0 - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Vertex(), 1) .≈ q) - @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Vertex(), nx + 1) .≈ q) - end - end - - @testset "1D Cartesian Vertex()" begin - nx = 8 - grid = UniformGrid(arch; origin=(-π,), extent=(2π,), dims=(nx,)) - field = Field(arch, grid, Vertex()) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[2] .≈ 0.0) - @test all(field_i[end-1] .≈ 0.0) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ field_i[2]) - @test all(field_i[end] .≈ field_i[end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = 2.0 - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[2] .≈ v) - @test all(field_i[end-1] .≈ v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = 2.0 - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Center(), 0) .≈ q) - @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Center(), nx + 1) .≈ q) - end - end - - @testset "2D Cartesian" begin - nx, ny = 8, 8 - grid = UniformGrid(arch; origin=(-π, -π), extent=(2π, 2π), dims=(nx, ny)) - field = Field(arch, grid, (Center(), Vertex())) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1]) - @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2] .≈ 0.0) - @test all(field_i[2:end-1, end-1] .≈ 0.0) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ field_i[2, 2:end-1]) - @test all(field_i[end, 2:end-1] .≈ field_i[end-1, 2:end-1]) - - @test all(field_i[2:end-1, 1] .≈ field_i[2:end-1, 2]) - @test all(field_i[2:end-1, end] .≈ field_i[2:end-1, end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = 2.0 - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1] .+ 2v) - @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1] .+ 2v) - - @test all(field_i[2:end-1, 2] .≈ v) - @test all(field_i[2:end-1, end-1] .≈ v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = 2.0 - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2, 2:end-1] .- field_i[1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1) .≈ q) - @test all((field_i[end, 2:end-1] .- field_i[end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2] .- field_i[2:end-1, 1]) ./ Δy(grid, Center(), 1, 0) .≈ q) - @test all((field_i[2:end-1, end] .- field_i[2:end-1, end-1]) ./ Δy(grid, Center(), 1, ny + 1) .≈ q) - end - end - - @testset "3D Cartesian" begin - nx, ny, nz = 8, 8, 6 - grid = UniformGrid(arch; origin=(-π, -π, -π), extent=(2π, 2π, 2π), dims=(nx, ny, nz)) - field = Field(arch, grid, (Center(), Vertex(), Center())) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1]) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2, 2:end-1] .≈ 0.0) - @test all(field_i[2:end-1, end-1, 2:end-1] .≈ 0.0) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2]) - @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1]) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ field_i[2, 2:end-1, 2:end-1]) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ field_i[end-1, 2:end-1, 2:end-1]) - - @test all(field_i[2:end-1, 1, 2:end-1] .≈ field_i[2:end-1, 2, 2:end-1]) - @test all(field_i[2:end-1, end, 2:end-1] .≈ field_i[2:end-1, end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ field_i[2:end-1, 2:end-1, 2]) - @test all(field_i[2:end-1, 2:end-1, end] .≈ field_i[2:end-1, 2:end-1, end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = 2.0 - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1] .+ 2v) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1] .+ 2v) - - @test all(field_i[2:end-1, 2, 2:end-1] .≈ v) - @test all(field_i[2:end-1, end-1, 2:end-1] .≈ v) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2] .+ 2v) - @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1] .+ 2v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = 2.0 - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2, 2:end-1, 2:end-1] .- field_i[1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1, 1) .≈ q) - @test all((field_i[end, 2:end-1, 2:end-1] .- field_i[end-1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2, 2:end-1] .- field_i[2:end-1, 1, 2:end-1]) ./ Δy(grid, Center(), 1, 0, 1) .≈ q) - @test all((field_i[2:end-1, end, 2:end-1] .- field_i[2:end-1, end-1, 2:end-1]) ./ Δy(grid, Center(), 1, ny + 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2:end-1, 2] .- field_i[2:end-1, 2:end-1, 1]) ./ Δz(grid, Vertex(), 1, 1, 1) .≈ q) - @test all((field_i[2:end-1, 2:end-1, end] .- field_i[2:end-1, 2:end-1, end-1]) ./ Δz(grid, Vertex(), 1, 1, nz + 1) .≈ q) +for (backend, skip) in zip(backends, skip_Float64), precis in precisions + if skip && precis==Float64 + continue + else + @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin + arch = Arch(backend) + + @testset "1D Cartesian Center()" begin + nx = 8 + grid = UniformGrid(arch; origin=(precis(-π),), extent=(precis(2π),), dims=(nx,)) + field = Field(arch, grid, Center()) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ .-field_i[2]) + @test all(field_i[end] .≈ .-field_i[end-1]) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ field_i[2]) + @test all(field_i[end] .≈ field_i[end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = precis(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ .-field_i[2] .+ 2v) + @test all(field_i[end] .≈ .-field_i[end-1] .+ 2v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = precis(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Vertex(), 1) .≈ q) + @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Vertex(), nx + 1) .≈ q) + end + end + + @testset "1D Cartesian Vertex()" begin + nx = 8 + grid = UniformGrid(arch; origin=(precis(-π),), extent=(precis(2π),), dims=(nx,)) + field = Field(arch, grid, Vertex()) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[2] .≈ 0.0) + @test all(field_i[end-1] .≈ 0.0) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ field_i[2]) + @test all(field_i[end] .≈ field_i[end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = precis(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[2] .≈ v) + @test all(field_i[end-1] .≈ v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = precis(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Center(), 0) .≈ q) + @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Center(), nx + 1) .≈ q) + end + end + + @testset "2D Cartesian" begin + nx, ny = 8, 8 + grid = UniformGrid(arch; origin=(precis(-π), precis(-π)), extent=(precis(2π), precis(2π)), dims=(nx, ny)) + field = Field(arch, grid, (Center(), Vertex())) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1]) + @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2] .≈ 0.0) + @test all(field_i[2:end-1, end-1] .≈ 0.0) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ field_i[2, 2:end-1]) + @test all(field_i[end, 2:end-1] .≈ field_i[end-1, 2:end-1]) + + @test all(field_i[2:end-1, 1] .≈ field_i[2:end-1, 2]) + @test all(field_i[2:end-1, end] .≈ field_i[2:end-1, end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = precis(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1] .+ 2v) + @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1] .+ 2v) + + @test all(field_i[2:end-1, 2] .≈ v) + @test all(field_i[2:end-1, end-1] .≈ v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = precis(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2, 2:end-1] .- field_i[1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1) .≈ q) + @test all((field_i[end, 2:end-1] .- field_i[end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2] .- field_i[2:end-1, 1]) ./ Δy(grid, Center(), 1, 0) .≈ q) + @test all((field_i[2:end-1, end] .- field_i[2:end-1, end-1]) ./ Δy(grid, Center(), 1, ny + 1) .≈ q) + end + end + + @testset "3D Cartesian" begin + nx, ny, nz = 8, 8, 6 + grid = UniformGrid(arch; origin=(precis(-π), precis(-π), precis(-π)), extent=(precis(2π), precis(2π), precis(2π)), dims=(nx, ny, nz)) + field = Field(arch, grid, (Center(), Vertex(), Center())) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1]) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2, 2:end-1] .≈ 0.0) + @test all(field_i[2:end-1, end-1, 2:end-1] .≈ 0.0) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2]) + @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1]) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ field_i[2, 2:end-1, 2:end-1]) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ field_i[end-1, 2:end-1, 2:end-1]) + + @test all(field_i[2:end-1, 1, 2:end-1] .≈ field_i[2:end-1, 2, 2:end-1]) + @test all(field_i[2:end-1, end, 2:end-1] .≈ field_i[2:end-1, end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ field_i[2:end-1, 2:end-1, 2]) + @test all(field_i[2:end-1, 2:end-1, end] .≈ field_i[2:end-1, 2:end-1, end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = precis(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1] .+ 2v) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1] .+ 2v) + + @test all(field_i[2:end-1, 2, 2:end-1] .≈ v) + @test all(field_i[2:end-1, end-1, 2:end-1] .≈ v) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2] .+ 2v) + @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1] .+ 2v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = precis(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2, 2:end-1, 2:end-1] .- field_i[1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1, 1) .≈ q) + @test all((field_i[end, 2:end-1, 2:end-1] .- field_i[end-1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2, 2:end-1] .- field_i[2:end-1, 1, 2:end-1]) ./ Δy(grid, Center(), 1, 0, 1) .≈ q) + @test all((field_i[2:end-1, end, 2:end-1] .- field_i[2:end-1, end-1, 2:end-1]) ./ Δy(grid, Center(), 1, ny + 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2:end-1, 2] .- field_i[2:end-1, 2:end-1, 1]) ./ Δz(grid, Vertex(), 1, 1, 1) .≈ q) + @test all((field_i[2:end-1, 2:end-1, end] .- field_i[2:end-1, 2:end-1, end-1]) ./ Δz(grid, Vertex(), 1, 1, nz + 1) .≈ q) + end end end end diff --git a/test/test_boundary_functions.jl b/test/test_boundary_functions.jl index 05208458..e9c5aa2a 100644 --- a/test/test_boundary_functions.jl +++ b/test/test_boundary_functions.jl @@ -4,94 +4,99 @@ using Chmy.Architectures using Chmy.Grids using Chmy.BoundaryConditions -@testset "$(basename(@__FILE__)) (backend: CPU)" begin - @testset "boundary functions" begin - arch = Arch(CPU()) - nx, ny = 8, 8 - grid = UniformGrid(arch; origin=(-π, -π), extent=(2π, 2π), dims=(nx, ny)) - - @testset "continuous" begin - @testset "reduced dimensions" begin - bf = BoundaryFunction(ξ -> cos(ξ)) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 1.0 - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ 1.0 - - # changing index along other dimension shouldn't affect bc value - @test bf(grid, Vertex(), Dim(1), ny + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) - @test bf(grid, Vertex(), Dim(1), ny ÷ 2 + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny + 1) - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny ÷ 2 + 1) +for precis in precisions + # deal with tolerances for isapprox + tol = precis==Float32 ? 1e-6 : 0 + + @testset "$(basename(@__FILE__)) (backend: CPU, precis: $precis)" begin + @testset "boundary functions" begin + arch = Arch(CPU()) + nx, ny = 8, 8 + grid = UniformGrid(arch; origin=(precis(-π), precis(-π)), extent=(precis(2π), precis(2π)), dims=(nx, ny)) + + @testset "continuous" begin + @testset "reduced dimensions" begin + bf = BoundaryFunction(ξ -> cos(ξ)) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 1.0 + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ 1.0 + + # changing index along other dimension shouldn't affect bc value + @test bf(grid, Vertex(), Dim(1), ny + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) + @test bf(grid, Vertex(), Dim(1), ny ÷ 2 + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny + 1) + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny ÷ 2 + 1) + end + + @testset "full dimensions" begin + bf = BoundaryFunction((ξ, η) -> cos(ξ) * η; reduce_dims=false) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ π + @test isapprox(bf(grid, Vertex(), Dim(1), 1, ny + 1), -π, atol=tol) + @test isapprox(bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1), 0.0, atol=tol) + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ π + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ π + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ -π + end + + @testset "with parameters" begin + bf = BoundaryFunction((ξ, η) -> cos(ξ) * η; parameters=(η = π)) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π + @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ π + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ π + end end - @testset "full dimensions" begin - bf = BoundaryFunction((ξ, η) -> cos(ξ) * η; reduce_dims=false) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 0.0 - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ -π - end - - @testset "with parameters" begin - bf = BoundaryFunction((ξ, η) -> cos(ξ) * η; parameters=(η = π)) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ π - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ π - end - end - - @testset "discrete" begin - @testset "reduced dimensions" begin - bf = BoundaryFunction((grid, loc, dim, i) -> cos(coord(grid, loc, dim, i)); discrete=true) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 1.0 - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -1.0 - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ 1.0 - - # changing index along other dimension shouldn't affect bc value - @test bf(grid, Vertex(), Dim(1), ny + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) - @test bf(grid, Vertex(), Dim(1), ny ÷ 2 + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny + 1) - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny ÷ 2 + 1) - end - - @testset "full dimensions" begin - bf_fun(grid, loc, dim, ix, iy) = cos(coord(grid, loc, ix, iy)[1]) * coord(grid, loc, ix, iy)[2] - bf = BoundaryFunction(bf_fun; discrete=true, reduce_dims=false) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 0.0 - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ π - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ -π - end - - @testset "with parameters" begin - bf = BoundaryFunction((grid, loc, dim, i, η) -> cos(coord(grid, loc, dim, i)) * η; discrete=true, parameters=(η = π)) - @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π - @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ π - - @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -π - @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ π + @testset "discrete" begin + @testset "reduced dimensions" begin + bf = BoundaryFunction((grid, loc, dim, i) -> cos(coord(grid, loc, dim, i)); discrete=true) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ 1.0 + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -1.0 + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ 1.0 + + # changing index along other dimension shouldn't affect bc value + @test bf(grid, Vertex(), Dim(1), ny + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) + @test bf(grid, Vertex(), Dim(1), ny ÷ 2 + 1, 1) ≈ bf(grid, Vertex(), Dim(1), 1, 1) + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny + 1) + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ bf(grid, Vertex(), Dim(2), 1, ny ÷ 2 + 1) + end + + @testset "full dimensions" begin + bf_fun(grid, loc, dim, ix, iy) = cos(coord(grid, loc, ix, iy)[1]) * coord(grid, loc, ix, iy)[2] + bf = BoundaryFunction(bf_fun; discrete=true, reduce_dims=false) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ π + @test isapprox(bf(grid, Vertex(), Dim(1), 1, ny + 1), -π, atol=tol) + @test isapprox(bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1), 0.0, atol=tol) + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ π + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ π + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ -π + end + + @testset "with parameters" begin + bf = BoundaryFunction((grid, loc, dim, i, η) -> cos(coord(grid, loc, dim, i)) * η; discrete=true, parameters=(η = π)) + @test bf(grid, Vertex(), Dim(1), 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(1), 1, ny + 1) ≈ -π + @test bf(grid, Vertex(), Dim(1), 1, ny ÷ 2 + 1) ≈ π + + @test bf(grid, Vertex(), Dim(2), 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(2), nx + 1, 1) ≈ -π + @test bf(grid, Vertex(), Dim(2), nx ÷ 2 + 1, 1) ≈ π + end end end end diff --git a/test/test_fields.jl b/test/test_fields.jl index 9e47ce8a..1f5b3896 100644 --- a/test/test_fields.jl +++ b/test/test_fields.jl @@ -6,77 +6,81 @@ using Chmy.Grids using LinearAlgebra -for backend in backends - @testset "$(basename(@__FILE__)) (backend: $backend)" begin - # test setup - arch = Arch(backend) - grid = UniformGrid(arch; origin=(0.0, 0.0, 0.0), extent=(1.0, 1.0, 1.0), dims=(2, 2, 2)) - loc = (Center(), Vertex(), Center()) - @testset "location" begin - @test location(Field(backend, grid, Center())) == (Center(), Center(), Center()) - @test location(Field(backend, grid, loc)) == loc - end - @testset "set" begin - f = Field(backend, grid, (Center(), Vertex(), Center()); halo=(1, 0, 1)) - @testset "discrete" begin - # no parameters vertex - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz) -> ycoord(grid, loc, iy); discrete=true) - @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; - 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] - # no parameters center - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz) -> xcoord(grid, loc, ix); discrete=true) - @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; - 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] - # with parameters - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz, sc) -> ycoord(grid, loc, iy) * sc; discrete=true, parameters=(2.0,)) - @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; - 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] - end - @testset "continuous" begin - # no parameters vertex - fill!(parent(f), NaN) - set!(f, grid, (x, y, z) -> y) - @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; - 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] - # no parameters center - fill!(parent(f), NaN) - set!(f, grid, (x, y, z) -> x) - @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; - 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] - # with parameters - fill!(parent(f), NaN) - set!(f, grid, (x, y, z, sc) -> y * sc; parameters=(2.0,)) - @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; - 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] - end - end - # @testset "linalg" begin - # f = Field(backend, grid, Center()) - # set!(f, 1.0) - # @test norm(f, 1) ≈ 8 - # @test norm(f, 2) ≈ norm(f) ≈ sqrt(8) - # end - @testset "constant field" begin - @testset "zero" begin - field = ZeroField{Float64}() - @test field[1, 1, 1] ≈ 0.0 - @test field[2, 2, 2] ≈ 0.0 - @test size(field) == () +for (backend, skip) in zip(backends, skip_Float64), precis in precisions + if skip && precis==Float64 + continue + else + @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin + # test setup + arch = Arch(backend) + grid = UniformGrid(arch; origin=(precis(0.0), precis(0.0), precis(0.0)), extent=(precis(1.0), precis(1.0), precis(1.0)), dims=(2, 2, 2)) + loc = (Center(), Vertex(), Center()) + @testset "location" begin + @test location(Field(backend, grid, Center())) == (Center(), Center(), Center()) + @test location(Field(backend, grid, loc)) == loc end - @testset "one" begin - field = OneField{Float64}() - @test field[1, 1, 1] ≈ 1.0 - @test field[2, 2, 2] ≈ 1.0 - @test size(field) == () + @testset "set" begin + f = Field(backend, grid, (Center(), Vertex(), Center()); halo=(1, 0, 1)) + @testset "discrete" begin + # no parameters vertex + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz) -> ycoord(grid, loc, iy); discrete=true) + @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; + 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] + # no parameters center + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz) -> xcoord(grid, loc, ix); discrete=true) + @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; + 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] + # with parameters + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz, sc) -> ycoord(grid, loc, iy) * sc; discrete=true, parameters=(precis(2.0),)) + @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; + 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] + end + @testset "continuous" begin + # no parameters vertex + fill!(parent(f), NaN) + set!(f, grid, (x, y, z) -> y) + @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; + 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] + # no parameters center + fill!(parent(f), NaN) + set!(f, grid, (x, y, z) -> x) + @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; + 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] + # with parameters + fill!(parent(f), NaN) + set!(f, grid, (x, y, z, sc) -> y * sc; parameters=(precis(2.0),)) + @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; + 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] + end end - @testset "const" begin - field = ValueField(2.0) - @test field[1, 1, 1] ≈ 2.0 - @test field[2, 2, 2] ≈ 2.0 - @test size(field) == () + # @testset "linalg" begin + # f = Field(backend, grid, Center()) + # set!(f, 1.0) + # @test norm(f, 1) ≈ 8 + # @test norm(f, 2) ≈ norm(f) ≈ sqrt(8) + # end + @testset "constant field" begin + @testset "zero" begin + field = ZeroField{Float64}() + @test field[1, 1, 1] ≈ 0.0 + @test field[2, 2, 2] ≈ 0.0 + @test size(field) == () + end + @testset "one" begin + field = OneField{Float64}() + @test field[1, 1, 1] ≈ 1.0 + @test field[2, 2, 2] ≈ 1.0 + @test size(field) == () + end + @testset "const" begin + field = ValueField(2.0) + @test field[1, 1, 1] ≈ 2.0 + @test field[2, 2, 2] ≈ 2.0 + @test size(field) == () + end end end end diff --git a/test/test_grids.jl b/test/test_grids.jl index bc8bdd72..79d404fd 100644 --- a/test/test_grids.jl +++ b/test/test_grids.jl @@ -3,168 +3,174 @@ include("common.jl") using Chmy.Grids using Chmy.Architectures -@testset "$(basename(@__FILE__)) (backend: CPU)" begin - @testset "common" begin - @test flip(Center()) == Vertex() - @test flip(Vertex()) == Center() - end +for precis in precisions + @testset "$(basename(@__FILE__)) (backend: CPU, precis: $precis)" begin + @testset "common" begin + @test flip(Center()) == Vertex() + @test flip(Vertex()) == Center() + end - @testset "grids" begin - arch = Arch(CPU()) - nx, ny = 5, 20 - @testset "uniform grids" begin - grid = UniformGrid(arch; origin=(-1, -2), extent=(2, 4), dims=(nx, ny)) - @test grid isa UniformGrid - - # connectivity - @test connectivity(grid, Dim(1), Side(1)) isa Bounded - @test connectivity(grid, Dim(1), Side(2)) isa Bounded - @test connectivity(grid, Dim(2), Side(1)) isa Bounded - @test connectivity(grid, Dim(2), Side(2)) isa Bounded - - # axes - @test axis(grid, Dim(1)) == grid.axes[1] - @test axis(grid, Dim(2)) == grid.axes[2] - - @testset "size" begin - @test size(grid, Center()) == (nx, ny) - @test size(grid, Vertex()) == (nx + 1, ny + 1) - @test size(grid, (Center(), Vertex())) == (nx, ny + 1) - @test size(grid, (Vertex(), Center())) == (nx + 1, ny) - # repeating locations - @test size(grid, Center()) == size(grid, (Center(), Center())) - @test size(grid, Vertex()) == size(grid, (Vertex(), Vertex())) - end + @testset "grids" begin + arch = Arch(CPU()) + nx, ny = 5, 20 + @testset "uniform grids" begin + grid = UniformGrid(arch; origin=(precis(-1), precis(-2)), extent=(precis(2), precis(4)), dims=(nx, ny)) + @test grid isa UniformGrid - @testset "bounds" begin - @test all(bounds(grid, Vertex(), Dim(1)) .≈ (-1.0, 1.0)) - @test all(bounds(grid, Vertex(), Dim(2)) .≈ (-2.0, 2.0)) - @test all(bounds(grid, Center(), Dim(1)) .≈ (-0.8, 0.8)) - @test all(bounds(grid, Center(), Dim(2)) .≈ (-1.9, 1.9)) - end + @testset "type" begin + @test eltype(grid) == precis + end - @testset "extent" begin - # one location - @test extent(grid, Vertex(), Dim(1)) ≈ 2.0 - @test extent(grid, Vertex(), Dim(2)) ≈ 4.0 - @test extent(grid, Center(), Dim(1)) ≈ 1.6 - @test extent(grid, Center(), Dim(2)) ≈ 3.8 - # many locations - @test all(extent(grid, (Vertex(), Vertex())) .≈ (2.0, 4.0)) - @test all(extent(grid, (Center(), Center())) .≈ (1.6, 3.8)) - @test all(extent(grid, (Center(), Vertex())) .≈ (1.6, 4.0)) - @test all(extent(grid, (Vertex(), Center())) .≈ (2.0, 3.8)) - # repeating locations - @test extent(grid, Vertex()) == extent(grid, (Vertex(), Vertex())) - @test extent(grid, Center()) == extent(grid, (Center(), Center())) - end + # connectivity + @test connectivity(grid, Dim(1), Side(1)) isa Bounded + @test connectivity(grid, Dim(1), Side(2)) isa Bounded + @test connectivity(grid, Dim(2), Side(1)) isa Bounded + @test connectivity(grid, Dim(2), Side(2)) isa Bounded - @testset "origin" begin - # one location - @test origin(grid, Vertex(), Dim(1)) ≈ -1 - @test origin(grid, Vertex(), Dim(2)) ≈ -2 - @test origin(grid, Center(), Dim(1)) ≈ -0.8 - @test origin(grid, Center(), Dim(2)) ≈ -1.9 - # many locations - @test all(origin(grid, (Vertex(), Vertex())) .≈ (-1.0, -2.0)) - @test all(origin(grid, (Center(), Center())) .≈ (-0.8, -1.9)) - @test all(origin(grid, (Center(), Vertex())) .≈ (-0.8, -2.0)) - @test all(origin(grid, (Vertex(), Center())) .≈ (-1.0, -1.9)) - # repeating locations - @test origin(grid, (Vertex(), Vertex())) == origin(grid, Vertex()) - @test origin(grid, (Center(), Center())) == origin(grid, Center()) - end + # axes + @test axis(grid, Dim(1)) == grid.axes[1] + @test axis(grid, Dim(2)) == grid.axes[2] - @testset "spacing" begin - @test Δ == spacing - # one location - @test spacing(grid, Vertex(), Dim(1), 1) ≈ 0.4 - @test spacing(grid, Vertex(), Dim(2), 1) ≈ 0.2 - @test spacing(grid, Center(), Dim(1), 1) ≈ 0.4 - @test spacing(grid, Center(), Dim(2), 1) ≈ 0.2 - # many locations - @test all(spacing(grid, (Center(), Center()), 1, 1) .≈ (0.4, 0.2)) - @test all(spacing(grid, (Vertex(), Vertex()), 1, 1) .≈ (0.4, 0.2)) - @test all(spacing(grid, (Center(), Vertex()), 1, 1) .≈ (0.4, 0.2)) - @test all(spacing(grid, (Vertex(), Center()), 1, 1) .≈ (0.4, 0.2)) - # repeating locations - @test spacing(grid, Vertex(), 1, 1) == spacing(grid, (Vertex(), Vertex()), 1, 1) - @test spacing(grid, Center(), 1, 1) == spacing(grid, (Center(), Center()), 1, 1) - end + @testset "size" begin + @test size(grid, Center()) == (nx, ny) + @test size(grid, Vertex()) == (nx + 1, ny + 1) + @test size(grid, (Center(), Vertex())) == (nx, ny + 1) + @test size(grid, (Vertex(), Center())) == (nx + 1, ny) + # repeating locations + @test size(grid, Center()) == size(grid, (Center(), Center())) + @test size(grid, Vertex()) == size(grid, (Vertex(), Vertex())) + end - @testset "inverse spacing" begin - @test iΔ == inv_spacing - # one location - @test inv_spacing(grid, Vertex(), Dim(1), 1) ≈ 2.5 - @test inv_spacing(grid, Vertex(), Dim(2), 1) ≈ 5.0 - @test inv_spacing(grid, Center(), Dim(1), 1) ≈ 2.5 - @test inv_spacing(grid, Center(), Dim(2), 1) ≈ 5.0 - # many locations - @test all(inv_spacing(grid, (Center(), Center()), 1, 1) .≈ (2.5, 5.0)) - @test all(inv_spacing(grid, (Vertex(), Vertex()), 1, 1) .≈ (2.5, 5.0)) - @test all(inv_spacing(grid, (Center(), Vertex()), 1, 1) .≈ (2.5, 5.0)) - @test all(inv_spacing(grid, (Vertex(), Center()), 1, 1) .≈ (2.5, 5.0)) - # repeating locations - @test inv_spacing(grid, Vertex(), 1, 1) == inv_spacing(grid, (Vertex(), Vertex()), 1, 1) - @test inv_spacing(grid, Center(), 1, 1) == inv_spacing(grid, (Center(), Center()), 1, 1) - end + @testset "bounds" begin + @test all(bounds(grid, Vertex(), Dim(1)) .≈ (-1.0, 1.0)) + @test all(bounds(grid, Vertex(), Dim(2)) .≈ (-2.0, 2.0)) + @test all(bounds(grid, Center(), Dim(1)) .≈ (-0.8, 0.8)) + @test all(bounds(grid, Center(), Dim(2)) .≈ (-1.9, 1.9)) + end - @testset "uniform spacing" begin - # spacing - @test all(spacing(grid) .≈ (0.4, 0.2)) - # inverse - @test all(inv_spacing(grid) .≈ (2.5, 5.0)) - # cartesian - @test Δx(grid) ≈ 0.4 - @test Δy(grid) ≈ 0.2 - end + @testset "extent" begin + # one location + @test extent(grid, Vertex(), Dim(1)) ≈ 2.0 + @test extent(grid, Vertex(), Dim(2)) ≈ 4.0 + @test extent(grid, Center(), Dim(1)) ≈ 1.6 + @test extent(grid, Center(), Dim(2)) ≈ 3.8 + # many locations + @test all(extent(grid, (Vertex(), Vertex())) .≈ (2.0, 4.0)) + @test all(extent(grid, (Center(), Center())) .≈ (1.6, 3.8)) + @test all(extent(grid, (Center(), Vertex())) .≈ (1.6, 4.0)) + @test all(extent(grid, (Vertex(), Center())) .≈ (2.0, 3.8)) + # repeating locations + @test extent(grid, Vertex()) == extent(grid, (Vertex(), Vertex())) + @test extent(grid, Center()) == extent(grid, (Center(), Center())) + end - @testset "coords" begin - # one index - @test coord(grid, Vertex(), Dim(1), 1) ≈ -1.0 - @test coord(grid, Vertex(), Dim(2), 1) ≈ -2.0 - @test coord(grid, Vertex(), Dim(1), nx + 1) ≈ 1.0 - @test coord(grid, Vertex(), Dim(2), ny + 1) ≈ 2.0 - @test coord(grid, Center(), Dim(1), 1) ≈ -0.8 - @test coord(grid, Center(), Dim(2), 1) ≈ -1.9 - @test coord(grid, Center(), Dim(1), nx) ≈ 0.8 - @test coord(grid, Center(), Dim(2), ny) ≈ 1.9 - # many indices - for loc in (Center(), Vertex()) - @test coord(grid, loc, Dim(1), 1, 1) == coord(grid, loc, Dim(1), 1) - @test coord(grid, loc, Dim(2), 1, 1) == coord(grid, loc, Dim(2), 1) - @test coord(grid, loc, Dim(1), nx + 1, 1) == coord(grid, loc, Dim(1), nx + 1) - @test coord(grid, loc, Dim(2), 1, ny + 1) == coord(grid, loc, Dim(2), ny + 1) + @testset "origin" begin + # one location + @test origin(grid, Vertex(), Dim(1)) ≈ -1 + @test origin(grid, Vertex(), Dim(2)) ≈ -2 + @test origin(grid, Center(), Dim(1)) ≈ -0.8 + @test origin(grid, Center(), Dim(2)) ≈ -1.9 + # many locations + @test all(origin(grid, (Vertex(), Vertex())) .≈ (-1.0, -2.0)) + @test all(origin(grid, (Center(), Center())) .≈ (-0.8, -1.9)) + @test all(origin(grid, (Center(), Vertex())) .≈ (-0.8, -2.0)) + @test all(origin(grid, (Vertex(), Center())) .≈ (-1.0, -1.9)) + # repeating locations + @test origin(grid, (Vertex(), Vertex())) == origin(grid, Vertex()) + @test origin(grid, (Center(), Center())) == origin(grid, Center()) end - # many locations - @test all(coord(grid, (Vertex(), Center()), 1, 1) .≈ (-1.0, -1.9)) - @test all(coord(grid, (Vertex(), Center()), nx + 1, 1) .≈ (1.0, -1.9)) - @test all(coord(grid, (Vertex(), Center()), 1, ny) .≈ (-1.0, 1.9)) - # repeated locations - @test coord(grid, (Vertex(), Center()), Dim(1), 1) == coord(grid, Vertex(), Dim(1), 1) == coord(grid, Vertex(), Dim(1), 1, 1) - @test coord(grid, (Vertex(), Center()), Dim(2), 1) == coord(grid, Center(), Dim(2), 1) == coord(grid, Center(), Dim(2), 1, 1) - end - @testset "shortcut coords" begin - # short coords - @test vertex(grid, Dim(1), 1) == vertex(grid, Dim(1), 1, 1) == coord(grid, Vertex(), Dim(1), 1) - @test vertex(grid, Dim(2), 1) == vertex(grid, Dim(2), 1, 1) == coord(grid, Vertex(), Dim(2), 1) - @test center(grid, Dim(1), 1) == center(grid, Dim(1), 1, 1) == coord(grid, Center(), Dim(1), 1) - @test center(grid, Dim(2), 1) == center(grid, Dim(2), 1, 1) == coord(grid, Center(), Dim(2), 1) - end + @testset "spacing" begin + @test Δ == spacing + # one location + @test spacing(grid, Vertex(), Dim(1), 1) ≈ 0.4 + @test spacing(grid, Vertex(), Dim(2), 1) ≈ 0.2 + @test spacing(grid, Center(), Dim(1), 1) ≈ 0.4 + @test spacing(grid, Center(), Dim(2), 1) ≈ 0.2 + # many locations + @test all(spacing(grid, (Center(), Center()), 1, 1) .≈ (0.4, 0.2)) + @test all(spacing(grid, (Vertex(), Vertex()), 1, 1) .≈ (0.4, 0.2)) + @test all(spacing(grid, (Center(), Vertex()), 1, 1) .≈ (0.4, 0.2)) + @test all(spacing(grid, (Vertex(), Center()), 1, 1) .≈ (0.4, 0.2)) + # repeating locations + @test spacing(grid, Vertex(), 1, 1) == spacing(grid, (Vertex(), Vertex()), 1, 1) + @test spacing(grid, Center(), 1, 1) == spacing(grid, (Center(), Center()), 1, 1) + end + + @testset "inverse spacing" begin + @test iΔ == inv_spacing + # one location + @test inv_spacing(grid, Vertex(), Dim(1), 1) ≈ 2.5 + @test inv_spacing(grid, Vertex(), Dim(2), 1) ≈ 5.0 + @test inv_spacing(grid, Center(), Dim(1), 1) ≈ 2.5 + @test inv_spacing(grid, Center(), Dim(2), 1) ≈ 5.0 + # many locations + @test all(inv_spacing(grid, (Center(), Center()), 1, 1) .≈ (2.5, 5.0)) + @test all(inv_spacing(grid, (Vertex(), Vertex()), 1, 1) .≈ (2.5, 5.0)) + @test all(inv_spacing(grid, (Center(), Vertex()), 1, 1) .≈ (2.5, 5.0)) + @test all(inv_spacing(grid, (Vertex(), Center()), 1, 1) .≈ (2.5, 5.0)) + # repeating locations + @test inv_spacing(grid, Vertex(), 1, 1) == inv_spacing(grid, (Vertex(), Vertex()), 1, 1) + @test inv_spacing(grid, Center(), 1, 1) == inv_spacing(grid, (Center(), Center()), 1, 1) + end + + @testset "uniform spacing" begin + # spacing + @test all(spacing(grid) .≈ (0.4, 0.2)) + # inverse + @test all(inv_spacing(grid) .≈ (2.5, 5.0)) + # cartesian + @test Δx(grid) ≈ 0.4 + @test Δy(grid) ≈ 0.2 + end + + @testset "coords" begin + # one index + @test coord(grid, Vertex(), Dim(1), 1) ≈ -1.0 + @test coord(grid, Vertex(), Dim(2), 1) ≈ -2.0 + @test coord(grid, Vertex(), Dim(1), nx + 1) ≈ 1.0 + @test coord(grid, Vertex(), Dim(2), ny + 1) ≈ 2.0 + @test coord(grid, Center(), Dim(1), 1) ≈ -0.8 + @test coord(grid, Center(), Dim(2), 1) ≈ -1.9 + @test coord(grid, Center(), Dim(1), nx) ≈ 0.8 + @test coord(grid, Center(), Dim(2), ny) ≈ 1.9 + # many indices + for loc in (Center(), Vertex()) + @test coord(grid, loc, Dim(1), 1, 1) == coord(grid, loc, Dim(1), 1) + @test coord(grid, loc, Dim(2), 1, 1) == coord(grid, loc, Dim(2), 1) + @test coord(grid, loc, Dim(1), nx + 1, 1) == coord(grid, loc, Dim(1), nx + 1) + @test coord(grid, loc, Dim(2), 1, ny + 1) == coord(grid, loc, Dim(2), ny + 1) + end + # many locations + @test all(coord(grid, (Vertex(), Center()), 1, 1) .≈ (-1.0, -1.9)) + @test all(coord(grid, (Vertex(), Center()), nx + 1, 1) .≈ (1.0, -1.9)) + @test all(coord(grid, (Vertex(), Center()), 1, ny) .≈ (-1.0, 1.9)) + # repeated locations + @test coord(grid, (Vertex(), Center()), Dim(1), 1) == coord(grid, Vertex(), Dim(1), 1) == coord(grid, Vertex(), Dim(1), 1, 1) + @test coord(grid, (Vertex(), Center()), Dim(2), 1) == coord(grid, Center(), Dim(2), 1) == coord(grid, Center(), Dim(2), 1, 1) + end + + @testset "shortcut coords" begin + # short coords + @test vertex(grid, Dim(1), 1) == vertex(grid, Dim(1), 1, 1) == coord(grid, Vertex(), Dim(1), 1) + @test vertex(grid, Dim(2), 1) == vertex(grid, Dim(2), 1, 1) == coord(grid, Vertex(), Dim(2), 1) + @test center(grid, Dim(1), 1) == center(grid, Dim(1), 1, 1) == coord(grid, Center(), Dim(1), 1) + @test center(grid, Dim(2), 1) == center(grid, Dim(2), 1, 1) == coord(grid, Center(), Dim(2), 1) + end - @testset "cartesian" begin - # coords - @test xvertex(grid, 1) == vertex(grid, Dim(1), 1) - @test xcenter(grid, 1) == center(grid, Dim(1), 1) - @test yvertex(grid, 1) == vertex(grid, Dim(2), 1) - @test ycenter(grid, 1) == center(grid, Dim(2), 1) - # spacing - for loc in (Center(), Vertex()) - @test Δx(grid, loc, 1) == spacing(grid, loc, Dim(1), 1) - @test Δx(grid, loc, 1) == spacing(grid, loc, Dim(1), 1) - @test Δy(grid, loc, 1) == spacing(grid, loc, Dim(2), 1) - @test Δy(grid, loc, 1) == spacing(grid, loc, Dim(2), 1) + @testset "cartesian" begin + # coords + @test xvertex(grid, 1) == vertex(grid, Dim(1), 1) + @test xcenter(grid, 1) == center(grid, Dim(1), 1) + @test yvertex(grid, 1) == vertex(grid, Dim(2), 1) + @test ycenter(grid, 1) == center(grid, Dim(2), 1) + # spacing + for loc in (Center(), Vertex()) + @test Δx(grid, loc, 1) == spacing(grid, loc, Dim(1), 1) + @test Δx(grid, loc, 1) == spacing(grid, loc, Dim(1), 1) + @test Δy(grid, loc, 1) == spacing(grid, loc, Dim(2), 1) + @test Δy(grid, loc, 1) == spacing(grid, loc, Dim(2), 1) + end end end end diff --git a/test/test_interpolations.jl b/test/test_interpolations.jl index a024ec97..b3774f02 100644 --- a/test/test_interpolations.jl +++ b/test/test_interpolations.jl @@ -9,68 +9,72 @@ using Chmy.Architectures @views avx(A) = 0.5 .* (A[1:end-1, :] .+ A[2:end, :]) @views avy(A) = 0.5 .* (A[:, 1:end-1] .+ A[:, 2:end]) -for backend in backends - @testset "$(basename(@__FILE__)) (backend: $backend)" begin - arch = Arch(backend) - grid = UniformGrid(arch; origin=(0, 0), extent=(1, 1), dims=(2, 2)) - @testset "center" begin - f_c = Field(arch, grid, Center()) - src = reshape(1:4, size(grid, Center())) |> collect - set!(f_c, src) - f_c_i = interior(f_c) |> Array - @testset "c2v" begin - f_v = Field(arch, grid, Vertex()) - set!(f_v, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_v_i = interior(f_v) |> Array - @test f_v_i[2:end-1, 2:end-1] ≈ av4(f_c_i) - end - @testset "c2c" begin - f_c2 = Field(arch, grid, Center()) - set!(f_c2, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_c2_i = interior(f_c2) |> Array - @test f_c_i ≈ f_c2_i - end - @testset "c2cv" begin - f_cv = Field(arch, grid, (Center(), Vertex())) - set!(f_cv, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_cv_i = interior(f_cv) |> Array - @test f_cv_i[:, 2:end-1] ≈ avy(f_c_i) - end - @testset "c2vc" begin - f_vc = Field(arch, grid, (Vertex(), Center())) - set!(f_vc, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_vc_i = interior(f_vc) |> Array - @test f_vc_i[2:end-1, :] ≈ avx(f_c_i) - end - end - @testset "vertex" begin - f_v = Field(arch, grid, Vertex()) - src = reshape(1:9, size(grid, Vertex())) |> collect - set!(f_v, src) - f_v_i = interior(f_v) |> Array - @testset "v2c" begin +for (backend, skip) in zip(backends, skip_Float64), precis in precisions + if skip && precis==Float64 + continue + else + @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin + arch = Arch(backend) + grid = UniformGrid(arch; origin=(precis(0.0), precis(0.0)), extent=(precis(1.0), precis(1.0)), dims=(2, 2)) + @testset "center" begin f_c = Field(arch, grid, Center()) - set!(f_c, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + src = reshape(1:4, size(grid, Center())) |> collect + set!(f_c, src) f_c_i = interior(f_c) |> Array - @test f_c_i ≈ av4(f_v_i) - end - @testset "v2v" begin - f_v2 = Field(arch, grid, Vertex()) - set!(f_v2, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_v2_i = interior(f_v2) |> Array - @test f_v2_i ≈ f_v_i - end - @testset "v2cv" begin - f_cv = Field(arch, grid, (Center(), Vertex())) - set!(f_cv, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_cv_i = interior(f_cv) |> Array - @test f_cv_i ≈ avx(f_v_i) + @testset "c2v" begin + f_v = Field(arch, grid, Vertex()) + set!(f_v, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_v_i = interior(f_v) |> Array + @test f_v_i[2:end-1, 2:end-1] ≈ av4(f_c_i) + end + @testset "c2c" begin + f_c2 = Field(arch, grid, Center()) + set!(f_c2, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_c2_i = interior(f_c2) |> Array + @test f_c_i ≈ f_c2_i + end + @testset "c2cv" begin + f_cv = Field(arch, grid, (Center(), Vertex())) + set!(f_cv, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_cv_i = interior(f_cv) |> Array + @test f_cv_i[:, 2:end-1] ≈ avy(f_c_i) + end + @testset "c2vc" begin + f_vc = Field(arch, grid, (Vertex(), Center())) + set!(f_vc, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_vc_i = interior(f_vc) |> Array + @test f_vc_i[2:end-1, :] ≈ avx(f_c_i) + end end - @testset "v2vc" begin - f_vc = Field(arch, grid, (Vertex(), Center())) - set!(f_vc, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_vc_i = interior(f_vc) |> Array - @test f_vc_i ≈ avy(f_v_i) + @testset "vertex" begin + f_v = Field(arch, grid, Vertex()) + src = reshape(1:9, size(grid, Vertex())) |> collect + set!(f_v, src) + f_v_i = interior(f_v) |> Array + @testset "v2c" begin + f_c = Field(arch, grid, Center()) + set!(f_c, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_c_i = interior(f_c) |> Array + @test f_c_i ≈ av4(f_v_i) + end + @testset "v2v" begin + f_v2 = Field(arch, grid, Vertex()) + set!(f_v2, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_v2_i = interior(f_v2) |> Array + @test f_v2_i ≈ f_v_i + end + @testset "v2cv" begin + f_cv = Field(arch, grid, (Center(), Vertex())) + set!(f_cv, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_cv_i = interior(f_cv) |> Array + @test f_cv_i ≈ avx(f_v_i) + end + @testset "v2vc" begin + f_vc = Field(arch, grid, (Vertex(), Center())) + set!(f_vc, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_vc_i = interior(f_vc) |> Array + @test f_vc_i ≈ avy(f_v_i) + end end end end From a57b0042ef63990f3dfdcf76f177c5a66bc9b61a Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Tue, 1 Oct 2024 18:33:13 +0200 Subject: [PATCH 04/13] Fixup --- .buildkite/run_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index 3a844505..ff20f310 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -57,7 +57,7 @@ steps: env: JULIA_NUM_THREADS: 4 - - label: "Metal Julia {{matrix.julia}}" + - label: "Metal Julia {{matrix.version}}" matrix: setup: version: From d81741514bf2fd9fee26bc43ba5833d887494ca8 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Tue, 1 Oct 2024 18:55:40 +0200 Subject: [PATCH 05/13] Update doc --- docs/src/concepts/architectures.md | 8 +++++++- docs/src/concepts/grids.md | 3 +++ docs/src/getting_started.md | 6 +++++- docs/src/index.md | 1 + 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/src/concepts/architectures.md b/docs/src/concepts/architectures.md index 3a673841..c9a8a2f5 100644 --- a/docs/src/concepts/architectures.md +++ b/docs/src/concepts/architectures.md @@ -2,7 +2,7 @@ ## Backend Selection & Architecture Initialization -Chmy.jl supports CPUs, as well as CUDA and ROC backends for Nvidia and AMD GPUs through a thin wrapper around the [`KernelAbstractions.jl`](https://github.com/JuliaGPU/KernelAbstractions.jl) for users to select desirable backends. +Chmy.jl supports CPUs, as well as CUDA, ROC and Metal backends for Nvidia, AMD and Apple M-serie GPUs through a thin wrapper around the [`KernelAbstractions.jl`](https://github.com/JuliaGPU/KernelAbstractions.jl) for users to select desirable backends. ```julia # Default with CPU @@ -21,6 +21,12 @@ using AMDGPU arch = Arch(ROCBackend()) ``` +```julia +using Metal + +arch = Arch(MetalBackend()) +``` + At the beginning of program, one may specify the backend and initialize the architecture they desire to use. The initialized `arch` variable will be required explicitly at creation of some objects such as grids and kernel launchers. ## Specifying the device ID and stream priority diff --git a/docs/src/concepts/grids.md b/docs/src/concepts/grids.md index 3cf07b29..ec7c50f7 100644 --- a/docs/src/concepts/grids.md +++ b/docs/src/concepts/grids.md @@ -48,6 +48,9 @@ grid = UniformGrid(arch; dims=(nx, ny, nz)) ``` +!!! warning "Metal backend" + If using the Metal backend, ensure to initialise the grid using `Float32` (`f0`) values in the `origin` and `extent` tuples. + !!! info "Interactive Grid Visualization" - [grids_2d.jl](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_2d.jl): Visualization of a 2D `StructuredGrid` - [grids_3d.jl](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_3d.jl): Visualization of a 3D `StructuredGrid` diff --git a/docs/src/getting_started.md b/docs/src/getting_started.md index 4dc281df..b087995c 100644 --- a/docs/src/getting_started.md +++ b/docs/src/getting_started.md @@ -47,6 +47,7 @@ using KernelAbstractions # for backend-agnostic kernels using Printf, CairoMakie # for I/O and plotting # using CUDA # using AMDGPU +# using Metal ``` In this introductory tutorial, we will use the CPU backend for simplicity: @@ -56,7 +57,10 @@ backend = CPU() arch = Arch(backend) ``` -If a different backend is desired, one needs to load the relevant package accordingly. For example, if Nvidia or AMD GPUs are available, one can comment out `using CUDA` or `using AMDGPU` and make sure to use `arch = Arch(CUDABackend())` or `arch = Arch(ROCBackend())`, respectively, when selecting the architecture. For further information about executing on a single-device or multi-device architecture, see the documentation section for [Architectures](./concepts/architectures.md) +If a different backend is desired, one needs to load the relevant package accordingly. For example, if Nvidia or AMD GPUs are available, one can comment out `using CUDA`, `using AMDGPU` or `using Metal` and make sure to use `arch = Arch(CUDABackend())`, `arch = Arch(ROCBackend())` or `arch = Arch(MetalBackend())`, respectively, when selecting the architecture. For further information about executing on a single-device or multi-device architecture, see the documentation section for [Architectures](./concepts/architectures.md) + +!!! warning "Metal backend" + Metal backend restricts floating point arithmetic precision of computations to `Float32` or lower. In Chmy, this can be achieved by initialising the grid object using `Float32` (`f0`) elements in the `origin` and `extent` tuples. ## Writing & Launch Compute Kernels diff --git a/docs/src/index.md b/docs/src/index.md index 087b885d..b5ee7a90 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -31,6 +31,7 @@ Chmy.jl provides a comprehensive framework for handling complex computational ta A general list of the features is: +- Backend-agnostic implementation relying on [KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) - Distributed computing support with [MPI.jl](https://github.com/JuliaParallel/MPI.jl) - Multi-dimensional, parameterizable discrete and continuous fields on structured grids - High-level interface for specifying boundary conditions with automatic batching for performance From 538354f7cb96dd22956b19a678abe3d62c89ddbd Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Tue, 1 Oct 2024 23:15:59 +0200 Subject: [PATCH 06/13] Fix typo --- docs/src/concepts/architectures.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/concepts/architectures.md b/docs/src/concepts/architectures.md index c9a8a2f5..8b4eb755 100644 --- a/docs/src/concepts/architectures.md +++ b/docs/src/concepts/architectures.md @@ -2,7 +2,7 @@ ## Backend Selection & Architecture Initialization -Chmy.jl supports CPUs, as well as CUDA, ROC and Metal backends for Nvidia, AMD and Apple M-serie GPUs through a thin wrapper around the [`KernelAbstractions.jl`](https://github.com/JuliaGPU/KernelAbstractions.jl) for users to select desirable backends. +Chmy.jl supports CPUs, as well as CUDA, ROC and Metal backends for Nvidia, AMD and Apple M-series GPUs through a thin wrapper around the [`KernelAbstractions.jl`](https://github.com/JuliaGPU/KernelAbstractions.jl) for users to select desirable backends. ```julia # Default with CPU From db63f7576e2212ba0f7ec5757f1dcf084617ea66 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Wed, 2 Oct 2024 08:57:40 +0200 Subject: [PATCH 07/13] Fix the docs --- docs/src/concepts/grids.md | 2 +- docs/src/getting_started.md | 2 +- docs/src/index.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/src/concepts/grids.md b/docs/src/concepts/grids.md index ec7c50f7..c8d585b6 100644 --- a/docs/src/concepts/grids.md +++ b/docs/src/concepts/grids.md @@ -49,7 +49,7 @@ grid = UniformGrid(arch; ``` !!! warning "Metal backend" - If using the Metal backend, ensure to initialise the grid using `Float32` (`f0`) values in the `origin` and `extent` tuples. + If using the Metal backend, ensure to use `Float32` (`f0`) element types in the `origin` and `extent` tuples when initialising the grid. !!! info "Interactive Grid Visualization" - [grids_2d.jl](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_2d.jl): Visualization of a 2D `StructuredGrid` diff --git a/docs/src/getting_started.md b/docs/src/getting_started.md index b087995c..45de62a5 100644 --- a/docs/src/getting_started.md +++ b/docs/src/getting_started.md @@ -57,7 +57,7 @@ backend = CPU() arch = Arch(backend) ``` -If a different backend is desired, one needs to load the relevant package accordingly. For example, if Nvidia or AMD GPUs are available, one can comment out `using CUDA`, `using AMDGPU` or `using Metal` and make sure to use `arch = Arch(CUDABackend())`, `arch = Arch(ROCBackend())` or `arch = Arch(MetalBackend())`, respectively, when selecting the architecture. For further information about executing on a single-device or multi-device architecture, see the documentation section for [Architectures](./concepts/architectures.md) +If a different backend is desired, one needs to load the relevant package accordingly. For example, if Nvidia or AMD GPUs are available, one can comment out `using CUDA`, `using AMDGPU` or `using Metal` and make sure to use `arch = Arch(CUDABackend())`, `arch = Arch(ROCBackend())` or `arch = Arch(MetalBackend())`, respectively, when selecting the architecture. For further information about executing on a single-device or multi-device architecture, see the documentation section for [Architectures](./concepts/architectures.md). !!! warning "Metal backend" Metal backend restricts floating point arithmetic precision of computations to `Float32` or lower. In Chmy, this can be achieved by initialising the grid object using `Float32` (`f0`) elements in the `origin` and `extent` tuples. diff --git a/docs/src/index.md b/docs/src/index.md index b5ee7a90..56807e0e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -31,9 +31,9 @@ Chmy.jl provides a comprehensive framework for handling complex computational ta A general list of the features is: -- Backend-agnostic implementation relying on [KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) +- Backend-agnostic capabilities leveraging [KernelAbstractions.jl](https://github.com/JuliaGPU/KernelAbstractions.jl) - Distributed computing support with [MPI.jl](https://github.com/JuliaParallel/MPI.jl) -- Multi-dimensional, parameterizable discrete and continuous fields on structured grids +- Multi-dimensional, parametrisable discrete and continuous fields on structured grids - High-level interface for specifying boundary conditions with automatic batching for performance - Finite difference and interpolation operators on discrete fields - Extensibility; The package is written in pure Julia, so adding new functions, simplification rules, and model transformations has no barrier From 807bac5d28142ac579675aa0e7b545b784fd5f12 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Wed, 2 Oct 2024 08:57:52 +0200 Subject: [PATCH 08/13] Add Metal f0 example --- docs/src/examples/overview.md | 19 ++++++------ examples/diffusion_1d_mtl.jl | 56 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 9 deletions(-) create mode 100644 examples/diffusion_1d_mtl.jl diff --git a/docs/src/examples/overview.md b/docs/src/examples/overview.md index 281baf27..09b11873 100644 --- a/docs/src/examples/overview.md +++ b/docs/src/examples/overview.md @@ -1,15 +1,16 @@ # Examples Overview -This page provides an overview of [Chmy.jl](https://github.com/PTsolvers/Chmy.jl) examples. These selected examples demonstrate how [Chmy.jl](https://github.com/PTsolvers/Chmy.jl) can be used to solve various numerical problems using architecture-agnostic kernels both on a single-device and in a distributed way. +This page provides an overview of [Chmy.jl](https://github.com/PTsolvers/Chmy.jl) examples. These selected examples demonstrate how Chmy.jl can be used to solve various numerical problems using architecture-agnostic kernels both on a single-device and in a distributed way. ## Table of Contents -| Example | Description | +| Example | Description | |:------------|:------------| -| [Diffusion 2D](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d.jl) | Solving the 2D diffusion equation on an uniform grid. | -| [Diffusion 2D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d_mpi.jl) | Solving the 2D diffusion equation on an uniform grid distributedly using MPI. | -| [Single-Device Performance Optimization](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d_perf.jl) | Revisiting the 2D diffusion problem with focus on performance optimization techniques on a single-device architecture | -| [Stokes 2D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/stokes_2d_inc_ve_T_mpi.jl) | Solving the 2D Stokes equation with thermal coupling on an uniform grid. | -| [Stokes 3D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/stokes_3d_inc_ve_T_mpi.jl) | Solving the 3D Stokes equation with thermal coupling on an uniform grid distributedly using MPI. | -| [2D Grid Visualization](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_2d.jl) | Visualization of a 2D `StructuredGrid`. | -| [3D Grid Visualization](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_3d.jl) | Visualization of a 3D `StructuredGrid` | +| [Diffusion 2D](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d.jl) | Solving the 2D diffusion equation on a uniform grid. | +| [Diffusion 2D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d_mpi.jl) | Solving the 2D diffusion equation on a uniform grid and distributed parallelisation using MPI. | +| [Single-Device Performance Optimisation](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_2d_perf.jl) | Revisiting the 2D diffusion problem with focus on performance optimisation techniques on a single-device architecture. | +| [Stokes 2D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/stokes_2d_inc_ve_T_mpi.jl) | Solving the 2D Stokes equation with thermal coupling on a uniform grid. | +| [Stokes 3D with MPI](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/stokes_3d_inc_ve_T_mpi.jl) | Solving the 3D Stokes equation with thermal coupling on a uniform grid and distributed parallelisation using MPI. | +| [Diffusion 1D with Metal](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/diffusion_1d_mtl.jl) | Solving the 1D diffusion equation using the Metal backend and single precision (`Float32`) on a uniform grid. | +| [2D Grid Visualization](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_2d.jl) | Visualization of a 2D `StructuredGrid`. | +| [3D Grid Visualization](https://github.com/PTsolvers/Chmy.jl/blob/main/examples/grids_3d.jl) | Visualization of a 3D `StructuredGrid`. | diff --git a/examples/diffusion_1d_mtl.jl b/examples/diffusion_1d_mtl.jl new file mode 100644 index 00000000..3ae5e253 --- /dev/null +++ b/examples/diffusion_1d_mtl.jl @@ -0,0 +1,56 @@ +using Chmy, Chmy.Architectures, Chmy.Grids, Chmy.Fields, Chmy.BoundaryConditions, Chmy.GridOperators, Chmy.KernelLaunch +using KernelAbstractions +using Printf +using CairoMakie + +using Metal + +@kernel inbounds = true function compute_q!(q, C, χ, g::StructuredGrid, O) + I = @index(Global, NTuple) + I = I + O + q.x[I...] = -χ * ∂x(C, g, I...) +end + +@kernel inbounds = true function update_C!(C, q, Δt, g::StructuredGrid, O) + I = @index(Global, NTuple) + I = I + O + C[I...] -= Δt * divg(q, g, I...) +end + +@views function main(backend=CPU(); nx=(32, )) + arch = Arch(backend) + # geometry + grid = UniformGrid(arch; origin=(-1f0, ), extent=(2f0, ), dims=nx) + launch = Launcher(arch, grid; outer_width=(4, )) + # physics + χ = 1.0f0 + # numerics + Δt = minimum(spacing(grid))^2 / χ / ndims(grid) / 2.1f0 + nt = 100 + # allocate fields + C = Field(backend, grid, Center()) + q = VectorField(backend, grid) + # initial conditions + set!(C, rand(Float32, size(C))) + bc!(arch, grid, C => Neumann()) + # visualisation + fig = Figure(; size=(400, 320)) + ax = Axis(fig[1, 1]; xlabel="x", ylabel="y", title="it = 0") + plt = lines!(ax, centers(grid)..., interior(C) |> Array) + display(fig) + # action + for it in 1:nt + @printf("it = %d/%d \n", it, nt) + launch(arch, grid, compute_q! => (q, C, χ, grid)) + launch(arch, grid, update_C! => (C, q, Δt, grid); bc=batch(grid, C => Neumann())) + end + KernelAbstractions.synchronize(backend) + plt[2] = interior(C) |> Array + ax.title = "it = $nt" + display(fig) + return +end + +n = 64 + +main(MetalBackend(); nx=(n, ) .- 2) From d513168f56a9baf32a73dd8fb8e2dbe1c7d66d0f Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Wed, 2 Oct 2024 09:07:10 +0200 Subject: [PATCH 09/13] Disable Metal Codecov --- .buildkite/run_tests.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index ff20f310..50d79d0f 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -57,6 +57,7 @@ steps: env: JULIA_NUM_THREADS: 4 +# We cannot sumbit coverage right now for Metal as this would require using a cryptic setup not enabled here. - label: "Metal Julia {{matrix.version}}" matrix: setup: @@ -67,7 +68,7 @@ steps: - JuliaCI/julia#v1: version: "{{matrix.version}}" - JuliaCI/julia-coverage#v1: - codecov: true + codecov: false command: | julia -e 'println("--- :julia: Instantiating project") using Pkg @@ -75,7 +76,7 @@ steps: julia -e 'println("+++ :julia: Running tests") using Pkg - Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=true)' + Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' agents: queue: "juliaecosystem" os: "macos" From ad6cd9a31197a5143b027f7146c67071ea8ae3a2 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Wed, 2 Oct 2024 09:12:38 +0200 Subject: [PATCH 10/13] Fixup --- .buildkite/run_tests.yml | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index 50d79d0f..6da13563 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -58,34 +58,34 @@ steps: JULIA_NUM_THREADS: 4 # We cannot sumbit coverage right now for Metal as this would require using a cryptic setup not enabled here. - - label: "Metal Julia {{matrix.version}}" - matrix: - setup: - version: - - "1.10" - - "1.11" - plugins: - - JuliaCI/julia#v1: - version: "{{matrix.version}}" - - JuliaCI/julia-coverage#v1: - codecov: false - command: | - julia -e 'println("--- :julia: Instantiating project") - using Pkg - Pkg.develop(; path=pwd())' || exit 3 + # - label: "Metal Julia {{matrix.version}}" + # matrix: + # setup: + # version: + # - "1.10" + # - "1.11" + # plugins: + # - JuliaCI/julia#v1: + # version: "{{matrix.version}}" + # - JuliaCI/julia-coverage#v1: + # codecov: false + # command: | + # julia -e 'println("--- :julia: Instantiating project") + # using Pkg + # Pkg.develop(; path=pwd())' || exit 3 - julia -e 'println("+++ :julia: Running tests") - using Pkg - Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' - agents: - queue: "juliaecosystem" - os: "macos" - arch: "aarch64" - timeout_in_minutes: 60 - soft_fail: - - exit_status: 3 - env: - JULIA_NUM_THREADS: 4 + # julia -e 'println("+++ :julia: Running tests") + # using Pkg + # Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' + # agents: + # queue: "juliaecosystem" + # os: "macos" + # arch: "aarch64" + # timeout_in_minutes: 60 + # soft_fail: + # - exit_status: 3 + # env: + # JULIA_NUM_THREADS: 4 env: SECRET_CODECOV_TOKEN: "D2H/GglFTcK7SKyfuO/Fy34xrVWHzXbtGTGQXAA3wpEPNAATGhHO/mIm0ILLzhMZSI1LplJBxJ7nV5WVsky0e/01nbSnW5iB0QqFHK8rD+lXUr4ls4zMlyUa0Lvsl/HixFyhwBtFhy8ruwUsqN8AbJNSJSiF9x4jXhzTgIvlO25/HqQObcfJa6qwcw0m9uMa3K26w1xrPhdE7F4mdUUREjB1W8dzfkKF+vZUeMqYFKgit21uQ9QsRjDJl0ExOEw0SC910rtGHtDO0bpIe+D1nEGQsQr8VEN3o0hOCgTJrya8MFitBqkKeVBV/NUImu4UtxlNb7r0ZrjTawiFle2tfg==;U2FsdGVkX1+sdgrm8OBTX9elIdJMwLMpOvXFFtHrG9lj5J8qDBdbjJDva3XMXkbF6I4PCh9G9NW0pEcF9ghb7g==" From fa8c3e8c4d6d80d107182649d19a182ac00904c9 Mon Sep 17 00:00:00 2001 From: Ludovic Raess Date: Wed, 2 Oct 2024 09:21:15 +0200 Subject: [PATCH 11/13] Fixup! --- .buildkite/run_tests.yml | 50 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index 6da13563..6326bcde 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -58,34 +58,34 @@ steps: JULIA_NUM_THREADS: 4 # We cannot sumbit coverage right now for Metal as this would require using a cryptic setup not enabled here. - # - label: "Metal Julia {{matrix.version}}" - # matrix: - # setup: - # version: - # - "1.10" - # - "1.11" - # plugins: - # - JuliaCI/julia#v1: - # version: "{{matrix.version}}" + - label: "Metal Julia {{matrix.version}}" + matrix: + setup: + version: + - "1.10" + - "1.11" + plugins: + - JuliaCI/julia#v1: + version: "{{matrix.version}}" # - JuliaCI/julia-coverage#v1: # codecov: false - # command: | - # julia -e 'println("--- :julia: Instantiating project") - # using Pkg - # Pkg.develop(; path=pwd())' || exit 3 + command: | + julia -e 'println("--- :julia: Instantiating project") + using Pkg + Pkg.develop(; path=pwd())' || exit 3 - # julia -e 'println("+++ :julia: Running tests") - # using Pkg - # Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' - # agents: - # queue: "juliaecosystem" - # os: "macos" - # arch: "aarch64" - # timeout_in_minutes: 60 - # soft_fail: - # - exit_status: 3 - # env: - # JULIA_NUM_THREADS: 4 + julia -e 'println("+++ :julia: Running tests") + using Pkg + Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' + agents: + queue: "juliaecosystem" + os: "macos" + arch: "aarch64" + timeout_in_minutes: 60 + soft_fail: + - exit_status: 3 + env: + JULIA_NUM_THREADS: 4 env: SECRET_CODECOV_TOKEN: "D2H/GglFTcK7SKyfuO/Fy34xrVWHzXbtGTGQXAA3wpEPNAATGhHO/mIm0ILLzhMZSI1LplJBxJ7nV5WVsky0e/01nbSnW5iB0QqFHK8rD+lXUr4ls4zMlyUa0Lvsl/HixFyhwBtFhy8ruwUsqN8AbJNSJSiF9x4jXhzTgIvlO25/HqQObcfJa6qwcw0m9uMa3K26w1xrPhdE7F4mdUUREjB1W8dzfkKF+vZUeMqYFKgit21uQ9QsRjDJl0ExOEw0SC910rtGHtDO0bpIe+D1nEGQsQr8VEN3o0hOCgTJrya8MFitBqkKeVBV/NUImu4UtxlNb7r0ZrjTawiFle2tfg==;U2FsdGVkX1+sdgrm8OBTX9elIdJMwLMpOvXFFtHrG9lj5J8qDBdbjJDva3XMXkbF6I4PCh9G9NW0pEcF9ghb7g==" From ea77b9d49d9939eff4d4e89125980312d116f455 Mon Sep 17 00:00:00 2001 From: Ivan Utkin Date: Fri, 4 Oct 2024 16:15:39 +0200 Subject: [PATCH 12/13] Update testing --- test/common.jl | 50 ++-- test/runtests.jl | 84 +++---- test/test_architectures.jl | 2 +- test/test_boundary_conditions.jl | 400 +++++++++++++++---------------- test/test_boundary_functions.jl | 8 +- test/test_fields.jl | 138 +++++------ test/test_grids.jl | 8 +- test/test_interpolations.jl | 124 +++++----- 8 files changed, 411 insertions(+), 403 deletions(-) diff --git a/test/common.jl b/test/common.jl index 978ad460..ebbf82dc 100644 --- a/test/common.jl +++ b/test/common.jl @@ -3,31 +3,45 @@ using Chmy using KernelAbstractions -# testing for various floating point arithmetic precisions -precisions = [Float32, Float64] +compatible(::Backend, ::DataType) = true -# add KA backends -backends = KernelAbstractions.Backend[CPU()] +# number types to test +TEST_TYPES = [Float32, Float64] -# do not test Float64 on Metal.jl -skip_Float64 = [false] +# add backends +TEST_BACKENDS = [] -if get(ENV, "JULIA_CHMY_BACKEND", "") == "AMDGPU" - using AMDGPU - if AMDGPU.functional() - push!(backends, ROCBackend()) - push!(skip_Float64, false) - end -elseif get(ENV, "JULIA_CHMY_BACKEND", "") == "CUDA" +if haskey(ENV, "JULIA_CHMY_BACKEND_CPU") + push!(TEST_BACKENDS, CPU()) +end + +if haskey(ENV, "JULIA_CHMY_BACKEND_CUDA") using CUDA if CUDA.functional() - push!(backends, CUDABackend()) - push!(skip_Float64, false) + push!(TEST_BACKENDS, CUDABackend()) end -elseif get(ENV, "JULIA_CHMY_BACKEND", "") == "Metal" +end + +if haskey(ENV, "JULIA_CHMY_BACKEND_AMDGPU") + using AMDGPU + if AMDGPU.functional() + push!(TEST_BACKENDS, ROCBackend()) + end +end + +if haskey(ENV, "JULIA_CHMY_BACKEND_Metal") using Metal + + function compatible(::MetalBackend, T::DataType) + try + Metal.check_eltype(T) + return true + catch + return false + end + end + if Metal.functional() - push!(backends, MetalBackend()) - push!(skip_Float64, true) + push!(TEST_BACKENDS, MetalBackend()) end end diff --git a/test/runtests.jl b/test/runtests.jl index 2f368cf2..ad4e52d4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,54 +3,58 @@ using Chmy using Pkg -excludedfiles = ["test_excluded.jl"] - # distributed using MPI -function parse_flags!(args, flag; default=nothing, typ=typeof(default)) - for f in args - startswith(f, flag) || continue - - if f != flag - val = split(f, '=')[2] - if !(typ ≡ nothing || typ <: AbstractString) - @show typ val - val = parse(typ, val) - end - else - val = default - end +EXCLUDE_TESTS = [] + +istest(f) = startswith(f, "test_") && endswith(f, ".jl") + +function parse_flag(args, flag; default=nothing, type::DataType=Nothing) + key = findfirst(arg -> startswith(arg, flag), args) + + if isnothing(key) + # flag not found + return false, default + elseif args[key] == flag + # flag found but no value + return true, default + end + + splitarg = split(args[key], '=') - filter!(x -> x != f, args) - return true, val + if splitarg[1] != flag + # argument started with flag but is not the flag + return false, default end - return false, default + + values = strip.(split(splitarg[2], ',')) + + if type <: Nothing || type <: AbstractString + # common cases, return as strings + return true, values + elseif !(type <: Number) || !isbitstype(type) + error("type must be a bitstype number, got '$type'") + end + + return true, parse.(Ref(type), values) end function runtests() - testdir = pwd() - istest(f) = endswith(f, ".jl") && startswith(basename(f), "test_") - testfiles = sort(filter(istest, vcat([joinpath.(root, files) for (root, dirs, files) in walkdir(testdir)]...))) + testdir = @__DIR__ + testfiles = sort(filter(istest, readdir(testdir))) nfail = 0 printstyled("Testing package Chmy.jl\n"; bold=true, color=:white) for f in testfiles println("") - if basename(f) ∈ excludedfiles - println("Test Skip:") - println("$f") + if f ∈ EXCLUDE_TESTS + @info "Skip test:" f continue end try - # if basename(f) ∈ test_distributed - # nprocs = contains(f, "2D") ? nprocs_2D : nprocs_3D - # cmd(n=nprocs) = `$(mpiexec()) -n $n $(Base.julia_cmd()) --startup-file=no --color=yes $(joinpath(testdir, f))` - # run(cmd()) - # else - run(`$(Base.julia_cmd()) --startup-file=no $(joinpath(testdir, f))`) - # end + run(`$(Base.julia_cmd()) --startup-file=no $(joinpath(testdir, f))`) catch ex @error ex nfail += 1 @@ -59,17 +63,13 @@ function runtests() return nfail end -_, backend_name = parse_flags!(ARGS, "--backend"; default="CPU", typ=String) - -@static if backend_name == "AMDGPU" - Pkg.add("AMDGPU") - ENV["JULIA_CHMY_BACKEND"] = "AMDGPU" -elseif backend_name == "CUDA" - Pkg.add("CUDA") - ENV["JULIA_CHMY_BACKEND"] = "CUDA" -elseif backend_name == "Metal" - Pkg.add("Metal") - ENV["JULIA_CHMY_BACKEND"] = "Metal" +_, backends = parse_flag(ARGS, "--backends"; default=["CPU"]) + +for backend in backends + if backend != "CPU" + Pkg.add(backend) + end + ENV["JULIA_CHMY_BACKEND_$backend"] = true end exit(runtests()) diff --git a/test/test_architectures.jl b/test/test_architectures.jl index 8245366b..374255e3 100644 --- a/test/test_architectures.jl +++ b/test/test_architectures.jl @@ -2,7 +2,7 @@ include("common.jl") using Chmy.Architectures -for backend in backends +for backend in TEST_BACKENDS @testset "$(basename(@__FILE__)) (backend: $backend)" begin device = get_device(backend, 1) arch = SingleDeviceArchitecture(backend, device) diff --git a/test/test_boundary_conditions.jl b/test/test_boundary_conditions.jl index 2354b63e..bceb4762 100644 --- a/test/test_boundary_conditions.jl +++ b/test/test_boundary_conditions.jl @@ -5,207 +5,207 @@ using Chmy.Fields using Chmy.Grids using Chmy.BoundaryConditions -for (backend, skip) in zip(backends, skip_Float64), precis in precisions - if skip && precis==Float64 +for backend in TEST_BACKENDS, T in TEST_TYPES + if !compatible(backend, T) continue - else - @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin - arch = Arch(backend) - - @testset "1D Cartesian Center()" begin - nx = 8 - grid = UniformGrid(arch; origin=(precis(-π),), extent=(precis(2π),), dims=(nx,)) - field = Field(arch, grid, Center()) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ .-field_i[2]) - @test all(field_i[end] .≈ .-field_i[end-1]) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ field_i[2]) - @test all(field_i[end] .≈ field_i[end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = precis(2.0) - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ .-field_i[2] .+ 2v) - @test all(field_i[end] .≈ .-field_i[end-1] .+ 2v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = precis(2.0) - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Vertex(), 1) .≈ q) - @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Vertex(), nx + 1) .≈ q) - end - end - - @testset "1D Cartesian Vertex()" begin - nx = 8 - grid = UniformGrid(arch; origin=(precis(-π),), extent=(precis(2π),), dims=(nx,)) - field = Field(arch, grid, Vertex()) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[2] .≈ 0.0) - @test all(field_i[end-1] .≈ 0.0) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1] .≈ field_i[2]) - @test all(field_i[end] .≈ field_i[end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = precis(2.0) - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[2] .≈ v) - @test all(field_i[end-1] .≈ v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = precis(2.0) - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Center(), 0) .≈ q) - @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Center(), nx + 1) .≈ q) - end - end - - @testset "2D Cartesian" begin - nx, ny = 8, 8 - grid = UniformGrid(arch; origin=(precis(-π), precis(-π)), extent=(precis(2π), precis(2π)), dims=(nx, ny)) - field = Field(arch, grid, (Center(), Vertex())) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1]) - @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2] .≈ 0.0) - @test all(field_i[2:end-1, end-1] .≈ 0.0) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ field_i[2, 2:end-1]) - @test all(field_i[end, 2:end-1] .≈ field_i[end-1, 2:end-1]) - - @test all(field_i[2:end-1, 1] .≈ field_i[2:end-1, 2]) - @test all(field_i[2:end-1, end] .≈ field_i[2:end-1, end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = precis(2.0) - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1] .+ 2v) - @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1] .+ 2v) - - @test all(field_i[2:end-1, 2] .≈ v) - @test all(field_i[2:end-1, end-1] .≈ v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = precis(2.0) - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2, 2:end-1] .- field_i[1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1) .≈ q) - @test all((field_i[end, 2:end-1] .- field_i[end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2] .- field_i[2:end-1, 1]) ./ Δy(grid, Center(), 1, 0) .≈ q) - @test all((field_i[2:end-1, end] .- field_i[2:end-1, end-1]) ./ Δy(grid, Center(), 1, ny + 1) .≈ q) - end - end - - @testset "3D Cartesian" begin - nx, ny, nz = 8, 8, 6 - grid = UniformGrid(arch; origin=(precis(-π), precis(-π), precis(-π)), extent=(precis(2π), precis(2π), precis(2π)), dims=(nx, ny, nz)) - field = Field(arch, grid, (Center(), Vertex(), Center())) - - @testset "default Dirichlet" begin - set!(field, 1) - bc!(arch, grid, field => Dirichlet()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1]) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2, 2:end-1] .≈ 0.0) - @test all(field_i[2:end-1, end-1, 2:end-1] .≈ 0.0) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2]) - @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1]) - end - - @testset "default Neumann" begin - set!(field, 1) - bc!(arch, grid, field => Neumann()) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ field_i[2, 2:end-1, 2:end-1]) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ field_i[end-1, 2:end-1, 2:end-1]) - - @test all(field_i[2:end-1, 1, 2:end-1] .≈ field_i[2:end-1, 2, 2:end-1]) - @test all(field_i[2:end-1, end, 2:end-1] .≈ field_i[2:end-1, end-1, 2:end-1]) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ field_i[2:end-1, 2:end-1, 2]) - @test all(field_i[2:end-1, 2:end-1, end] .≈ field_i[2:end-1, 2:end-1, end-1]) - end - - @testset "non-homogeneous Dirichlet" begin - set!(field, 1) - v = precis(2.0) - bc!(arch, grid, field => Dirichlet(v)) - field_i = interior(field; with_halo=true) |> Array - @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1] .+ 2v) - @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1] .+ 2v) - - @test all(field_i[2:end-1, 2, 2:end-1] .≈ v) - @test all(field_i[2:end-1, end-1, 2:end-1] .≈ v) - - @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2] .+ 2v) - @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1] .+ 2v) - end - - @testset "non-homogeneous Neumann" begin - set!(field, 1) - q = precis(2.0) - bc!(arch, grid, field => Neumann(q)) - field_i = interior(field; with_halo=true) |> Array - @test all((field_i[2, 2:end-1, 2:end-1] .- field_i[1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1, 1) .≈ q) - @test all((field_i[end, 2:end-1, 2:end-1] .- field_i[end-1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2, 2:end-1] .- field_i[2:end-1, 1, 2:end-1]) ./ Δy(grid, Center(), 1, 0, 1) .≈ q) - @test all((field_i[2:end-1, end, 2:end-1] .- field_i[2:end-1, end-1, 2:end-1]) ./ Δy(grid, Center(), 1, ny + 1, 1) .≈ q) - - @test all((field_i[2:end-1, 2:end-1, 2] .- field_i[2:end-1, 2:end-1, 1]) ./ Δz(grid, Vertex(), 1, 1, 1) .≈ q) - @test all((field_i[2:end-1, 2:end-1, end] .- field_i[2:end-1, 2:end-1, end-1]) ./ Δz(grid, Vertex(), 1, 1, nz + 1) .≈ q) - end + end + + @testset "$(basename(@__FILE__)) (backend: $backend, type: $T)" begin + arch = Arch(backend) + + @testset "1D Cartesian Center()" begin + nx = 8 + grid = UniformGrid(arch; origin=(T(-π),), extent=(T(2π),), dims=(nx,)) + field = Field(arch, grid, Center()) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ .-field_i[2]) + @test all(field_i[end] .≈ .-field_i[end-1]) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ field_i[2]) + @test all(field_i[end] .≈ field_i[end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = T(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ .-field_i[2] .+ 2v) + @test all(field_i[end] .≈ .-field_i[end-1] .+ 2v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = T(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Vertex(), 1) .≈ q) + @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Vertex(), nx + 1) .≈ q) + end + end + + @testset "1D Cartesian Vertex()" begin + nx = 8 + grid = UniformGrid(arch; origin=(T(-π),), extent=(T(2π),), dims=(nx,)) + field = Field(arch, grid, Vertex()) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[2] .≈ 0.0) + @test all(field_i[end-1] .≈ 0.0) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1] .≈ field_i[2]) + @test all(field_i[end] .≈ field_i[end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = T(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[2] .≈ v) + @test all(field_i[end-1] .≈ v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = T(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2] .- field_i[1]) ./ Δx(grid, Center(), 0) .≈ q) + @test all((field_i[end] .- field_i[end-1]) ./ Δx(grid, Center(), nx + 1) .≈ q) + end + end + + @testset "2D Cartesian" begin + nx, ny = 8, 8 + grid = UniformGrid(arch; origin=(T(-π), T(-π)), extent=(T(2π), T(2π)), dims=(nx, ny)) + field = Field(arch, grid, (Center(), Vertex())) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1]) + @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2] .≈ 0.0) + @test all(field_i[2:end-1, end-1] .≈ 0.0) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ field_i[2, 2:end-1]) + @test all(field_i[end, 2:end-1] .≈ field_i[end-1, 2:end-1]) + + @test all(field_i[2:end-1, 1] .≈ field_i[2:end-1, 2]) + @test all(field_i[2:end-1, end] .≈ field_i[2:end-1, end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = T(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1] .≈ .-field_i[2, 2:end-1] .+ 2v) + @test all(field_i[end, 2:end-1] .≈ .-field_i[end-1, 2:end-1] .+ 2v) + + @test all(field_i[2:end-1, 2] .≈ v) + @test all(field_i[2:end-1, end-1] .≈ v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = T(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2, 2:end-1] .- field_i[1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1) .≈ q) + @test all((field_i[end, 2:end-1] .- field_i[end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2] .- field_i[2:end-1, 1]) ./ Δy(grid, Center(), 1, 0) .≈ q) + @test all((field_i[2:end-1, end] .- field_i[2:end-1, end-1]) ./ Δy(grid, Center(), 1, ny + 1) .≈ q) + end + end + + @testset "3D Cartesian" begin + nx, ny, nz = 8, 8, 6 + grid = UniformGrid(arch; origin=(T(-π), T(-π), T(-π)), extent=(T(2π), T(2π), T(2π)), dims=(nx, ny, nz)) + field = Field(arch, grid, (Center(), Vertex(), Center())) + + @testset "default Dirichlet" begin + set!(field, 1) + bc!(arch, grid, field => Dirichlet()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1]) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2, 2:end-1] .≈ 0.0) + @test all(field_i[2:end-1, end-1, 2:end-1] .≈ 0.0) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2]) + @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1]) + end + + @testset "default Neumann" begin + set!(field, 1) + bc!(arch, grid, field => Neumann()) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ field_i[2, 2:end-1, 2:end-1]) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ field_i[end-1, 2:end-1, 2:end-1]) + + @test all(field_i[2:end-1, 1, 2:end-1] .≈ field_i[2:end-1, 2, 2:end-1]) + @test all(field_i[2:end-1, end, 2:end-1] .≈ field_i[2:end-1, end-1, 2:end-1]) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ field_i[2:end-1, 2:end-1, 2]) + @test all(field_i[2:end-1, 2:end-1, end] .≈ field_i[2:end-1, 2:end-1, end-1]) + end + + @testset "non-homogeneous Dirichlet" begin + set!(field, 1) + v = T(2.0) + bc!(arch, grid, field => Dirichlet(v)) + field_i = interior(field; with_halo=true) |> Array + @test all(field_i[1, 2:end-1, 2:end-1] .≈ .-field_i[2, 2:end-1, 2:end-1] .+ 2v) + @test all(field_i[end, 2:end-1, 2:end-1] .≈ .-field_i[end-1, 2:end-1, 2:end-1] .+ 2v) + + @test all(field_i[2:end-1, 2, 2:end-1] .≈ v) + @test all(field_i[2:end-1, end-1, 2:end-1] .≈ v) + + @test all(field_i[2:end-1, 2:end-1, 1] .≈ .-field_i[2:end-1, 2:end-1, 2] .+ 2v) + @test all(field_i[2:end-1, 2:end-1, end] .≈ .-field_i[2:end-1, 2:end-1, end-1] .+ 2v) + end + + @testset "non-homogeneous Neumann" begin + set!(field, 1) + q = T(2.0) + bc!(arch, grid, field => Neumann(q)) + field_i = interior(field; with_halo=true) |> Array + @test all((field_i[2, 2:end-1, 2:end-1] .- field_i[1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), 1, 1, 1) .≈ q) + @test all((field_i[end, 2:end-1, 2:end-1] .- field_i[end-1, 2:end-1, 2:end-1]) ./ Δx(grid, Vertex(), nx + 1, 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2, 2:end-1] .- field_i[2:end-1, 1, 2:end-1]) ./ Δy(grid, Center(), 1, 0, 1) .≈ q) + @test all((field_i[2:end-1, end, 2:end-1] .- field_i[2:end-1, end-1, 2:end-1]) ./ Δy(grid, Center(), 1, ny + 1, 1) .≈ q) + + @test all((field_i[2:end-1, 2:end-1, 2] .- field_i[2:end-1, 2:end-1, 1]) ./ Δz(grid, Vertex(), 1, 1, 1) .≈ q) + @test all((field_i[2:end-1, 2:end-1, end] .- field_i[2:end-1, 2:end-1, end-1]) ./ Δz(grid, Vertex(), 1, 1, nz + 1) .≈ q) end end end diff --git a/test/test_boundary_functions.jl b/test/test_boundary_functions.jl index e9c5aa2a..86d9da33 100644 --- a/test/test_boundary_functions.jl +++ b/test/test_boundary_functions.jl @@ -4,15 +4,15 @@ using Chmy.Architectures using Chmy.Grids using Chmy.BoundaryConditions -for precis in precisions +for T in TEST_TYPES # deal with tolerances for isapprox - tol = precis==Float32 ? 1e-6 : 0 + tol = T==Float32 ? 1e-6 : 0 - @testset "$(basename(@__FILE__)) (backend: CPU, precis: $precis)" begin + @testset "$(basename(@__FILE__)) (backend: CPU, type: $T)" begin @testset "boundary functions" begin arch = Arch(CPU()) nx, ny = 8, 8 - grid = UniformGrid(arch; origin=(precis(-π), precis(-π)), extent=(precis(2π), precis(2π)), dims=(nx, ny)) + grid = UniformGrid(arch; origin=(T(-π), T(-π)), extent=(T(2π), T(2π)), dims=(nx, ny)) @testset "continuous" begin @testset "reduced dimensions" begin diff --git a/test/test_fields.jl b/test/test_fields.jl index 1f5b3896..365eedb9 100644 --- a/test/test_fields.jl +++ b/test/test_fields.jl @@ -6,81 +6,75 @@ using Chmy.Grids using LinearAlgebra -for (backend, skip) in zip(backends, skip_Float64), precis in precisions - if skip && precis==Float64 +for backend in TEST_BACKENDS, T in TEST_TYPES + if !compatible(backend, T) continue - else - @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin - # test setup - arch = Arch(backend) - grid = UniformGrid(arch; origin=(precis(0.0), precis(0.0), precis(0.0)), extent=(precis(1.0), precis(1.0), precis(1.0)), dims=(2, 2, 2)) - loc = (Center(), Vertex(), Center()) - @testset "location" begin - @test location(Field(backend, grid, Center())) == (Center(), Center(), Center()) - @test location(Field(backend, grid, loc)) == loc + end + + @testset "$(basename(@__FILE__)) (backend: $backend, type: $T)" begin + # test setup + arch = Arch(backend) + grid = UniformGrid(arch; origin=(T(0.0), T(0.0), T(0.0)), extent=(T(1.0), T(1.0), T(1.0)), dims=(2, 2, 2)) + loc = (Center(), Vertex(), Center()) + @testset "location" begin + @test location(Field(backend, grid, Center())) == (Center(), Center(), Center()) + @test location(Field(backend, grid, loc)) == loc + end + @testset "set" begin + f = Field(backend, grid, (Center(), Vertex(), Center()); halo=(1, 0, 1)) + @testset "discrete" begin + # no parameters vertex + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz) -> ycoord(grid, loc, iy); discrete=true) + @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; + 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] + # no parameters center + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz) -> xcoord(grid, loc, ix); discrete=true) + @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; + 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] + # with parameters + fill!(parent(f), NaN) + set!(f, grid, (grid, loc, ix, iy, iz, sc) -> ycoord(grid, loc, iy) * sc; discrete=true, parameters=(T(2.0),)) + @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; + 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] + end + @testset "continuous" begin + # no parameters vertex + fill!(parent(f), NaN) + set!(f, grid, (x, y, z) -> y) + @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; + 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] + # no parameters center + fill!(parent(f), NaN) + set!(f, grid, (x, y, z) -> x) + @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; + 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] + # with parameters + fill!(parent(f), NaN) + set!(f, grid, (x, y, z, sc) -> y * sc; parameters=(T(2.0),)) + @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; + 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] + end + end + @testset "constant field" begin + @testset "zero" begin + field = ZeroField{Float64}() + @test field[1, 1, 1] ≈ 0.0 + @test field[2, 2, 2] ≈ 0.0 + @test size(field) == () end - @testset "set" begin - f = Field(backend, grid, (Center(), Vertex(), Center()); halo=(1, 0, 1)) - @testset "discrete" begin - # no parameters vertex - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz) -> ycoord(grid, loc, iy); discrete=true) - @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; - 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] - # no parameters center - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz) -> xcoord(grid, loc, ix); discrete=true) - @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; - 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] - # with parameters - fill!(parent(f), NaN) - set!(f, grid, (grid, loc, ix, iy, iz, sc) -> ycoord(grid, loc, iy) * sc; discrete=true, parameters=(precis(2.0),)) - @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; - 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] - end - @testset "continuous" begin - # no parameters vertex - fill!(parent(f), NaN) - set!(f, grid, (x, y, z) -> y) - @test Array(interior(f)) == [0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0;;; - 0.0; 0.0;; 0.5; 0.5;; 1.0; 1.0] - # no parameters center - fill!(parent(f), NaN) - set!(f, grid, (x, y, z) -> x) - @test Array(interior(f)) == [0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75;;; - 0.25; 0.75;; 0.25; 0.75;; 0.25; 0.75] - # with parameters - fill!(parent(f), NaN) - set!(f, grid, (x, y, z, sc) -> y * sc; parameters=(precis(2.0),)) - @test Array(interior(f)) == [0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0;;; - 0.0; 0.0;; 1.0; 1.0;; 2.0; 2.0] - end + @testset "one" begin + field = OneField{Float64}() + @test field[1, 1, 1] ≈ 1.0 + @test field[2, 2, 2] ≈ 1.0 + @test size(field) == () end - # @testset "linalg" begin - # f = Field(backend, grid, Center()) - # set!(f, 1.0) - # @test norm(f, 1) ≈ 8 - # @test norm(f, 2) ≈ norm(f) ≈ sqrt(8) - # end - @testset "constant field" begin - @testset "zero" begin - field = ZeroField{Float64}() - @test field[1, 1, 1] ≈ 0.0 - @test field[2, 2, 2] ≈ 0.0 - @test size(field) == () - end - @testset "one" begin - field = OneField{Float64}() - @test field[1, 1, 1] ≈ 1.0 - @test field[2, 2, 2] ≈ 1.0 - @test size(field) == () - end - @testset "const" begin - field = ValueField(2.0) - @test field[1, 1, 1] ≈ 2.0 - @test field[2, 2, 2] ≈ 2.0 - @test size(field) == () - end + @testset "const" begin + field = ValueField(2.0) + @test field[1, 1, 1] ≈ 2.0 + @test field[2, 2, 2] ≈ 2.0 + @test size(field) == () end end end diff --git a/test/test_grids.jl b/test/test_grids.jl index 79d404fd..1de01627 100644 --- a/test/test_grids.jl +++ b/test/test_grids.jl @@ -3,8 +3,8 @@ include("common.jl") using Chmy.Grids using Chmy.Architectures -for precis in precisions - @testset "$(basename(@__FILE__)) (backend: CPU, precis: $precis)" begin +for T in TEST_TYPES + @testset "$(basename(@__FILE__)) (backend: CPU, type: $T)" begin @testset "common" begin @test flip(Center()) == Vertex() @test flip(Vertex()) == Center() @@ -14,11 +14,11 @@ for precis in precisions arch = Arch(CPU()) nx, ny = 5, 20 @testset "uniform grids" begin - grid = UniformGrid(arch; origin=(precis(-1), precis(-2)), extent=(precis(2), precis(4)), dims=(nx, ny)) + grid = UniformGrid(arch; origin=(T(-1), T(-2)), extent=(T(2), T(4)), dims=(nx, ny)) @test grid isa UniformGrid @testset "type" begin - @test eltype(grid) == precis + @test eltype(grid) == T end # connectivity diff --git a/test/test_interpolations.jl b/test/test_interpolations.jl index b3774f02..1a777e08 100644 --- a/test/test_interpolations.jl +++ b/test/test_interpolations.jl @@ -9,72 +9,72 @@ using Chmy.Architectures @views avx(A) = 0.5 .* (A[1:end-1, :] .+ A[2:end, :]) @views avy(A) = 0.5 .* (A[:, 1:end-1] .+ A[:, 2:end]) -for (backend, skip) in zip(backends, skip_Float64), precis in precisions - if skip && precis==Float64 +for backend in TEST_BACKENDS, T in TEST_TYPES + if !compatible(backend, T) continue - else - @testset "$(basename(@__FILE__)) (backend: $backend, precis: $precis)" begin - arch = Arch(backend) - grid = UniformGrid(arch; origin=(precis(0.0), precis(0.0)), extent=(precis(1.0), precis(1.0)), dims=(2, 2)) - @testset "center" begin + end + + @testset "$(basename(@__FILE__)) (backend: $backend, type: $T)" begin + arch = Arch(backend) + grid = UniformGrid(arch; origin=(T(0.0), T(0.0)), extent=(T(1.0), T(1.0)), dims=(2, 2)) + @testset "center" begin + f_c = Field(arch, grid, Center()) + src = reshape(1:4, size(grid, Center())) |> collect + set!(f_c, src) + f_c_i = interior(f_c) |> Array + @testset "c2v" begin + f_v = Field(arch, grid, Vertex()) + set!(f_v, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_v_i = interior(f_v) |> Array + @test f_v_i[2:end-1, 2:end-1] ≈ av4(f_c_i) + end + @testset "c2c" begin + f_c2 = Field(arch, grid, Center()) + set!(f_c2, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_c2_i = interior(f_c2) |> Array + @test f_c_i ≈ f_c2_i + end + @testset "c2cv" begin + f_cv = Field(arch, grid, (Center(), Vertex())) + set!(f_cv, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_cv_i = interior(f_cv) |> Array + @test f_cv_i[:, 2:end-1] ≈ avy(f_c_i) + end + @testset "c2vc" begin + f_vc = Field(arch, grid, (Vertex(), Center())) + set!(f_vc, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) + f_vc_i = interior(f_vc) |> Array + @test f_vc_i[2:end-1, :] ≈ avx(f_c_i) + end + end + @testset "vertex" begin + f_v = Field(arch, grid, Vertex()) + src = reshape(1:9, size(grid, Vertex())) |> collect + set!(f_v, src) + f_v_i = interior(f_v) |> Array + @testset "v2c" begin f_c = Field(arch, grid, Center()) - src = reshape(1:4, size(grid, Center())) |> collect - set!(f_c, src) + set!(f_c, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) f_c_i = interior(f_c) |> Array - @testset "c2v" begin - f_v = Field(arch, grid, Vertex()) - set!(f_v, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_v_i = interior(f_v) |> Array - @test f_v_i[2:end-1, 2:end-1] ≈ av4(f_c_i) - end - @testset "c2c" begin - f_c2 = Field(arch, grid, Center()) - set!(f_c2, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_c2_i = interior(f_c2) |> Array - @test f_c_i ≈ f_c2_i - end - @testset "c2cv" begin - f_cv = Field(arch, grid, (Center(), Vertex())) - set!(f_cv, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_cv_i = interior(f_cv) |> Array - @test f_cv_i[:, 2:end-1] ≈ avy(f_c_i) - end - @testset "c2vc" begin - f_vc = Field(arch, grid, (Vertex(), Center())) - set!(f_vc, grid, (grid, loc, ix, iy, f_c) -> lerp(f_c, loc, grid, ix, iy); discrete=true, parameters=(f_c,)) - f_vc_i = interior(f_vc) |> Array - @test f_vc_i[2:end-1, :] ≈ avx(f_c_i) - end + @test f_c_i ≈ av4(f_v_i) end - @testset "vertex" begin - f_v = Field(arch, grid, Vertex()) - src = reshape(1:9, size(grid, Vertex())) |> collect - set!(f_v, src) - f_v_i = interior(f_v) |> Array - @testset "v2c" begin - f_c = Field(arch, grid, Center()) - set!(f_c, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_c_i = interior(f_c) |> Array - @test f_c_i ≈ av4(f_v_i) - end - @testset "v2v" begin - f_v2 = Field(arch, grid, Vertex()) - set!(f_v2, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_v2_i = interior(f_v2) |> Array - @test f_v2_i ≈ f_v_i - end - @testset "v2cv" begin - f_cv = Field(arch, grid, (Center(), Vertex())) - set!(f_cv, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_cv_i = interior(f_cv) |> Array - @test f_cv_i ≈ avx(f_v_i) - end - @testset "v2vc" begin - f_vc = Field(arch, grid, (Vertex(), Center())) - set!(f_vc, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) - f_vc_i = interior(f_vc) |> Array - @test f_vc_i ≈ avy(f_v_i) - end + @testset "v2v" begin + f_v2 = Field(arch, grid, Vertex()) + set!(f_v2, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_v2_i = interior(f_v2) |> Array + @test f_v2_i ≈ f_v_i + end + @testset "v2cv" begin + f_cv = Field(arch, grid, (Center(), Vertex())) + set!(f_cv, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_cv_i = interior(f_cv) |> Array + @test f_cv_i ≈ avx(f_v_i) + end + @testset "v2vc" begin + f_vc = Field(arch, grid, (Vertex(), Center())) + set!(f_vc, grid, (grid, loc, ix, iy, f_v) -> lerp(f_v, loc, grid, ix, iy); discrete=true, parameters=(f_v,)) + f_vc_i = interior(f_vc) |> Array + @test f_vc_i ≈ avy(f_v_i) end end end From d170479bf1795424b27b5b22941830d6637e2791 Mon Sep 17 00:00:00 2001 From: Ivan Utkin Date: Fri, 4 Oct 2024 16:20:52 +0200 Subject: [PATCH 13/13] Update workflows --- .buildkite/run_tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.buildkite/run_tests.yml b/.buildkite/run_tests.yml index 6326bcde..34b561c1 100644 --- a/.buildkite/run_tests.yml +++ b/.buildkite/run_tests.yml @@ -18,7 +18,7 @@ steps: julia -e 'println("+++ :julia: Running tests") using Pkg - Pkg.test("Chmy"; test_args=["--backend=CUDA"], coverage=true)' + Pkg.test("Chmy"; test_args=["--backends=CUDA"], coverage=true)' agents: queue: "juliagpu" cuda: "*" @@ -46,7 +46,7 @@ steps: julia -e 'println("+++ :julia: Running tests") using Pkg - Pkg.test("Chmy"; test_args=["--backend=AMDGPU"], coverage=true)' + Pkg.test("Chmy"; test_args=["--backends=AMDGPU"], coverage=true)' agents: queue: "juliagpu" rocm: "*" @@ -76,7 +76,7 @@ steps: julia -e 'println("+++ :julia: Running tests") using Pkg - Pkg.test("Chmy"; test_args=["--backend=Metal"], coverage=false)' + Pkg.test("Chmy"; test_args=["--backends=Metal"], coverage=false)' agents: queue: "juliaecosystem" os: "macos"