comparison src/Grids/equidistant_grid.jl @ 1143:9275d95e2d90 refactor/grids

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