Mercurial > repos > public > sbplib_julia
comparison src/Grids/equidistant_grid.jl @ 1355:102ebdaf7c11 feature/variable_derivatives
Merge default
author | Jonatan Werpers <jonatan@werpers.com> |
---|---|
date | Wed, 08 Feb 2023 21:21:28 +0100 |
parents | src/Grids/EquidistantGrid.jl@c4ea28d904f5 src/Grids/EquidistantGrid.jl@dfbd62c7eb09 |
children | 4684c7f1c4cb |
comparison
equal
deleted
inserted
replaced
1210:fa0800591306 | 1355:102ebdaf7c11 |
---|---|
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 function Base.getindex(g::EquidistantGrid, I::Vararg{Int}) | |
66 h = spacing(g) | |
67 return g.limit_lower .+ (I.-1).*h | |
68 end | |
69 | |
70 Base.getindex(g::EquidistantGrid, I::CartesianIndex) = g[Tuple(I)...] | |
71 # TBD: Can this method be removed if `EquidistantGrid` is an AbstractArray? | |
72 | |
73 Base.ndims(::EquidistantGrid{Dim}) where Dim = Dim | |
74 | |
75 """ | |
76 spacing(grid::EquidistantGrid) | |
77 | |
78 The spacing between grid points. | |
79 """ | |
80 spacing(grid::EquidistantGrid) = (grid.limit_upper.-grid.limit_lower)./(grid.size.-1) | |
81 | |
82 | |
83 """ | |
84 inverse_spacing(grid::EquidistantGrid) | |
85 | |
86 The reciprocal of the spacing between grid points. | |
87 """ | |
88 inverse_spacing(grid::EquidistantGrid) = 1 ./ spacing(grid) | |
89 | |
90 | |
91 """ | |
92 points(grid::EquidistantGrid) | |
93 | |
94 The point of the grid as an array of tuples with the same dimension as the grid. | |
95 The points are stored as [(x1,y1), (x1,y2), … (x1,yn); | |
96 (x2,y1), (x2,y2), … (x2,yn); | |
97 ⋮ ⋮ ⋮ | |
98 (xm,y1), (xm,y2), … (xm,yn)] | |
99 """ | |
100 function points(grid::EquidistantGrid) | |
101 indices = Tuple.(CartesianIndices(grid.size)) | |
102 h = spacing(grid) | |
103 return broadcast(I -> grid.limit_lower .+ (I.-1).*h, indices) | |
104 end | |
105 | |
106 | |
107 """ | |
108 restrict(::EquidistantGrid, dim) | |
109 | |
110 Pick out given dimensions from the grid and return a grid for them. | |
111 """ | |
112 function restrict(grid::EquidistantGrid, dim) | |
113 size = grid.size[dim] | |
114 limit_lower = grid.limit_lower[dim] | |
115 limit_upper = grid.limit_upper[dim] | |
116 | |
117 return EquidistantGrid(size, limit_lower, limit_upper) | |
118 end | |
119 | |
120 | |
121 """ | |
122 orthogonal_dims(grid::EquidistantGrid,dim) | |
123 | |
124 Returns the dimensions of grid orthogonal to that of dim. | |
125 """ | |
126 function orthogonal_dims(grid::EquidistantGrid, dim) | |
127 orth_dims = filter(i -> i != dim, dims(grid)) | |
128 if orth_dims == dims(grid) | |
129 throw(DomainError(string("dimension ",string(dim)," not matching grid"))) | |
130 end | |
131 return orth_dims | |
132 end | |
133 | |
134 | |
135 """ | |
136 boundary_identifiers(::EquidistantGrid) | |
137 | |
138 Returns a tuple containing the boundary identifiers for the grid, stored as | |
139 (CartesianBoundary(1,Lower), | |
140 CartesianBoundary(1,Upper), | |
141 CartesianBoundary(2,Lower), | |
142 ...) | |
143 """ | |
144 boundary_identifiers(g::EquidistantGrid) = (((ntuple(i->(CartesianBoundary{i,Lower}(),CartesianBoundary{i,Upper}()),ndims(g)))...)...,) | |
145 | |
146 | |
147 """ | |
148 boundary_grid(grid::EquidistantGrid, id::CartesianBoundary) | |
149 | |
150 Creates the lower-dimensional restriciton of `grid` spanned by the dimensions | |
151 orthogonal to the boundary specified by `id`. The boundary grid of a 1-dimensional | |
152 grid is a zero-dimensional grid. | |
153 """ | |
154 function boundary_grid(grid::EquidistantGrid, id::CartesianBoundary) | |
155 orth_dims = orthogonal_dims(grid, dim(id)) | |
156 return restrict(grid, orth_dims) | |
157 end | |
158 boundary_grid(::EquidistantGrid{1,T},::CartesianBoundary{1}) where T = EquidistantGrid{T}() | |
159 | |
160 | |
161 """ | |
162 refine(grid::EquidistantGrid, r::Int) | |
163 | |
164 Refines `grid` by a factor `r`. The factor is applied to the number of | |
165 intervals which is 1 less than the size of the grid. | |
166 | |
167 See also: [`coarsen`](@ref) | |
168 """ | |
169 function refine(grid::EquidistantGrid, r::Int) | |
170 sz = size(grid) | |
171 new_sz = (sz .- 1).*r .+ 1 | |
172 return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper) | |
173 end | |
174 | |
175 | |
176 """ | |
177 coarsen(grid::EquidistantGrid, r::Int) | |
178 | |
179 Coarsens `grid` by a factor `r`. The factor is applied to the number of | |
180 intervals which is 1 less than the size of the grid. If the number of | |
181 intervals are not divisible by `r` an error is raised. | |
182 | |
183 See also: [`refine`](@ref) | |
184 """ | |
185 function coarsen(grid::EquidistantGrid, r::Int) | |
186 sz = size(grid) | |
187 | |
188 if !all(n -> (n % r == 0), sz.-1) | |
189 throw(DomainError(r, "Size minus 1 must be divisible by the ratio.")) | |
190 end | |
191 | |
192 new_sz = (sz .- 1).÷r .+ 1 | |
193 | |
194 return EquidistantGrid{ndims(grid), eltype(grid)}(new_sz, grid.limit_lower, grid.limit_upper) | |
195 end |