Mercurial > repos > public > sbplib_julia
comparison src/Grids/equidistant_grid.jl @ 1222:5f677cd6f0b6 refactor/grids
Start refactoring
| author | Jonatan Werpers <jonatan@werpers.com> |
|---|---|
| date | Sat, 18 Feb 2023 11:37:35 +0100 |
| parents | 50b008d2e937 |
| children | 2abec782cf5b |
comparison
equal
deleted
inserted
replaced
| 1221:b3b4d29b46c3 | 1222:5f677cd6f0b6 |
|---|---|
| 1 struct EquidistantGrid{T,R<:AbstractRange{T}} <: Grid{T,1,1} | |
| 2 points::R | |
| 3 end | |
| 4 | |
| 5 Base.eltype(g::EquidistantGrid{T}) where T = T | |
| 6 Base.getindex(g::EquidistantGrid, i) = g.points[i] | |
| 7 Base.size(g::EquidistantGrid) = size(g.points) | |
| 8 Base.length(g::EquidistantGrid) = length(g.points) | |
| 9 Base.eachindex(g::EquidistantGrid) = eachindex(g.points) | |
| 10 | |
| 11 # TODO: Make sure collect works! | |
| 12 | |
| 13 | |
| 1 """ | 14 """ |
| 2 EquidistantGrid{Dim,T<:Real} <: Grid | 15 spacing(grid::EquidistantGrid) |
| 3 | 16 |
| 4 `Dim`-dimensional equidistant grid with coordinates of type `T`. | 17 The spacing between grid points. |
| 5 """ | 18 """ |
| 6 struct EquidistantGrid{Dim,T<:Real} <: Grid | 19 spacing(g::EquidistantGrid) = step(g.points) |
| 7 size::NTuple{Dim, Int} | |
| 8 limit_lower::NTuple{Dim, T} | |
| 9 limit_upper::NTuple{Dim, T} | |
| 10 | 20 |
| 11 function EquidistantGrid{Dim,T}(size::NTuple{Dim, Int}, limit_lower::NTuple{Dim, T}, limit_upper::NTuple{Dim, T}) where {Dim,T} | 21 |
| 12 if any(size .<= 0) | 22 """ |
| 13 throw(DomainError("all components of size must be postive")) | 23 inverse_spacing(grid::EquidistantGrid) |
| 14 end | 24 |
| 15 if any(limit_upper.-limit_lower .<= 0) | 25 The reciprocal of the spacing between grid points. |
| 16 throw(DomainError("all side lengths must be postive")) | 26 """ |
| 17 end | 27 inverse_spacing(g::EquidistantGrid) = 1/step(g.points) |
| 18 return new{Dim,T}(size, limit_lower, limit_upper) | 28 |
| 19 end | 29 |
| 30 boundary_identifiers(::EquidistantGrid) = (Lower(), Upper()) | |
| 31 boundary_grid(g::EquidistantGrid, id::Lower) = ZeroDimGrid(g[begin]) | |
| 32 boundary_grid(g::EquidistantGrid, id::Upper) = ZeroDimGrid(g[end]) | |
| 33 | |
| 34 | |
| 35 """ | |
| 36 refine(g::EquidistantGrid, r::Int) | |
| 37 | |
| 38 Refines `grid` by a factor `r`. The factor is applied to the number of | |
| 39 intervals which is 1 less than the size of the grid. | |
| 40 | |
| 41 See also: [`coarsen`](@ref) | |
| 42 """ | |
| 43 function refine(g::EquidistantGrid, r::Int) | |
| 44 new_sz = (length(g) - 1)*r + 1 | |
| 45 return EquidistantGrid(change_length(g.points, new_sz)) | |
| 20 end | 46 end |
| 21 | 47 |
| 22 """ | 48 """ |
| 23 EquidistantGrid(size, limit_lower, limit_upper) | 49 coarsen(grid::EquidistantGrid, r::Int) |
| 50 | |
| 51 Coarsens `grid` by a factor `r`. The factor is applied to the number of | |
| 52 intervals which is 1 less than the size of the grid. If the number of | |
| 53 intervals are not divisible by `r` an error is raised. | |
| 54 | |
| 55 See also: [`refine`](@ref) | |
| 56 """ | |
| 57 function coarsen(g::EquidistantGrid, r::Int) | |
| 58 if (length(g)-1)%r != 0 | |
| 59 throw(DomainError(r, "Size minus 1 must be divisible by the ratio.")) | |
| 60 end | |
| 61 | |
| 62 new_sz = (length(g) - 1)÷r + 1 | |
| 63 | |
| 64 return EquidistantGrid(change_length(g.points), new_sz) | |
| 65 end | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 | |
| 72 | |
| 73 """ | |
| 74 equidistant_grid(size::Dims, limit_lower, limit_upper) | |
| 24 | 75 |
| 25 Construct an equidistant grid with corners at the coordinates `limit_lower` and | 76 Construct an equidistant grid with corners at the coordinates `limit_lower` and |
| 26 `limit_upper`. | 77 `limit_upper`. |
| 27 | 78 |
| 28 The length of the domain sides are given by the components of | 79 The length of the domain sides are given by the components of |
| 30 as `(-1,1)x(0,2)`. The side lengths of the grid are not allowed to be negative. | 81 as `(-1,1)x(0,2)`. The side lengths of the grid are not allowed to be negative. |
| 31 | 82 |
| 32 The number of equidistantly spaced points in each coordinate direction are given | 83 The number of equidistantly spaced points in each coordinate direction are given |
| 33 by the tuple `size`. | 84 by the tuple `size`. |
| 34 """ | 85 """ |
| 35 function EquidistantGrid(size, limit_lower, limit_upper) | 86 function equidistant_grid(size::Dims, limit_lower, limit_upper) |
| 36 return EquidistantGrid{length(size), eltype(limit_lower)}(size, limit_lower, limit_upper) | 87 gs = map(size, limit_lower, limit_upper) do s,l,u |
| 37 end | 88 EquidistantGrid(range(l, u, length=s)) # TBD: Should it use LinRange instead? |
| 89 end | |
| 38 | 90 |
| 39 """ | 91 return TensorGrid(gs...) |
| 40 EquidistantGrid{T}() | |
| 41 | |
| 42 Constructs a 0-dimensional grid. | |
| 43 """ | |
| 44 EquidistantGrid{T}() where T = EquidistantGrid{0,T}((),(),()) # Convenience constructor for 0-dim grid | |
| 45 | |
| 46 | |
| 47 """ | |
| 48 EquidistantGrid(size::Int, limit_lower::T, limit_upper::T) | |
| 49 | |
| 50 Convenience constructor for 1D grids. | |
| 51 """ | |
| 52 function EquidistantGrid(size::Int, limit_lower::T, limit_upper::T) where T | |
| 53 return EquidistantGrid((size,),(limit_lower,),(limit_upper,)) | |
| 54 end | |
| 55 | |
| 56 Base.eltype(grid::EquidistantGrid{Dim,T}) where {Dim,T} = T | |
| 57 | |
| 58 Base.eachindex(grid::EquidistantGrid) = CartesianIndices(grid.size) | |
| 59 | |
| 60 Base.size(g::EquidistantGrid) = g.size | |
| 61 | |
| 62 Base.ndims(::EquidistantGrid{Dim}) where Dim = Dim | |
| 63 | |
| 64 function Base.getindex(g::EquidistantGrid, I::Vararg{Int}) | |
| 65 h = spacing(g) | |
| 66 return g.limit_lower .+ (I.-1).*h | |
| 67 end | |
| 68 | |
| 69 Base.getindex(g::EquidistantGrid, I::CartesianIndex) = g[Tuple(I)...] | |
| 70 | |
| 71 # Review: | |
| 72 # Is it not strange that evalOn(::Grid) is non-lazy while evalOn(::EquidistantGrid) is? | |
| 73 # Also: Change name to evalon or eval_on!!!!!! | |
| 74 function evalOn(grid::EquidistantGrid, f::Function) | |
| 75 F(I...) = f(grid[I...]...) | |
| 76 | |
| 77 return LazyFunctionArray(F, size(grid)) | |
| 78 end | |
| 79 | |
| 80 """ | |
| 81 spacing(grid::EquidistantGrid) | |
| 82 | |
| 83 The spacing between grid points. | |
| 84 """ | |
| 85 spacing(grid::EquidistantGrid) = (grid.limit_upper.-grid.limit_lower)./(grid.size.-1) | |
| 86 | |
| 87 | |
| 88 """ | |
| 89 inverse_spacing(grid::EquidistantGrid) | |
| 90 | |
| 91 The reciprocal of the spacing between grid points. | |
| 92 """ | |
| 93 inverse_spacing(grid::EquidistantGrid) = 1 ./ spacing(grid) | |
| 94 | |
| 95 | |
| 96 """ | |
| 97 points(grid::EquidistantGrid) | |
| 98 | |
| 99 The point of the grid as an array of tuples with the same dimension as the grid. | |
| 100 The points are stored as [(x1,y1), (x1,y2), … (x1,yn); | |
| 101 (x2,y1), (x2,y2), … (x2,yn); | |
| 102 ⋮ ⋮ ⋮ | |
| 103 (xm,y1), (xm,y2), … (xm,yn)] | |
| 104 """ | |
| 105 function points(grid::EquidistantGrid) | |
| 106 indices = Tuple.(CartesianIndices(grid.size)) | |
| 107 h = spacing(grid) | |
| 108 return broadcast(I -> grid.limit_lower .+ (I.-1).*h, indices) | |
| 109 end | |
| 110 | |
| 111 """ | |
| 112 restrict(::EquidistantGrid, dim) | |
| 113 | |
| 114 Pick out given dimensions from the grid and return a grid for them. | |
| 115 """ | |
| 116 function restrict(grid::EquidistantGrid, dim) | |
| 117 size = grid.size[dim] | |
| 118 limit_lower = grid.limit_lower[dim] | |
| 119 limit_upper = grid.limit_upper[dim] | |
| 120 | |
| 121 return EquidistantGrid(size, limit_lower, limit_upper) | |
| 122 end | 92 end |
| 123 | 93 |
| 124 | 94 |
| 125 """ | 95 """ |
| 126 orthogonal_dims(grid::EquidistantGrid,dim) | 96 equidistant_grid(size::Int, limit_lower::T, limit_upper::T) |
| 127 | 97 |
| 128 Returns the dimensions of grid orthogonal to that of dim. | 98 Constructs a 1D equidistant grid. |
| 129 """ | 99 """ |
| 130 function orthogonal_dims(grid::EquidistantGrid, dim) | 100 function equidistant_grid(size::Int, limit_lower::T, limit_upper::T) where T |
| 131 orth_dims = filter(i -> i != dim, dims(grid)) | 101 return equidistant_grid((size,),(limit_lower,),(limit_upper,)) |
| 132 if orth_dims == dims(grid) | |
| 133 throw(DomainError(string("dimension ",string(dim)," not matching grid"))) | |
| 134 end | |
| 135 return orth_dims | |
| 136 end | 102 end |
| 137 | 103 |
| 138 | 104 |
| 139 """ | |
| 140 boundary_identifiers(::EquidistantGrid) | |
| 141 | |
| 142 Returns a tuple containing the boundary identifiers for the grid, stored as | |
| 143 (CartesianBoundary(1,Lower), | |
| 144 CartesianBoundary(1,Upper), | |
| 145 CartesianBoundary(2,Lower), | |
| 146 ...) | |
| 147 """ | |
| 148 boundary_identifiers(g::EquidistantGrid) = (((ntuple(i->(CartesianBoundary{i,Lower}(),CartesianBoundary{i,Upper}()),ndims(g)))...)...,) | |
| 149 | |
| 150 | 105 |
| 151 """ | 106 """ |
| 152 boundary_grid(grid::EquidistantGrid, id::CartesianBoundary) | 107 change_length(::AbstractRange, n) |
| 153 | 108 |
| 154 Creates the lower-dimensional restriciton of `grid` spanned by the dimensions | 109 Change the length of a range to `n`, keeping the same start and stop. |
| 155 orthogonal to the boundary specified by `id`. The boundary grid of a 1-dimensional | |
| 156 grid is a zero-dimensional grid. | |
| 157 """ | 110 """ |
| 158 function boundary_grid(grid::EquidistantGrid, id::CartesianBoundary) | 111 function change_length(::AbstractRange, n) end |
| 159 orth_dims = orthogonal_dims(grid, dim(id)) | |
| 160 return restrict(grid, orth_dims) | |
| 161 end | |
| 162 boundary_grid(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = EquidistantGrid{T}() | |
| 163 | 112 |
| 164 | 113 change_length(r::LinRange, n) = LinRange(r[begin], r[end], n) |
| 165 """ | 114 change_length(r::StepRangeLen, n) = range(r[begin], r[end], n) |
| 166 refine(grid::EquidistantGrid, r::Int) | 115 # TODO: Test the above |
| 167 | |
| 168 Refines `grid` by a factor `r`. The factor is applied to the number of | |
| 169 intervals which is 1 less than the size of the grid. | |
| 170 | |
| 171 See also: [`coarsen`](@ref) | |
| 172 """ | |
| 173 function refine(grid::EquidistantGrid, r::Int) | |
| 174 sz = size(grid) | |
| 175 new_sz = (sz .- 1).*r .+ 1 | |
| 176 return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper) | |
| 177 end | |
| 178 | |
| 179 | |
| 180 """ | |
| 181 coarsen(grid::EquidistantGrid, r::Int) | |
| 182 | |
| 183 Coarsens `grid` by a factor `r`. The factor is applied to the number of | |
| 184 intervals which is 1 less than the size of the grid. If the number of | |
| 185 intervals are not divisible by `r` an error is raised. | |
| 186 | |
| 187 See also: [`refine`](@ref) | |
| 188 """ | |
| 189 function coarsen(grid::EquidistantGrid, r::Int) | |
| 190 sz = size(grid) | |
| 191 | |
| 192 if !all(n -> (n % r == 0), sz.-1) | |
| 193 throw(DomainError(r, "Size minus 1 must be divisible by the ratio.")) | |
| 194 end | |
| 195 | |
| 196 new_sz = (sz .- 1).÷r .+ 1 | |
| 197 | |
| 198 return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper) | |
| 199 end |
