ProjectTorreyPines / ProjectTorreyPines/IMASdd.jl
Allow getproperty, setproperty, getindex, and setindex on vectors of IDS
Nobody has claimed this yet.
- Dominant language
- Julia
- Stars
- 9
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
Use case
ids.edge_profiles.ggd is the array of ggd element with each representing a time step. So if I want a property value on 5th time step, I need to do: ids.edge_profiles.ggd[5].electrons.density[1].values. However, if the want that property values for all teh time steps, I will need to run a for loop because I can not do ids.edge_profiles.ggd[:].electrons.density[1].values.
This motivated me to think of some feature request for overloading getproperty, setproperty, getindex and setindex to operate over arrays of IDS objects so that we can access these quantities in a similar way they are descibed on OMAS Schema page
Feature request
I am not sure how to describe the request best other than to show some example. If you run the following in julia REPL or notebook, it will show you what I mean:
using Pkg
Pkg.activate(".")
Pkg.add(; url="git@github.com:ProjectTorreyPines/IMASDD.jl.git", rev="master")
Pkg.instantiate()
using IMASDD: IMASDD
function Base.getproperty(vec::Vector{T}, field::Symbol) where {T<:IMASDD.IDS}
if fieldtype(eltype(vec), field) <: AbstractArray{U} where {U<:Real}
println(" (1.1 Using getproperty(vec::Vector{T}, field::Symbol) for vector fields)")
return mapreduce(permutedims, vcat, getfield.(vec, field))
else
println(" (1.2 Using getproperty(vec::Vector{T}, field::Symbol)")
return getfield.(vec, field)
end
end
function Base.getproperty(vec::Matrix{T}, field::Symbol) where {T<:IMASDD.IDS}
if fieldtype(eltype(vec), field) <: AbstractArray{U} where {U<:Real}
println(" (2.1 Using getproperty(vec::Matrix{T}, field::Symbol) for vector fields)")
return permutedims(stack(getfield.(vec, field)), [2, 3, 1])
else
println(" (2.2 Using getproperty(vec::Matrix{T}, field::Symbol)")
return getfield.(vec, field)
end
end
function Base.getindex(vec::Vector{T}, iter::Colon, I_2::Int) where {T<:IMASDD.IDSvector{U}} where {U<:IMASDD.IDSvectorElement}
println(" (3.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))")
return getindex.(vec, I_2)
end
function Base.getindex(vec::Vector{T}, iter::Colon, iter2::Colon) where {T<:IMASDD.IDSvector{U}} where {U<:IMASDD.IDSvectorElement}
println(" (4.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))")
return mapreduce(permutedims, vcat, [ids_vec for ids_vec in vec])
end
Let's define a small IDS with some edge_profiles data. Ideally, even this step would become free of for loops if setproperty and setindex are overloaded properly:
ids = IMASDD.dd();
resize!(ids.edge_profiles.ggd, 5)
for epggd in ids.edge_profiles.ggd
resize!(epggd.electrons.density, 2)
epggd.electrons.density[1].values = zeros(3)
epggd.electrons.density[2].values = ones(3)
epggd.electrons.density[1].grid_subset_index = 1
epggd.electrons.density[2].grid_subset_index = 2
end
julia> ids.edge_profiles.ggd
ggd
├─ 1
│ └─ electrons
│ └─ density
│ ├─ 1
│ │ ├─ grid_subset_index ➡ 1
│ │ └─ values ➡ [0,0,0] [m^-3]
│ └─ 2
│ ├─ grid_subset_index ➡ 2
│ └─ values ➡ [1,1,1] [m^-3]
├─ 2
│ └─ electrons
│ └─ density
│ ├─ 1
│ │ ├─ grid_subset_index ➡ 1
│ │ └─ values ➡ [0,0,0] [m^-3]
│ └─ 2
│ ├─ grid_subset_index ➡ 2
│ └─ values ➡ [1,1,1] [m^-3]
├─ 3
│ └─ electrons
│ └─ density
│ ├─ 1
│ │ ├─ grid_subset_index ➡ 1
│ │ └─ values ➡ [0,0,0] [m^-3]
│ └─ 2
│ ├─ grid_subset_index ➡ 2
│ └─ values ➡ [1,1,1] [m^-3]
├─ 4
│ └─ electrons
│ └─ density
│ ├─ 1
│ │ ├─ grid_subset_index ➡ 1
│ │ └─ values ➡ [0,0,0] [m^-3]
│ └─ 2
│ ├─ grid_subset_index ➡ 2
│ └─ values ➡ [1,1,1] [m^-3]
└─ 5
└─ electrons
└─ density
├─ 1
│ ├─ grid_subset_index ➡ 1
│ └─ values ➡ [0,0,0] [m^-3]
└─ 2
├─ grid_subset_index ➡ 2
└─ values ➡ [1,1,1] [m^-3]
Now let's try to access values inside ggd array without specifying an index but giving a colon to emphasize that it is a vector.
julia> ids.edge_profiles.ggd[:].electrons.density
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
5-element Vector{IMASDD.IDSvector{IMASDD.edge_profiles__ggd___electrons__density{Float64}}}:
edge_profiles.ggd[1].electrons.density[1...2]
edge_profiles.ggd[2].electrons.density[1...2]
edge_profiles.ggd[3].electrons.density[1...2]
edge_profiles.ggd[4].electrons.density[1...2]
edge_profiles.ggd[5].electrons.density[1...2]
One can do further indexing as if it is a 2-D array
julia> ids.edge_profiles.ggd[:].electrons.density[:, 1]
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(3.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))
5-element Vector{IMASDD.edge_profiles__ggd___electrons__density{Float64}}:
edge_profiles.ggd[1].electrons.density[1]{grid_subset_index, values}
edge_profiles.ggd[2].electrons.density[1]{grid_subset_index, values}
edge_profiles.ggd[3].electrons.density[1]{grid_subset_index, values}
edge_profiles.ggd[4].electrons.density[1]{grid_subset_index, values}
edge_profiles.ggd[5].electrons.density[1]{grid_subset_index, values}
One can do further getpropert and get a stacked matrix:
julia> ids.edge_profiles.ggd[:].electrons.density[:, 1].values
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(3.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))
(1.1 Using getproperty(vec::Vector{T}, field::Symbol) for vector fields)
5×3 Matrix{Float64}:
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
0.0 0.0 0.0
One can also get matrix of all sub-IDS objects by using the conventional [:, :]
julia> ids.edge_profiles.ggd[:].electrons.density[:, :]
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(4.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))
5×2 Matrix{IMASDD.edge_profiles__ggd___electrons__density{Float64}}:
edge_profiles.ggd[1].electrons.density[1]{grid_subset_index, values} … edge_profiles.ggd[1].electrons.density[2]{grid_subset_index, values}
edge_profiles.ggd[2].electrons.density[1]{grid_subset_index, values} edge_profiles.ggd[2].electrons.density[2]{grid_subset_index, values}
edge_profiles.ggd[3].electrons.density[1]{grid_subset_index, values} edge_profiles.ggd[3].electrons.density[2]{grid_subset_index, values}
edge_profiles.ggd[4].electrons.density[1]{grid_subset_index, values} edge_profiles.ggd[4].electrons.density[2]{grid_subset_index, values}
edge_profiles.ggd[5].electrons.density[1]{grid_subset_index, values} edge_profiles.ggd[5].electrons.density[2]{grid_subset_index, values}
One can access a field of a matrix of IDS if the field values have the same dimensions, returning a higher dimensional array:
julia> ids.edge_profiles.ggd[:].electrons.density[:, :].values
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(4.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))
(2.1 Using getproperty(vec::Matrix{T}, field::Symbol) for vector fields)
5×2×3 Array{Float64, 3}:
[:, :, 1] =
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
[:, :, 2] =
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
[:, :, 3] =
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
0.0 1.0
Or same dimensions if the value is just a scalar
julia> ids.edge_profiles.ggd[:].electrons.density[:, :].grid_subset_index
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(1.2 Using getproperty(vec::Vector{T}, field::Symbol)
(4.0 Using getindex(vec::Vector{T}, iter::Colon, I_2::Int))
(2.2 Using getproperty(vec::Matrix{T}, field::Symbol)
5×2 Matrix{Int64}:
1 2
1 2
1 2
1 2
1 2
So I hope this gives the idea of the kind of feature I am requesting. Infact, for getproperty and getindex, I am already content with the 4 functions I defined above. But I might be missing nuances about speed, allocations, and interference with other use cases while writing these functions. I believe similar functionality can be given to setproperty and setindex too, but I think that is more complex. If you all think this is worth exploring and someone has time, we should get these features. I'd be happy to help in any way I can to this effort.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the Julia REPL examples and the proposed Base.getproperty, Base.getindex, setproperty, and setindex entry points for vectors and matrices of IMASDD.IDS objects. Review the IDSvector and IDSvectorElement cases shown in the issue, then define and validate behavior for chained property access, scalar and array fields, and assignment. Done means the demonstrated ggd[:].electrons.density access patterns work without manual loops.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- julia
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 28/100