-
Notifications
You must be signed in to change notification settings - Fork 24
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
GridVariable3D, 4D; SpectralVariable3D, 4D #493
base: main
Are you sure you want to change the base?
Conversation
I've just Base.@propagate_inbounds Base.getindex(S::SpectralVariable4D, i::Integer, j::Integer, k::Integer, t::Integer) = S.data[k, t][i, j] which I believe is correct because then all boundschecks are just done for the underlying vectors/matrices in there, or not at all with |
k::Integer, | ||
) where NF | ||
npoints2D = RingGrids.get_npoints(Grid, nlat_half) | ||
G3D = [zeros(Grid, nlat_half) for _ in 1:k] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it more convenient to have a vector of vectors rather than a two-dimensional vector?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
G3D here is a vector of vectors because the two horizontal dimensions of grid are unraveled because of our reduced grids that cannot be written as matrix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So every grid is ::AbstractVector not Matrix even though it represents a 2D field
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is also primarily thought for the upcoming GPU version, right?
To be honest, I am also not certain 100% yet how exactly to do it right either, and I would need to do some tests for it, but I am not so sure, the GridVariable3D
, etc is the way to go.
You are implementing all structures as Vector
of Vectors
/CuArrays
. The outer Vector
is then a CPU array with pointers to the other Vectors
/CuArrays
that are likely to not be contiguous in memory. Intuitively, this doesn't seem ideal to me, and possibly detrimental to future GPU performance. Again, I only have a bit half-knowledge here, and didn't do some proper tests.
The alternative that I see, is to really make all low-level implementations of AbstractGrid
and LowerTriangularMatrix
N dimensional. I do think that this is actually reasonable easy to do, as you can just pass on any trailing indices during indexing. Like a grid then becoming
struct MyNewGrid{T,N,A<:AbstractArray} <: AbstractGridClass{T}
data::A{T,N}
nlat_half::Int # resolution: latitude rings on one hemisphere (Equator incl)
end
@inline function Base.getindex(G::AbstractGrid, k::Integer, I...) # something like this
@boundscheck 0 < k <= length(G.data) || throw(BoundsError(G, k))
# add another boundscheck for dimension here
@inbounds r = getindex(G.data, k, I)
return r
end
The advantage I see when It also means that you can more easily reuse the internal functions and expose them to the user. If our spectral transforms are only defined between |
Yes, but also generally to index variables simply as |
I think avoiding allocations from indexing the N-dimensional isn't really that hard, if it's properly tested. I admit, that I am also sometimes a bit confused when Julia allocates something and when not, but we can definitely set it up in a way that that's not the case, and could also set up convenience functions like The more I think about it, the more I like the idea of just having N-dimensional Grid and LowerTriangularMatrix. It makes sure everything is contigous in memory, which (at least for GPU) I am almost certain will be an advantage for the performance, especially if we want to write kernels over the layer dimension as well. It would also make the code basis smaller and introduce less new types. You'd just have |
So here I've defined
meaning that performance-related, we'd really only care about the 3D cases, the We could write everything for the 3D structs using |
Absolutely! That's also why I was directly asking whether this is primarily for the GPU version, because this is something that should work for it as well then.
I was thinking that exactly this is actually a major part of making the model GPU compatible, as the old structure isn't really ideally suited for it, and possibly should be done together with writing the actual GPU kernels. At least I think it would also save a lot of work to only do it once it that regard as well. |
Yes, it should be reasonably future-proof restructuring for GPU and I believe we can still do the current multi-threading by writing the kernels as I think we need to make a better informed decision by benchmarking. Once we just use the indexing as outlined above, it's just a matter of redefining |
Yes, the beauty of Julia is that you can really manipulate all of those things and implement it in this very generic way. I am just not sure if we (or you) really want to invest this time now, or not wait until we tackle the full GPU implementation. And for the full GPU implementation I'd still go bottom to top and start with the most low-level parts, because this allows us to actually test things on GPU as we go. |
Sure, when do you want to start 😉 |
Just had a call with @maximilian-gelbrecht we concluded the following
struct FullGaussianND{Eltype, Ndims, ArrayType} <: AbstractArray{Eltype,Ndims}
data::ArrayType{Eltype,Ndims}
nlat_half::Int # resolution parameter for grids
rings::ArrayType{UnitRange{Int},1} # precalculated vector for indexing rings, e.g. [1:20, 21:44,...]
end
# current FullGaussianGrid would be a subtype
FullGaussianGrid{T} = FullGaussianND{T, 1, Vector}
|
New I'd really like instead of this (currently) humid = simulation.diagnostic_variables.layers[end].grid_variables.humid_grid this to work humid = simulation.diagnostic_variables.grid.humid[:,end] returning surface humidity as |
This introduces
GridVariable3D
,GridVariable4D
,SpectralVariable3D
,SpectralVariable4D
, four types that extend the horizontal grids and horizontalLowerTriangularMatrices
for the spherical harmonics in 1-2 dimensions. At the moment we still have a layer-oriented structure which puts the layer on the outside, i.e. we have dimensions currently structured like (x, y for grids, technically xy as they only have one index, or equivalently l, m for spectral)but I think we want for the future (an GPUs)
Now one can create a
GridVariable3D
(88 grid points, 5 layers) asa
GridVariable4D
similarly (88 grid points, 5 layers, 2 timesteps)a
SpectralVariable3D
similarly (3x3 LowerTriangularMatrix with 2 layers)or a
SpectralVariable4D
3x3 LowerTriangularMatrix with 2 layers and 1 timestep