Mercurial > repos > public > sbplib_julia
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) |