comparison src/Grids/equidistant_grid.jl @ 1116:c2d7e940639e feature/grids

Rename AbstractGrid to Grid and clean up Grids module
author Vidar Stiernström <vidar.stiernstrom@it.uu.se>
date Fri, 15 Jul 2022 09:54:15 +0200
parents src/Grids/EquidistantGrid.jl@6530fceef37c
children 832ac87a54a3
comparison
equal deleted inserted replaced
1115:6530fceef37c 1116:c2d7e940639e
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 """
25 EquidistantGrid(size, limit_lower, limit_upper)
26
27 Construct an equidistant grid with corners at the coordinates `limit_lower` and
28 `limit_upper`.
29
30 The length of the domain sides are given by the components of
31 `limit_upper-limit_lower`. E.g for a 2D grid with `limit_lower=(-1,0)` and `limit_upper=(1,2)` the domain is defined
32 as `(-1,1)x(0,2)`. The side lengths of the grid are not allowed to be negative.
33
34 The number of equidistantly spaced points in each coordinate direction are given
35 by the tuple `size`.
36 """
37 function EquidistantGrid(size, limit_lower, limit_upper)
38 return EquidistantGrid{length(size), eltype(limit_lower)}(size, limit_lower, limit_upper)
39 end
40
41
42 """
43 EquidistantGrid{T}()
44
45 Constructs a 0-dimensional grid.
46 """
47 EquidistantGrid{T}() where T = EquidistantGrid{0,T}((),(),()) # Convenience constructor for 0-dim grid
48
49
50 """
51 EquidistantGrid(size::Int, limit_lower::T, limit_upper::T)
52
53 Convenience constructor for 1D grids.
54 """
55 function EquidistantGrid(size::Int, limit_lower::T, limit_upper::T) where T
56 return EquidistantGrid((size,),(limit_lower,),(limit_upper,))
57 end
58
59 Base.eltype(grid::EquidistantGrid{Dim,T}) where {Dim,T} = T
60
61 Base.eachindex(grid::EquidistantGrid) = CartesianIndices(grid.size)
62
63 Base.size(g::EquidistantGrid) = g.size
64
65
66 """
67 dim(grid::EquidistantGrid)
68
69 The dimension of the grid.
70 """
71 dim(::EquidistantGrid{Dim}) where Dim = Dim
72
73
74 """
75 spacing(grid::EquidistantGrid)
76
77 The spacing between grid points.
78 """
79 spacing(grid::EquidistantGrid) = (grid.limit_upper.-grid.limit_lower)./(grid.size.-1)
80
81
82 """
83 inverse_spacing(grid::EquidistantGrid)
84
85 The reciprocal of the spacing between grid points.
86 """
87 inverse_spacing(grid::EquidistantGrid) = 1 ./ spacing(grid)
88
89
90 """
91 points(grid::EquidistantGrid)
92
93 The point of the grid as an array of tuples with the same dimension as the grid.
94 The points are stored as [(x1,y1), (x1,y2), … (x1,yn);
95 (x2,y1), (x2,y2), … (x2,yn);
96 ⋮ ⋮ ⋮
97 (xm,y1), (xm,y2), … (xm,yn)]
98 """
99 function points(grid::EquidistantGrid)
100 indices = Tuple.(CartesianIndices(grid.size))
101 h = spacing(grid)
102 return broadcast(I -> grid.limit_lower .+ (I.-1).*h, indices)
103 end
104
105
106 """
107 restrict(::EquidistantGrid, dim)
108
109 Pick out given dimensions from the grid and return a grid for them.
110 """
111 function restrict(grid::EquidistantGrid, dim)
112 size = grid.size[dim]
113 limit_lower = grid.limit_lower[dim]
114 limit_upper = grid.limit_upper[dim]
115
116 return EquidistantGrid(size, limit_lower, limit_upper)
117 end
118
119
120 """
121 orthogonal_dims(grid::EquidistantGrid,dim)
122
123 Returns the dimensions of grid orthogonal to that of dim.
124 """
125 function orthogonal_dims(grid::EquidistantGrid, dim)
126 orth_dims = filter(i -> i != dim, dims(grid))
127 if orth_dims == dims(grid)
128 throw(DomainError(string("dimension ",string(dim)," not matching grid")))
129 end
130 return orth_dims
131 end
132
133
134 """
135 boundary_identifiers(::EquidistantGrid)
136
137 Returns a tuple containing the boundary identifiers for the grid, stored as
138 (CartesianBoundary(1,Lower),
139 CartesianBoundary(1,Upper),
140 CartesianBoundary(2,Lower),
141 ...)
142 """
143 boundary_identifiers(g::EquidistantGrid) = (((ntuple(i->(CartesianBoundary{i,Lower}(),CartesianBoundary{i,Upper}()),dim(g)))...)...,)
144
145
146 """
147 boundary_grid(grid::EquidistantGrid, id::CartesianBoundary)
148
149 Creates the lower-dimensional restriciton of `grid` spanned by the dimensions
150 orthogonal to the boundary specified by `id`. The boundary grid of a 1-dimensional
151 grid is a zero-dimensional grid.
152 """
153 function boundary_grid(grid::EquidistantGrid, id::CartesianBoundary)
154 orth_dims = orthogonal_dims(grid, dim(id))
155 return restrict(grid, orth_dims)
156 end
157 boundary_grid(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = EquidistantGrid{T}()
158
159
160 """
161 boundary_size(grid::EquidistantGrid, id::CartesianBoundary)
162
163 Returns the size of the boundary of `grid` specified by `id`.
164 """
165 function boundary_size(grid::EquidistantGrid, id::CartesianBoundary)
166 orth_dims = orthogonal_dims(grid, dim(id))
167 return grid.size[orth_dims]
168 end
169 boundary_size(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = ()
170
171
172 """
173 refine(grid::EquidistantGrid, r::Int)
174
175 Refines `grid` by a factor `r`. The factor is applied to the number of
176 intervals which is 1 less than the size of the grid.
177
178 See also: [`coarsen`](@ref)
179 """
180 function refine(grid::EquidistantGrid, r::Int)
181 sz = size(grid)
182 new_sz = (sz .- 1).*r .+ 1
183 return EquidistantGrid{dim(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
184 end
185
186
187 """
188 coarsen(grid::EquidistantGrid, r::Int)
189
190 Coarsens `grid` by a factor `r`. The factor is applied to the number of
191 intervals which is 1 less than the size of the grid. If the number of
192 intervals are not divisible by `r` an error is raised.
193
194 See also: [`refine`](@ref)
195 """
196 function coarsen(grid::EquidistantGrid, r::Int)
197 sz = size(grid)
198
199 if !all(n -> (n % r == 0), sz.-1)
200 throw(DomainError(r, "Size minus 1 must be divisible by the ratio."))
201 end
202
203 new_sz = (sz .- 1).÷r .+ 1
204
205 return EquidistantGrid{dim(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper)
206 end