Mercurial > repos > public > sbplib_julia
comparison src/Grids/equidistant_grid.jl @ 2057:8a2a0d678d6f feature/lazy_tensors/pretty_printing
Merge default
| author | Jonatan Werpers <jonatan@werpers.com> |
|---|---|
| date | Tue, 10 Feb 2026 22:41:19 +0100 |
| parents | 04c251bccbd4 |
| children |
comparison
equal
deleted
inserted
replaced
| 1110:c0bff9f6e0fb | 2057:8a2a0d678d6f |
|---|---|
| 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::Number, limit_upper::Number, size::Int) | |
| 139 | |
| 140 Constructs a 1D equidistant grid. | |
| 141 """ | |
| 142 function equidistant_grid(limit_lower::Number, limit_upper::Number, size::Int) | |
| 143 if size <= 0 | |
| 144 throw(DomainError("size must be postive")) | |
| 145 end | |
| 146 | |
| 147 if limit_upper-limit_lower <= 0 | |
| 148 throw(DomainError("side length must be postive")) | |
| 149 end | |
| 150 | |
| 151 return EquidistantGrid(range(limit_lower, limit_upper, length=size)) # TBD: Should it use LinRange instead? | |
| 152 end | |
| 153 | |
| 154 equidistant_grid(d::Interval, size::Int) = equidistant_grid(limits(d)..., size) | |
| 155 equidistant_grid(hb::HyperBox, dims::Vararg{Int}) = equidistant_grid(limits(hb)..., dims...) | |
| 156 | |
| 157 function equidistant_grid(c::Chart, dims::Vararg{Int}) | |
| 158 mapped_grid(c, ξ->jacobian(c,ξ), parameterspace(c), dims...) | |
| 159 end | |
| 160 | |
| 161 | |
| 162 CartesianBoundary{D,BID} = TensorGridBoundary{D,BID} # TBD: What should we do about the naming of this boundary? | |
| 163 | |
| 164 | |
| 165 """ | |
| 166 change_length(r::AbstractRange, n) | |
| 167 | |
| 168 Change the length of `r` to `n`, keeping the same start and stop. | |
| 169 """ | |
| 170 function change_length end | |
| 171 | |
| 172 change_length(r::UnitRange, n) = StepRange{Int,Int}(range(r[begin], r[end], n)) | |
| 173 change_length(r::StepRange, n) = StepRange{Int,Int}(range(r[begin], r[end], n)) | |
| 174 change_length(r::StepRangeLen, n) = range(r[begin], r[end], n) | |
| 175 change_length(r::LinRange, n) = LinRange(r[begin], r[end], n) |
