From 68a788beaacae9c7c383e65248ad724628678de8 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Thu, 27 Mar 2025 09:07:02 +0100 Subject: [PATCH 01/30] add extents tools --- src/tools.jl | 466 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 462 insertions(+), 4 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 5c28697..06de9c7 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -1,4 +1,4 @@ -export nx_g, ny_g, nz_g, x_g, y_g, z_g, tic, toc +export nx_g, ny_g, nz_g, x_g, y_g, z_g, ix_g, iy_g, iz_g, extents, extents_g, metagrid, tic, toc macro nx_g() esc(:( global_grid().nxyz_g[1] )) end macro ny_g() esc(:( global_grid().nxyz_g[2] )) end @@ -6,15 +6,24 @@ macro nz_g() esc(:( global_grid().nxyz_g[3] )) end macro nx() esc(:( global_grid().nxyz[1] )) end macro ny() esc(:( global_grid().nxyz[2] )) end macro nz() esc(:( global_grid().nxyz[3] )) end +macro nxyz() esc(:( (Int.(global_grid().nxyz)...,) )) end macro coordx() esc(:( global_grid().coords[1] )) end macro coordy() esc(:( global_grid().coords[2] )) end macro coordz() esc(:( global_grid().coords[3] )) end +macro coords() esc(:( (Int.(global_grid().coords)...,) )) end +macro dimx() esc(:( global_grid().dims[1] )) end +macro dimy() esc(:( global_grid().dims[2] )) end +macro dimz() esc(:( global_grid().dims[3] )) end +macro dims() esc(:( (Int.(global_grid().dims)...,) )) end macro olx() esc(:( global_grid().overlaps[1] )) end macro oly() esc(:( global_grid().overlaps[2] )) end macro olz() esc(:( global_grid().overlaps[3] )) end +macro ols() esc(:( (Int.(global_grid().overlaps)...,) )) end macro periodx() esc(:( convert(Bool, global_grid().periods[1]) )) end macro periody() esc(:( convert(Bool, global_grid().periods[2]) )) end macro periodz() esc(:( convert(Bool, global_grid().periods[3]) )) end +macro periods() esc(:( (Bool.(global_grid().periods)...,) )) end + """ nx_g() @@ -61,7 +70,7 @@ nz_g(A::AbstractArray) = @nz_g() + (size(A,3)-@nz()) """ x_g(ix, dx, A) -Return the global x-coordinate for the element `ix` in the local array `A` (`dx` is the space step between the elements). +Return the global x-coordinate for the index `ix` in the local array `A` (`dx` is the space step between the elements). # Examples ```jldoctest @@ -109,7 +118,7 @@ end """ y_g(iy, dy, A) -Return the global y-coordinate for the element `iy` in the local array `A` (`dy` is the space step between the elements). +Return the global y-coordinate for the index `iy` in the local array `A` (`dy` is the space step between the elements). # Examples ```jldoctest @@ -157,7 +166,7 @@ end """ z_g(iz, dz, A) -Return the global z-coordinate for the element `iz` in the local array `A` (`dz` is the space step between the elements). +Return the global z-coordinate for the index `iz` in the local array `A` (`dz` is the space step between the elements). # Examples ```jldoctest @@ -202,6 +211,455 @@ function z_g(iz::Integer, dz::Real, A::AbstractArray) return z end +""" + ix_g(ix; coords, wrap_periodic) + ix_g(ix, A; coords, wrap_periodic) + +Return the global x-index for the local index `ix` in the base grid or in the local array `A`. + +# Keyword arguments +- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). +- `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> lx=4; nx=5; ny=3; nz=3; + +julia> init_global_grid(nx, ny, nz, periodx=1); +Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) + +julia> A = zeros(nx,ny,nz); + +julia> Vx = zeros(nx+1,ny,nz); + +julia> [ix_g(ix) for ix=1:size(A, 1)] +5-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + +julia> [ix_g(ix, Vx) for ix=1:size(Vx, 1)] +6-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + 2 + +julia> finalize_global_grid() +``` +""" +function ix_g(ix::Integer; coordx::Integer=@coordx(), wrap_periodic::Bool=true) + _ix_g(ix, @nx(), coordx, wrap_periodic) +end + +function ix_g(ix::Integer, A::AbstractArray; coordx::Integer=@coordx(), wrap_periodic::Bool=true) + _ix_g(ix, size(A,1), coordx, wrap_periodic) +end + +function _ix_g(ix::Integer, nx_A::Integer, coordx::Integer, wrap_periodic::Bool) + olx_A = @olx() + (nx_A-@nx()) + ix0_g = @periodx() ? 0 : olx_A÷2 + ix0 = -olx_A÷2 + ix = coordx*(@nx()-olx_A) + ix + ix0 + ix0_g + if wrap_periodic && @periodx() + if (ix > @nx_g()) ix = ix - @nx_g(); end + if (ix < 1) ix = ix + @nx_g(); end + end + return ix +end + +""" + iy_g(iy; coords, wrap_periodic) + iy_g(iy, A; coords, wrap_periodic) + +Return the global y-index for the local index `iy` in the base grid or in the local array `A`. + +# Keyword arguments +- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). +- `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> ly=4; nx=3; ny=5; nz=3; + +julia> init_global_grid(nx, ny, nz, periody=1); +Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) + +julia> A = zeros(nx,ny,nz); + +julia> Vy = zeros(nx,ny+1,nz); + +julia> [iy_g(iy) for iy=1:size(A, 2)] +5-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + +julia> [iy_g(iy, Vy) for iy=1:size(Vy, 2)] +6-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + 2 + +julia> finalize_global_grid() +``` +""" +function iy_g(iy::Integer; coordy::Integer=@coordy(), wrap_periodic::Bool=true) + _iy_g(iy, @ny(), coordy, wrap_periodic) +end + +function iy_g(iy::Integer, A::AbstractArray; coordy::Integer=@coordy(), wrap_periodic::Bool=true) + _iy_g(iy, size(A,2), coordy, wrap_periodic) +end + +function _iy_g(iy::Integer, ny_A::Integer, coordy::Integer, wrap_periodic::Bool) + oly_A = @oly() + (ny_A-@ny()) + iy0_g = @periody() ? 0 : oly_A÷2 + iy0 = -oly_A÷2 + iy = coordy*(@ny()-oly_A) + iy + iy0 + iy0_g + if wrap_periodic && @periody() + if (iy > @ny_g()) iy = iy - @ny_g(); end + if (iy < 1) iy = iy + @ny_g(); end + end + return iy +end + +""" + iz_g(iz; coords, wrap_periodic) + iz_g(iz, A; coords, wrap_periodic) + +Return the global z-index for the local index `iz` in the base grid or in the local array `A`. + +# Keyword arguments +- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). +- `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> lz=4; nx=3; ny=3; nz=5; + +julia> init_global_grid(nx, ny, nz, periodz=1); +Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) + +julia> A = zeros(nx,ny,nz); + +julia> Vz = zeros(nx,ny,nz+1); + +julia> [iz_g(iz) for iz=1:size(A, 3)] +5-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + +julia> [iz_g(iz; wrap_periodic=false) for iz=1:size(A, 3)] +5-element Vector{Int64}: + 0 + 1 + 2 + 3 + 4 + +julia> [iz_g(iz, Vz) for iz=1:size(Vz, 3)] +6-element Vector{Int64}: + 3 + 1 + 2 + 3 + 1 + 2 + +julia> [iz_g(iz, Vz; wrap_periodic=false) for iz=1:size(Vz, 3)] +6-element Vector{Int64}: + 0 + 1 + 2 + 3 + 4 + 5 + +julia> finalize_global_grid() +``` +""" +function iz_g(iz::Integer; coordz::Integer=@coordz(), wrap_periodic::Bool=true) + _iz_g(iz, @nz(), coordz, wrap_periodic) +end + +function iz_g(iz::Integer, A::AbstractArray; coordz::Integer=@coordz(), wrap_periodic::Bool=true) + _iz_g(iz, size(A,3), coordz, wrap_periodic) +end + +function _iz_g(iz::Integer, nz_A::Integer, coordz::Integer, wrap_periodic::Bool) + olz_A = @olz() + (nz_A-@nz()) + iz0_g = @periodz() ? 0 : olz_A÷2 + iz0 = -olz_A÷2 + iz = coordz*(@nz()-olz_A) + iz + iz0 + iz0_g + if wrap_periodic && @periodz() + if (iz > @nz_g()) iz = iz - @nz_g(); end + if (iz < 1) iz = iz + @nz_g(); end + end + return iz +end + +""" + extents(; fix_global_boundaries, coords) + extents(A; fix_global_boundaries, coords) + extents(overlaps; fix_global_boundaries, coords) + extents(A, overlaps; fix_global_boundaries, coords) + +Return the local extents in each dimension of the array `A` or the local extents of the base grid if `A` is not provided (return type: tuple of ranges). + +# Arguments +- `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid (i.e., the extents are simply the full ranges of the array or of the base grid, respectively). + +# Keyword arguments +- `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. +- `coords::Tuple{Int,Int,Int}`: the coordinates of the process for which the local extents is requested. The default is the coordinates of the current process. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> init_global_grid(5, 5, 7; periodz=1); +Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) + +julia> extents() +(1:5, 1:5, 2:6) + +julia> extents(; fix_global_boundaries=false) +(1:5, 1:5, 1:7) + +julia> extents(0) +(1:5, 1:5, 2:6) + +julia> extents(0; fix_global_boundaries=false) +(2:4, 2:4, 2:6) + +julia> extents(1) # The extents as required by VTK +(1:5, 1:5, 2:6) + +julia> finalize_global_grid() +``` +""" +function extents(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + extents = (1:@nx(), 1:@ny(), 1:@nz()) + return _adjust_extents(extents, @nxyz(), @ols(), coords, fix_global_boundaries) +end + +function extents(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) + extents = (1:size(A,1), 1:size(A,2), 1:size(A,3)) + return _adjust_extents(extents, size(A), ol_A, coords, fix_global_boundaries) +end + +function extents(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps + if (overlaps[1] > @olx()) || (overlaps[2] > @oly()) || (overlaps[3] > @olz()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + # extents = (1:@nx()-@olx()+overlaps[1], 1:@ny()-@oly()+overlaps[2], 1:@nz()-@olz()+overlaps[3]) + bx, by, bz = (@olx()-overlaps[1]) ÷ 2, (@oly()-overlaps[2]) ÷ 2, (@olz()-overlaps[3]) ÷ 2 + ex, ey, ez = cld(@olx()-overlaps[1], 2), cld(@oly()-overlaps[2], 2), cld(@olz()-overlaps[3], 2) + extents = (1+bx:@nx()-ex, 1+by:@ny()-ey, 1+bz:@nz()-ez) + return _adjust_extents(extents, @nxyz(), @ols(), coords, fix_global_boundaries) +end + +function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps + ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) + if (overlaps[1] > ol_A[1]) || (overlaps[2] > ol_A[2]) || (overlaps[3] > ol_A[3]) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + # extents = (1:size(A,1)-olx_A+overlaps[1], 1:size(A,2)-oly_A+overlaps[2], 1:size(A,3)-olz_A+overlaps[3]) + bx, by, bz = (ol_A[1]-overlaps[1]) ÷ 2, (ol_A[2]-overlaps[2]) ÷ 2, (ol_A[3]-overlaps[3]) ÷ 2 + ex, ey, ez = cld(ol_A[1]-overlaps[1], 2), cld(ol_A[2]-overlaps[2], 2), cld(ol_A[3]-overlaps[3], 2) + extents = (1+bx:size(A,1)-ex, 1+by:size(A,2)-ey, 1+bz:size(A,3)-ez) + return _adjust_extents(extents, size(A), ol_A, coords, fix_global_boundaries) +end + +# function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) +# @show extents +# if fix_global_boundaries +# extents_new = ( if !(@periods()[i]) +# if coords[i] == 0 +# 1:extents[i].stop +# end +# if coords[i] == @dims()[i]-1 +# extents[i].start:nxyz_A[i] +# end +# else +# extents[i] +# end +# for i in 1:3 ) +# else +# extents_new = extents +# end +# return extents_new +# end + +function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) + extents = [extents...] + if fix_global_boundaries + b_g = (ol_A[1] ÷ 2, ol_A[2] ÷ 2, ol_A[3] ÷ 2) + e_g = (cld(ol_A[1], 2), cld(ol_A[2], 2), cld(ol_A[3], 2)) + for i in 1:3 + if @periods()[i] + if coords[i] == 0 + extents[i] = 1+b_g[i]:extents[i].stop + end + if coords[i] == @dims()[i]-1 + extents[i] = extents[i].start:nxyz_A[i]-e_g[i] + end + else + if coords[i] == 0 + extents[i] = 1:extents[i].stop + end + if coords[i] == @dims()[i]-1 + extents[i] = extents[i].start:nxyz_A[i] + end + end + end + end + return (extents...,) +end + +""" + extents_g(; fix_global_boundaries, coords) + extents_g(A; fix_global_boundaries, coords) + extents_g(overlaps; fix_global_boundaries, coords) + extents_g(A, overlaps; fix_global_boundaries, coords) + +Return the global extents in each dimension of the array `A` or the global extents of the base grid if `A` is not provided (return type: tuple of ranges). + +# Arguments +- `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid. + +# Keyword arguments +- `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. +- `coords::Tuple{Int,Int,Int}`: the coordinates of the process for which the global extents is requested. The default is the coordinates of the current process. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> init_global_grid(5, 5, 7; periodz=1); +Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) + +julia> extents_g() +(1:5, 1:5, 1:5) + +julia> extents_g(; fix_global_boundaries=false) +(1:5, 1:5, 0:6) + +julia> extents_g(0) +(1:5, 1:5, 1:5) + +julia> extents_g(0; fix_global_boundaries=false) +(2:4, 2:4, 1:5) + +julia> extents_g(1) # The extents as required by VTK +(1:5, 1:5, 1:5) + +julia> finalize_global_grid() +``` +""" +function extents_g(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords) + return extents_g(extents_l, @nxyz(), coords) +end + +function extents_g(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords) + return extents_g(extents_l, size(A), coords) +end + +function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords) + return extents_g(extents_l, @nxyz(), coords) +end + +function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) + extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords) + return extents_g(extents_l, size(A), coords) +end + +function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}) + return (_ix_g(extents[1].start, nxyz_A[1], coords[1], false):_ix_g(extents[1].stop, nxyz_A[1], coords[1], false), + _iy_g(extents[2].start, nxyz_A[2], coords[2], false):_iy_g(extents[2].stop, nxyz_A[2], coords[2], false), + _iz_g(extents[3].start, nxyz_A[3], coords[3], false):_iz_g(extents[3].stop, nxyz_A[3], coords[3], false)) +end + +""" + metagrid(f::Function, args...; kwargs...) + metagrid(dims, f::Function, args...; kwargs...) + +Return a metadata grid containing the results of the function `f` applied to each process coordinates in the global grid or the imaginary grid with the dimensions `dims` (return type: array with elements of the same type as the return type of `f`). + +# Arguments +- `dims::Tuple{Int,Int,Int}`: the dimensions of the (imaginary) grid. The default is the actual dimensions of the global grid. +- `f::Function`: the function to apply to each process coordinates; the function must accept the keyword argument `coords` which is a tuple of the coordinates of the process. +- `args...`: the arguments to pass to the function `f`. +- `kwargs...`: the keyword arguments to pass to the function `f`; the keyword argument `coords` is automatically added. + +# Examples +```jldoctest +julia> using ImplicitGlobalGrid + +julia> init_global_grid(5, 5, 7; periodz=1); +Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) + +julia> metagrid((; coords)->coords) +1×1×1 Array{Tuple{Int64, Int64, Int64}, 3}: +[:, :, 1] = + (0, 0, 0) + +julia> metagrid((2, 2, 2), (; coords)->coords) +2×2×2 Array{Tuple{Int64, Int64, Int64}, 3}: +[:, :, 1] = + (0, 0, 0) (0, 1, 0) + (1, 0, 0) (1, 1, 0) + +[:, :, 2] = + (0, 0, 1) (0, 1, 1) + (1, 0, 1) (1, 1, 1) + +julia> metagrid(extents_g, 1) # The extents grid as required by VTK +1×1×1 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: +[:, :, 1] = + (1:5, 1:5, 1:5) + +julia> metagrid((2, 2, 2), extents_g, 1) # The extents grid as required by VTK for an imaginary grid with dimensions (2, 2, 2) +2×2×2 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: +[:, :, 1] = + (1:5, 1:5, 1:5) (1:5, 4:7, 1:5) + (4:7, 1:5, 1:5) (4:7, 4:7, 1:5) + +[:, :, 2] = + (1:5, 1:5, 5:10) (1:5, 4:7, 5:10) + (4:7, 1:5, 5:10) (4:7, 4:7, 5:10) + +julia> finalize_global_grid() +``` +""" +function metagrid(dims::Tuple{Int,Int,Int}, f::Function, args...; kwargs...) + return [f(args...; coords=(x,y,z), kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] +end + +metagrid(f::Function, args...; kwargs...) = metagrid(@dims(), f, args...; kwargs...) + + # Timing tools. @doc """ tic() From 36ed799ac607d59dc841ea9cfdae2c264d2c653a Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 28 Mar 2025 11:37:17 +0100 Subject: [PATCH 02/30] fix metagrid --- src/tools.jl | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 06de9c7..319a15f 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -457,28 +457,28 @@ julia> extents(1) # The extents as required by VTK julia> finalize_global_grid() ``` """ -function extents(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) +function extents(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents = (1:@nx(), 1:@ny(), 1:@nz()) - return _adjust_extents(extents, @nxyz(), @ols(), coords, fix_global_boundaries) + return _adjust_extents(extents, @nxyz(), @ols(), coords, dims, fix_global_boundaries) end -function extents(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) +function extents(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) extents = (1:size(A,1), 1:size(A,2), 1:size(A,3)) - return _adjust_extents(extents, size(A), ol_A, coords, fix_global_boundaries) + return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) end -function extents(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) +function extents(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps if (overlaps[1] > @olx()) || (overlaps[2] > @oly()) || (overlaps[3] > @olz()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end # extents = (1:@nx()-@olx()+overlaps[1], 1:@ny()-@oly()+overlaps[2], 1:@nz()-@olz()+overlaps[3]) bx, by, bz = (@olx()-overlaps[1]) ÷ 2, (@oly()-overlaps[2]) ÷ 2, (@olz()-overlaps[3]) ÷ 2 ex, ey, ez = cld(@olx()-overlaps[1], 2), cld(@oly()-overlaps[2], 2), cld(@olz()-overlaps[3], 2) extents = (1+bx:@nx()-ex, 1+by:@ny()-ey, 1+bz:@nz()-ez) - return _adjust_extents(extents, @nxyz(), @ols(), coords, fix_global_boundaries) + return _adjust_extents(extents, @nxyz(), @ols(), coords, dims, fix_global_boundaries) end -function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) +function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) if (overlaps[1] > ol_A[1]) || (overlaps[2] > ol_A[2]) || (overlaps[3] > ol_A[3]) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end @@ -486,10 +486,10 @@ function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; bx, by, bz = (ol_A[1]-overlaps[1]) ÷ 2, (ol_A[2]-overlaps[2]) ÷ 2, (ol_A[3]-overlaps[3]) ÷ 2 ex, ey, ez = cld(ol_A[1]-overlaps[1], 2), cld(ol_A[2]-overlaps[2], 2), cld(ol_A[3]-overlaps[3], 2) extents = (1+bx:size(A,1)-ex, 1+by:size(A,2)-ey, 1+bz:size(A,3)-ez) - return _adjust_extents(extents, size(A), ol_A, coords, fix_global_boundaries) + return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) end -# function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) +# function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) # @show extents # if fix_global_boundaries # extents_new = ( if !(@periods()[i]) @@ -509,7 +509,7 @@ end # return extents_new # end -function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) +function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) extents = [extents...] if fix_global_boundaries b_g = (ol_A[1] ÷ 2, ol_A[2] ÷ 2, ol_A[3] ÷ 2) @@ -519,14 +519,14 @@ function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{ if coords[i] == 0 extents[i] = 1+b_g[i]:extents[i].stop end - if coords[i] == @dims()[i]-1 + if coords[i] == dims[i]-1 extents[i] = extents[i].start:nxyz_A[i]-e_g[i] end else if coords[i] == 0 extents[i] = 1:extents[i].stop end - if coords[i] == @dims()[i]-1 + if coords[i] == dims[i]-1 extents[i] = extents[i].start:nxyz_A[i] end end @@ -575,23 +575,23 @@ julia> extents_g(1) # The extents as required by VTK julia> finalize_global_grid() ``` """ -function extents_g(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) - extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords) +function extents_g(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) + extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, @nxyz(), coords) end -function extents_g(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) - extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords) +function extents_g(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) + extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, size(A), coords) end -function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) - extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords) +function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) + extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, @nxyz(), coords) end -function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords()) - extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords) +function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) + extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, size(A), coords) end @@ -654,7 +654,7 @@ julia> finalize_global_grid() ``` """ function metagrid(dims::Tuple{Int,Int,Int}, f::Function, args...; kwargs...) - return [f(args...; coords=(x,y,z), kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] + return [f(args...; coords=(x,y,z), dims=dims, kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] end metagrid(f::Function, args...; kwargs...) = metagrid(@dims(), f, args...; kwargs...) From 5fef5a1d5e24bce3edbdaa388c3e2254b9d9ead9 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Mon, 31 Mar 2025 15:50:30 +0200 Subject: [PATCH 03/30] add Cartesian extents and improve --- src/tools.jl | 340 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 228 insertions(+), 112 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 319a15f..68257b3 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -23,6 +23,10 @@ macro periodx() esc(:( convert(Bool, global_grid().periods[1]) )) end macro periody() esc(:( convert(Bool, global_grid().periods[2]) )) end macro periodz() esc(:( convert(Bool, global_grid().periods[3]) )) end macro periods() esc(:( (Bool.(global_grid().periods)...,) )) end +macro halowidthx() esc(:( global_grid().halowidths[1] )) end +macro halowidthy() esc(:( global_grid().halowidths[2] )) end +macro halowidthz() esc(:( global_grid().halowidths[3] )) end +macro halowidths() esc(:( global_grid().halowidths )) end """ @@ -32,6 +36,7 @@ Return the size of the global grid in dimension x. """ nx_g() = @nx_g() + """ ny_g() @@ -39,6 +44,7 @@ Return the size of the global grid in dimension y. """ ny_g() = @ny_g() + """ nz_g() @@ -46,6 +52,7 @@ Return the size of the global grid in dimension z. """ nz_g() = @nz_g() + """ nx_g(A) @@ -53,6 +60,7 @@ Return the size of array `A` in the global grid in dimension x. """ nx_g(A::AbstractArray) = @nx_g() + (size(A,1)-@nx()) + """ ny_g(A) @@ -60,6 +68,7 @@ Return the size of array `A` in the global grid in dimension y. """ ny_g(A::AbstractArray) = @ny_g() + (size(A,2)-@ny()) + """ nz_g(A) @@ -67,11 +76,16 @@ Return the size of array `A` in the global grid in dimension z. """ nz_g(A::AbstractArray) = @nz_g() + (size(A,3)-@nz()) + """ x_g(ix, dx, A) + x_g(ix, dx, A; wrap_periodic) Return the global x-coordinate for the index `ix` in the local array `A` (`dx` is the space step between the elements). +# Keyword arguments +- `wrap_periodic::Bool=true`: whether to wrap the coordinate at the periodic boundaries (default: `true`). + # Examples ```jldoctest julia> using ImplicitGlobalGrid @@ -104,22 +118,30 @@ julia> [x_g(ix, dx, Vx) for ix=1:size(Vx, 1)] julia> finalize_global_grid() ``` """ -function x_g(ix::Integer, dx::Real, A::AbstractArray) - x0 = 0.5*(@nx()-size(A,1))*dx; - x = (@coordx()*(@nx()-@olx()) + ix-1)*dx + x0; - if @periodx() - x = x - dx; # The first cell of the global problem is a ghost cell; so, all must be shifted by dx to the left. - if (x > (@nx_g()-1)*dx) x = x - @nx_g()*dx; end # It must not be (nx_g()-1)*dx as the distance between the local problems (1*dx) must also be taken into account! - if (x < 0) x = x + @nx_g()*dx; end # ... +x_g(ix::Integer, dx::Real, A::AbstractArray; wrap_periodic::Bool=true) =_x_g(ix, dx, size(A,1), wrap_periodic) + +function _x_g(ix::Integer, dx::Real, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) + nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) + x0_g = @periodx() ? -dx*@halowidthx() : dx*0 # The first cells of the global problem are halo cells; so, all must be shifted by dx to the left. + x0 = 0.5*(@nx()-nx_A)*dx + x = (coordx*(@nx()-@olx()) + ix-1)*dx + x0 + x0_g + if @periodx() && wrap_periodic + if (x > (nx_g-1)*dx) x = x - nx_g*dx; end # It must not be (nx_g()-1)*dx as the distance between the local problems (1*dx) must also be taken into account! + if (x < 0) x = x + nx_g*dx; end # ... end return x end + """ y_g(iy, dy, A) + y_g(iy, dy, A; wrap_periodic) Return the global y-coordinate for the index `iy` in the local array `A` (`dy` is the space step between the elements). +# Keyword arguments +- `wrap_periodic::Bool=true`: whether to wrap the coordinate at the periodic boundaries (default: `true`). + # Examples ```jldoctest julia> using ImplicitGlobalGrid @@ -152,22 +174,30 @@ julia> [y_g(iy, dy, Vy) for iy=1:size(Vy, 2)] julia> finalize_global_grid() ``` """ -function y_g(iy::Integer, dy::Real, A::AbstractArray) - y0 = 0.5*(@ny()-size(A,2))*dy; - y = (@coordy()*(@ny()-@oly()) + iy-1)*dy + y0; - if @periody() - y = y - dy; - if (y > (@ny_g()-1)*dy) y = y - @ny_g()*dy; end - if (y < 0) y = y + @ny_g()*dy; end +y_g(iy::Integer, dy::Real, A::AbstractArray; wrap_periodic::Bool=true) =_y_g(iy, dy, size(A,2), wrap_periodic) + +function _y_g(iy::Integer, dy::Real, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) + ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) + y0_g = @periody() ? -dy*@halowidthy() : dy*0 # The first cells of the global problem are halo cells; so, all must be shifted by dy to the left. + y0 = 0.5*(@ny()-ny_A)*dy + y = (coordy*(@ny()-@oly()) + iy-1)*dy + y0 + y0_g + if @periody() && wrap_periodic + if (y > (ny_g-1)*dy) y = y - ny_g*dy; end # It must not be (ny_g()-1)*dy as the distance between the local problems (1*dy) must also be taken into account! + if (y < 0) y = y + ny_g*dy; end # ... end return y end + """ z_g(iz, dz, A) + z_g(iz, dz, A; wrap_periodic) Return the global z-coordinate for the index `iz` in the local array `A` (`dz` is the space step between the elements). +# Keyword arguments +- `wrap_periodic::Bool=true`: whether to wrap the coordinate at the periodic boundaries (default: `true`). + # Examples ```jldoctest julia> using ImplicitGlobalGrid @@ -200,32 +230,35 @@ julia> [z_g(iz, dz, Vz) for iz=1:size(Vz, 3)] julia> finalize_global_grid() ``` """ -function z_g(iz::Integer, dz::Real, A::AbstractArray) - z0 = 0.5*(@nz()-size(A,3))*dz; - z = (@coordz()*(@nz()-@olz()) + iz-1)*dz + z0; - if @periodz() - z = z - dz; - if (z > (@nz_g()-1)*dz) z = z - @nz_g()*dz; end - if (z < 0) z = z + @nz_g()*dz; end +z_g(iz::Integer, dz::Real, A::AbstractArray; wrap_periodic::Bool=true) =_z_g(iz, dz, size(A,3), wrap_periodic) + +function _z_g(iz::Integer, dz::Real, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) + z0_g = @periodz() ? -dz*@halowidthz() : dz*0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. + z0 = 0.5*(@nz()-nz_A)*dz + z = (coordz*(@nz()-@olz()) + iz-1)*dz + z0 + z0_g + if @periodz() && wrap_periodic + if (z > (nz_g-1)*dz) z = z - nz_g*dz; end # It must not be (nz_g()-1)*dz as the distance between the local problems (1*dz) must also be taken into account! + if (z < 0) z = z + nz_g*dz; end # ... end return z end + """ - ix_g(ix; coords, wrap_periodic) - ix_g(ix, A; coords, wrap_periodic) + ix_g(ix, A) + ix_g(ix, A; wrap_periodic) -Return the global x-index for the local index `ix` in the base grid or in the local array `A`. +Return the global x-index for the local index `ix` in the local array `A`. # Keyword arguments -- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). - `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. # Examples ```jldoctest julia> using ImplicitGlobalGrid -julia> lx=4; nx=5; ny=3; nz=3; +julia> nx=5; ny=3; nz=3; julia> init_global_grid(nx, ny, nz, periodx=1); Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) @@ -234,7 +267,7 @@ julia> A = zeros(nx,ny,nz); julia> Vx = zeros(nx+1,ny,nz); -julia> [ix_g(ix) for ix=1:size(A, 1)] +julia> [ix_g(ix, A) for ix=1:size(A, 1)] 5-element Vector{Int64}: 3 1 @@ -254,41 +287,37 @@ julia> [ix_g(ix, Vx) for ix=1:size(Vx, 1)] julia> finalize_global_grid() ``` """ -function ix_g(ix::Integer; coordx::Integer=@coordx(), wrap_periodic::Bool=true) - _ix_g(ix, @nx(), coordx, wrap_periodic) -end +ix_g(ix::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _ix_g(ix, size(A,1), wrap_periodic) -function ix_g(ix::Integer, A::AbstractArray; coordx::Integer=@coordx(), wrap_periodic::Bool=true) - _ix_g(ix, size(A,1), coordx, wrap_periodic) -end -function _ix_g(ix::Integer, nx_A::Integer, coordx::Integer, wrap_periodic::Bool) +function _ix_g(ix::Integer, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) + nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) olx_A = @olx() + (nx_A-@nx()) ix0_g = @periodx() ? 0 : olx_A÷2 ix0 = -olx_A÷2 ix = coordx*(@nx()-olx_A) + ix + ix0 + ix0_g if wrap_periodic && @periodx() - if (ix > @nx_g()) ix = ix - @nx_g(); end - if (ix < 1) ix = ix + @nx_g(); end + if (ix > nx_g) ix = ix - nx_g; end + if (ix < 1) ix = ix + nx_g; end end return ix end + """ - iy_g(iy; coords, wrap_periodic) - iy_g(iy, A; coords, wrap_periodic) + iy_g(iy, A) + iy_g(iy, A; wrap_periodic) -Return the global y-index for the local index `iy` in the base grid or in the local array `A`. +Return the global y-index for the local index `iy` in the local array `A`. # Keyword arguments -- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). - `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. # Examples ```jldoctest julia> using ImplicitGlobalGrid -julia> ly=4; nx=3; ny=5; nz=3; +julia> nx=3; ny=5; nz=3; julia> init_global_grid(nx, ny, nz, periody=1); Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) @@ -297,7 +326,7 @@ julia> A = zeros(nx,ny,nz); julia> Vy = zeros(nx,ny+1,nz); -julia> [iy_g(iy) for iy=1:size(A, 2)] +julia> [iy_g(iy, A) for iy=1:size(A, 2)] 5-element Vector{Int64}: 3 1 @@ -317,41 +346,36 @@ julia> [iy_g(iy, Vy) for iy=1:size(Vy, 2)] julia> finalize_global_grid() ``` """ -function iy_g(iy::Integer; coordy::Integer=@coordy(), wrap_periodic::Bool=true) - _iy_g(iy, @ny(), coordy, wrap_periodic) -end +iy_g(iy::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iy_g(iy, size(A,2), wrap_periodic) -function iy_g(iy::Integer, A::AbstractArray; coordy::Integer=@coordy(), wrap_periodic::Bool=true) - _iy_g(iy, size(A,2), coordy, wrap_periodic) -end - -function _iy_g(iy::Integer, ny_A::Integer, coordy::Integer, wrap_periodic::Bool) +function _iy_g(iy::Integer, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) + ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) oly_A = @oly() + (ny_A-@ny()) iy0_g = @periody() ? 0 : oly_A÷2 iy0 = -oly_A÷2 iy = coordy*(@ny()-oly_A) + iy + iy0 + iy0_g if wrap_periodic && @periody() - if (iy > @ny_g()) iy = iy - @ny_g(); end - if (iy < 1) iy = iy + @ny_g(); end + if (iy > ny_g) iy = iy - ny_g; end + if (iy < 1) iy = iy + ny_g; end end return iy end + """ - iz_g(iz; coords, wrap_periodic) - iz_g(iz, A; coords, wrap_periodic) + iz_g(iz, A) + iz_g(iz, A; wrap_periodic) -Return the global z-index for the local index `iz` in the base grid or in the local array `A`. +Return the global z-index for the local index `iz` in the local array `A`. # Keyword arguments -- `coords::Integer`: the coordinates of the process for which the global index is requested (default: the coordinates of the current process). - `wrap_periodic::Bool=true`: whether to wrap the index at the periodic boundaries (default: `true`). If `wrap_periodic=false`, the global index can be negative or bigger than the size of the global grid. # Examples ```jldoctest julia> using ImplicitGlobalGrid -julia> lz=4; nx=3; ny=3; nz=5; +julia> nx=3; ny=3; nz=5; julia> init_global_grid(nx, ny, nz, periodz=1); Global grid: 3x3x3 (nprocs: 1, dims: 1x1x1) @@ -360,7 +384,7 @@ julia> A = zeros(nx,ny,nz); julia> Vz = zeros(nx,ny,nz+1); -julia> [iz_g(iz) for iz=1:size(A, 3)] +julia> [iz_g(iz, A) for iz=1:size(A, 3)] 5-element Vector{Int64}: 3 1 @@ -368,7 +392,7 @@ julia> [iz_g(iz) for iz=1:size(A, 3)] 3 1 -julia> [iz_g(iz; wrap_periodic=false) for iz=1:size(A, 3)] +julia> [iz_g(iz, A; wrap_periodic=false) for iz=1:size(A, 3)] 5-element Vector{Int64}: 0 1 @@ -397,22 +421,17 @@ julia> [iz_g(iz, Vz; wrap_periodic=false) for iz=1:size(Vz, 3)] julia> finalize_global_grid() ``` """ -function iz_g(iz::Integer; coordz::Integer=@coordz(), wrap_periodic::Bool=true) - _iz_g(iz, @nz(), coordz, wrap_periodic) -end +iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) -function iz_g(iz::Integer, A::AbstractArray; coordz::Integer=@coordz(), wrap_periodic::Bool=true) - _iz_g(iz, size(A,3), coordz, wrap_periodic) -end - -function _iz_g(iz::Integer, nz_A::Integer, coordz::Integer, wrap_periodic::Bool) +function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) olz_A = @olz() + (nz_A-@nz()) iz0_g = @periodz() ? 0 : olz_A÷2 iz0 = -olz_A÷2 iz = coordz*(@nz()-olz_A) + iz + iz0 + iz0_g if wrap_periodic && @periodz() - if (iz > @nz_g()) iz = iz - @nz_g(); end - if (iz < 1) iz = iz + @nz_g(); end + if (iz > nz_g) iz = iz - nz_g; end + if (iz < 1) iz = iz + nz_g; end end return iz end @@ -436,7 +455,9 @@ Return the local extents in each dimension of the array `A` or the local extents ```jldoctest julia> using ImplicitGlobalGrid -julia> init_global_grid(5, 5, 7; periodz=1); +julia> nx=5; ny=5; nz=7; + +julia> init_global_grid(nx, ny, nz; periodz=1); Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) julia> extents() @@ -454,6 +475,16 @@ julia> extents(0; fix_global_boundaries=false) julia> extents(1) # The extents as required by VTK (1:5, 1:5, 2:6) +julia> Vx = zeros(nx+1,ny,nz); + +julia> extents(Vx, 1) # The extents as required by VTK +(1:6, 1:5, 2:6) + +julia> Vx_IO = view(Vx, extents(Vx, 1)...); + +julia> summary(Vx_IO) +"6×5×5 view(::Array{Float64, 3}, 1:6, 1:5, 2:6) with eltype Float64" + julia> finalize_global_grid() ``` """ @@ -463,28 +494,34 @@ function extents(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}= end function extents(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) + # ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) + ol_A = @ols() .+ (size(A) .- @nxyz()) extents = (1:size(A,1), 1:size(A,2), 1:size(A,3)) return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) end function extents(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps - if (overlaps[1] > @olx()) || (overlaps[2] > @oly()) || (overlaps[3] > @olz()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end - # extents = (1:@nx()-@olx()+overlaps[1], 1:@ny()-@oly()+overlaps[2], 1:@nz()-@olz()+overlaps[3]) - bx, by, bz = (@olx()-overlaps[1]) ÷ 2, (@oly()-overlaps[2]) ÷ 2, (@olz()-overlaps[3]) ÷ 2 - ex, ey, ez = cld(@olx()-overlaps[1], 2), cld(@oly()-overlaps[2], 2), cld(@olz()-overlaps[3], 2) + # if (overlaps[1] > @olx()) || (overlaps[2] > @oly()) || (overlaps[3] > @olz()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + if any(overlaps .> @ols()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + # bx, by, bz = (@olx()-overlaps[1]) ÷ 2, (@oly()-overlaps[2]) ÷ 2, (@olz()-overlaps[3]) ÷ 2 + bx, by, bz = (@ols() .- overlaps) .÷ 2 + # ex, ey, ez = cld(@olx()-overlaps[1], 2), cld(@oly()-overlaps[2], 2), cld(@olz()-overlaps[3], 2) + ex, ey, ez = cld.(@ols() .- overlaps, 2) extents = (1+bx:@nx()-ex, 1+by:@ny()-ey, 1+bz:@nz()-ez) return _adjust_extents(extents, @nxyz(), @ols(), coords, dims, fix_global_boundaries) end function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps - ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) - if (overlaps[1] > ol_A[1]) || (overlaps[2] > ol_A[2]) || (overlaps[3] > ol_A[3]) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end - # extents = (1:size(A,1)-olx_A+overlaps[1], 1:size(A,2)-oly_A+overlaps[2], 1:size(A,3)-olz_A+overlaps[3]) - bx, by, bz = (ol_A[1]-overlaps[1]) ÷ 2, (ol_A[2]-overlaps[2]) ÷ 2, (ol_A[3]-overlaps[3]) ÷ 2 - ex, ey, ez = cld(ol_A[1]-overlaps[1], 2), cld(ol_A[2]-overlaps[2], 2), cld(ol_A[3]-overlaps[3], 2) + # ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) + ol_A = @ols() .+ (size(A) .- @nxyz()) + # if (overlaps[1] > ol_A[1]) || (overlaps[2] > ol_A[2]) || (overlaps[3] > ol_A[3]) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + if any(overlaps .> ol_A) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + # bx, by, bz = (ol_A[1]-overlaps[1]) ÷ 2, (ol_A[2]-overlaps[2]) ÷ 2, (ol_A[3]-overlaps[3]) ÷ 2 + bx, by, bz = (ol_A .- overlaps) .÷ 2 + # ex, ey, ez = cld(ol_A[1]-overlaps[1], 2), cld(ol_A[2]-overlaps[2], 2), cld(ol_A[3]-overlaps[3], 2) + ex, ey, ez = cld.(ol_A .- overlaps, 2) extents = (1+bx:size(A,1)-ex, 1+by:size(A,2)-ey, 1+bz:size(A,3)-ez) return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) end @@ -512,8 +549,10 @@ end function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) extents = [extents...] if fix_global_boundaries - b_g = (ol_A[1] ÷ 2, ol_A[2] ÷ 2, ol_A[3] ÷ 2) - e_g = (cld(ol_A[1], 2), cld(ol_A[2], 2), cld(ol_A[3], 2)) + # b_g = (ol_A[1] ÷ 2, ol_A[2] ÷ 2, ol_A[3] ÷ 2) + b_g = ol_A .÷ 2 + # e_g = (cld(ol_A[1], 2), cld(ol_A[2], 2), cld(ol_A[3], 2)) + e_g = cld.(ol_A, 2) for i in 1:3 if @periods()[i] if coords[i] == 0 @@ -536,17 +575,18 @@ function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{ end """ - extents_g(; fix_global_boundaries, coords) - extents_g(A; fix_global_boundaries, coords) - extents_g(overlaps; fix_global_boundaries, coords) - extents_g(A, overlaps; fix_global_boundaries, coords) + extents_g(; dxyz, fix_global_boundaries, coords) + extents_g(A; dxyz, fix_global_boundaries, coords) + extents_g(overlaps; dxyz, fix_global_boundaries, coords) + extents_g(A, overlaps; dxyz, fix_global_boundaries, coords) -Return the global extents in each dimension of the array `A` or the global extents of the base grid if `A` is not provided (return type: tuple of ranges). +Return the global extents in each dimension of the array `A` or the global extents of the base grid if `A` is not provided (return type: tuple of ranges); if `dxyz` is set, global Cartesian coordinates extents are returned, else global index extents are returned. # Arguments - `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid. # Keyword arguments +- `dxyz::Tuple{Real,Real,Real}`: the space step between the elements in each dimension if global Cartesian coordinates are desired. - `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. - `coords::Tuple{Int,Int,Int}`: the coordinates of the process for which the global extents is requested. The default is the coordinates of the current process. @@ -554,7 +594,9 @@ Return the global extents in each dimension of the array `A` or the global exten ```jldoctest julia> using ImplicitGlobalGrid -julia> init_global_grid(5, 5, 7; periodz=1); +julia> lx=8; ly=8; lz=8; nx=5; ny=5; nz=7; + +julia> init_global_grid(nx, ny, nz; periodz=1); Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) julia> extents_g() @@ -572,54 +614,81 @@ julia> extents_g(0; fix_global_boundaries=false) julia> extents_g(1) # The extents as required by VTK (1:5, 1:5, 1:5) +julia> dx, dy, dz = lx/(nx_g()-1), ly/(ny_g()-1), lz/(nz_g()-1) +(2.0, 2.0, 2.0) + +julia> extents_g(; dxyz=(dx, dy, dz)) +(0.0:2.0:8.0, 0.0:2.0:8.0, 1.0:2.0:7.0) + +julia> extents_g(; dxyz=(dx, dy, dz), fix_global_boundaries=false) +(0.0:2.0:8.0, 0.0:2.0:8.0, -2.0:2.0:10.0) + +julia> extents_g(0; dxyz=(dx, dy, dz), fix_global_boundaries=false) +(2.0:2.0:6.0, 2.0:2.0:6.0, 0.0:2.0:8.0) + +julia> extents_g(1; dxyz=(dx, dy, dz)) # The Cartesian coordinates corresponding to the extents required by VTK +(0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:2.0:8.0) + julia> finalize_global_grid() ``` """ -function extents_g(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, @nxyz(), coords) + return extents_g(extents_l, @nxyz(), dxyz, coords, dims) end -function extents_g(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(A::AbstractArray; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, size(A), coords) + return extents_g(extents_l, size(A), dxyz, coords, dims) end -function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, @nxyz(), coords) + return extents_g(extents_l, @nxyz(), dxyz, coords, dims) end -function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, size(A), coords) + return extents_g(extents_l, size(A), dxyz, coords, dims) +end + +function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Nothing, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) + return (_ix_g(extents[1].start, nxyz_A[1], false, coords[1], dims[1]) : _ix_g(extents[1].stop, nxyz_A[1], false, coords[1], dims[1]), + _iy_g(extents[2].start, nxyz_A[2], false, coords[2], dims[2]) : _iy_g(extents[2].stop, nxyz_A[2], false, coords[2], dims[2]), + _iz_g(extents[3].start, nxyz_A[3], false, coords[3], dims[3]) : _iz_g(extents[3].stop, nxyz_A[3], false, coords[3], dims[3])) end -function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}) - return (_ix_g(extents[1].start, nxyz_A[1], coords[1], false):_ix_g(extents[1].stop, nxyz_A[1], coords[1], false), - _iy_g(extents[2].start, nxyz_A[2], coords[2], false):_iy_g(extents[2].stop, nxyz_A[2], coords[2], false), - _iz_g(extents[3].start, nxyz_A[3], coords[3], false):_iz_g(extents[3].stop, nxyz_A[3], coords[3], false)) +function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Tuple{Real,Real,Real}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) + return (_x_g(extents[1].start, dxyz[1], nxyz_A[1], false, coords[1], dims[1]) : dxyz[1] : _x_g(extents[1].stop, dxyz[1], nxyz_A[1], false, coords[1], dims[1]), + _y_g(extents[2].start, dxyz[2], nxyz_A[2], false, coords[2], dims[2]) : dxyz[2] : _y_g(extents[2].stop, dxyz[2], nxyz_A[2], false, coords[2], dims[2]), + _z_g(extents[3].start, dxyz[3], nxyz_A[3], false, coords[3], dims[3]) : dxyz[3] : _z_g(extents[3].stop, dxyz[3], nxyz_A[3], false, coords[3], dims[3])) end + """ metagrid(f::Function, args...; kwargs...) metagrid(dims, f::Function, args...; kwargs...) -Return a metadata grid containing the results of the function `f` applied to each process coordinates in the global grid or the imaginary grid with the dimensions `dims` (return type: array with elements of the same type as the return type of `f`). +Return a metadata grid containing the results of the function `f` applied to each process coordinates in the global grid; if `dims` is provided, the function is applied to each process coordinates in an imaginary grid with the dimensions `dims` (the other grid parameters like periodicity and overlaps are inherited from the actual global grid). The return type is an array with elements of the same type as the return type of `f`. # Arguments -- `dims::Tuple{Int,Int,Int}`: the dimensions of the (imaginary) grid. The default is the actual dimensions of the global grid. -- `f::Function`: the function to apply to each process coordinates; the function must accept the keyword argument `coords` which is a tuple of the coordinates of the process. +- `f::Function`: the function to apply to each process coordinates; the function must accept the keyword argument `coords` (a tuple of the coordinates of the process). Furthermore, for imaginary grids, the function can optionally also accept the keyword arguments `dims` (the dimensions of the imaginary grid). - `args...`: the arguments to pass to the function `f`. -- `kwargs...`: the keyword arguments to pass to the function `f`; the keyword argument `coords` is automatically added. +- `kwargs...`: the keyword arguments to pass to the function `f`; the keyword argument `coords` (and optionally `dims` for imaginary grids) is automatically added. +- `dims::Tuple{Int,Int,Int}`: the dimensions of the imaginary grid to use instead of the global grid. # Examples ```jldoctest julia> using ImplicitGlobalGrid -julia> init_global_grid(5, 5, 7; periodz=1); +julia> lx=8; ly=8; lz=8; nx=5; ny=5; nz=7; + +julia> init_global_grid(nx, ny, nz; periodz=1); Global grid: 5x5x5 (nprocs: 1, dims: 1x1x1) +julia> dx, dy, dz = lx/(nx_g()-1), ly/(ny_g()-1), lz/(nz_g()-1) +(2.0, 2.0, 2.0) + julia> metagrid((; coords)->coords) 1×1×1 Array{Tuple{Int64, Int64, Int64}, 3}: [:, :, 1] = @@ -635,29 +704,76 @@ julia> metagrid((2, 2, 2), (; coords)->coords) (0, 0, 1) (0, 1, 1) (1, 0, 1) (1, 1, 1) +julia> metagrid(extents_g, 0) +1×1×1 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: +[:, :, 1] = + (1:5, 1:5, 1:5) + +julia> metagrid(extents_g, 0; fix_global_boundaries=false) +1×1×1 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: +[:, :, 1] = + (2:4, 2:4, 1:5) + +julia> metagrid((2, 2, 2), extents_g, 0) +2×2×2 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: +[:, :, 1] = + (1:4, 1:4, 1:5) (1:4, 5:8, 1:5) + (5:8, 1:4, 1:5) (5:8, 5:8, 1:5) + +[:, :, 2] = + (1:4, 1:4, 6:10) (1:4, 5:8, 6:10) + (5:8, 1:4, 6:10) (5:8, 5:8, 6:10) + julia> metagrid(extents_g, 1) # The extents grid as required by VTK 1×1×1 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: [:, :, 1] = (1:5, 1:5, 1:5) -julia> metagrid((2, 2, 2), extents_g, 1) # The extents grid as required by VTK for an imaginary grid with dimensions (2, 2, 2) +julia> metagrid(extents_g, 1; dxyz=(dx, dy, dz)) # The Cartesian coordinates corresponding to the extents required by VTK +1×1×1 Array{Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}, 3}: +[:, :, 1] = + (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:2.0:8.0) + + +julia> metagrid((2, 2, 2), extents_g, 1) # The extents grid as required by VTK for an imaginary grid with dimensions (2, 2, 2) and periodic in z (inherited from the global grid) 2×2×2 Array{Tuple{UnitRange{Int64}, UnitRange{Int64}, UnitRange{Int64}}, 3}: [:, :, 1] = - (1:5, 1:5, 1:5) (1:5, 4:7, 1:5) - (4:7, 1:5, 1:5) (4:7, 4:7, 1:5) + (1:4, 1:4, 1:5) (1:4, 4:8, 1:5) + (4:8, 1:4, 1:5) (4:8, 4:8, 1:5) [:, :, 2] = - (1:5, 1:5, 5:10) (1:5, 4:7, 5:10) - (4:7, 1:5, 5:10) (4:7, 4:7, 5:10) + (1:4, 1:4, 5:10) (1:4, 4:8, 5:10) + (4:8, 1:4, 5:10) (4:8, 4:8, 5:10) + +julia> metagrid((2, 2, 2), extents_g, 1; dxyz=(dx, dy, dz)) # The Cartesian coordinates corresponding to the extents required by VTK for an imaginary grid with dimensions (2, 2, 2) and periodic in z (inherited from the global grid) +2×2×2 Array{Tuple{StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}, StepRangeLen{Float64, Base.TwicePrecision{Float64}, Base.TwicePrecision{Float64}, Int64}}, 3}: +[:, :, 1] = + (0.0:2.0:6.0, 0.0:2.0:6.0, 0.0:2.0:8.0) (0.0:2.0:6.0, 6.0:2.0:14.0, 0.0:2.0:8.0) + (6.0:2.0:14.0, 0.0:2.0:6.0, 0.0:2.0:8.0) (6.0:2.0:14.0, 6.0:2.0:14.0, 0.0:2.0:8.0) + +[:, :, 2] = + (0.0:2.0:6.0, 0.0:2.0:6.0, 8.0:2.0:18.0) (0.0:2.0:6.0, 6.0:2.0:14.0, 8.0:2.0:18.0) + (6.0:2.0:14.0, 0.0:2.0:6.0, 8.0:2.0:18.0) (6.0:2.0:14.0, 6.0:2.0:14.0, 8.0:2.0:18.0) julia> finalize_global_grid() ``` """ +function metagrid(f::Function, args...; kwargs...) + return [f(args...; coords=(x,y,z), kwargs...) for x=0:@dimx()-1, y=0:@dimy()-1, z=0:@dimz()-1] +end + function metagrid(dims::Tuple{Int,Int,Int}, f::Function, args...; kwargs...) - return [f(args...; coords=(x,y,z), dims=dims, kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] + if haskwarg(f, :dims) && haskwarg(f, :coords) + return [f(args...; coords=(x,y,z), dims=dims, kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] + elseif haskwarg(f, :coords) + return [f(args...; coords=(x,y,z), kwargs...) for x=0:dims[1]-1, y=0:dims[2]-1, z=0:dims[3]-1] + else + @ArgumentError("The function `f` must accept the keyword argument `coords` (and, for imaginary grids, optionally also `dims`).") + end end -metagrid(f::Function, args...; kwargs...) = metagrid(@dims(), f, args...; kwargs...) +haskwarg(f::Function, kwarg::Symbol) = any(kwarg ∈ Base.kwarg_decl(m) for m in methods(f)) + # Timing tools. From d50995b5e92780083bc7fa617491c6545f7ca473 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Mon, 31 Mar 2025 16:52:41 +0200 Subject: [PATCH 04/30] fix halowidths argument description in doc string --- src/init_global_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index fb43c3e..f848ba1 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -13,7 +13,7 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de - `quiet::Bool=false`: whether to suppress printing information like the size of the global grid (`true`) or not (`false`). !!! note "Advanced keyword arguments" - `overlaps::Tuple{Int,Int,Int}=(2,2,2)`: the number of elements adjacent local grids overlap in dimension x, y and z. By default (value `(2,2,2)`), an array `A` of size (`nx`, `ny`, `nz`) on process 1 (`A_1`) overlaps the corresponding array `A` on process 2 (`A_2`) by `2` indices if the two processes are adjacent. E.g., if `overlaps[1]=2` and process 2 is the right neighbor of process 1 in dimension x, then `A_1[end-1:end,:,:]` overlaps `A_2[1:2,:,:]`. That means, after every call `update_halo!(A)`, we have `all(A_1[end-1:end,:,:] .== A_2[1:2,:,:])` (`A_1[end,:,:]` is the halo of process 1 and `A_2[1,:,:]` is the halo of process 2). The analog applies for the dimensions y and z. - - `halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2)`: the default width of an array's halo in dimension x, y and z (must be greater than 1). The default can be overwritten per array in the function [`update_halo`](@ref). + - `halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2)`: the default width of an array's halo in dimension x, y and z (must be greater or equal to 1). The default can be overwritten per array in the function [`update_halo`](@ref). - `disp::Integer=1`: the displacement argument to `MPI.Cart_shift` in order to determine the neighbors. - `reorder::Integer=1`: the reorder argument to `MPI.Cart_create` in order to create the Cartesian process topology. - `comm::MPI.Comm=MPI.COMM_WORLD`: the input communicator argument to `MPI.Cart_create` in order to create the Cartesian process topology. From e40a570e5589a9afb5e9336765077f20abd406d1 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Mon, 31 Mar 2025 17:48:52 +0200 Subject: [PATCH 05/30] use first and last instead of start and stop --- src/tools.jl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 68257b3..264c20c 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -531,10 +531,10 @@ end # if fix_global_boundaries # extents_new = ( if !(@periods()[i]) # if coords[i] == 0 -# 1:extents[i].stop +# 1:extents[i].last # end # if coords[i] == @dims()[i]-1 -# extents[i].start:nxyz_A[i] +# extents[i].first:nxyz_A[i] # end # else # extents[i] @@ -556,17 +556,17 @@ function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{ for i in 1:3 if @periods()[i] if coords[i] == 0 - extents[i] = 1+b_g[i]:extents[i].stop + extents[i] = 1+b_g[i]:last(extents[i]) end if coords[i] == dims[i]-1 - extents[i] = extents[i].start:nxyz_A[i]-e_g[i] + extents[i] = first(extents[i]):nxyz_A[i]-e_g[i] end else if coords[i] == 0 - extents[i] = 1:extents[i].stop + extents[i] = 1:last(extents[i]) end if coords[i] == dims[i]-1 - extents[i] = extents[i].start:nxyz_A[i] + extents[i] = first(extents[i]):nxyz_A[i] end end end @@ -653,15 +653,15 @@ function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}} end function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Nothing, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) - return (_ix_g(extents[1].start, nxyz_A[1], false, coords[1], dims[1]) : _ix_g(extents[1].stop, nxyz_A[1], false, coords[1], dims[1]), - _iy_g(extents[2].start, nxyz_A[2], false, coords[2], dims[2]) : _iy_g(extents[2].stop, nxyz_A[2], false, coords[2], dims[2]), - _iz_g(extents[3].start, nxyz_A[3], false, coords[3], dims[3]) : _iz_g(extents[3].stop, nxyz_A[3], false, coords[3], dims[3])) + return (_ix_g(first(extents[1]), nxyz_A[1], false, coords[1], dims[1]) : _ix_g(last(extents[1]), nxyz_A[1], false, coords[1], dims[1]), + _iy_g(first(extents[2]), nxyz_A[2], false, coords[2], dims[2]) : _iy_g(last(extents[2]), nxyz_A[2], false, coords[2], dims[2]), + _iz_g(first(extents[3]), nxyz_A[3], false, coords[3], dims[3]) : _iz_g(last(extents[3]), nxyz_A[3], false, coords[3], dims[3])) end function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Tuple{Real,Real,Real}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) - return (_x_g(extents[1].start, dxyz[1], nxyz_A[1], false, coords[1], dims[1]) : dxyz[1] : _x_g(extents[1].stop, dxyz[1], nxyz_A[1], false, coords[1], dims[1]), - _y_g(extents[2].start, dxyz[2], nxyz_A[2], false, coords[2], dims[2]) : dxyz[2] : _y_g(extents[2].stop, dxyz[2], nxyz_A[2], false, coords[2], dims[2]), - _z_g(extents[3].start, dxyz[3], nxyz_A[3], false, coords[3], dims[3]) : dxyz[3] : _z_g(extents[3].stop, dxyz[3], nxyz_A[3], false, coords[3], dims[3])) + return (_x_g(first(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]) : dxyz[1] : _x_g(last(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]), + _y_g(first(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]) : dxyz[2] : _y_g(last(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]), + _z_g(first(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3]) : dxyz[3] : _z_g(last(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3])) end From dfbc317dbf6db626fdea6fb717089b24d501a7c3 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 23 Apr 2025 16:50:59 +0200 Subject: [PATCH 06/30] add more parameters for grid --- src/init_global_grid.jl | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index f848ba1..2821a8e 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -8,8 +8,13 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de # Arguments - {`nx`|`ny`|`nz`}`::Integer`: the number of elements of the local grid in dimension {x|y|z}. + +# Keyword arguments - {`dimx`|`dimy`|`dimz`}`::Integer=0`: the desired number of processes in dimension {x|y|z}. By default, (value `0`) the process topology is created as compact as possible with the given constraints. This is handled by the MPI implementation which is installed on your system. For more information, refer to the specifications of `MPI_Dims_create` in the corresponding documentation. -- {`periodx`|`periody`|`periodz`}`::Integer=0`: whether the grid is periodic (`1`) or not (`0`) in dimension {x|y|z}. +- {`periodx`|`periody`|`periodz`}`::Bool|Integer=false`: whether the grid is periodic (`true`) or not (`false`) in dimension {x|y|z}. The argument is also accepted as an integer as traditionally in the MPI standard (`1` for `true` and `0` for `false`). +- `origin::Tuple|AbstractFloat`: the origin of the global grid. By default, it is set to `(0.0, 0.0, 0.0)` (`(0.0, 0.0)` for 2D and `0.0` for 1D). +- `origin_on_vertex::Bool=false`: whether the origin is on the cell vertex; else, it is on the cell center (default). The default implies that the space step `dx` is computed in the user code as `dx=lx/(nx-1)`, where `lx` is the length of the global grid in dimension x. Setting the origin on the vertex implies that the space step is computed as `dx=lx/nx`, instead. The analog applies for the dimensions y and z. +- {`centerx`|`centery`|`centerz`}`::Bool=false`: whether to center the grid on the origin (`true`) or not (`false`) in dimension {x|y|z}. By default, the grid is extends from `origin` in the positive direction of the corresponding dimension. - `quiet::Bool=false`: whether to suppress printing information like the size of the global grid (`true`) or not (`false`). !!! note "Advanced keyword arguments" - `overlaps::Tuple{Int,Int,Int}=(2,2,2)`: the number of elements adjacent local grids overlap in dimension x, y and z. By default (value `(2,2,2)`), an array `A` of size (`nx`, `ny`, `nz`) on process 1 (`A_1`) overlaps the corresponding array `A` on process 2 (`A_2`) by `2` indices if the two processes are adjacent. E.g., if `overlaps[1]=2` and process 2 is the right neighbor of process 1 in dimension x, then `A_1[end-1:end,:,:]` overlaps `A_2[1:2,:,:]`. That means, after every call `update_halo!(A)`, we have `all(A_1[end-1:end,:,:] .== A_2[1:2,:,:])` (`A_1[end,:,:]` is the halo of process 1 and `A_2[1,:,:]` is the halo of process 2). The analog applies for the dimensions y and z. @@ -38,7 +43,7 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de See also: [`finalize_global_grid`](@ref), [`select_device`](@ref) """ -function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Integer=0, periody::Integer=0, periodz::Integer=0, overlaps::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) +function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Union{Bool,Integer}=0, periody::Union{Bool,Integer}=0, periodz::Union{Bool,Integer}=0, origin::Union{NTuple,AbstractFloat}, origin_on_vertex::Bool=false, centerx::Bool=false, centery::Bool=false, centerz::Bool=false, overlap::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) if grid_is_initialized() error("The global grid has already been initialized.") end set_cuda_loaded() set_cuda_functional() @@ -46,7 +51,9 @@ function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0 set_amdgpu_functional() nxyz = [nx, ny, nz]; dims = [dimx, dimy, dimz]; - periods = [periodx, periody, periodz]; + periods = Int64.([periodx, periody, periodz]); + origin = Float64.[(length(Tuple(origin)) == 3) ? origin : ((length(Tuple(origin)) == 2) ? (origin..., 0) : (origin, 0, 0))...]; + centerxyz = [centerx, centery, centerz]; overlaps = [overlaps...]; halowidths = [halowidths...]; cuda_enabled = false @@ -82,6 +89,12 @@ function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0 if (any(nxyz .< 1)) error("Invalid arguments: nx, ny, and nz cannot be less than 1."); end if (any(dims .< 0)) error("Invalid arguments: dimx, dimy, and dimz cannot be negative."); end if (any(periods .∉ ((0,1),))) error("Invalid arguments: periodx, periody, and periodz must be either 0 or 1."); end + if (centerx && origin_on_vertex && isodd(nx)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and nx being odd; set either `origin_on_vertex=false` or make nx even."); end + if (centery && origin_on_vertex && isodd(ny)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and ny being odd; set either `origin_on_vertex=false` or make ny even."); end + if (centerz && origin_on_vertex && isodd(nz)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and nz being odd; set either `origin_on_vertex=false` or make nz even."); end + if (centerx && !origin_on_vertex && iseven(nx)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin the cell center and nx being even; set either `origin_on_vertex=true` or make nx odd."); end + if (centery && !origin_on_vertex && iseven(ny)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin the cell center and ny being even; set either `origin_on_vertex=true` or make ny odd."); end + if (centerz && !origin_on_vertex && iseven(nz)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin the cell center and nz being even; set either `origin_on_vertex=true` or make nz odd."); end if (any(halowidths .< 1)) error("Invalid arguments: halowidths cannot be less than 1."); end if (nx==1) error("Invalid arguments: nx can never be 1.") end if (ny==1 && nz>1) error("Invalid arguments: ny cannot be 1 if nz is greater than 1.") end @@ -105,7 +118,7 @@ function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0 neighbors[:,i] .= MPI.Cart_shift(comm_cart, i-1, disp); end nxyz_g = dims.*(nxyz.-overlaps) .+ overlaps.*(periods.==0); # E.g. for dimension x with ol=2 and periodx=0: dimx*(nx-2)+2 - set_global_grid(GlobalGrid(nxyz_g, nxyz, dims, overlaps, halowidths, nprocs, me, coords, neighbors, periods, disp, reorder, comm_cart, cuda_enabled, amdgpu_enabled, cudaaware_MPI, amdgpuaware_MPI, use_polyester, quiet)); + set_global_grid(GlobalGrid(nxyz_g, nxyz, dims, overlaps, halowidths, origin, origin_on_vertex, centerxyz, nprocs, me, coords, neighbors, periods, disp, reorder, comm_cart, cuda_enabled, amdgpu_enabled, cudaaware_MPI, amdgpuaware_MPI, use_polyester, quiet)); cuda_support_string = (cuda_enabled && all(cudaaware_MPI)) ? "CUDA-aware" : (cuda_enabled && any(cudaaware_MPI)) ? "CUDA(-aware)" : (cuda_enabled) ? "CUDA" : ""; amdgpu_support_string = (amdgpu_enabled && all(amdgpuaware_MPI)) ? "AMDGPU-aware" : (amdgpu_enabled && any(amdgpuaware_MPI)) ? "AMDGPU(-aware)" : (amdgpu_enabled) ? "AMDGPU" : ""; gpu_support_string = join(filter(!isempty, [cuda_support_string, amdgpu_support_string]), ", "); From f6ad3d1db9828ec02dda2152b21c03fb050d0b7c Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 23 Apr 2025 16:54:03 +0200 Subject: [PATCH 07/30] adjust tools to new grid parameters --- src/tools.jl | 66 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 264c20c..765973b 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -23,6 +23,15 @@ macro periodx() esc(:( convert(Bool, global_grid().periods[1]) )) end macro periody() esc(:( convert(Bool, global_grid().periods[2]) )) end macro periodz() esc(:( convert(Bool, global_grid().periods[3]) )) end macro periods() esc(:( (Bool.(global_grid().periods)...,) )) end +macro originx() esc(:( global_grid().origin[1] )) end +macro originy() esc(:( global_grid().origin[2] )) end +macro originz() esc(:( global_grid().origin[3] )) end +macro origin() esc(:( (global_grid().origin...,) )) end +macro origin_on_vertex() esc(:( global_grid().origin_on_vertex )) end +macro centerx() esc(:( global_grid().center[1] )) end +macro centery() esc(:( global_grid().center[2] )) end +macro centerz() esc(:( global_grid().center[3] )) end +macro centerxyz() esc(:( (global_grid().center...,) )) end macro halowidthx() esc(:( global_grid().halowidths[1] )) end macro halowidthy() esc(:( global_grid().halowidths[2] )) end macro halowidthz() esc(:( global_grid().halowidths[3] )) end @@ -118,13 +127,16 @@ julia> [x_g(ix, dx, Vx) for ix=1:size(Vx, 1)] julia> finalize_global_grid() ``` """ -x_g(ix::Integer, dx::Real, A::AbstractArray; wrap_periodic::Bool=true) =_x_g(ix, dx, size(A,1), wrap_periodic) +x_g(ix::Integer, dx::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_x_g(ix, dx, size(A,1), wrap_periodic) -function _x_g(ix::Integer, dx::Real, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) - nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) - x0_g = @periodx() ? -dx*@halowidthx() : dx*0 # The first cells of the global problem are halo cells; so, all must be shifted by dx to the left. - x0 = 0.5*(@nx()-nx_A)*dx - x = (coordx*(@nx()-@olx()) + ix-1)*dx + x0 + x0_g +function _x_g(ix::Integer, dx::AbstractFloat, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) + nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) + haloshiftx = @periodx() ? -dx*@halowidthx() : dx*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dx to the left. + vertexshiftx = @origin_on_vertex() ? dx*0.5 : dx*0.0 + centershiftx = @centerx() ? (@origin_on_vertex() ? -nx_g*dx*0.5 : -(nx_g-1)*dx*0.5) : dx*0.0 + x0_g = @originx() + haloshiftx + vertexshiftx + centershiftx + x0 = 0.5*(@nx()-nx_A)*dx + x = (coordx*(@nx()-@olx()) + ix-1)*dx + x0 + x0_g if @periodx() && wrap_periodic if (x > (nx_g-1)*dx) x = x - nx_g*dx; end # It must not be (nx_g()-1)*dx as the distance between the local problems (1*dx) must also be taken into account! if (x < 0) x = x + nx_g*dx; end # ... @@ -174,13 +186,16 @@ julia> [y_g(iy, dy, Vy) for iy=1:size(Vy, 2)] julia> finalize_global_grid() ``` """ -y_g(iy::Integer, dy::Real, A::AbstractArray; wrap_periodic::Bool=true) =_y_g(iy, dy, size(A,2), wrap_periodic) +y_g(iy::Integer, dy::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_y_g(iy, dy, size(A,2), wrap_periodic) -function _y_g(iy::Integer, dy::Real, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) - ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) - y0_g = @periody() ? -dy*@halowidthy() : dy*0 # The first cells of the global problem are halo cells; so, all must be shifted by dy to the left. - y0 = 0.5*(@ny()-ny_A)*dy - y = (coordy*(@ny()-@oly()) + iy-1)*dy + y0 + y0_g +function _y_g(iy::Integer, dy::AbstractFloat, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) + ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) + haloshifty = @periody() ? -dy*@halowidthy() : dy*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dy to the left. + vertexshifty = @origin_on_vertex() ? dy*0.5 : dy*0.0 + centershifty = @centery() ? (@origin_on_vertex() ? -ny_g*dy*0.5 : -(ny_g-1)*dy*0.5) : dy*0.0 + y0_g = @originy() + haloshifty + vertexshifty + centershifty + y0 = 0.5*(@ny()-ny_A)*dy + y = (coordy*(@ny()-@oly()) + iy-1)*dy + y0 + y0_g if @periody() && wrap_periodic if (y > (ny_g-1)*dy) y = y - ny_g*dy; end # It must not be (ny_g()-1)*dy as the distance between the local problems (1*dy) must also be taken into account! if (y < 0) y = y + ny_g*dy; end # ... @@ -230,13 +245,16 @@ julia> [z_g(iz, dz, Vz) for iz=1:size(Vz, 3)] julia> finalize_global_grid() ``` """ -z_g(iz::Integer, dz::Real, A::AbstractArray; wrap_periodic::Bool=true) =_z_g(iz, dz, size(A,3), wrap_periodic) +z_g(iz::Integer, dz::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_z_g(iz, dz, size(A,3), wrap_periodic) -function _z_g(iz::Integer, dz::Real, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - z0_g = @periodz() ? -dz*@halowidthz() : dz*0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. - z0 = 0.5*(@nz()-nz_A)*dz - z = (coordz*(@nz()-@olz()) + iz-1)*dz + z0 + z0_g +function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) + haloshifty = @periodz() ? -dz*@halowidthz() : dz*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. + vertexshifty = @origin_on_vertex() ? dz*0.5 : dz*0.0 + centershifty = @centerz() ? (@origin_on_vertex() ? -nz_g*dz*0.5 : -(nz_g-1)*dz*0.5) : dz*0.0 + z0_g = @originz() + haloshifty + vertexshifty + centershifty + z0 = 0.5*(@nz()-nz_A)*dz + z = (coordz*(@nz()-@olz()) + iz-1)*dz + z0 + z0_g if @periodz() && wrap_periodic if (z > (nz_g-1)*dz) z = z - nz_g*dz; end # It must not be (nz_g()-1)*dz as the distance between the local problems (1*dz) must also be taken into account! if (z < 0) z = z + nz_g*dz; end # ... @@ -586,7 +604,7 @@ Return the global extents in each dimension of the array `A` or the global exten - `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid. # Keyword arguments -- `dxyz::Tuple{Real,Real,Real}`: the space step between the elements in each dimension if global Cartesian coordinates are desired. +- `dxyz::Tuple{AbstractFloat,AbstractFloat,AbstractFloat}`: the space step between the elements in each dimension if global Cartesian coordinates are desired. - `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. - `coords::Tuple{Int,Int,Int}`: the coordinates of the process for which the global extents is requested. The default is the coordinates of the current process. @@ -632,22 +650,22 @@ julia> extents_g(1; dxyz=(dx, dy, dz)) # The Cartesian coordinates corresponding julia> finalize_global_grid() ``` """ -function extents_g(; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, @nxyz(), dxyz, coords, dims) end -function extents_g(A::AbstractArray; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(A::AbstractArray; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, size(A), dxyz, coords, dims) end -function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, @nxyz(), dxyz, coords, dims) end -function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{Real,Real,Real}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) return extents_g(extents_l, size(A), dxyz, coords, dims) end @@ -658,7 +676,7 @@ function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, _iz_g(first(extents[3]), nxyz_A[3], false, coords[3], dims[3]) : _iz_g(last(extents[3]), nxyz_A[3], false, coords[3], dims[3])) end -function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Tuple{Real,Real,Real}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) +function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Tuple{AbstractFloat,AbstractFloat,AbstractFloat}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) return (_x_g(first(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]) : dxyz[1] : _x_g(last(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]), _y_g(first(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]) : dxyz[2] : _y_g(last(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]), _z_g(first(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3]) : dxyz[3] : _z_g(last(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3])) From ee1bdd37a692ab9211ef9dcf380097e46ab622d1 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 23 Apr 2025 16:55:09 +0200 Subject: [PATCH 08/30] add more parameters to GlobalGrid --- src/shared.jl | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shared.jl b/src/shared.jl index 2e131d8..d66bfa3 100644 --- a/src/shared.jl +++ b/src/shared.jl @@ -61,6 +61,9 @@ struct GlobalGrid dims::Vector{GGInt} overlaps::Vector{GGInt} halowidths::Vector{GGInt} + origin::Vector{GGInt} + origin_on_vertex::Bool + centerxyz::Vector{Bool} nprocs::GGInt me::GGInt coords::Vector{GGInt} @@ -76,7 +79,7 @@ struct GlobalGrid use_polyester::Vector{Bool} quiet::Bool end -const GLOBAL_GRID_NULL = GlobalGrid(GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], -1, -1, GGInt[-1,-1,-1], GGInt[-1 -1 -1; -1 -1 -1], GGInt[-1,-1,-1], -1, -1, MPI.COMM_NULL, false, false, [false,false,false], [false,false,false], [false,false,false], false) +const GLOBAL_GRID_NULL = GlobalGrid(GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], GGInt[-1,-1,-1], false, [false,false,false], -1, -1, GGInt[-1,-1,-1], GGInt[-1 -1 -1; -1 -1 -1], GGInt[-1,-1,-1], -1, -1, MPI.COMM_NULL, false, false, [false,false,false], [false,false,false], [false,false,false], false) # Macro to switch on/off check_initialized() for performance reasons (potentially relevant for tools.jl). macro check_initialized() :(check_initialized();) end #FIXME: Alternative: macro check_initialized() end From d6f234a58ef4a99a52670af9464cdf92ab65d99f Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 23 Apr 2025 17:34:30 +0200 Subject: [PATCH 09/30] update doc string --- src/init_global_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index 2821a8e..61d8d43 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -12,7 +12,7 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de # Keyword arguments - {`dimx`|`dimy`|`dimz`}`::Integer=0`: the desired number of processes in dimension {x|y|z}. By default, (value `0`) the process topology is created as compact as possible with the given constraints. This is handled by the MPI implementation which is installed on your system. For more information, refer to the specifications of `MPI_Dims_create` in the corresponding documentation. - {`periodx`|`periody`|`periodz`}`::Bool|Integer=false`: whether the grid is periodic (`true`) or not (`false`) in dimension {x|y|z}. The argument is also accepted as an integer as traditionally in the MPI standard (`1` for `true` and `0` for `false`). -- `origin::Tuple|AbstractFloat`: the origin of the global grid. By default, it is set to `(0.0, 0.0, 0.0)` (`(0.0, 0.0)` for 2D and `0.0` for 1D). +- `origin::Tuple|AbstractFloat`: the origin of the global grid. By default, it is set to `(0.0, 0.0, 0.0)` for 3D, `(0.0, 0.0)` for 2D and `0.0` for 1D. - `origin_on_vertex::Bool=false`: whether the origin is on the cell vertex; else, it is on the cell center (default). The default implies that the space step `dx` is computed in the user code as `dx=lx/(nx-1)`, where `lx` is the length of the global grid in dimension x. Setting the origin on the vertex implies that the space step is computed as `dx=lx/nx`, instead. The analog applies for the dimensions y and z. - {`centerx`|`centery`|`centerz`}`::Bool=false`: whether to center the grid on the origin (`true`) or not (`false`) in dimension {x|y|z}. By default, the grid is extends from `origin` in the positive direction of the corresponding dimension. - `quiet::Bool=false`: whether to suppress printing information like the size of the global grid (`true`) or not (`false`). From bb6af6aa5a3c01dc34e8fc71d9bd448c3650b769 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 25 Apr 2025 12:56:09 +0200 Subject: [PATCH 10/30] update and versions to test --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cdcb39..d4ed284 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,7 @@ jobs: matrix: version: - '1.9' # Minimum version supporting extensions + - '1.10' # Long-term support version - '1' # Latest stable 1.x release of Julia # - 'nightly' os: @@ -35,7 +36,7 @@ jobs: with: version: ${{ matrix.version }} arch: ${{ matrix.arch }} - - uses: actions/cache@v1 + - uses: actions/cache@v4 env: cache-name: cache-artifacts with: From 2ae32baaace29a7ab37b42a288a4159b136ff1eb Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 25 Apr 2025 17:20:47 +0200 Subject: [PATCH 11/30] enable omitting an nz and ny and fix origin --- src/init_global_grid.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index 61d8d43..81743f0 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -1,13 +1,15 @@ export init_global_grid """ + init_global_grid(nx) + init_global_grid(nx, ny) init_global_grid(nx, ny, nz) me, dims, nprocs, coords, comm_cart = init_global_grid(nx, ny, nz; ) Initialize a Cartesian grid of MPI processes (and also MPI itself by default) defining implicitely a global grid. # Arguments -- {`nx`|`ny`|`nz`}`::Integer`: the number of elements of the local grid in dimension {x|y|z}. +- {`nx`|`ny`|`nz`}`::Integer`: the number of elements of the local grid in dimension {x|y|z}. For 2D problems, setting `nz` to 1 is equivalent to ommitting the argument; for 1D problems, setting `ny` and `nz` to 1 is equivalent to ommitting the arguments. # Keyword arguments - {`dimx`|`dimy`|`dimz`}`::Integer=0`: the desired number of processes in dimension {x|y|z}. By default, (value `0`) the process topology is created as compact as possible with the given constraints. This is handled by the MPI implementation which is installed on your system. For more information, refer to the specifications of `MPI_Dims_create` in the corresponding documentation. @@ -43,7 +45,7 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de See also: [`finalize_global_grid`](@ref), [`select_device`](@ref) """ -function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Union{Bool,Integer}=0, periody::Union{Bool,Integer}=0, periodz::Union{Bool,Integer}=0, origin::Union{NTuple,AbstractFloat}, origin_on_vertex::Bool=false, centerx::Bool=false, centery::Bool=false, centerz::Bool=false, overlap::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) +function init_global_grid(nx::Integer, ny::Integer=1, nz::Integer=1; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Union{Bool,Integer}=0, periody::Union{Bool,Integer}=0, periodz::Union{Bool,Integer}=0, origin::Union{Tuple,AbstractFloat}, origin_on_vertex::Bool=false, centerx::Bool=false, centery::Bool=false, centerz::Bool=false, overlaps::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) if grid_is_initialized() error("The global grid has already been initialized.") end set_cuda_loaded() set_cuda_functional() @@ -52,7 +54,7 @@ function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0 nxyz = [nx, ny, nz]; dims = [dimx, dimy, dimz]; periods = Int64.([periodx, periody, periodz]); - origin = Float64.[(length(Tuple(origin)) == 3) ? origin : ((length(Tuple(origin)) == 2) ? (origin..., 0) : (origin, 0, 0))...]; + origin = Float64.([((length((origin...,)) == 1) ? (origin, 0, 0) : ((length(origin) == 2) ? (origin..., 0) : origin))...]); centerxyz = [centerx, centery, centerz]; overlaps = [overlaps...]; halowidths = [halowidths...]; @@ -89,6 +91,7 @@ function init_global_grid(nx::Integer, ny::Integer, nz::Integer; dimx::Integer=0 if (any(nxyz .< 1)) error("Invalid arguments: nx, ny, and nz cannot be less than 1."); end if (any(dims .< 0)) error("Invalid arguments: dimx, dimy, and dimz cannot be negative."); end if (any(periods .∉ ((0,1),))) error("Invalid arguments: periodx, periody, and periodz must be either 0 or 1."); end + if length(origin) != 3 error("Invalid argument: the length of the origin tuple must be at most 3.") end if (centerx && origin_on_vertex && isodd(nx)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and nx being odd; set either `origin_on_vertex=false` or make nx even."); end if (centery && origin_on_vertex && isodd(ny)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and ny being odd; set either `origin_on_vertex=false` or make ny even."); end if (centerz && origin_on_vertex && isodd(nz)) error("Incoherent arguments: the grid cannot be centered on the origin with the constraint to have the origin on the cell vertex and nz being odd; set either `origin_on_vertex=false` or make nz even."); end From a33550f332411bcbb1b87ac1b3634d8f6d1983de Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 25 Apr 2025 17:34:54 +0200 Subject: [PATCH 12/30] enable omitting an nz and ny and fix origin --- src/init_global_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index 81743f0..7fe4d9f 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -9,7 +9,7 @@ export init_global_grid Initialize a Cartesian grid of MPI processes (and also MPI itself by default) defining implicitely a global grid. # Arguments -- {`nx`|`ny`|`nz`}`::Integer`: the number of elements of the local grid in dimension {x|y|z}. For 2D problems, setting `nz` to 1 is equivalent to ommitting the argument; for 1D problems, setting `ny` and `nz` to 1 is equivalent to ommitting the arguments. +- {`nx`|`ny`|`nz`}`::Integer`: the number of elements of the local grid in dimension {x|y|z}. For 2D problems, setting `nz` to 1 is equivalent to omitting the argument; for 1D problems, setting `ny` and `nz` to 1 is equivalent to omitting the arguments. # Keyword arguments - {`dimx`|`dimy`|`dimz`}`::Integer=0`: the desired number of processes in dimension {x|y|z}. By default, (value `0`) the process topology is created as compact as possible with the given constraints. This is handled by the MPI implementation which is installed on your system. For more information, refer to the specifications of `MPI_Dims_create` in the corresponding documentation. From f111f7f2ee71b5f95b011e392e29d5dbde7a1ea0 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 25 Apr 2025 17:38:19 +0200 Subject: [PATCH 13/30] enable omitting an nz and ny and fix origin --- src/tools.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 765973b..c6e48c1 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -28,10 +28,10 @@ macro originy() esc(:( global_grid().origin[2] )) end macro originz() esc(:( global_grid().origin[3] )) end macro origin() esc(:( (global_grid().origin...,) )) end macro origin_on_vertex() esc(:( global_grid().origin_on_vertex )) end -macro centerx() esc(:( global_grid().center[1] )) end -macro centery() esc(:( global_grid().center[2] )) end -macro centerz() esc(:( global_grid().center[3] )) end -macro centerxyz() esc(:( (global_grid().center...,) )) end +macro centerx() esc(:( global_grid().centerxyz[1] )) end +macro centery() esc(:( global_grid().centerxyz[2] )) end +macro centerz() esc(:( global_grid().centerxyz[3] )) end +macro centerxyz() esc(:( (global_grid().centerxyz...,) )) end macro halowidthx() esc(:( global_grid().halowidths[1] )) end macro halowidthy() esc(:( global_grid().halowidths[2] )) end macro halowidthz() esc(:( global_grid().halowidths[3] )) end From 5e36adc3bb41cf0a46e59bf1b09fbde8225c2bfe Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Mon, 28 Apr 2025 09:45:19 +0200 Subject: [PATCH 14/30] add default initialization for origin --- src/init_global_grid.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/init_global_grid.jl b/src/init_global_grid.jl index 7fe4d9f..7e80f98 100644 --- a/src/init_global_grid.jl +++ b/src/init_global_grid.jl @@ -45,7 +45,7 @@ Initialize a Cartesian grid of MPI processes (and also MPI itself by default) de See also: [`finalize_global_grid`](@ref), [`select_device`](@ref) """ -function init_global_grid(nx::Integer, ny::Integer=1, nz::Integer=1; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Union{Bool,Integer}=0, periody::Union{Bool,Integer}=0, periodz::Union{Bool,Integer}=0, origin::Union{Tuple,AbstractFloat}, origin_on_vertex::Bool=false, centerx::Bool=false, centery::Bool=false, centerz::Bool=false, overlaps::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) +function init_global_grid(nx::Integer, ny::Integer=1, nz::Integer=1; dimx::Integer=0, dimy::Integer=0, dimz::Integer=0, periodx::Union{Bool,Integer}=0, periody::Union{Bool,Integer}=0, periodz::Union{Bool,Integer}=0, origin::Union{Tuple,AbstractFloat}=(0.0, 0.0, 0.0), origin_on_vertex::Bool=false, centerx::Bool=false, centery::Bool=false, centerz::Bool=false, overlaps::Tuple{Int,Int,Int}=(2,2,2), halowidths::Tuple{Int,Int,Int}=max.(1,overlaps.÷2), disp::Integer=1, reorder::Integer=1, comm::MPI.Comm=MPI.COMM_WORLD, init_MPI::Bool=true, device_type::String=DEVICE_TYPE_AUTO, select_device::Bool=true, quiet::Bool=false) if grid_is_initialized() error("The global grid has already been initialized.") end set_cuda_loaded() set_cuda_functional() From b18e8400d321fcd674dfc458fae2525425ca72c2 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 9 May 2025 15:45:50 +0200 Subject: [PATCH 15/30] add unit tests for origin and center initialization --- test/test_init_global_grid.jl | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/test_init_global_grid.jl b/test/test_init_global_grid.jl index 19c1d02..66bbce5 100644 --- a/test/test_init_global_grid.jl +++ b/test/test_init_global_grid.jl @@ -46,6 +46,9 @@ nz = 1; @test GG.global_grid().reorder == 1 @test GG.global_grid().comm == comm_cart @test GG.global_grid().quiet == true + @test GG.global_grid().origin == [0.0, 0.0, 0.0] + @test GG.global_grid().origin_on_vertex == false + @test GG.global_grid().centerxyz == [false, false, false] end; finalize_global_grid(finalize_MPI=false); end; @@ -106,6 +109,13 @@ nz = 1; @test_throws ErrorException init_global_grid(nx, ny, nz, periody=1, overlaps=(2,3,2), quiet=true, init_MPI=false); # Error: periody==1 while ny<2*overlaps[2]-1 (4<5). @test_throws ErrorException init_global_grid(nx, ny, nz, halowidths=(1,0,1), quiet=true, init_MPI=false); # Error: halowidths[2]<1. @test_throws ErrorException init_global_grid(nx, ny, nz, overlaps=(4,3,2), halowidths=(2,2,1), quiet=true, init_MPI=false); # Error: halowidths[2]==2 while overlaps[2]==3. + @test_throws ErrorException init_global_grid(nx, ny, nz, origin=(0.0, 0.0, 0.0, 0.0), quiet=true, init_MPI=false); # Error: origin length > 3 + @test_throws ErrorException init_global_grid(5, ny, nz, centerx=true, origin_on_vertex=true, quiet=true, init_MPI=false); # Error: centerx && origin_on_vertex && nx odd + @test_throws ErrorException init_global_grid(nx, 5, nz, centery=true, origin_on_vertex=true, quiet=true, init_MPI=false); # Error: centery && origin_on_vertex && ny odd + @test_throws ErrorException init_global_grid(nx, ny, 5, centerz=true, origin_on_vertex=true, quiet=true, init_MPI=false); # Error: centerz && origin_on_vertex && nz odd + @test_throws ErrorException init_global_grid(4, ny, nz, centerx=true, origin_on_vertex=false, quiet=true, init_MPI=false); # Error: centerx && !origin_on_vertex && nx even + @test_throws ErrorException init_global_grid(nx, 4, nz, centery=true, origin_on_vertex=false, quiet=true, init_MPI=false); # Error: centery && !origin_on_vertex && ny even + @test_throws ErrorException init_global_grid(nx, ny, 4, centerz=true, origin_on_vertex=false, quiet=true, init_MPI=false); # Error: centerz && !origin_on_vertex && nz even @test_throws ErrorException init_global_grid(nx, ny, nz, quiet=true); # Error: MPI already initialized @testset "already initialized exception" begin init_global_grid(nx, ny, nz, quiet=true, init_MPI=false); From a671ba00ebc4aada2f23e630f13363fd5846039c Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 9 May 2025 15:47:37 +0200 Subject: [PATCH 16/30] update unit tests for global problem size and coordinates --- test/test_tools.jl | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/test_tools.jl b/test/test_tools.jl index d2785d2..a08e34c 100644 --- a/test/test_tools.jl +++ b/test/test_tools.jl @@ -29,6 +29,21 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nx_g() == nx @test ny_g() == ny @test nz_g() == nz-2 + @test nx_g(P) == nx + @test ny_g(P) == ny + @test nz_g(P) == nz-2 + @test nx_g(Vx) == nx+1 + @test ny_g(Vx) == ny + @test nz_g(Vx) == nz-2 + @test nx_g(Vz) == nx + @test ny_g(Vz) == ny + @test nz_g(Vz) == nz-2+1 + @test nx_g(A) == nx + @test ny_g(A) == ny + @test nz_g(A) == nz-2+2 + @test nx_g(Sxz) == nx-2 + @test ny_g(Sxz) == ny-1 + @test nz_g(Sxz) == nz-2-2 end; @testset "x_g / y_g / z_g" begin dx = lx/(nx_g()-1); @@ -38,14 +53,17 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [x_g(ix,dx,P) for ix = 1:size(P,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [8.0, 0.0, 4.0, 8.0, 0.0] + @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [-4.0, 0.0, 4.0, 8.0, 12.0] # (for Vx) @test [x_g(ix,dx,Vx) for ix = 1:size(Vx,1)] == [-1.0, 1.0, 3.0, 5.0, 7.0, 9.0] @test [y_g(iy,dy,Vx) for iy = 1:size(Vx,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,Vx) for iz = 1:size(Vx,3)] == [8.0, 0.0, 4.0, 8.0, 0.0] + @test [z_g(iz,dz,Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [-4.0, 0.0, 4.0, 8.0, 12.0] # (for Vz) @test [x_g(ix,dx,Vz) for ix = 1:size(Vz,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [y_g(iy,dy,Vz) for iy = 1:size(Vz,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [ 6.0, 10.0, 2.0, 6.0, 10.0, 2.0] + @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-6.0, -2.0, 2.0, 6.0, 10.0, 14.0] # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] # possible alternative: [ 6.0, -2.0, 2.0, 6.0, -2.0, 2.0] # This would be a possible alternative way to define {x,y,z}_g; however, we decided that the grid should start at 0.0 in this case and the overlap be at the end (we avoid completely any negative z_g). # wrong: [ 6.0, -2.0, 2.0, 6.0, 10.0, 2.0] # The 2nd and the 2nd-last cell must be the same due to the overlap of 3. @@ -53,6 +71,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [4.0, 8.0, 0.0, 4.0, 8.0, 0.0, 4.0] + @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-8.0, -4.0, 0.0, 4.0, 8.0, 12.0, 16.0] # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] # (for Sxz) @test [x_g(ix,dx,Sxz) for ix = 1:size(Sxz,1)] == [2.0, 4.0, 6.0] @@ -60,6 +79,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [y_g(iy,dy,Sxz) for iy = 1:size(Sxz,2)] == [1.0, 3.0, 5.0, 7.0] # base grid (y dim): [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] + @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] end; finalize_global_grid(finalize_MPI=false); @@ -82,6 +102,21 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nx_g() == nx @test ny_g() == ny @test nz_g() == nz-3 + @test nx_g(P) == nx + @test ny_g(P) == ny + @test nz_g(P) == nz-3 + @test nx_g(Vx) == nx+1 + @test ny_g(Vx) == ny + @test nz_g(Vx) == nz-3 + @test nx_g(Vz) == nx + @test ny_g(Vz) == ny + @test nz_g(Vz) == nz-3+1 + @test nx_g(A) == nx + @test ny_g(A) == ny + @test nz_g(A) == nz-3+2 + @test nx_g(Sxz) == nx-2 + @test ny_g(Sxz) == ny-1 + @test nz_g(Sxz) == nz-3-2 end; @testset "x_g / y_g / z_g" begin dx = lx/(nx_g()-1); @@ -91,16 +126,19 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [x_g(ix,dx,P) for ix = 1:size(P,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] + @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0] # (for Vz) @test [x_g(ix,dx,Vz) for ix = 1:size(Vz,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [y_g(iy,dy,Vz) for iy = 1:size(Vz,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [7.0, 9.0, 1.0, 3.0, 5.0, 7.0, 9.0, 1.0, 3.0] + @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-3.0, -1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0] # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0. 8.0, 0.0, 2.0] # possible alternative: [7.0,-1.0, 1.0, 3.0, 5.0, 7.0,-1.0, 1.0, 3.0] # (for A) @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0, 4.0] + @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] # (for Sxz) @test [x_g(ix,dx,Sxz) for ix = 1:size(Sxz,1)] == [2.0, 4.0, 6.0] # (same as in the first test) @@ -108,6 +146,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [y_g(iy,dy,Sxz) for iy = 1:size(Sxz,2)] == [1.0, 3.0, 5.0, 7.0] # (same as in the first test) # base grid (y dim): [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 0.0] + @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] end; finalize_global_grid(finalize_MPI=false); @@ -136,6 +175,12 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nx_g() == nxyz_g[1] @test ny_g() == nxyz_g[2] @test nz_g() == nxyz_g[3] + @test nx_g(P) == nxyz_g[1] + @test ny_g(P) == nxyz_g[2] + @test nz_g(P) == nxyz_g[3] + @test nx_g(A) == nxyz_g[1]+1 + @test ny_g(A) == nxyz_g[2]-2 + @test nz_g(A) == nxyz_g[3]+2 end; @testset "x_g / y_g / z_g" begin dx = lx/(nx_g()-1); @@ -149,8 +194,11 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(2)=1; @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [6.0, 8.0, 10.0, 12.0, 14.0] @coords(2)=2; @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [12.0, 14.0, 16.0, 18.0, 20.0] @coords(3)=0; @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [16.0, 0.0, 2.0, 4.0, 6.0] + @coords(3)=0; @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [-2.0, 0.0, 2.0, 4.0, 6.0] @coords(3)=1; @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [4.0, 6.0, 8.0, 10.0, 12.0] + @coords(3)=1; @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [4.0, 6.0, 8.0, 10.0, 12.0] @coords(3)=2; @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [10.0, 12.0, 14.0, 16.0, 0.0] + @coords(3)=2; @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [10.0, 12.0, 14.0, 16.0, 18.0] # (for A) @coords(1)=0; @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [-1.0, 1.0, 3.0, 5.0, 7.0, 9.0] @coords(1)=1; @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [5.0, 7.0, 9.0, 11.0, 13.0, 15.0] @@ -159,8 +207,11 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(2)=1; @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [8.0, 10.0, 12.0] @coords(2)=2; @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [14.0, 16.0, 18.0] @coords(3)=0; @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [14.0, 16.0, 0.0, 2.0, 4.0, 6.0, 8.0] + @coords(3)=0; @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0] @coords(3)=1; @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] + @coords(3)=1; @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] @coords(3)=2; @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 0.0, 2.0] + @coords(3)=2; @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0] end; finalize_global_grid(finalize_MPI=false); end; From 9032167ca8cf9c621cf9d4b9e598c4cb3f6e4ca9 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Fri, 9 May 2025 16:54:39 +0200 Subject: [PATCH 17/30] add tests for global indices --- test/test_tools.jl | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/test/test_tools.jl b/test/test_tools.jl index a08e34c..3c34778 100644 --- a/test/test_tools.jl +++ b/test/test_tools.jl @@ -82,6 +82,33 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] end; + @testset "ix_g / iy_g / iz_g" begin + # (for P) + @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 1, 2, 3, 1] + @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] + # (for Vx) + @test [ix_g(ix, Vx) for ix = 1:size(Vx,1)] == [1, 2, 3, 4, 5, 6] + @test [iy_g(iy, Vx) for iy = 1:size(Vx,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [3, 1, 2, 3, 1] + @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4] + # (for Vz) + @test [ix_g(ix, Vz) for ix = 1:size(Vz,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, Vz) for iy = 1:size(Vz,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vz) for iz = 1:size(Vz,3)] == [3, 1, 2, 3, 1, 2] + @test [iz_g(iz, Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [0, 1, 2, 3, 4, 5] + # (for A) + @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, A) for iz = 1:size(A,3)] == [2, 3, 1, 2, 3, 1, 2] + @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] + # (for Sxz) + @test [ix_g(ix, Sxz) for ix = 1:size(Sxz,1)] == [1, 2, 3] + @test [iy_g(iy, Sxz) for iy = 1:size(Sxz,2)] == [1, 2, 3, 4] + @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3] + @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3] + end; finalize_global_grid(finalize_MPI=false); end; @@ -149,6 +176,33 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] end; + @testset "ix_g / iy_g / iz_g" begin + # (for P) + @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, P) for iz = 1:size(P,3)] == [5, 1, 2, 3, 4, 5, 1, 2] + @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4, 5, 6, 7] + # (for Vx) + @test [ix_g(ix, Vx) for ix = 1:size(Vx,1)] == [1, 2, 3, 4, 5, 6] + @test [iy_g(iy, Vx) for iy = 1:size(Vx,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [5, 1, 2, 3, 4, 5, 1, 2] + @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4, 5, 6, 7] + # (for Vz) + @test [ix_g(ix, Vz) for ix = 1:size(Vz,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, Vz) for iy = 1:size(Vz,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vz) for iz = 1:size(Vz,3)] == [4, 5, 1, 2, 3, 4, 5, 1, 2] + @test [iz_g(iz, Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-1, 0, 1, 2, 3, 4, 5, 6, 7] + # (for A) + @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, A) for iz = 1:size(A,3)] == [4, 5, 1, 2, 3, 4, 5, 1, 2, 3] + @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] + # (for Sxz) + @test [ix_g(ix, Sxz) for ix = 1:size(Sxz,1)] == [1, 2, 3] + @test [iy_g(iy, Sxz) for iy = 1:size(Sxz,2)] == [1, 2, 3, 4] + @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 1] + @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 6] + end; finalize_global_grid(finalize_MPI=false); end; @@ -213,6 +267,34 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(3)=2; @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 0.0, 2.0] @coords(3)=2; @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0] end; + @testset "ix_g / iy_g / iz_g" begin + # (for P) + @coords(1)=0; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] + @coords(1)=1; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [4, 5, 6, 7, 8] + @coords(1)=2; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [7, 8, 9, 10, 11] + @coords(2)=0; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] + @coords(2)=1; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [4, 5, 6, 7, 8] + @coords(2)=2; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [7, 8, 9, 10, 11] + @coords(3)=0; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [9, 1, 2, 3, 4] + @coords(3)=0; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] + @coords(3)=1; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] + @coords(3)=1; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] + @coords(3)=2; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [6, 7, 8, 9, 1] + @coords(3)=2; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [6, 7, 8, 9, 10] + # (for A) + @coords(1)=0; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5, 6] + @coords(1)=1; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [3, 4, 5, 6, 7, 8] + @coords(1)=2; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [5, 6, 7, 8, 9, 10] + @coords(2)=0; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3] + @coords(2)=1; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [6, 7, 8] + @coords(2)=2; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [11, 12, 13] + @coords(3)=0; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [8, 9, 1, 2, 3, 4, 5] + @coords(3)=0; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] + @coords(3)=1; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [9, 1, 2, 3, 4, 5, 6] + @coords(3)=1; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [0, 1, 2, 3, 4, 5, 6] + @coords(3)=2; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [1, 2, 3, 4, 5, 6, 7] + @coords(3)=2; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [1, 2, 3, 4, 5, 6, 7] + end; finalize_global_grid(finalize_MPI=false); end; end; From fe0787c598d6552e124940bd413b3feab6e5a007 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 14 May 2025 16:47:32 +0200 Subject: [PATCH 18/30] fix _z_g and _iz_g --- src/tools.jl | 64 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 52 insertions(+), 12 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index c6e48c1..8c9de08 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -249,10 +249,10 @@ z_g(iz::Integer, dz::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - haloshifty = @periodz() ? -dz*@halowidthz() : dz*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. - vertexshifty = @origin_on_vertex() ? dz*0.5 : dz*0.0 - centershifty = @centerz() ? (@origin_on_vertex() ? -nz_g*dz*0.5 : -(nz_g-1)*dz*0.5) : dz*0.0 - z0_g = @originz() + haloshifty + vertexshifty + centershifty + haloshiftz = @periodz() ? -dz*@halowidthz() : dz*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. + vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 + centershiftz = @centerz() ? (@origin_on_vertex() ? -nz_g*dz*0.5 : -(nz_g-1)*dz*0.5) : dz*0.0 + z0_g = @originz() + haloshiftz + vertexshiftz + centershiftz z0 = 0.5*(@nz()-nz_A)*dz z = (coordz*(@nz()-@olz()) + iz-1)*dz + z0 + z0_g if @periodz() && wrap_periodic @@ -441,17 +441,57 @@ julia> finalize_global_grid() """ iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) + +function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) + olz_A = @olz() + (nz_A-@nz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) + # nz_g_A = nz_g + (nz_A-@nz())*(@periodz()==0) #TODO: check if this is correct if >0 + # periodshiftz = @periodz() ? -dz*@olz()*0.5 : dz*0.0 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. + olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. + vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 + centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 + z0_g = @originz() + olshiftz + vertexshiftz + centershiftz + # z0 = dz*(@nz()-nz_A)*0.5 #TODO: check if, for example, OLZ should be added here in case that the coordinate is greater than 0, but what about period shift + z0 = -dz*olz_A*0.5 + z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g + if @periodz() && wrap_periodic + lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) + z1 = z0_g + dz*max((@nz()-nz_A)*0.5, 0) + z2 = z1 + lz - dz*max((@nz()-nz_A)*0.5, 0) + if (z > z2) z = z - z2; end + if (z < z1) z = z + z1; end + end + return z +end + function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - olz_A = @olz() + (nz_A-@nz()) - iz0_g = @periodz() ? 0 : olz_A÷2 - iz0 = -olz_A÷2 - iz = coordz*(@nz()-olz_A) + iz + iz0 + iz0_g - if wrap_periodic && @periodz() - if (iz > nz_g) iz = iz - nz_g; end - if (iz < 1) iz = iz + nz_g; end + olz_A = @olz() + (nz_A-@nz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) + # nz_g_A = nz_g + (nz_A-@nz())*(@periodz()==0) #TODO: check if this is correct if >0 + olshiftz = @periodz() ? 0 : olz_A÷2 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. + originz = 1 + iz0_g = originz + olshiftz + # iz0 = (@nz()-nz_A)÷2 + iz0 = -olz_A÷2 + iz = (coordz*(@nz()-@olz()) + iz-1) + iz0 + iz0_g + if @periodz() && wrap_periodic + nz_g_A = nz_g + min((nz_A-@nz()), 0) + if (iz > nz_g_A) iz = iz - nz_g_A; end + if (iz < 1) iz = iz + nz_g_A; end end return iz + + + # nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) + # olz_A = @olz() + (nz_A-@nz()) + # iz0_g = @periodz() ? 0 : olz_A÷2 + # iz0 = -olz_A÷2 + # iz = coordz*(@nz()-olz_A) + iz + iz0 + iz0_g + # if wrap_periodic && @periodz() + # if (iz > nz_g) iz = iz - nz_g; end + # if (iz < 1) iz = iz + nz_g; end + # end + # return iz end """ From f29813666653dd254a8e25bc37f1b04bd8c5bfd8 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 20 May 2025 16:08:22 +0200 Subject: [PATCH 19/30] improve iz_g, z_g --- src/tools.jl | 65 ++++++++++++++-------------------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 8c9de08..89c2035 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -248,16 +248,21 @@ julia> finalize_global_grid() z_g(iz::Integer, dz::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_z_g(iz, dz, size(A,3), wrap_periodic) function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - haloshiftz = @periodz() ? -dz*@halowidthz() : dz*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dz to the left. + olz_A = @olz() + (nz_A-@nz()) + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) # NOTE: nz_g() cannot be used as dimz needs to be used. + olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 - centershiftz = @centerz() ? (@origin_on_vertex() ? -nz_g*dz*0.5 : -(nz_g-1)*dz*0.5) : dz*0.0 - z0_g = @originz() + haloshiftz + vertexshiftz + centershiftz - z0 = 0.5*(@nz()-nz_A)*dz - z = (coordz*(@nz()-@olz()) + iz-1)*dz + z0 + z0_g + centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 + z0_g = @originz() + olshiftz + vertexshiftz + centershiftz + z0 = -dz*olz_A*0.5 + z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g if @periodz() && wrap_periodic - if (z > (nz_g-1)*dz) z = z - nz_g*dz; end # It must not be (nz_g()-1)*dz as the distance between the local problems (1*dz) must also be taken into account! - if (z < 0) z = z + nz_g*dz; end # ... + lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) + lz_A = lz + dz*(nz_A-@nz()) + z1 = z0_g - dz*(nz_A-@nz())*0.5 # dz*max((@nz()-nz_A)*0.5, 0) + z2 = z1 + lz_A #lz + dz*(nz_A-@nz())*0.5 #dz*max((@nz()-nz_A)*0.5, 0) + if (z > z2) z = z - dz - lz_A; end + if (z < z1) z = z + dz + lz_A; end end return z end @@ -441,59 +446,23 @@ julia> finalize_global_grid() """ iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) - -function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - olz_A = @olz() + (nz_A-@nz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - # nz_g_A = nz_g + (nz_A-@nz())*(@periodz()==0) #TODO: check if this is correct if >0 - # periodshiftz = @periodz() ? -dz*@olz()*0.5 : dz*0.0 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. - olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. - vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 - centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 - z0_g = @originz() + olshiftz + vertexshiftz + centershiftz - # z0 = dz*(@nz()-nz_A)*0.5 #TODO: check if, for example, OLZ should be added here in case that the coordinate is greater than 0, but what about period shift - z0 = -dz*olz_A*0.5 - z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g - if @periodz() && wrap_periodic - lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) - z1 = z0_g + dz*max((@nz()-nz_A)*0.5, 0) - z2 = z1 + lz - dz*max((@nz()-nz_A)*0.5, 0) - if (z > z2) z = z - z2; end - if (z < z1) z = z + z1; end - end - return z -end - function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) olz_A = @olz() + (nz_A-@nz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - # nz_g_A = nz_g + (nz_A-@nz())*(@periodz()==0) #TODO: check if this is correct if >0 - olshiftz = @periodz() ? 0 : olz_A÷2 # The first cells of the global problem are overlap cells; so, all must be shifted to the left. + nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) # NOTE: nz_g() cannot be used as dimz needs to be used. + olshiftz = @periodz() ? 0 : olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. originz = 1 iz0_g = originz + olshiftz - # iz0 = (@nz()-nz_A)÷2 iz0 = -olz_A÷2 iz = (coordz*(@nz()-@olz()) + iz-1) + iz0 + iz0_g if @periodz() && wrap_periodic - nz_g_A = nz_g + min((nz_A-@nz()), 0) + nz_g_A = nz_g + (nz_A-@nz()) #min((nz_A-@nz()), 0) if (iz > nz_g_A) iz = iz - nz_g_A; end if (iz < 1) iz = iz + nz_g_A; end end return iz - - - # nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) - # olz_A = @olz() + (nz_A-@nz()) - # iz0_g = @periodz() ? 0 : olz_A÷2 - # iz0 = -olz_A÷2 - # iz = coordz*(@nz()-olz_A) + iz + iz0 + iz0_g - # if wrap_periodic && @periodz() - # if (iz > nz_g) iz = iz - nz_g; end - # if (iz < 1) iz = iz + nz_g; end - # end - # return iz end + """ extents(; fix_global_boundaries, coords) extents(A; fix_global_boundaries, coords) From 500971e0ac5811048c0ca9ef7be4a396b6e4a22c Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Thu, 22 May 2025 19:10:37 +0200 Subject: [PATCH 20/30] improve iz_g and z_g --- test/test_tools.jl | 478 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 369 insertions(+), 109 deletions(-) diff --git a/test/test_tools.jl b/test/test_tools.jl index 3c34778..850da76 100644 --- a/test/test_tools.jl +++ b/test/test_tools.jl @@ -12,7 +12,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @require nprocs == 1 # NOTE: these tests require nprocs == 1. @testset "$(basename(@__FILE__))" begin - @testset "1. *_g functions" begin + @testset "1. grid functions" begin lx = 8; ly = 8; lz = 8; @@ -22,7 +22,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); P = zeros(nx, ny, nz ); Vx = zeros(nx+1,ny, nz ); Vz = zeros(nx, ny, nz+1); - A = zeros(nx, ny, nz+2); + A = zeros(nx+2,ny, nz+2); Sxz = zeros(nx-2,ny-1,nz-2); init_global_grid(nx, ny, nz, dimx=1, dimy=1, dimz=1, periodz=1, quiet=true, init_MPI=false); @testset "nx_g / ny_g / nz_g" begin @@ -38,13 +38,40 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nx_g(Vz) == nx @test ny_g(Vz) == ny @test nz_g(Vz) == nz-2+1 - @test nx_g(A) == nx + @test nx_g(A) == nx+2 @test ny_g(A) == ny @test nz_g(A) == nz-2+2 @test nx_g(Sxz) == nx-2 @test ny_g(Sxz) == ny-1 @test nz_g(Sxz) == nz-2-2 end; + @testset "ix_g / iy_g / iz_g" begin + # (for P) + @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 1, 2, 3, 1] + @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] + # (for Vx) + @test [ix_g(ix, Vx) for ix = 1:size(Vx,1)] == [1, 2, 3, 4, 5, 6] + @test [iy_g(iy, Vx) for iy = 1:size(Vx,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [3, 1, 2, 3, 1] + @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4] + # (for Vz) + @test [ix_g(ix, Vz) for ix = 1:size(Vz,1)] == [1, 2, 3, 4, 5] + @test [iy_g(iy, Vz) for iy = 1:size(Vz,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, Vz) for iz = 1:size(Vz,3)] == [3, 1, 2, 3, 1, 2] #Alternative: [2, 3, 1, 2, 3, 1] + @test [iz_g(iz, Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [0, 1, 2, 3, 4, 5] #Alternative: [-1, 0, 1, 2, 3, 4] + # (for A) + @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5, 6, 7] + @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3, 4, 5] + @test [iz_g(iz, A) for iz = 1:size(A,3)] == [2, 3, 1, 2, 3, 1, 2] + @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] + # (for Sxz) + @test [ix_g(ix, Sxz) for ix = 1:size(Sxz,1)] == [1, 2, 3] + @test [iy_g(iy, Sxz) for iy = 1:size(Sxz,2)] == [1, 2, 3, 4] + @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3] + @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3] + end; @testset "x_g / y_g / z_g" begin dx = lx/(nx_g()-1); dy = ly/(ny_g()-1); @@ -62,57 +89,94 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); # (for Vz) @test [x_g(ix,dx,Vz) for ix = 1:size(Vz,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [y_g(iy,dy,Vz) for iy = 1:size(Vz,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] - @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [ 6.0, 10.0, 2.0, 6.0, 10.0, 2.0] - @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-6.0, -2.0, 2.0, 6.0, 10.0, 14.0] + @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [ 6.0, -2.0, 2.0, 6.0, -2.0, 2.0] # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] - # possible alternative: [ 6.0, -2.0, 2.0, 6.0, -2.0, 2.0] # This would be a possible alternative way to define {x,y,z}_g; however, we decided that the grid should start at 0.0 in this case and the overlap be at the end (we avoid completely any negative z_g). + # possible alternative: [6.0, 10.0, 2.0, 6.0, 10.0, 2.0] # This would be a possible alternative way to define {x,y,z}_g; however, we decided that the grid should start at -2.0 in this case and have more overlap be at the end (the advantage is that it is more in agreement with the non-periodic case: +1 cell, means starts one earlier... furthermore, the extents_g function relies on this) # wrong: [ 6.0, -2.0, 2.0, 6.0, 10.0, 2.0] # The 2nd and the 2nd-last cell must be the same due to the overlap of 3. + @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-6.0, -2.0, 2.0, 6.0, 10.0, 14.0] # (for A) - @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] + @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0] @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [4.0, 8.0, 0.0, 4.0, 8.0, 0.0, 4.0] + # base grid (z dim): [8.0, 0.0, 4.0, 8.0, 0.0] @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-8.0, -4.0, 0.0, 4.0, 8.0, 12.0, 16.0] - # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] # (for Sxz) @test [x_g(ix,dx,Sxz) for ix = 1:size(Sxz,1)] == [2.0, 4.0, 6.0] # base grid (x dim): [0.0, 2.0, 4.0, 6.0, 8.0] @test [y_g(iy,dy,Sxz) for iy = 1:size(Sxz,2)] == [1.0, 3.0, 5.0, 7.0] # base grid (y dim): [0.0, 2.0, 4.0, 6.0, 8.0] - @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] - @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] - # base grid (z dim): [ 8.0, 0.0, 4.0, 8.0, 0.0] + @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] + # base grid (z dim): [8.0, 0.0, 4.0, 8.0, 0.0] + @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 4.0, 8.0] end; - @testset "ix_g / iy_g / iz_g" begin - # (for P) - @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] - @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 1, 2, 3, 1] - @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] - # (for Vx) - @test [ix_g(ix, Vx) for ix = 1:size(Vx,1)] == [1, 2, 3, 4, 5, 6] - @test [iy_g(iy, Vx) for iy = 1:size(Vx,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [3, 1, 2, 3, 1] - @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4] - # (for Vz) - @test [ix_g(ix, Vz) for ix = 1:size(Vz,1)] == [1, 2, 3, 4, 5] - @test [iy_g(iy, Vz) for iy = 1:size(Vz,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, Vz) for iz = 1:size(Vz,3)] == [3, 1, 2, 3, 1, 2] - @test [iz_g(iz, Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [0, 1, 2, 3, 4, 5] - # (for A) - @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5] - @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, A) for iz = 1:size(A,3)] == [2, 3, 1, 2, 3, 1, 2] - @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] - # (for Sxz) - @test [ix_g(ix, Sxz) for ix = 1:size(Sxz,1)] == [1, 2, 3] - @test [iy_g(iy, Sxz) for iy = 1:size(Sxz,2)] == [1, 2, 3, 4] - @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3] - @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3] + @testset "extents" begin + @testset "default" begin + @test extents() == (1:5, 1:5, 2:4) + @test extents(P) == (1:5, 1:5, 2:4) + @test extents(Vx) == (1:6, 1:5, 2:4) + @test extents(Vz) == (1:5, 1:5, 2:4) + @test extents(A) == (1:7, 1:5, 3:5) + @test extents(Sxz) == (1:3, 1:4, 1:3) + end; + @testset "fix_global_boundaries" begin + @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(Vx; fix_global_boundaries=false) == (1:6, 1:5, 1:5) + @test extents(Vz; fix_global_boundaries=false) == (1:5, 1:5, 1:6) + @test extents(A; fix_global_boundaries=false) == (1:7, 1:5, 1:7) + @test extents(Sxz; fix_global_boundaries=false) == (1:3, 1:4, 1:3) + end; + @testset "overlap" begin + @test extents(0) == (1:5, 1:5, 2:4) + @test extents(1) == (1:5, 1:5, 2:4) + @test extents(P, 0) == (1:5, 1:5, 2:4) + @test extents(Vx, 1) == (1:6, 1:5, 2:4) + @test extents(Vz, 0) == (1:5, 1:5, 2:4) + @test extents(A, 1) == (1:7, 1:5, 3:5) + end; + end; + @testset "extents_g" begin + dx = lx/(nx_g()-1); + dy = ly/(ny_g()-1); + dz = lz/(nz_g()-1); + @testset "fix_global_boundaries" begin + @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:4) + @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:4) + @test extents_g(Vx; fix_global_boundaries=false) == (1:6, 1:5, 0:4) + @test extents_g(Vz; fix_global_boundaries=false) == (1:5, 1:5, 0:5) + @test extents_g(A; fix_global_boundaries=false) == (1:7, 1:5, -1:5) + @test extents_g(Sxz; fix_global_boundaries=false) == (1:3, 1:4, 1:3) + end; + @testset "default" begin + @test extents_g() == (1:5, 1:5, 1:3) + @test extents_g(1) == (1:5, 1:5, 1:3) + @test extents_g(P) == (1:5, 1:5, 1:3) + @test extents_g(Vx) == (1:6, 1:5, 1:3) + @test extents_g(Vz) == (1:5, 1:5, 1:3) + @test extents_g(A) == (1:7, 1:5, 1:3) + @test extents_g(Sxz) == (1:3, 1:4, 1:3) + end; + @testset "overlap" begin + @test extents_g(0) == (1:5, 1:5, 1:3) + @test extents_g(1) == (1:5, 1:5, 1:3) + @test extents_g(P, 0) == (1:5, 1:5, 1:3) + @test extents_g(Vx, 1) == (1:6, 1:5, 1:3) + @test extents_g(Vz, 0) == (1:5, 1:5, 1:3) + @test extents_g(A, 1) == (1:7, 1:5, 1:3) + end; + @testset "coordinates" begin + @test extents_g(; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:4.0:8.0) + @test extents_g(1; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:4.0:8.0) + @test extents_g(P; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:4.0:8.0) + @test extents_g(Vx; dxyz=(dx, dy, dz)) == (-1.0:2.0:9.0, 0.0:2.0:8.0, 0.0:4.0:8.0) + @test extents_g(Vz; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, -2.0:4.0:6.0) + @test extents_g(A; dxyz=(dx, dy, dz)) == (-2.0:2.0:10.0, 0.0:2.0:8.0, 0.0:4.0:8.0) + end; end; finalize_global_grid(finalize_MPI=false); end; - @testset "2. *_g functions with non-default overlap" begin + @testset "2. grid functions with non-default overlap" begin lx = 8; ly = 8; lz = 8; @@ -122,9 +186,9 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); P = zeros(nx, ny, nz ); Vx = zeros(nx+1,ny, nz ); Vz = zeros(nx, ny, nz+1); - A = zeros(nx, ny, nz+2); + A = zeros(nx+2,ny, nz+2); Sxz = zeros(nx-2,ny-1,nz-2); - init_global_grid(nx, ny, nz, dimx=1, dimy=1, dimz=1, periodz=1, overlaps=(3,2,3), quiet=true, init_MPI=false); + init_global_grid(nx, ny, nz, dimx=1, dimy=1, dimz=1, periodz=1, origin=(0.0,-5.0,0.0), centery=true, overlaps=(3,2,3), quiet=true, init_MPI=false); @testset "nx_g / ny_g / nz_g" begin @test nx_g() == nx @test ny_g() == ny @@ -138,75 +202,146 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nx_g(Vz) == nx @test ny_g(Vz) == ny @test nz_g(Vz) == nz-3+1 - @test nx_g(A) == nx + @test nx_g(A) == nx+2 @test ny_g(A) == ny @test nz_g(A) == nz-3+2 @test nx_g(Sxz) == nx-2 @test ny_g(Sxz) == ny-1 @test nz_g(Sxz) == nz-3-2 end; - @testset "x_g / y_g / z_g" begin - dx = lx/(nx_g()-1); - dy = ly/(ny_g()-1); - dz = lz/(nz_g()-1); - # (for P) - @test [x_g(ix,dx,P) for ix = 1:size(P,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] - @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0] - # (for Vz) - @test [x_g(ix,dx,Vz) for ix = 1:size(Vz,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [y_g(iy,dy,Vz) for iy = 1:size(Vz,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [7.0, 9.0, 1.0, 3.0, 5.0, 7.0, 9.0, 1.0, 3.0] - @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-3.0, -1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0] - # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0. 8.0, 0.0, 2.0] - # possible alternative: [7.0,-1.0, 1.0, 3.0, 5.0, 7.0,-1.0, 1.0, 3.0] - # (for A) - @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [0.0, 2.0, 4.0, 6.0, 8.0] # (same as in the first test) - @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0, 4.0] - @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] - # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] - # (for Sxz) - @test [x_g(ix,dx,Sxz) for ix = 1:size(Sxz,1)] == [2.0, 4.0, 6.0] # (same as in the first test) - # base grid (x dim): [0.0, 2.0, 4.0, 6.0, 8.0] - @test [y_g(iy,dy,Sxz) for iy = 1:size(Sxz,2)] == [1.0, 3.0, 5.0, 7.0] # (same as in the first test) - # base grid (y dim): [0.0, 2.0, 4.0, 6.0, 8.0] - @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 0.0] - @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] - # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] - end; @testset "ix_g / iy_g / iz_g" begin # (for P) @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, P) for iz = 1:size(P,3)] == [5, 1, 2, 3, 4, 5, 1, 2] - @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4, 5, 6, 7] + @test [iz_g(iz, P) for iz = 1:size(P,3)] == [5, 1, 2, 3, 4, 5, 1, 2] #Alternative: [4, 5, 1, 2, 3, 4, 5, 1] + @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4, 5, 6, 7] #Alternative: [-1, 0, 1, 2, 3, 4, 5, 6] # (for Vx) @test [ix_g(ix, Vx) for ix = 1:size(Vx,1)] == [1, 2, 3, 4, 5, 6] @test [iy_g(iy, Vx) for iy = 1:size(Vx,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [5, 1, 2, 3, 4, 5, 1, 2] - @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4, 5, 6, 7] + @test [iz_g(iz, Vx) for iz = 1:size(Vx,3)] == [5, 1, 2, 3, 4, 5, 1, 2] #Alternative: [4, 5, 1, 2, 3, 4, 5, 1] + @test [iz_g(iz, Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [0, 1, 2, 3, 4, 5, 6, 7]#Alternative: [-1, 0, 1, 2, 3, 4, 5, 6] # (for Vz) @test [ix_g(ix, Vz) for ix = 1:size(Vz,1)] == [1, 2, 3, 4, 5] @test [iy_g(iy, Vz) for iy = 1:size(Vz,2)] == [1, 2, 3, 4, 5] @test [iz_g(iz, Vz) for iz = 1:size(Vz,3)] == [4, 5, 1, 2, 3, 4, 5, 1, 2] @test [iz_g(iz, Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-1, 0, 1, 2, 3, 4, 5, 6, 7] # (for A) - @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5] + @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5, 6, 7] @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3, 4, 5] - @test [iz_g(iz, A) for iz = 1:size(A,3)] == [4, 5, 1, 2, 3, 4, 5, 1, 2, 3] - @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] + @test [iz_g(iz, A) for iz = 1:size(A,3)] == [4, 5, 1, 2, 3, 4, 5, 1, 2, 3] #Alternative: [3, 4, 5, 1, 2, 3, 4, 5, 1, 2] + @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8] #Alternative: [-2, -1, 0, 1, 2, 3, 4, 5, 6, 7] # (for Sxz) @test [ix_g(ix, Sxz) for ix = 1:size(Sxz,1)] == [1, 2, 3] @test [iy_g(iy, Sxz) for iy = 1:size(Sxz,2)] == [1, 2, 3, 4] - @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 1] - @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 6] + @test [iz_g(iz, Sxz) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 1] #Alternative: [5, 1, 2, 3, 4, 5] + @test [iz_g(iz, Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [1, 2, 3, 4, 5, 6] #Alternative: [0, 1, 2, 3, 4, 5] + end; + @testset "x_g / y_g / z_g" begin + dx = lx/(nx_g()-1); + dy = ly/(ny_g()-1); + dz = lz/(nz_g()-1); + # (for P) + @test [x_g(ix,dx,P) for ix = 1:size(P,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] + @test [y_g(iy,dy,P) for iy = 1:size(P,2)] == [-9.0, -7.0, -5.0, -3.0, -1.0] + @test [z_g(iz,dz,P) for iz = 1:size(P,3)] == [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] #Alternative: [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0] + @test [z_g(iz,dz,P; wrap_periodic=false) for iz = 1:size(P,3)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0] #Alternative: [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0] + # (for Vx) + @test [x_g(ix,dx,Vx) for ix = 1:size(Vx,1)] == [-1.0, 1.0, 3.0, 5.0, 7.0, 9.0] + @test [y_g(iy,dy,Vx) for iy = 1:size(Vx,2)] == [-9.0, -7.0, -5.0, -3.0, -1.0] + @test [z_g(iz,dz,Vx) for iz = 1:size(Vx,3)] == [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] #Alternative: [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0] + @test [z_g(iz,dz,Vx; wrap_periodic=false) for iz = 1:size(Vx,3)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0] #Alternative: [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0] + # (for Vz) + @test [x_g(ix,dx,Vz) for ix = 1:size(Vz,1)] == [0.0, 2.0, 4.0, 6.0, 8.0] + @test [y_g(iy,dy,Vz) for iy = 1:size(Vz,2)] == [-9.0, -7.0, -5.0, -3.0, -1.0] + @test [z_g(iz,dz,Vz) for iz = 1:size(Vz,3)] == [5.0, 7.0, -1.0, 1.0, 3.0, 5.0, 7.0, -1.0, 1.0] #Alternative: [7.0, 9.0, 1.0, 3.0, 5.0, 7.0, 9.0, 1.0, 3.0] + # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0. 8.0, 0.0, 2.0] + # possible alternative: [7.0,-1.0, 1.0, 3.0, 5.0, 7.0,-1.0, 1.0, 3.0] + @test [z_g(iz,dz,Vz; wrap_periodic=false) for iz = 1:size(Vz,3)] == [-5.0, -3.0, -1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0] #Alternative: [-3.0, -1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 13.0] + # (for A) + @test [x_g(ix,dx,A) for ix = 1:size(A,1)] == [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0] + @test [y_g(iy,dy,A) for iy = 1:size(A,2)] == [-9.0, -7.0, -5.0, -3.0, -1.0] + @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0, 4.0] #Alternative: [4.0, 6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] + # base grid (z dim): [8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0, 2.0] + @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [-4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0, 14.0] #Alternative: [-6.0, -4.0, -2.0, 0.0, 2.0, 4.0, 6.0, 8.0, 10.0, 12.0] + # (for Sxz) + @test [x_g(ix,dx,Sxz) for ix = 1:size(Sxz,1)] == [2.0, 4.0, 6.0] + # base grid (x dim): [0.0, 2.0, 4.0, 6.0, 8.0] + @test [y_g(iy,dy,Sxz) for iy = 1:size(Sxz,2)] == [-8.0, -6.0, -4.0, -2.0] + # base grid (y dim): [0.0, 2.0, 4.0, 6.0, 8.0] + @test [z_g(iz,dz,Sxz) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 0.0] #Alternative: [8.0, 0.0, 2.0, 4.0, 6.0, 8.0] + # base grid (z dim): [6.0, 8.0, 0.0, 2.0, 4.0, 6.0, 8.0, 0.0] + @test [z_g(iz,dz,Sxz; wrap_periodic=false) for iz = 1:size(Sxz,3)] == [0.0, 2.0, 4.0, 6.0, 8.0, 10.0] #Alternative: [-2.0, 0.0, 2.0, 4.0, 6.0, 8.0] + end; + @testset "extents" begin + @testset "default" begin + @test extents() == (1:5, 1:5, 2:6) + @test extents(P) == (1:5, 1:5, 2:6) + @test extents(Vx) == (1:6, 1:5, 2:6) + @test extents(Vz) == (1:5, 1:5, 3:7) + @test extents(A) == (1:7, 1:5, 3:7) + @test extents(Sxz) == (1:3, 1:4, 1:5) + end; + @testset "fix_global_boundaries" begin + @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:8) + @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:8) + @test extents(Vx; fix_global_boundaries=false) == (1:6, 1:5, 1:8) + @test extents(Vz; fix_global_boundaries=false) == (1:5, 1:5, 1:9) + @test extents(A; fix_global_boundaries=false) == (1:7, 1:5, 1:10) + @test extents(Sxz; fix_global_boundaries=false) == (1:3, 1:4, 1:6) + end; + @testset "overlap" begin + @test extents(0) == (1:5, 1:5, 2:6) + @test extents(1) == (1:5, 1:5, 2:6) + @test extents(2) == (1:5, 1:5, 2:6) + @test extents(P, 0) == (1:5, 1:5, 2:6) + @test extents(Vx, 1) == (1:6, 1:5, 2:6) + @test extents(Vz, 1) == (1:5, 1:5, 3:7) + @test extents(A, 2) == (1:7, 1:5, 3:7) + end; + end; + @testset "extents_g" begin + dx = lx/(nx_g()-1); + dy = ly/(ny_g()-1); + dz = lz/(nz_g()-1); + @testset "default" begin + @test extents_g() == (1:5, 1:5, 1:5) + @test extents_g(1) == (1:5, 1:5, 1:5) + @test extents_g(P) == (1:5, 1:5, 1:5) + @test extents_g(Vx) == (1:6, 1:5, 1:5) + @test extents_g(Vz) == (1:5, 1:5, 1:5) + @test extents_g(A) == (1:7, 1:5, 1:5) + @test extents_g(Sxz) == (1:3, 1:4, 1:5) + end; + @testset "fix_global_boundaries" begin + @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:7) + @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:7) + @test extents_g(Vx; fix_global_boundaries=false) == (1:6, 1:5, 0:7) + @test extents_g(Vz; fix_global_boundaries=false) == (1:5, 1:5, -1:7) + @test extents_g(A; fix_global_boundaries=false) == (1:7, 1:5, -1:8) + @test extents_g(Sxz; fix_global_boundaries=false) == (1:3, 1:4, 1:6) + end; + @testset "overlap" begin + @test extents_g(0) == (1:5, 1:5, 1:5) + @test extents_g(1) == (1:5, 1:5, 1:5) + @test extents_g(2) == (1:5, 1:5, 1:5) + @test extents_g(P, 0) == (1:5, 1:5, 1:5) + @test extents_g(Vx, 1) == (1:6, 1:5, 1:5) + @test extents_g(Vz, 1) == (1:5, 1:5, 1:5) + @test extents_g(A, 2) == (1:7, 1:5, 1:5) + end; + @testset "coordinates" begin + @test extents_g(; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, -9.0:2.0:-1.0, 0.0:2.0:8.0) + @test extents_g(1; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, -9.0:2.0:-1.0, 0.0:2.0:8.0) + @test extents_g(P; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, -9.0:2.0:-1.0, 0.0:2.0:8.0) + @test extents_g(Vx; dxyz=(dx, dy, dz)) == (-1.0:2.0:9.0, -9.0:2.0:-1.0, 0.0:2.0:8.0) + @test extents_g(Vz; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, -9.0:2.0:-1.0, -1.0:2.0:7.0) + @test extents_g(A; dxyz=(dx, dy, dz)) == (-2.0:2.0:10.0, -9.0:2.0:-1.0, 0.0:2.0:8.0) + end; end; finalize_global_grid(finalize_MPI=false); end; - @testset "3. *_g functions (simulated 3x3x3 processes)" begin + @testset "3. grid functions (simulated 3x3x3 processes)" begin lx = 20; ly = 20; lz = 16; @@ -236,6 +371,34 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test ny_g(A) == nxyz_g[2]-2 @test nz_g(A) == nxyz_g[3]+2 end; + @testset "ix_g / iy_g / iz_g" begin + # (for P) + @coords(1)=0; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] + @coords(1)=1; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [4, 5, 6, 7, 8] + @coords(1)=2; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [7, 8, 9, 10, 11] + @coords(2)=0; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] + @coords(2)=1; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [4, 5, 6, 7, 8] + @coords(2)=2; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [7, 8, 9, 10, 11] + @coords(3)=0; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [9, 1, 2, 3, 4] + @coords(3)=0; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] + @coords(3)=1; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] + @coords(3)=1; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] + @coords(3)=2; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [6, 7, 8, 9, 1] + @coords(3)=2; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [6, 7, 8, 9, 10] + # (for A) + @coords(1)=0; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5, 6] + @coords(1)=1; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [4, 5, 6, 7, 8, 9] + @coords(1)=2; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [7, 8, 9, 10, 11, 12] + @coords(2)=0; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3] + @coords(2)=1; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [6, 7, 8] + @coords(2)=2; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [11, 12, 13] + @coords(3)=0; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [8, 9, 1, 2, 3, 4, 5] + @coords(3)=0; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] + @coords(3)=1; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [2, 3, 4, 5, 6, 7, 8] + @coords(3)=1; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [2, 3, 4, 5, 6, 7, 8] + @coords(3)=2; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [5, 6, 7, 8, 9, 1, 2] + @coords(3)=2; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [5, 6, 7, 8, 9, 10, 11] + end; @testset "x_g / y_g / z_g" begin dx = lx/(nx_g()-1); dy = ly/(ny_g()-1); @@ -267,33 +430,130 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(3)=2; @test [z_g(iz,dz,A) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 0.0, 2.0] @coords(3)=2; @test [z_g(iz,dz,A; wrap_periodic=false) for iz = 1:size(A,3)] == [8.0, 10.0, 12.0, 14.0, 16.0, 18.0, 20.0] end; - @testset "ix_g / iy_g / iz_g" begin - # (for P) - @coords(1)=0; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [1, 2, 3, 4, 5] - @coords(1)=1; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [4, 5, 6, 7, 8] - @coords(1)=2; @test [ix_g(ix, P) for ix = 1:size(P,1)] == [7, 8, 9, 10, 11] - @coords(2)=0; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [1, 2, 3, 4, 5] - @coords(2)=1; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [4, 5, 6, 7, 8] - @coords(2)=2; @test [iy_g(iy, P) for iy = 1:size(P,2)] == [7, 8, 9, 10, 11] - @coords(3)=0; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [9, 1, 2, 3, 4] - @coords(3)=0; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [0, 1, 2, 3, 4] - @coords(3)=1; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] - @coords(3)=1; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [3, 4, 5, 6, 7] - @coords(3)=2; @test [iz_g(iz, P) for iz = 1:size(P,3)] == [6, 7, 8, 9, 1] - @coords(3)=2; @test [iz_g(iz, P; wrap_periodic=false) for iz = 1:size(P,3)] == [6, 7, 8, 9, 10] - # (for A) - @coords(1)=0; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [1, 2, 3, 4, 5, 6] - @coords(1)=1; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [3, 4, 5, 6, 7, 8] - @coords(1)=2; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [5, 6, 7, 8, 9, 10] - @coords(2)=0; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3] - @coords(2)=1; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [6, 7, 8] - @coords(2)=2; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [11, 12, 13] - @coords(3)=0; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [8, 9, 1, 2, 3, 4, 5] - @coords(3)=0; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] - @coords(3)=1; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [9, 1, 2, 3, 4, 5, 6] - @coords(3)=1; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [0, 1, 2, 3, 4, 5, 6] - @coords(3)=2; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [1, 2, 3, 4, 5, 6, 7] - @coords(3)=2; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [1, 2, 3, 4, 5, 6, 7] + @testset "extents" begin + @testset "default" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents() == (1:5, 1:5, 2:5) + @test extents(P) == (1:5, 1:5, 2:5) + @test extents(A) == (1:6, 1:3, 3:7) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents() == (1:5, 1:5, 1:5) + @test extents(P) == (1:5, 1:5, 1:5) + @test extents(A) == (1:6, 1:3, 1:7) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents() == (1:5, 1:5, 1:4) + @test extents(P) == (1:5, 1:5, 1:4) + @test extents(A) == (1:6, 1:3, 1:5) + end; + @testset "fix_global_boundaries" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(A; fix_global_boundaries=false) == (1:6, 1:3, 1:7) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(A; fix_global_boundaries=false) == (1:6, 1:3, 1:7) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) + @test extents(A; fix_global_boundaries=false) == (1:6, 1:3, 1:7) + end; + @testset "overlap" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents(0) == (1:4, 1:4, 2:4) + @test extents(1) == (1:4, 1:4, 2:4) + @test extents(P, 0) == (1:4, 1:4, 2:4) + @test extents(A, 0) == (1:4, 1:3, 3:5) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents(0) == (2:4, 2:4, 2:4) + @test extents(1) == (1:4, 1:4, 1:4) + @test extents(P, 0) == (2:4, 2:4, 2:4) + @test extents(A, 0) == (2:4, 1:3, 3:5) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents(0) == (2:5, 2:5, 2:4) + @test extents(1) == (1:5, 1:5, 1:4) + @test extents(P, 0) == (2:5, 2:5, 2:4) + @test extents(A, 0) == (2:6, 1:3, 3:5) + end; + end; + @testset "extents_g" begin + dx = lx/(nx_g()-1); + dy = ly/(ny_g()-1); + dz = lz/(nz_g()-1); + @testset "default" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents_g() == (1:5, 1:5, 1:4) + @test extents_g(P) == (1:5, 1:5, 1:4) + @test extents_g(A) == (1:6, 1:3, 1:5) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents_g() == (4:8, 4:8, 3:7) + @test extents_g(P) == (4:8, 4:8, 3:7) + @test extents_g(A) == (3:8, 6:8, 2:8) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents_g() == (7:11, 7:11, 6:9) + @test extents_g(P) == (7:11, 7:11, 6:9) + @test extents_g(A) == (5:10, 11:13, 5:9) + end; + @testset "fix_global_boundaries" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:4) + @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:4) + @test extents_g(A; fix_global_boundaries=false) == (1:6, 1:3, -1:5) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents_g(; fix_global_boundaries=false) == (4:8, 4:8, 3:7) + @test extents_g(P; fix_global_boundaries=false) == (4:8, 4:8, 3:7) + @test extents_g(A; fix_global_boundaries=false) == (3:8, 6:8, 2:8) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents_g(; fix_global_boundaries=false) == (7:11, 7:11, 6:10) + @test extents_g(P; fix_global_boundaries=false) == (7:11, 7:11, 6:10) + @test extents_g(A; fix_global_boundaries=false) == (5:10, 11:13, 5:11) + end; + @testset "overlap" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents_g(0) == (1:4, 1:4, 1:3) + @test extents_g(1) == (1:4, 1:4, 1:3) + @test extents_g(P, 0) == (1:4, 1:4, 1:3) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents_g(0) == (5:7, 5:7, 4:6) + @test extents_g(1) == (4:7, 4:7, 3:6) + @test extents_g(P, 0) == (5:7, 5:7, 4:6) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents_g(0) == (8:11, 8:11, 7:9) + @test extents_g(1) == (7:11, 7:11, 6:9) + @test extents_g(P, 0) == (8:11, 8:11, 7:9) + end; + @testset "coordinates" begin + @coords(1)=0; @coords(2)=0; @coords(3)=0; + @test extents_g(; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:2.0:6.0) + @test extents_g(1; dxyz=(dx, dy, dz)) == (0.0:2.0:6.0, 0.0:2.0:6.0, 0.0:2.0:4.0) + @test extents_g(P; dxyz=(dx, dy, dz)) == (0.0:2.0:8.0, 0.0:2.0:8.0, 0.0:2.0:6.0) + @test extents_g(A; dxyz=(dx, dy, dz)) == (-1.0:2.0:9.0, 2.0:2.0:6.0, 0.0:2.0:8.0) + + @coords(1)=1; @coords(2)=1; @coords(3)=1; + @test extents_g(; dxyz=(dx, dy, dz)) == (6.0:2.0:14.0, 6.0:2.0:14.0, 4.0:2.0:12.0) + @test extents_g(1; dxyz=(dx, dy, dz)) == (6.0:2.0:12.0, 6.0:2.0:12.0, 4.0:2.0:10.0) + @test extents_g(P; dxyz=(dx, dy, dz)) == (6.0:2.0:14.0, 6.0:2.0:14.0, 4.0:2.0:12.0) + @test extents_g(A; dxyz=(dx, dy, dz)) == (5.0:2.0:15.0, 8.0:2.0:12.0, 2.0:2.0:14.0) + + @coords(1)=2; @coords(2)=2; @coords(3)=2; + @test extents_g(; dxyz=(dx, dy, dz)) == (12.0:2.0:20.0, 12.0:2.0:20.0, 10.0:2.0:16.0) + @test extents_g(1; dxyz=(dx, dy, dz)) == (12.0:2.0:20.0, 12.0:2.0:20.0, 10.0:2.0:16.0) + @test extents_g(P; dxyz=(dx, dy, dz)) == (12.0:2.0:20.0, 12.0:2.0:20.0, 10.0:2.0:16.0) + @test extents_g(A; dxyz=(dx, dy, dz)) == (11.0:2.0:21.0, 14.0:2.0:18.0, 8.0:2.0:16.0) + end; end; finalize_global_grid(finalize_MPI=false); end; From ed0c18fd5978693cfb2c6b6c4325b88bf8f7fb1d Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Thu, 22 May 2025 19:10:54 +0200 Subject: [PATCH 21/30] improve iz_g and z_g --- src/tools.jl | 80 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 89c2035..20e91c0 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -248,25 +248,56 @@ julia> finalize_global_grid() z_g(iz::Integer, dz::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_z_g(iz, dz, size(A,3), wrap_periodic) function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - olz_A = @olz() + (nz_A-@nz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) # NOTE: nz_g() cannot be used as dimz needs to be used. - olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. - vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 - centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 - z0_g = @originz() + olshiftz + vertexshiftz + centershiftz - z0 = -dz*olz_A*0.5 - z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g - if @periodz() && wrap_periodic - lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) - lz_A = lz + dz*(nz_A-@nz()) - z1 = z0_g - dz*(nz_A-@nz())*0.5 # dz*max((@nz()-nz_A)*0.5, 0) - z2 = z1 + lz_A #lz + dz*(nz_A-@nz())*0.5 #dz*max((@nz()-nz_A)*0.5, 0) - if (z > z2) z = z - dz - lz_A; end - if (z < z1) z = z + dz + lz_A; end + iz_g = _iz_g(iz, nz_A, wrap_periodic, coordz, dimz) + z_g_A = _z_g(dz, nz_A, wrap_periodic, coordz, dimz) + nz_g_A = length(z_g_A) + if (iz_g > nz_g_A) z = z_g_A[end] + dz*(iz_g - nz_g_A) + elseif (iz_g < 1) z = z_g_A[1] - dz*(1 - iz_g) + else z = z_g_A[iz_g] end return z end +function _z_g(dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) + # wrap_periodz = @periodz() && wrap_periodic + nz_diff = nz_A - @nz() + olz_A = @olz() + nz_diff + nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. + nz_g_A = nz_g + nz_diff*!@periodz() + min(nz_diff+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) + vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 + centershiftz = @centerz() ? lz_A*0.5 : dz*0.0 + # localshift = !@periodz() ? -dz*nz_diff*0.5 : dz*0.0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. + localshift = !@periodz() ? -dz*olz_A*0.5 : dz*0.0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. + staggershift = (@periodz() && isodd(nz_diff)) ? -dz*0.5 : dz*0.0 #dz*0.5 : dz*0.0 # In the periodic case (and wrapped), both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the right of the first grid cell, but it could also be on the left instead. + z1_A = @originz() + vertexshiftz + centershiftz + localshift + staggershift #+ periodshiftz + z2_A = z1_A + lz_A + z_g_A = z1_A:dz:z2_A + return z_g_A +end +# TODO: nz_g(A) must be fixed for periodic! And round the tests and fix the current issue + +# function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) +# nz_diff = nz_A - @nz() +# olz_A = @olz() + nz_diff +# nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. +# olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. +# vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 +# centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 +# z0_g = @originz() + olshiftz + vertexshiftz + centershiftz +# z0 = -dz*olz_A*0.5 +# z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g +# if @periodz() && wrap_periodic +# lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) +# lz_A = lz + dz*nz_diff +# z1 = z0_g - dz*nz_diff*0.5 # dz*max((@nz()-nz_A)*0.5, 0) +# z2 = z1 + lz_A #lz + dz*nz_diff*0.5 #dz*max((@nz()-nz_A)*0.5, 0) +# if (z > z2) z = z - dz - lz_A; end +# if (z < z1) z = z + dz + lz_A; end +# end +# return z +# end + """ ix_g(ix, A) @@ -447,15 +478,22 @@ julia> finalize_global_grid() iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - olz_A = @olz() + (nz_A-@nz()) - nz_g = dimz*(@nz()-@olz()) + @olz()*(@periodz()==0) # NOTE: nz_g() cannot be used as dimz needs to be used. - olshiftz = @periodz() ? 0 : olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. + # wrap_periodz = @periodz() && wrap_periodic + nz_diff = nz_A - @nz() + olz_A = @olz() + nz_diff + # nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. + # nz_g = dimz*(@nz()-@olz()) + @olz()*!wrap_periodz # NOTE: nz_g() cannot be used as dimz needs to be used. + # nz_g_A = nz_g + nz_diff*!wrap_periodz + min(nz_diff+@olz(), 0)*wrap_periodz # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. + nz_g_A = nz_g + nz_diff*!@periodz() + min(nz_diff+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + periodshiftz = @periodz() ? -olz_A÷2 : 0 #-cld(olz_A,2) : 0 #olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. If it is periodic (and wrapped), this shift must not happen and in the contrary, we must shift in the other direction in order to have the local overlap more on the left side rather than on the right side. originz = 1 - iz0_g = originz + olshiftz - iz0 = -olz_A÷2 + iz0_g = originz + periodshiftz + iz0 = 0 #-olz_A÷2 iz = (coordz*(@nz()-@olz()) + iz-1) + iz0 + iz0_g + # if wrap_periodz if @periodz() && wrap_periodic - nz_g_A = nz_g + (nz_A-@nz()) #min((nz_A-@nz()), 0) + # nz_g_A = nz_g + min(nz_diff, 0) if (iz > nz_g_A) iz = iz - nz_g_A; end if (iz < 1) iz = iz + nz_g_A; end end From 28d4949043e66e68f4bbdf7a2f28d5c6193f8c5e Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 27 May 2025 16:32:41 +0200 Subject: [PATCH 22/30] update nz_g --- src/tools.jl | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 20e91c0..bb2b861 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -44,6 +44,7 @@ macro halowidths() esc(:( global_grid().halowidths )) end Return the size of the global grid in dimension x. """ nx_g() = @nx_g() +nx_g(dimx::Integer) = dimx*(@nx()-@olx()) + @olx()*!@periodx() # NOTE: nx_g() cannot be used as dimx needs to be used. """ @@ -52,6 +53,7 @@ nx_g() = @nx_g() Return the size of the global grid in dimension y. """ ny_g() = @ny_g() +ny_g(dimy::Integer) = dimy*(@ny()-@oly()) + @oly()*!@periody() # NOTE: ny_g() cannot be used as dimy needs to be used. """ @@ -60,6 +62,7 @@ ny_g() = @ny_g() Return the size of the global grid in dimension z. """ nz_g() = @nz_g() +nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. """ @@ -68,6 +71,7 @@ nz_g() = @nz_g() Return the size of array `A` in the global grid in dimension x. """ nx_g(A::AbstractArray) = @nx_g() + (size(A,1)-@nx()) +nx_g(nx_A::Integer, dimx::Integer) = nx_g(dimx) + (nx_A - @nx())*!@periodx() + min((nx_A - @nx())+@olx(), 0)*@periodx() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -75,7 +79,8 @@ nx_g(A::AbstractArray) = @nx_g() + (size(A,1)-@nx()) Return the size of array `A` in the global grid in dimension y. """ -ny_g(A::AbstractArray) = @ny_g() + (size(A,2)-@ny()) +ny_g(A::AbstractArray) = @ny_g() + (size(A,2)-@ny()) +ny_g(ny_A::Integer, dimy::Integer) = ny_g(dimy) + (ny_A - @ny())*!@periody() + min((ny_A - @ny())+@oly(), 0)*@periody() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -83,7 +88,8 @@ ny_g(A::AbstractArray) = @ny_g() + (size(A,2)-@ny()) Return the size of array `A` in the global grid in dimension z. """ -nz_g(A::AbstractArray) = @nz_g() + (size(A,3)-@nz()) +nz_g(A::AbstractArray) = @nz_g() + (size(A,3)-@nz()) +nz_g(nz_A::Integer, dimz::Integer) = nz_g(dimz) + (nz_A - @nz())*!@periodz() + min((nz_A - @nz())+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -262,8 +268,7 @@ function _z_g(dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Int # wrap_periodz = @periodz() && wrap_periodic nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff - nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. - nz_g_A = nz_g + nz_diff*!@periodz() + min(nz_diff+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + nz_g_A = nz_g(nz_A, dimz) lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 centershiftz = @centerz() ? lz_A*0.5 : dz*0.0 @@ -484,8 +489,7 @@ function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer= # nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. # nz_g = dimz*(@nz()-@olz()) + @olz()*!wrap_periodz # NOTE: nz_g() cannot be used as dimz needs to be used. # nz_g_A = nz_g + nz_diff*!wrap_periodz + min(nz_diff+@olz(), 0)*wrap_periodz # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). - nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. - nz_g_A = nz_g + nz_diff*!@periodz() + min(nz_diff+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + nz_g_A = nz_g(nz_A, dimz) periodshiftz = @periodz() ? -olz_A÷2 : 0 #-cld(olz_A,2) : 0 #olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. If it is periodic (and wrapped), this shift must not happen and in the contrary, we must shift in the other direction in order to have the local overlap more on the left side rather than on the right side. originz = 1 iz0_g = originz + periodshiftz From d1ebb0e8f87003b0e013c9bd27523d829cad1c38 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 27 May 2025 17:33:46 +0200 Subject: [PATCH 23/30] update nxyz_g --- src/tools.jl | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index bb2b861..1faec97 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -70,17 +70,18 @@ nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() ca Return the size of array `A` in the global grid in dimension x. """ -nx_g(A::AbstractArray) = @nx_g() + (size(A,1)-@nx()) -nx_g(nx_A::Integer, dimx::Integer) = nx_g(dimx) + (nx_A - @nx())*!@periodx() + min((nx_A - @nx())+@olx(), 0)*@periodx() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). - +nx_g(A::AbstractArray) = _nx_g(size(A,1), nx_g()) +nx_g(nx_A::Integer, dimx::Integer) = _nx_g(nx_A, nx_g(dimx)) # NOTE: this function is only for imaginary grids; nx_g(dimx) cannot be pre-computed like nx_g(); thus the specific implementation with _nx_g. +_nx_g(nx_A::Integer, nx_g::Integer) = nx_g + (nx_A-@nx())*!@periodx() + min((nx_A-@nx())+@olx(), 0)*@periodx() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ ny_g(A) Return the size of array `A` in the global grid in dimension y. """ -ny_g(A::AbstractArray) = @ny_g() + (size(A,2)-@ny()) -ny_g(ny_A::Integer, dimy::Integer) = ny_g(dimy) + (ny_A - @ny())*!@periody() + min((ny_A - @ny())+@oly(), 0)*@periody() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). +ny_g(A::AbstractArray) = _ny_g(size(A,2), ny_g()) +ny_g(ny_A::Integer, dimy::Integer) = _ny_g(ny_A, ny_g(dimy)) # NOTE: this function is only for imaginary grids; ny_g(dimy) cannot be pre-computed like ny_g(); thus the specific implementation with _ny_g. +_ny_g(ny_A::Integer, ny_g::Integer) = ny_g + (ny_A-@ny())*!@periody() + min((ny_A-@ny())+@oly(), 0)*@periody() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -88,8 +89,9 @@ ny_g(ny_A::Integer, dimy::Integer) = ny_g(dimy) + (ny_A - @ny())*!@periody() + m Return the size of array `A` in the global grid in dimension z. """ -nz_g(A::AbstractArray) = @nz_g() + (size(A,3)-@nz()) -nz_g(nz_A::Integer, dimz::Integer) = nz_g(dimz) + (nz_A - @nz())*!@periodz() + min((nz_A - @nz())+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). +nz_g(A::AbstractArray) = _nz_g(size(A,3), nz_g()) +nz_g(nz_A::Integer, dimz::Integer) = _nz_g(nz_A, nz_g(dimz)) # NOTE: this function is only for imaginary grids; nz_g(dimz) cannot be pre-computed like nz_g(); thus the specific implementation with _nz_g. +_nz_g(nz_A::Integer, nz_g::Integer) = nz_g + (nz_A-@nz())*!@periodz() + min((nz_A-@nz())+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -265,14 +267,12 @@ function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool end function _z_g(dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - # wrap_periodz = @periodz() && wrap_periodic nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff nz_g_A = nz_g(nz_A, dimz) lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 centershiftz = @centerz() ? lz_A*0.5 : dz*0.0 - # localshift = !@periodz() ? -dz*nz_diff*0.5 : dz*0.0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. localshift = !@periodz() ? -dz*olz_A*0.5 : dz*0.0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. staggershift = (@periodz() && isodd(nz_diff)) ? -dz*0.5 : dz*0.0 #dz*0.5 : dz*0.0 # In the periodic case (and wrapped), both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the right of the first grid cell, but it could also be on the left instead. z1_A = @originz() + vertexshiftz + centershiftz + localshift + staggershift #+ periodshiftz @@ -483,21 +483,15 @@ julia> finalize_global_grid() iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - # wrap_periodz = @periodz() && wrap_periodic nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff - # nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. - # nz_g = dimz*(@nz()-@olz()) + @olz()*!wrap_periodz # NOTE: nz_g() cannot be used as dimz needs to be used. - # nz_g_A = nz_g + nz_diff*!wrap_periodz + min(nz_diff+@olz(), 0)*wrap_periodz # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). nz_g_A = nz_g(nz_A, dimz) periodshiftz = @periodz() ? -olz_A÷2 : 0 #-cld(olz_A,2) : 0 #olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. If it is periodic (and wrapped), this shift must not happen and in the contrary, we must shift in the other direction in order to have the local overlap more on the left side rather than on the right side. originz = 1 iz0_g = originz + periodshiftz iz0 = 0 #-olz_A÷2 iz = (coordz*(@nz()-@olz()) + iz-1) + iz0 + iz0_g - # if wrap_periodz if @periodz() && wrap_periodic - # nz_g_A = nz_g + min(nz_diff, 0) if (iz > nz_g_A) iz = iz - nz_g_A; end if (iz < 1) iz = iz + nz_g_A; end end From ef87fa6cc608580e271a72810efe9a61f2dba26c Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 27 May 2025 18:28:02 +0200 Subject: [PATCH 24/30] update nxyz_g --- src/tools.jl | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 1faec97..52738b9 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -44,7 +44,7 @@ macro halowidths() esc(:( global_grid().halowidths )) end Return the size of the global grid in dimension x. """ nx_g() = @nx_g() -nx_g(dimx::Integer) = dimx*(@nx()-@olx()) + @olx()*!@periodx() # NOTE: nx_g() cannot be used as dimx needs to be used. +_nx_g(dimx::Integer) = dimx*(@nx()-@olx()) + @olx()*!@periodx() # NOTE: nx_g() cannot be used as dimx needs to be used. """ @@ -53,7 +53,7 @@ nx_g(dimx::Integer) = dimx*(@nx()-@olx()) + @olx()*!@periodx() # NOTE: nx_g() ca Return the size of the global grid in dimension y. """ ny_g() = @ny_g() -ny_g(dimy::Integer) = dimy*(@ny()-@oly()) + @oly()*!@periody() # NOTE: ny_g() cannot be used as dimy needs to be used. +_ny_g(dimy::Integer) = dimy*(@ny()-@oly()) + @oly()*!@periody() # NOTE: ny_g() cannot be used as dimy needs to be used. """ @@ -62,7 +62,7 @@ ny_g(dimy::Integer) = dimy*(@ny()-@oly()) + @oly()*!@periody() # NOTE: ny_g() ca Return the size of the global grid in dimension z. """ nz_g() = @nz_g() -nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. +_nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. """ @@ -70,18 +70,23 @@ nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() ca Return the size of array `A` in the global grid in dimension x. """ -nx_g(A::AbstractArray) = _nx_g(size(A,1), nx_g()) -nx_g(nx_A::Integer, dimx::Integer) = _nx_g(nx_A, nx_g(dimx)) # NOTE: this function is only for imaginary grids; nx_g(dimx) cannot be pre-computed like nx_g(); thus the specific implementation with _nx_g. -_nx_g(nx_A::Integer, nx_g::Integer) = nx_g + (nx_A-@nx())*!@periodx() + min((nx_A-@nx())+@olx(), 0)*@periodx() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). +nx_g(A::AbstractArray) = nx_g(size(A,1)) +nx_g(nx_A::Integer) = _adjust_nx_g(nx_g(), nx_A) +_nx_g(nx_A::Integer, dimx::Integer) = _adjust_nx_g(_nx_g(dimx), nx_A) # NOTE: this function is only for imaginary grids; _nx_g(dimx) cannot be pre-computed like nx_g(); thus the specific implementation with _nx_g. + +_adjust_nx_g(nx_g::Integer, nx_A::Integer) = nx_g + (nx_A-@nx())*!@periodx() + min((nx_A-@nx())+@olx(), 0)*@periodx() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). + """ ny_g(A) Return the size of array `A` in the global grid in dimension y. """ -ny_g(A::AbstractArray) = _ny_g(size(A,2), ny_g()) -ny_g(ny_A::Integer, dimy::Integer) = _ny_g(ny_A, ny_g(dimy)) # NOTE: this function is only for imaginary grids; ny_g(dimy) cannot be pre-computed like ny_g(); thus the specific implementation with _ny_g. -_ny_g(ny_A::Integer, ny_g::Integer) = ny_g + (ny_A-@ny())*!@periody() + min((ny_A-@ny())+@oly(), 0)*@periody() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). +ny_g(A::AbstractArray) = ny_g(size(A,2)) +ny_g(ny_A::Integer) = _adjust_ny_g(ny_g(), ny_A) +_ny_g(ny_A::Integer, dimy::Integer) = _adjust_ny_g(_ny_g(dimy), ny_A) # NOTE: this function is only for imaginary grids; _ny_g(dimy) cannot be pre-computed like ny_g(); thus the specific implementation with _ny_g. + +_adjust_ny_g(ny_g::Integer, ny_A::Integer) = ny_g + (ny_A-@ny())*!@periody() + min((ny_A-@ny())+@oly(), 0)*@periody() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -89,9 +94,11 @@ _ny_g(ny_A::Integer, ny_g::Integer) = ny_g + (ny_A-@ny())*!@periody() + min((ny_ Return the size of array `A` in the global grid in dimension z. """ -nz_g(A::AbstractArray) = _nz_g(size(A,3), nz_g()) -nz_g(nz_A::Integer, dimz::Integer) = _nz_g(nz_A, nz_g(dimz)) # NOTE: this function is only for imaginary grids; nz_g(dimz) cannot be pre-computed like nz_g(); thus the specific implementation with _nz_g. -_nz_g(nz_A::Integer, nz_g::Integer) = nz_g + (nz_A-@nz())*!@periodz() + min((nz_A-@nz())+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). +nz_g(A::AbstractArray) = nz_g(size(A,3)) +nz_g(nz_A::Integer) = _adjust_nz_g(nz_g(), nz_A) +_nz_g(nz_A::Integer, dimz::Integer) = _adjust_nz_g(_nz_g(dimz), nz_A) # NOTE: this function is only for imaginary grids; _nz_g(dimz) cannot be pre-computed like nz_g(); thus the specific implementation with _nz_g. + +_adjust_nz_g(nz_g::Integer, nz_A::Integer) = nz_g + (nz_A-@nz())*!@periodz() + min((nz_A-@nz())+@olz(), 0)*@periodz() # NOTE: if the array is bigger, it doesn't matter when it is periodic: the global array simply overlaps more on itself (also, when it is staggered). """ @@ -269,7 +276,7 @@ end function _z_g(dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff - nz_g_A = nz_g(nz_A, dimz) + nz_g_A = _nz_g(nz_A, dimz) lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 centershiftz = @centerz() ? lz_A*0.5 : dz*0.0 @@ -485,7 +492,7 @@ iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff - nz_g_A = nz_g(nz_A, dimz) + nz_g_A = _nz_g(nz_A, dimz) periodshiftz = @periodz() ? -olz_A÷2 : 0 #-cld(olz_A,2) : 0 #olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. If it is periodic (and wrapped), this shift must not happen and in the contrary, we must shift in the other direction in order to have the local overlap more on the left side rather than on the right side. originz = 1 iz0_g = originz + periodshiftz From d7d0f3ed08d4cfbdf40a8a3489c11580f987430b Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 27 May 2025 19:06:13 +0200 Subject: [PATCH 25/30] clean up [i]z_g --- src/tools.jl | 49 ++++++++++++------------------------------------- 1 file changed, 12 insertions(+), 37 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index 52738b9..e8109ee 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -264,7 +264,7 @@ z_g(iz::Integer, dz::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) iz_g = _iz_g(iz, nz_A, wrap_periodic, coordz, dimz) - z_g_A = _z_g(dz, nz_A, wrap_periodic, coordz, dimz) + z_g_A = _z_g(dz, nz_A, dimz) nz_g_A = length(z_g_A) if (iz_g > nz_g_A) z = z_g_A[end] + dz*(iz_g - nz_g_A) elseif (iz_g < 1) z = z_g_A[1] - dz*(1 - iz_g) @@ -273,42 +273,20 @@ function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool return z end -function _z_g(dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) +function _z_g(dz::T, nz_A::Integer, dimz::Integer=@dimz()) where T <: AbstractFloat nz_diff = nz_A - @nz() olz_A = @olz() + nz_diff nz_g_A = _nz_g(nz_A, dimz) lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) - vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 - centershiftz = @centerz() ? lz_A*0.5 : dz*0.0 - localshift = !@periodz() ? -dz*olz_A*0.5 : dz*0.0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. - staggershift = (@periodz() && isodd(nz_diff)) ? -dz*0.5 : dz*0.0 #dz*0.5 : dz*0.0 # In the periodic case (and wrapped), both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the right of the first grid cell, but it could also be on the left instead. - z1_A = @originz() + vertexshiftz + centershiftz + localshift + staggershift #+ periodshiftz + centershiftz = @centerz() ? lz_A*T(0.5) : T(0.0) + vertexshiftz = @origin_on_vertex() ? T(0.5) : T(0.0) + localshift = !@periodz() ? -T(olz_A)*T(0.5) : T(0.0) # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. + staggershift = (@periodz() && isodd(nz_diff)) ? -T(0.5) : T(0.0) # In the periodic case, both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the left of the first grid cell, but it could also be on the right instead. + z1_A = @originz() + centershiftz + dz*(vertexshiftz + localshift + staggershift) # dz has been factored out of the last three shifts to reduce the amount of multiplications. z2_A = z1_A + lz_A z_g_A = z1_A:dz:z2_A return z_g_A end -# TODO: nz_g(A) must be fixed for periodic! And round the tests and fix the current issue - -# function _z_g(iz::Integer, dz::AbstractFloat, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) -# nz_diff = nz_A - @nz() -# olz_A = @olz() + nz_diff -# nz_g = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() cannot be used as dimz needs to be used. -# olshiftz = @periodz() ? dz*0.0 : +dz*olz_A*0.5 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. -# vertexshiftz = @origin_on_vertex() ? dz*0.5 : dz*0.0 -# centershiftz = @centerz() ? (@origin_on_vertex() ? -dz*nz_g*0.5 : -dz*(nz_g-1)*0.5) : dz*0.0 -# z0_g = @originz() + olshiftz + vertexshiftz + centershiftz -# z0 = -dz*olz_A*0.5 -# z = dz*(coordz*(@nz()-@olz()) + iz-1) + z0 + z0_g -# if @periodz() && wrap_periodic -# lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) -# lz_A = lz + dz*nz_diff -# z1 = z0_g - dz*nz_diff*0.5 # dz*max((@nz()-nz_A)*0.5, 0) -# z2 = z1 + lz_A #lz + dz*nz_diff*0.5 #dz*max((@nz()-nz_A)*0.5, 0) -# if (z > z2) z = z - dz - lz_A; end -# if (z < z1) z = z + dz + lz_A; end -# end -# return z -# end """ @@ -490,14 +468,11 @@ julia> finalize_global_grid() iz_g(iz::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iz_g(iz, size(A,3), wrap_periodic) function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer=@coordz(), dimz::Integer=@dimz()) - nz_diff = nz_A - @nz() - olz_A = @olz() + nz_diff - nz_g_A = _nz_g(nz_A, dimz) - periodshiftz = @periodz() ? -olz_A÷2 : 0 #-cld(olz_A,2) : 0 #olz_A÷2 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. If it is periodic (and wrapped), this shift must not happen and in the contrary, we must shift in the other direction in order to have the local overlap more on the left side rather than on the right side. - originz = 1 - iz0_g = originz + periodshiftz - iz0 = 0 #-olz_A÷2 - iz = (coordz*(@nz()-@olz()) + iz-1) + iz0 + iz0_g + nz_diff = nz_A - @nz() + olz_A = @olz() + nz_diff + nz_g_A = _nz_g(nz_A, dimz) + iz0_g = @periodz() ? -olz_A÷2 : 0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, in this case, we must shift to the left. If we wanted to have more overlap on the left then on the right then we would have to do the following: -cld(olz_A,2) : 0 + iz = coordz*(@nz()-@olz()) + iz + iz0_g if @periodz() && wrap_periodic if (iz > nz_g_A) iz = iz - nz_g_A; end if (iz < 1) iz = iz + nz_g_A; end From 09d6aa31c2b8bc97118c15fa39360b867ea2e8fb Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Tue, 27 May 2025 19:10:06 +0200 Subject: [PATCH 26/30] complete docstring for nxyz_g --- src/tools.jl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index e8109ee..ffc6253 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -67,8 +67,9 @@ _nz_g(dimz::Integer) = dimz*(@nz()-@olz()) + @olz()*!@periodz() # NOTE: nz_g() c """ nx_g(A) + nx_g(nx_A) -Return the size of array `A` in the global grid in dimension x. +Return the size of array `A` in the global grid in dimension x. Alternatively to passing `A`, the size of the array in dimension x can be provided. """ nx_g(A::AbstractArray) = nx_g(size(A,1)) nx_g(nx_A::Integer) = _adjust_nx_g(nx_g(), nx_A) @@ -79,8 +80,9 @@ _adjust_nx_g(nx_g::Integer, nx_A::Integer) = nx_g + (nx_A-@nx())*!@periodx() + m """ ny_g(A) + ny_g(ny_A) -Return the size of array `A` in the global grid in dimension y. +Return the size of array `A` in the global grid in dimension y. Alternatively to passing `A`, the size of the array in dimension y can be provided. """ ny_g(A::AbstractArray) = ny_g(size(A,2)) ny_g(ny_A::Integer) = _adjust_ny_g(ny_g(), ny_A) @@ -92,7 +94,7 @@ _adjust_ny_g(ny_g::Integer, ny_A::Integer) = ny_g + (ny_A-@ny())*!@periody() + m """ nz_g(A) -Return the size of array `A` in the global grid in dimension z. +Return the size of array `A` in the global grid in dimension z. Alternatively to passing `A`, the size of the array in dimension z can be provided. """ nz_g(A::AbstractArray) = nz_g(size(A,3)) nz_g(nz_A::Integer) = _adjust_nz_g(nz_g(), nz_A) From e15b73aab14310e3d37b6bf9efa35efa40fe219a Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 4 Jun 2025 10:06:49 +0200 Subject: [PATCH 27/30] update ix_g,iy_g --- src/tools.jl | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index ffc6253..a67d836 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -335,16 +335,15 @@ julia> finalize_global_grid() """ ix_g(ix::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _ix_g(ix, size(A,1), wrap_periodic) - function _ix_g(ix::Integer, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) - nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) - olx_A = @olx() + (nx_A-@nx()) - ix0_g = @periodx() ? 0 : olx_A÷2 - ix0 = -olx_A÷2 - ix = coordx*(@nx()-olx_A) + ix + ix0 + ix0_g - if wrap_periodic && @periodx() - if (ix > nx_g) ix = ix - nx_g; end - if (ix < 1) ix = ix + nx_g; end + nx_diff = nx_A - @nx() + olx_A = @olx() + nx_diff + nx_g_A = _nx_g(nx_A, dimx) + ix0_g = @periodx() ? -olx_A÷2 : 0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, in this case, we must shift to the left. If we wanted to have more overlap on the left then on the right then we would have to do the following: -cld(olx_A,2) : 0 + ix = coordx*(@nx()-@olx()) + ix + ix0_g + if @periodx() && wrap_periodic + if (ix > nx_g_A) ix = ix - nx_g_A; end + if (ix < 1) ix = ix + nx_g_A; end end return ix end @@ -395,14 +394,14 @@ julia> finalize_global_grid() iy_g(iy::Integer, A::AbstractArray; wrap_periodic::Bool=true) = _iy_g(iy, size(A,2), wrap_periodic) function _iy_g(iy::Integer, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) - ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) - oly_A = @oly() + (ny_A-@ny()) - iy0_g = @periody() ? 0 : oly_A÷2 - iy0 = -oly_A÷2 - iy = coordy*(@ny()-oly_A) + iy + iy0 + iy0_g - if wrap_periodic && @periody() - if (iy > ny_g) iy = iy - ny_g; end - if (iy < 1) iy = iy + ny_g; end + ny_diff = ny_A - @ny() + oly_A = @oly() + ny_diff + ny_g_A = _ny_g(ny_A, dimy) + iy0_g = @periody() ? -oly_A÷2 : 0 # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, in this case, we must shift to the left. If we wanted to have more overlap on the left then on the right then we would have to do the following: -cld(oly_A,2) : 0 + iy = coordy*(@ny()-@oly()) + iy + iy0_g + if @periody() && wrap_periodic + if (iy > ny_g_A) iy = iy - ny_g_A; end + if (iy < 1) iy = iy + ny_g_A; end end return iy end From 971bfd33d9f10b88a5f1557b802f7acb257de6e0 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 4 Jun 2025 10:07:42 +0200 Subject: [PATCH 28/30] update ix_g,iy_g --- test/test_tools.jl | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/test/test_tools.jl b/test/test_tools.jl index 850da76..8b4696a 100644 --- a/test/test_tools.jl +++ b/test/test_tools.jl @@ -37,13 +37,13 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nz_g(Vx) == nz-2 @test nx_g(Vz) == nx @test ny_g(Vz) == ny - @test nz_g(Vz) == nz-2+1 + @test nz_g(Vz) == nz-2 @test nx_g(A) == nx+2 @test ny_g(A) == ny - @test nz_g(A) == nz-2+2 + @test nz_g(A) == nz-2 @test nx_g(Sxz) == nx-2 @test ny_g(Sxz) == ny-1 - @test nz_g(Sxz) == nz-2-2 + @test nz_g(Sxz) == nz-2 end; @testset "ix_g / iy_g / iz_g" begin # (for P) @@ -118,7 +118,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test extents(A) == (1:7, 1:5, 3:5) @test extents(Sxz) == (1:3, 1:4, 1:3) end; - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) @test extents(Vx; fix_global_boundaries=false) == (1:6, 1:5, 1:5) @@ -139,7 +139,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); dx = lx/(nx_g()-1); dy = ly/(ny_g()-1); dz = lz/(nz_g()-1); - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:4) @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:4) @test extents_g(Vx; fix_global_boundaries=false) == (1:6, 1:5, 0:4) @@ -201,13 +201,13 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nz_g(Vx) == nz-3 @test nx_g(Vz) == nx @test ny_g(Vz) == ny - @test nz_g(Vz) == nz-3+1 + @test nz_g(Vz) == nz-3 @test nx_g(A) == nx+2 @test ny_g(A) == ny - @test nz_g(A) == nz-3+2 + @test nz_g(A) == nz-3 @test nx_g(Sxz) == nx-2 @test ny_g(Sxz) == ny-1 - @test nz_g(Sxz) == nz-3-2 + @test nz_g(Sxz) == nz-3 end; @testset "ix_g / iy_g / iz_g" begin # (for P) @@ -281,7 +281,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test extents(A) == (1:7, 1:5, 3:7) @test extents(Sxz) == (1:3, 1:4, 1:5) end; - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:8) @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:8) @test extents(Vx; fix_global_boundaries=false) == (1:6, 1:5, 1:8) @@ -312,7 +312,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test extents_g(A) == (1:7, 1:5, 1:5) @test extents_g(Sxz) == (1:3, 1:4, 1:5) end; - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:7) @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:7) @test extents_g(Vx; fix_global_boundaries=false) == (1:6, 1:5, 0:7) @@ -369,7 +369,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test nz_g(P) == nxyz_g[3] @test nx_g(A) == nxyz_g[1]+1 @test ny_g(A) == nxyz_g[2]-2 - @test nz_g(A) == nxyz_g[3]+2 + @test nz_g(A) == nxyz_g[3] end; @testset "ix_g / iy_g / iz_g" begin # (for P) @@ -390,8 +390,8 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(1)=1; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [4, 5, 6, 7, 8, 9] @coords(1)=2; @test [ix_g(ix, A) for ix = 1:size(A,1)] == [7, 8, 9, 10, 11, 12] @coords(2)=0; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [1, 2, 3] - @coords(2)=1; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [6, 7, 8] - @coords(2)=2; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [11, 12, 13] + @coords(2)=1; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [4, 5, 6] + @coords(2)=2; @test [iy_g(iy, A) for iy = 1:size(A,2)] == [7, 8, 9] @coords(3)=0; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [8, 9, 1, 2, 3, 4, 5] @coords(3)=0; @test [iz_g(iz, A; wrap_periodic=false) for iz = 1:size(A,3)] == [-1, 0, 1, 2, 3, 4, 5] @coords(3)=1; @test [iz_g(iz, A) for iz = 1:size(A,3)] == [2, 3, 4, 5, 6, 7, 8] @@ -447,7 +447,7 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @test extents(P) == (1:5, 1:5, 1:4) @test extents(A) == (1:6, 1:3, 1:5) end; - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @coords(1)=0; @coords(2)=0; @coords(3)=0; @test extents(; fix_global_boundaries=false) == (1:5, 1:5, 1:5) @test extents(P; fix_global_boundaries=false) == (1:5, 1:5, 1:5) @@ -496,14 +496,14 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(1)=1; @coords(2)=1; @coords(3)=1; @test extents_g() == (4:8, 4:8, 3:7) @test extents_g(P) == (4:8, 4:8, 3:7) - @test extents_g(A) == (3:8, 6:8, 2:8) + @test extents_g(A) == (4:9, 4:6, 2:8) @coords(1)=2; @coords(2)=2; @coords(3)=2; @test extents_g() == (7:11, 7:11, 6:9) @test extents_g(P) == (7:11, 7:11, 6:9) - @test extents_g(A) == (5:10, 11:13, 5:9) + @test extents_g(A) == (7:12, 7:9, 5:9) end; - @testset "fix_global_boundaries" begin + @testset "!fix_global_boundaries" begin @coords(1)=0; @coords(2)=0; @coords(3)=0; @test extents_g(; fix_global_boundaries=false) == (1:5, 1:5, 0:4) @test extents_g(P; fix_global_boundaries=false) == (1:5, 1:5, 0:4) @@ -512,12 +512,12 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); @coords(1)=1; @coords(2)=1; @coords(3)=1; @test extents_g(; fix_global_boundaries=false) == (4:8, 4:8, 3:7) @test extents_g(P; fix_global_boundaries=false) == (4:8, 4:8, 3:7) - @test extents_g(A; fix_global_boundaries=false) == (3:8, 6:8, 2:8) + @test extents_g(A; fix_global_boundaries=false) == (4:9, 4:6, 2:8) @coords(1)=2; @coords(2)=2; @coords(3)=2; @test extents_g(; fix_global_boundaries=false) == (7:11, 7:11, 6:10) @test extents_g(P; fix_global_boundaries=false) == (7:11, 7:11, 6:10) - @test extents_g(A; fix_global_boundaries=false) == (5:10, 11:13, 5:11) + @test extents_g(A; fix_global_boundaries=false) == (7:12, 7:9, 5:11) end; @testset "overlap" begin @coords(1)=0; @coords(2)=0; @coords(3)=0; @@ -557,6 +557,8 @@ nprocs = MPI.Comm_size(MPI.COMM_WORLD); end; finalize_global_grid(finalize_MPI=false); end; + + #TODO: add testset with metagrid with origin_on_vertex and center and periodic and origin on the other dimensions. Add missing tests for nx_g etc. including wrap periodic end; ## Test tear down From 8b41b4cea5c20f5c88d8e0a2cb8c7e9c6e688589 Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Wed, 4 Jun 2025 17:07:45 +0200 Subject: [PATCH 29/30] fix Shift Calculations --- src/tools.jl | 72 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index a67d836..b92fbe6 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -147,20 +147,31 @@ julia> finalize_global_grid() x_g(ix::Integer, dx::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_x_g(ix, dx, size(A,1), wrap_periodic) function _x_g(ix::Integer, dx::AbstractFloat, nx_A::Integer, wrap_periodic::Bool, coordx::Integer=@coordx(), dimx::Integer=@dimx()) - nx_g = dimx*(@nx()-@olx()) + @olx()*(@periodx()==0) - haloshiftx = @periodx() ? -dx*@halowidthx() : dx*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dx to the left. - vertexshiftx = @origin_on_vertex() ? dx*0.5 : dx*0.0 - centershiftx = @centerx() ? (@origin_on_vertex() ? -nx_g*dx*0.5 : -(nx_g-1)*dx*0.5) : dx*0.0 - x0_g = @originx() + haloshiftx + vertexshiftx + centershiftx - x0 = 0.5*(@nx()-nx_A)*dx - x = (coordx*(@nx()-@olx()) + ix-1)*dx + x0 + x0_g - if @periodx() && wrap_periodic - if (x > (nx_g-1)*dx) x = x - nx_g*dx; end # It must not be (nx_g()-1)*dx as the distance between the local problems (1*dx) must also be taken into account! - if (x < 0) x = x + nx_g*dx; end # ... + ix_g = _ix_g(ix, nx_A, wrap_periodic, coordx, dimx) + x_g_A = _x_g(dx, nx_A, dimx) + nx_g_A = length(x_g_A) + if (ix_g > nx_g_A) x = x_g_A[end] + dx*(ix_g - nx_g_A) + elseif (ix_g < 1) x = x_g_A[1] - dx*(1 - ix_g) + else x = x_g_A[ix_g] end return x end +function _x_g(dx::T, nx_A::Integer, dimx::Integer=@dimx()) where T <: AbstractFloat + nx_diff = nx_A - @nx() + nx_g = _nx_g(dimx) + lx = @origin_on_vertex() ? dx*nx_g : dx*(nx_g-1) + lx_A = lx + dx*nx_diff + centershiftx = @centerx() ? -lx*T(0.5) : T(0.0) + vertexshiftx = @origin_on_vertex() ? T(0.5) : T(0.0) + localshift = !@periodx() ? -T(nx_diff)*T(0.5) : T(0.0) # The overlap cells at the beginning of the global problem are part of it (except if it is periodic - this case is handled differently...); so, only arrays overlapping the base grid must be shifted to the left. + staggershift = (@periodx() && isodd(nx_diff)) ? -T(0.5) : T(0.0) # In the periodic case, both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the left of the first grid cell, but it could also be on the right instead. + x1_A = @originx() + centershiftx + dx*(vertexshiftx + localshift + staggershift) # dx has been factored out of the last three shifts to reduce the amount of multiplications. + x2_A = x1_A + lx_A + x_g_A = x1_A:dx:x2_A + return x_g_A +end + """ y_g(iy, dy, A) @@ -206,20 +217,31 @@ julia> finalize_global_grid() y_g(iy::Integer, dy::AbstractFloat, A::AbstractArray; wrap_periodic::Bool=true) =_y_g(iy, dy, size(A,2), wrap_periodic) function _y_g(iy::Integer, dy::AbstractFloat, ny_A::Integer, wrap_periodic::Bool, coordy::Integer=@coordy(), dimy::Integer=@dimy()) - ny_g = dimy*(@ny()-@oly()) + @oly()*(@periody()==0) - haloshifty = @periody() ? -dy*@halowidthy() : dy*0.0 # The first cells of the global problem are halo cells; so, all must be shifted by dy to the left. - vertexshifty = @origin_on_vertex() ? dy*0.5 : dy*0.0 - centershifty = @centery() ? (@origin_on_vertex() ? -ny_g*dy*0.5 : -(ny_g-1)*dy*0.5) : dy*0.0 - y0_g = @originy() + haloshifty + vertexshifty + centershifty - y0 = 0.5*(@ny()-ny_A)*dy - y = (coordy*(@ny()-@oly()) + iy-1)*dy + y0 + y0_g - if @periody() && wrap_periodic - if (y > (ny_g-1)*dy) y = y - ny_g*dy; end # It must not be (ny_g()-1)*dy as the distance between the local problems (1*dy) must also be taken into account! - if (y < 0) y = y + ny_g*dy; end # ... + iy_g = _iy_g(iy, ny_A, wrap_periodic, coordy, dimy) + y_g_A = _y_g(dy, ny_A, dimy) + ny_g_A = length(y_g_A) + if (iy_g > ny_g_A) y = y_g_A[end] + dy*(iy_g - ny_g_A) + elseif (iy_g < 1) y = y_g_A[1] - dy*(1 - iy_g) + else y = y_g_A[iy_g] end return y end +function _y_g(dy::T, ny_A::Integer, dimy::Integer=@dimy()) where T <: AbstractFloat + ny_diff = ny_A - @ny() + ny_g = _ny_g(dimy) + ly = @origin_on_vertex() ? dy*ny_g : dy*(ny_g-1) + ly_A = ly + dy*ny_diff + centershifty = @centery() ? -ly*T(0.5) : T(0.0) + vertexshifty = @origin_on_vertex() ? T(0.5) : T(0.0) + localshifty = !@periody() ? -T(ny_diff)*T(0.5) : T(0.0) # The overlap cells at the beginning of the global problem are part of it (except if it is periodic - this case is handled differently...); so, only arrays overlapping the base grid must be shifted to the left. + staggershifty = (@periody() && isodd(ny_diff)) ? -T(0.5) : T(0.0) # In the periodic case, both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the left of the first grid cell, but it could also be on the right instead. + y1_A = @originy() + centershifty + dy*(vertexshifty + localshifty + staggershifty) # dy has been factored out of the last three shifts to reduce the amount of multiplications. + y2_A = y1_A + ly_A + y_g_A = y1_A:dy:y2_A + return y_g_A +end + """ z_g(iz, dz, A) @@ -277,12 +299,12 @@ end function _z_g(dz::T, nz_A::Integer, dimz::Integer=@dimz()) where T <: AbstractFloat nz_diff = nz_A - @nz() - olz_A = @olz() + nz_diff - nz_g_A = _nz_g(nz_A, dimz) - lz_A = @origin_on_vertex() ? dz*nz_g_A : dz*(nz_g_A-1) - centershiftz = @centerz() ? lz_A*T(0.5) : T(0.0) + nz_g = _nz_g(dimz) + lz = @origin_on_vertex() ? dz*nz_g : dz*(nz_g-1) + lz_A = lz + dz*nz_diff + centershiftz = @centerz() ? -lz*T(0.5) : T(0.0) vertexshiftz = @origin_on_vertex() ? T(0.5) : T(0.0) - localshift = !@periodz() ? -T(olz_A)*T(0.5) : T(0.0) # The overlap cells at the beginning of the global problem are part of it except if it is periodic; so, all must be shifted to the left. + localshift = !@periodz() ? -T(nz_diff)*T(0.5) : T(0.0) # The overlap cells at the beginning of the global problem are part of it (except if it is periodic - this case is handled differently...); so, only arrays overlapping the base grid must be shifted to the left. staggershift = (@periodz() && isodd(nz_diff)) ? -T(0.5) : T(0.0) # In the periodic case, both the staggered grid and the grid arrays have the same amount of actual values (as it is a ring... - there is the same amount of vertices as cells); we decide here to put the first value on the left of the first grid cell, but it could also be on the right instead. z1_A = @originz() + centershiftz + dz*(vertexshiftz + localshift + staggershift) # dz has been factored out of the last three shifts to reduce the amount of multiplications. z2_A = z1_A + lz_A From f50d542bd6f682c51994478f261a316cf028d58e Mon Sep 17 00:00:00 2001 From: Samuel Omlin Date: Mon, 7 Jul 2025 19:44:26 +0200 Subject: [PATCH 30/30] adjustfor 1D and 2D --- src/tools.jl | 136 +++++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 59 deletions(-) diff --git a/src/tools.jl b/src/tools.jl index b92fbe6..5000a93 100644 --- a/src/tools.jl +++ b/src/tools.jl @@ -313,6 +313,15 @@ function _z_g(dz::T, nz_A::Integer, dimz::Integer=@dimz()) where T <: AbstractFl end +function _i_g(i::Integer, ii::Integer, di::AbstractFloat, ni_A::Integer, wrap_periodic::Bool, coordi::Integer=@coords()[i], dimi::Integer=@dims()[i]) + if (i==1) _x_g(ii, di, ni_A, wrap_periodic, coordi, dimi) + elseif (i==2) _y_g(ii, di, ni_A, wrap_periodic, coordi, dimi) + elseif (i==3) _z_g(ii, di, ni_A, wrap_periodic, coordi, dimi) + else error("Invalid dimension index $i.") + end +end + + """ ix_g(ix, A) ix_g(ix, A; wrap_periodic) @@ -504,16 +513,27 @@ function _iz_g(iz::Integer, nz_A::Integer, wrap_periodic::Bool, coordz::Integer= end +function _ii_g(i::Integer, ii::Integer, ni_A::Integer, wrap_periodic::Bool, coordi::Integer=@coords()[i], dimi::Integer=@dims()[i]) + if (i==1) _ix_g(ii, ni_A, wrap_periodic, coordi, dimi) + elseif (i==2) _iy_g(ii, ni_A, wrap_periodic, coordi, dimi) + elseif (i==3) _iz_g(ii, ni_A, wrap_periodic, coordi, dimi) + else error("Invalid dimension index $i.") + end +end + + """ - extents(; fix_global_boundaries, coords) extents(A; fix_global_boundaries, coords) - extents(overlaps; fix_global_boundaries, coords) + extents(nxyz; fix_global_boundaries, coords) + extents(; fix_global_boundaries, coords) extents(A, overlaps; fix_global_boundaries, coords) + extents(nxyz, overlaps; fix_global_boundaries, coords) + extents(overlaps; fix_global_boundaries, coords) -Return the local extents in each dimension of the array `A` or the local extents of the base grid if `A` is not provided (return type: tuple of ranges). +Return the local extents in each dimension of the array `A` or of an array of length `nxyz` or the local extents of the base grid with the length `nxyz` (return type: NTuple of ranges with N = ndims(A) or N = ndims(nxyz)). If neither `A` nor `nxyz` is provided, the extents of the base grid are returned as a 3-dimensional tuple of ranges; for 2D grids, it can be preferable to call `extents((nx, ny); ...)` in order to obtain a 2-dimensional tuple; for 1D grids, the analogue is true. # Arguments -- `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid (i.e., the extents are simply the full ranges of the array or of the base grid, respectively). +- `overlaps::Integer`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid (i.e., the extents are simply the full ranges of the array or of the base grid, respectively). # Keyword arguments - `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. @@ -556,44 +576,36 @@ julia> summary(Vx_IO) julia> finalize_global_grid() ``` """ -function extents(; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - extents = (1:@nx(), 1:@ny(), 1:@nz()) - return _adjust_extents(extents, @nxyz(), @ols(), coords, dims, fix_global_boundaries) +function extents(A::AbstractArray{T,N}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where {T,N} + extents(size(A); fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) end -function extents(A::AbstractArray; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - # ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) - ol_A = @ols() .+ (size(A) .- @nxyz()) - extents = (1:size(A,1), 1:size(A,2), 1:size(A,3)) - return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) +function extents(nxyz_A::NTuple{N,Int}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + nxyz_A = (N==1 ? (nxyz_A[1],1,1) : (N==2 ? (nxyz_A[1:2]...,1) : nxyz_A)) + ol_A = @ols() .+ (nxyz_A .- @nxyz()) + extents = (1:nxyz_A[1], 1:nxyz_A[2], 1:nxyz_A[3]) + return _adjust_extents(extents, nxyz_A[1:N], ol_A, coords, dims, fix_global_boundaries) # NOTE: N is used to trigger correct dispatch. end -function extents(overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps - # if (overlaps[1] > @olx()) || (overlaps[2] > @oly()) || (overlaps[3] > @olz()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end - if any(overlaps .> @ols()) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end - # bx, by, bz = (@olx()-overlaps[1]) ÷ 2, (@oly()-overlaps[2]) ÷ 2, (@olz()-overlaps[3]) ÷ 2 - bx, by, bz = (@ols() .- overlaps) .÷ 2 - # ex, ey, ez = cld(@olx()-overlaps[1], 2), cld(@oly()-overlaps[2], 2), cld(@olz()-overlaps[3], 2) - ex, ey, ez = cld.(@ols() .- overlaps, 2) - extents = (1+bx:@nx()-ex, 1+by:@ny()-ey, 1+bz:@nz()-ez) - return _adjust_extents(extents, @nxyz(), @ols(), coords, dims, fix_global_boundaries) +function extents(A::AbstractArray{T,N}, overlaps::Integer; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where {T,N} + extents(size(A), overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) end -function extents(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) +function extents(nxyz_A::NTuple{N,Int}, overlaps::Integer; fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + nxyz_A = (N==1 ? (nxyz_A[1],1,1) : (N==2 ? (nxyz_A[1:2]...,1) : nxyz_A)) overlaps = isa(overlaps, Integer) ? (Int(overlaps), Int(overlaps), Int(overlaps)) : overlaps - # ol_A = @olx() + (size(A,1)-@nx()), @oly() + (size(A,2)-@ny()), @olz() + (size(A,3)-@nz()) - ol_A = @ols() .+ (size(A) .- @nxyz()) - # if (overlaps[1] > ol_A[1]) || (overlaps[2] > ol_A[2]) || (overlaps[3] > ol_A[3]) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end + ol_A = @ols() .+ (nxyz_A .- @nxyz()) if any(overlaps .> ol_A) @ArgumentError("The overlaps chosen cannot be bigger than the actual overlaps on the global grid.") end - # bx, by, bz = (ol_A[1]-overlaps[1]) ÷ 2, (ol_A[2]-overlaps[2]) ÷ 2, (ol_A[3]-overlaps[3]) ÷ 2 bx, by, bz = (ol_A .- overlaps) .÷ 2 - # ex, ey, ez = cld(ol_A[1]-overlaps[1], 2), cld(ol_A[2]-overlaps[2], 2), cld(ol_A[3]-overlaps[3], 2) ex, ey, ez = cld.(ol_A .- overlaps, 2) - extents = (1+bx:size(A,1)-ex, 1+by:size(A,2)-ey, 1+bz:size(A,3)-ez) - return _adjust_extents(extents, size(A), ol_A, coords, dims, fix_global_boundaries) + extents = (1+bx:nxyz_A[1]-ex, 1+by:nxyz_A[2]-ey, 1+bz:nxyz_A[3]-ez) + return _adjust_extents(extents, nxyz_A[1:N], ol_A, coords, dims, fix_global_boundaries) # NOTE: N is used to trigger correct dispatch. end +extents(; kwargs...) = extents(@nxyz(); kwargs...) +extents(overlaps::Integer; kwargs...) = extents(@nxyz(), overlaps; kwargs...) + + # function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) # @show extents # if fix_global_boundaries @@ -614,12 +626,11 @@ end # return extents_new # end -function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) +function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::NTuple{N,Int}, ol_A::Tuple{Int,Int,Int}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}, fix_global_boundaries::Bool) where N + nxyz_A = (N==1 ? (nxyz_A[1],1,1) : (N==2 ? (nxyz_A[1:2]...,1) : nxyz_A)) # NOTE: for simplicity we always treat every case like a 3D case; in this particular case, however, we want to return a tuple with dimensions of the array (or base grid)... Using N here ensures type stability. extents = [extents...] if fix_global_boundaries - # b_g = (ol_A[1] ÷ 2, ol_A[2] ÷ 2, ol_A[3] ÷ 2) b_g = ol_A .÷ 2 - # e_g = (cld(ol_A[1], 2), cld(ol_A[2], 2), cld(ol_A[3], 2)) e_g = cld.(ol_A, 2) for i in 1:3 if @periods()[i] @@ -639,22 +650,25 @@ function _adjust_extents(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{ end end end - return (extents...,) + return (extents[1:N]...,) end + """ - extents_g(; dxyz, fix_global_boundaries, coords) extents_g(A; dxyz, fix_global_boundaries, coords) - extents_g(overlaps; dxyz, fix_global_boundaries, coords) + extents_g(nxyz; dxyz, fix_global_boundaries, coords) + extents_g(; dxyz, fix_global_boundaries, coords) extents_g(A, overlaps; dxyz, fix_global_boundaries, coords) + extents_g(nxyz, overlaps; dxyz, fix_global_boundaries, coords) + extents_g(overlaps; dxyz, fix_global_boundaries, coords) -Return the global extents in each dimension of the array `A` or the global extents of the base grid if `A` is not provided (return type: tuple of ranges); if `dxyz` is set, global Cartesian coordinates extents are returned, else global index extents are returned. +Return the global extents in each dimension of the array `A` or of an array of length `nxyz` or the global extents of the base grid with the length `nxyz` (return type: NTuple of ranges with N = ndims(A) or N = ndims(nxyz)); if `dxyz` is set, global Cartesian coordinates extents are returned, else global index extents are returned. If neither `A` nor `nxyz` is provided, the global extents of the base grid are returned as a 3-dimensional tuple of ranges; for 2D grids, it can be preferable to call `extents_g((nx, ny); ...)` in order to obtain a 2-dimensional tuple; for 1D grids, the analogue is true. # Arguments -- `overlaps::Integer|Tuple{Int,Int,Int}`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid. +- `overlaps::Integer`: the overlap of the "extent" with the neighboring processes' extents in each dimension; the overlaps chosen cannot be bigger than the actual overlaps on the global grid of `A` or of the base grid, respectively. To obtain the extents as required by VTK, set `overlaps=1`. The default is the actual full overlaps on the global grid. # Keyword arguments -- `dxyz::Tuple{AbstractFloat,AbstractFloat,AbstractFloat}`: the space step between the elements in each dimension if global Cartesian coordinates are desired. +- `dxyz::NTuple{N, AbstractFloat}`: the space step between the elements in each dimension if global Cartesian coordinates are desired. - `fix_global_boundaries::Bool=true`: by default, the extents are fixed at the global boundaries to include them on all sides (attention, the extents are not of equal size for all processes in this case). If `fix_global_boundaries=false`, the extents are not fixed at the global boundaries and the size of the extents is equal for all processes. - `coords::Tuple{Int,Int,Int}`: the coordinates of the process for which the global extents is requested. The default is the coordinates of the current process. @@ -700,36 +714,40 @@ julia> extents_g(1; dxyz=(dx, dy, dz)) # The Cartesian coordinates corresponding julia> finalize_global_grid() ``` """ -function extents_g(; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - extents_l = extents(; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, @nxyz(), dxyz, coords, dims) +function extents_g(A::AbstractArray{T,N}; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where {T,N} + extents_g(size(A); dxyz=dxyz, fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) +end + +function extents_g(nxyz_A::NTuple{N,Int}; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + extents_l = extents(nxyz_A; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) + return extents_g(extents_l, nxyz_A, dxyz, coords, dims) +end + +function extents_g(A::AbstractArray{T,N}, overlaps::Integer; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where {T,N} + extents_g(size(A), overlaps; dxyz=dxyz, fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) end -function extents_g(A::AbstractArray; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - extents_l = extents(A; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, size(A), dxyz, coords, dims) +function extents_g(nxyz_A::NTuple{N,Int}, overlaps::Integer; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + extents_l = extents(nxyz_A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) + return extents_g(extents_l, nxyz_A, dxyz, coords, dims) end -function extents_g(overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - extents_l = extents(overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, @nxyz(), dxyz, coords, dims) +function extents_g(extents::NTuple{N,UnitRange{Int}}, nxyz_A::NTuple{N,Int}, dxyz::Nothing, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) where N + return ntuple(i -> _ii_g(i, first(extents[i]), nxyz_A[i], false, coords[i], dims[i]) : _ii_g(i, last(extents[i]), nxyz_A[i], false, coords[i], dims[i]), Val(N)) end -function extents_g(A::AbstractArray, overlaps::Union{Integer,Tuple{Int,Int,Int}}; dxyz::Union{Nothing,Tuple{AbstractFloat,AbstractFloat,AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) - extents_l = extents(A, overlaps; fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) - return extents_g(extents_l, size(A), dxyz, coords, dims) +function extents_g(extents::NTuple{N,UnitRange{Int}}, nxyz_A::NTuple{N,Int}, dxyz::NTuple{N,AbstractFloat}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) where N + return ntuple(i -> (_i_g(i, first(extents[i]), dxyz[i], nxyz_A[i], false, coords[i], dims[i]) : dxyz[i] : _i_g(i, last(extents[i]), dxyz[i], nxyz_A[i], false, coords[i], dims[i])), Val(N)) end -function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Nothing, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) - return (_ix_g(first(extents[1]), nxyz_A[1], false, coords[1], dims[1]) : _ix_g(last(extents[1]), nxyz_A[1], false, coords[1], dims[1]), - _iy_g(first(extents[2]), nxyz_A[2], false, coords[2], dims[2]) : _iy_g(last(extents[2]), nxyz_A[2], false, coords[2], dims[2]), - _iz_g(first(extents[3]), nxyz_A[3], false, coords[3], dims[3]) : _iz_g(last(extents[3]), nxyz_A[3], false, coords[3], dims[3])) +function extents_g(; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + if (!isnothing(dxyz) && N != 3) error("extents_g(;...) returns a 3-dimensional tuple of ranges, but you provided a $N-dimensional dxyz. Please use extents_g((nx, ny); ...) instead to obtain a 2-dimensional tuple of ranges or extents_g((nx,); ...) to obtain a 1-dimensional tuple of ranges.") end + extents_g(@nxyz(); dxyz=dxyz, fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) end -function extents_g(extents::Tuple{UnitRange{Int},UnitRange{Int},UnitRange{Int}}, nxyz_A::Tuple{Int,Int,Int}, dxyz::Tuple{AbstractFloat,AbstractFloat,AbstractFloat}, coords::Tuple{Int,Int,Int}, dims::Tuple{Int,Int,Int}) - return (_x_g(first(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]) : dxyz[1] : _x_g(last(extents[1]), dxyz[1], nxyz_A[1], false, coords[1], dims[1]), - _y_g(first(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]) : dxyz[2] : _y_g(last(extents[2]), dxyz[2], nxyz_A[2], false, coords[2], dims[2]), - _z_g(first(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3]) : dxyz[3] : _z_g(last(extents[3]), dxyz[3], nxyz_A[3], false, coords[3], dims[3])) +function extents_g(overlaps::Integer; dxyz::Union{Nothing,NTuple{N, AbstractFloat}}=nothing, fix_global_boundaries::Bool=true, coords::Tuple{Int,Int,Int}=@coords(), dims::Tuple{Int,Int,Int}=@dims()) where N + if (!isnothing(dxyz) && N != 3) error("extents_g(overlaps;...) returns a 3-dimensional tuple of ranges, but you provided a $N-dimensional dxyz. Please use extents_g((nx, ny), overlaps; ...) instead to obtain a 2-dimensional tuple of ranges or extents_g((nx,), overlaps; ...) to obtain a 1-dimensional tuple of ranges.") end + extents_g(@nxyz(), overlaps; dxyz=dxyz, fix_global_boundaries=fix_global_boundaries, coords=coords, dims=dims) end