comparison src/Grids/equidistant_grid.jl @ 1858:4a9be96f2569 feature/documenter_logo

Merge default
author Jonatan Werpers <jonatan@werpers.com>
date Sun, 12 Jan 2025 21:18:44 +0100
parents 244311761969
children 516eaabf1169 81559cb7b11c
comparison
equal deleted inserted replaced
1857:ffde7dad9da5 1858:4a9be96f2569
1 """
2 EquidistantGrid{T,R<:AbstractRange{T}} <: Grid{T,1}
3
4 A one-dimensional equidistant grid. Most users are expected to use
5 [`equidistant_grid`](@ref) for constructing equidistant grids.
6
7 See also: [`equidistant_grid`](@ref)
8
9
10 ## Note
11 The type of range used for the points can likely impact performance.
12 """
13 struct EquidistantGrid{T,R<:AbstractRange{T}} <: Grid{T,1}
14 points::R
15 end
16
17 # Indexing interface
18 Base.getindex(g::EquidistantGrid, i::Int) = g.points[i]
19 Base.eachindex(g::EquidistantGrid) = eachindex(g.points)
20 Base.firstindex(g::EquidistantGrid) = firstindex(g.points)
21 Base.lastindex(g::EquidistantGrid) = lastindex(g.points)
22
23 Base.axes(g::EquidistantGrid, d) = axes(g.points, d)
24
25 # Iteration interface
26 Base.iterate(g::EquidistantGrid) = iterate(g.points)
27 Base.iterate(g::EquidistantGrid, state) = iterate(g.points, state)
28
29 Base.IteratorSize(::Type{<:EquidistantGrid}) = Base.HasShape{1}()
30 Base.length(g::EquidistantGrid) = length(g.points)
31 Base.size(g::EquidistantGrid) = size(g.points)
32 Base.size(g::EquidistantGrid, d) = size(g.points)[d]
33
34
35 """
36 spacing(grid::EquidistantGrid)
37
38 The spacing between grid points.
39 """
40 spacing(g::EquidistantGrid) = step(g.points)
41
42
43 """
44 inverse_spacing(grid::EquidistantGrid)
45
46 The reciprocal of the spacing between grid points.
47 """
48 inverse_spacing(g::EquidistantGrid) = 1/step(g.points)
49
50 min_spacing(g::EquidistantGrid) = spacing(g)
51
52 """
53 LowerBoundary <: BoundaryIdentifier
54
55 Boundary identifier for the the lower (left) boundary of a one-dimensional grid.
56
57 See also: [`BoundaryIdentifier`](@ref)
58 """
59 struct LowerBoundary <: BoundaryIdentifier end
60
61 """
62 UpperBoundary <: BoundaryIdentifier
63
64 Boundary identifier for the the upper (right) boundary of a one-dimensional grid.
65
66 See also: [`BoundaryIdentifier`](@ref)
67 """
68 struct UpperBoundary <: BoundaryIdentifier end
69
70
71 boundary_identifiers(::EquidistantGrid) = (LowerBoundary(), UpperBoundary())
72 boundary_grid(g::EquidistantGrid, id::LowerBoundary) = ZeroDimGrid(g[begin])
73 boundary_grid(g::EquidistantGrid, id::UpperBoundary) = ZeroDimGrid(g[end])
74 boundary_indices(g::EquidistantGrid, id::LowerBoundary) = (firstindex(g),)
75 boundary_indices(g::EquidistantGrid, id::UpperBoundary) = (lastindex(g),)
76
77 """
78 refine(g::EquidistantGrid, r::Int)
79
80 The grid where `g` is refined by the factor `r`. The factor is applied to the number of
81 intervals, i.e., 1 less than the size of `g`.
82
83 See also: [`coarsen`](@ref)
84 """
85 function refine(g::EquidistantGrid, r::Int)
86 new_sz = (length(g) - 1)*r + 1
87 return EquidistantGrid(change_length(g.points, new_sz))
88 end
89
90 """
91 coarsen(g::EquidistantGrid, r::Int)
92
93 The grid where `g` is coarsened by the factor `r`. The factor is applied to the number of
94 intervals, i.e., 1 less than the size of `g`. If the number of
95 intervals are not divisible by `r` an error is raised.
96
97 See also: [`refine`](@ref)
98 """
99 function coarsen(g::EquidistantGrid, r::Int)
100 if (length(g)-1)%r != 0
101 throw(DomainError(r, "Size minus 1 must be divisible by the ratio."))
102 end
103
104 new_sz = (length(g) - 1)÷r + 1
105
106 return EquidistantGrid(change_length(g.points, new_sz))
107 end
108
109
110 """
111 equidistant_grid(limit_lower, limit_upper, dims...)
112
113 Construct an equidistant grid with corners at the coordinates `limit_lower` and
114 `limit_upper`.
115
116 The length of the domain sides are given by the components of
117 `limit_upper-limit_lower`. E.g for a 2D grid with `limit_lower=(-1,0)` and
118 `limit_upper=(1,2)` the domain is defined as `(-1,1)x(0,2)`. The side lengths
119 of the grid are not allowed to be negative.
120
121 The number of equispaced points in each coordinate direction are given
122 by the tuple `dims`.
123
124 Note: If `limit_lower` and `limit_upper` are integers and `dims` would allow a
125 completely integer grid, `equidistant_grid` will still return a floating point
126 grid. This simplifies the implementation and avoids certain surprise
127 behaviors.
128 """
129 function equidistant_grid(limit_lower, limit_upper, dims::Vararg{Int})
130 if !(length(limit_lower) == length(limit_upper) == length(dims))
131 throw(ArgumentError("All arguments must be of the same length"))
132 end
133 gs = map(equidistant_grid, limit_lower, limit_upper, dims)
134 return TensorGrid(gs...)
135 end
136
137 """
138 equidistant_grid(limit_lower::T, limit_upper::T, size::Int)
139
140 Constructs a 1D equidistant grid.
141 """
142 function equidistant_grid(limit_lower::Number, limit_upper::Number, size::Int)
143 if any(size .<= 0)
144 throw(DomainError("size must be postive"))
145 end
146
147 if any(limit_upper.-limit_lower .<= 0)
148 throw(DomainError("side length must be postive"))
149 end
150 return EquidistantGrid(range(limit_lower, limit_upper, length=size)) # TBD: Should it use LinRange instead?
151 end
152
153 CartesianBoundary{D,BID} = TensorGridBoundary{D,BID} # TBD: What should we do about the naming of this boundary?
154
155
156 """
157 change_length(r::AbstractRange, n)
158
159 Change the length of `r` to `n`, keeping the same start and stop.
160 """
161 function change_length end
162
163 change_length(r::UnitRange, n) = StepRange{Int,Int}(range(r[begin], r[end], n))
164 change_length(r::StepRange, n) = StepRange{Int,Int}(range(r[begin], r[end], n))
165 change_length(r::StepRangeLen, n) = range(r[begin], r[end], n)
166 change_length(r::LinRange, n) = LinRange(r[begin], r[end], n)