Skip to content

Commit be3133c

Browse files
Add 1D interpolation.
1 parent 8c8d463 commit be3133c

File tree

8 files changed

+318
-0
lines changed

8 files changed

+318
-0
lines changed

.dev/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[deps]
2+
JuliaFormatter = "98e50ef6-434e-11e9-1051-2b60c6c9e899"

.dev/climaformat.jl

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
#!/usr/bin/env julia
2+
#
3+
# This is an adapted version of format.jl from JuliaFormatter with the
4+
# following license:
5+
#
6+
# MIT License
7+
# Copyright (c) 2019 Dominique Luna
8+
#
9+
# Permission is hereby granted, free of charge, to any person obtaining a
10+
# copy of this software and associated documentation files (the
11+
# "Software"), to deal in the Software without restriction, including
12+
# without limitation the rights to use, copy, modify, merge, publish,
13+
# distribute, sublicense, and/or sell copies of the Software, and to permit
14+
# persons to whom the Software is furnished to do so, subject to the
15+
# following conditions:
16+
#
17+
# The above copyright notice and this permission notice shall be included
18+
# in all copies or substantial portions of the Software.
19+
#
20+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21+
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
23+
# NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
24+
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
25+
# OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
26+
# USE OR OTHER DEALINGS IN THE SOFTWARE.
27+
#
28+
using Pkg
29+
Pkg.activate(@__DIR__)
30+
Pkg.instantiate()
31+
32+
using JuliaFormatter
33+
34+
help = """
35+
Usage: climaformat.jl [flags] [FILE/PATH]...
36+
37+
Formats the given julia files using the CLIMA formatting options. If paths
38+
are given it will format the julia files in the paths. Otherwise, it will
39+
format all changed julia files.
40+
41+
-v, --verbose
42+
Print the name of the files being formatted with relevant details.
43+
44+
-h, --help
45+
Print this message.
46+
"""
47+
48+
function parse_opts!(args::Vector{String})
49+
i = 1
50+
opts = Dict{Symbol,Union{Int,Bool}}()
51+
while i length(args)
52+
arg = args[i]
53+
if arg[1] != '-'
54+
i += 1
55+
continue
56+
end
57+
if arg == "-v" || arg == "--verbose"
58+
opt = :verbose
59+
elseif arg == "-h" || arg == "--help"
60+
opt = :help
61+
else
62+
error("invalid option $arg")
63+
end
64+
if opt in (:verbose, :help)
65+
opts[opt] = true
66+
deleteat!(args, i)
67+
end
68+
end
69+
return opts
70+
end
71+
72+
opts = parse_opts!(ARGS)
73+
if haskey(opts, :help)
74+
write(stdout, help)
75+
exit(0)
76+
end
77+
if isempty(ARGS)
78+
filenames = readlines(`git ls-files "*.jl"`)
79+
else
80+
filenames = ARGS
81+
end
82+
83+
format(filenames; opts...)

Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name = "ClimaInterpolations"
2+
uuid = "dd0f122e-fa3b-47f3-bcf0-93bbc60d885e"
3+
authors = ["sriharshakandala <[email protected]>"]
4+
version = "0.1.0"

src/ClimaInterpolations.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
module ClimaInterpolations
2+
3+
include("Interpolation1D.jl")
4+
5+
end

src/Interpolation1D.jl

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
module Interpolation1D
2+
3+
include("stencils1d.jl")
4+
5+
"""
6+
interpolate(xpts, fval, xtarg)
7+
8+
Interpolate `fval` defined on `xpts` at `xtarg`.
9+
Reference:
10+
1). Berrut, J., and Trefethen, L. N., 2004. Barycentric Lagrange Interpolation, SIAM REVIEW
11+
Vol. 46, No. 3, pp. 501–517.
12+
DOI. 10.1137/S0036144502417715
13+
"""
14+
Base.@pure function interpolate(
15+
xpts::AbstractArray{FT,1},
16+
fval::AbstractArray{FT,1},
17+
xtarg::FT,
18+
) where {FT<:AbstractFloat}
19+
length(xpts) == 1 && return fval[1] # flat extrapolation
20+
l, tot, mi, tol = FT(1), -FT(0), 0, (10 * eps(FT))
21+
@inbounds begin
22+
for i in eachindex(xpts)
23+
dx = xtarg - xpts[i]
24+
if abs(dx) < tol
25+
mi = i
26+
break
27+
else
28+
l *= dx
29+
end
30+
end
31+
if mi == 0
32+
for i in eachindex(xpts)
33+
xi = xpts[i]
34+
wi = FT(1)
35+
for j in eachindex(xpts)
36+
if j i
37+
wi *= (xi - xpts[j])
38+
end
39+
end
40+
tot += fval[i] * l / ((xtarg - xi) * wi)
41+
end
42+
else
43+
tot = fval[mi]
44+
end
45+
end
46+
return tot
47+
end
48+
49+
"""
50+
interpolate1d!(
51+
ftarget::AbstractArray{FT,N},
52+
xsource::AbstractArray{FT,N},
53+
xtarget::AbstractArray{FT,N},
54+
fsource::AbstractArray{FT,N},
55+
order,
56+
extrapolate = Flat(),
57+
) where {FT,N}
58+
59+
Interpolate `fsource`, defined on grid `xsource`, onto the `xtarget` grid.
60+
Here the source grid `xsource` is an N-dimensional array of columns.
61+
The first dimension is assumed to be the column dimension.
62+
Each column can have a different grid.
63+
"""
64+
function interpolate1d!(
65+
ftarget::AbstractArray{FT,N},
66+
xsource::AbstractArray{FT,N},
67+
xtarget::AbstractArray{FT,N},
68+
fsource::AbstractArray{FT,N},
69+
order,
70+
extrapolate = Flat(),
71+
) where {FT,N}
72+
@assert N 1
73+
(nsource, coldims_source...) = size(xsource)
74+
(ntarget, coldims_target...) = size(xtarget)
75+
@assert coldims_source == coldims_target
76+
@assert size(ftarget) == size(xtarget)
77+
@assert size(fsource) == size(xsource)
78+
coldims = coldims_source
79+
colcidxs = CartesianIndices(coldims)
80+
@inbounds begin
81+
for colcidx in colcidxs
82+
colidx = Tuple(colcidx)
83+
first = 1
84+
for i1 = 1:ntarget
85+
(st, en) = get_stencil(
86+
order,
87+
view(xsource, :, colidx...),
88+
xtarget[i1, colidx...],
89+
first = first,
90+
extrapolate = extrapolate,
91+
)
92+
first = st
93+
ftarget[i1, colidx...] = interpolate(
94+
view(xsource, st:en, colidx...),
95+
view(fsource, st:en, colidx...),
96+
xtarget[i1, colidx...],
97+
)
98+
end
99+
end
100+
end
101+
return nothing
102+
end
103+
104+
end

src/stencils1d.jl

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
abstract type Order1D end
3+
abstract type Extrapolate1D end
4+
5+
struct Linear <: Order1D end
6+
7+
struct Flat <: Extrapolate1D end
8+
struct LinearExtrapolation <: Extrapolate1D end
9+
10+
function get_stencil(alg::Linear, xsource, xtarg; first = 1, extrapolate = Flat())
11+
last = length(xsource)
12+
if xtarg < xsource[1] # extrapolation
13+
# Linear extrapolation
14+
extrapolate == LinearExtrapolation() && return (1, 2)
15+
# Flat extrapolation by default
16+
return (1, 1)
17+
end
18+
if xtarg > xsource[last] # extrapolation
19+
# Linear extrapolation
20+
extrapolate == LinearExtrapolation() && return (last - 1, last)
21+
# Flat extrapolation by default
22+
return (last, last)
23+
end
24+
st = first
25+
for i = first:last
26+
if xtarg xsource[i]
27+
st = max(i - 1, 1)
28+
break
29+
end
30+
end
31+
return (st, st < last ? st + 1 : st)
32+
end

test/Project.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[deps]
2+
BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
3+
CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0"
4+
ClimaInterpolations = "dd0f122e-fa3b-47f3-bcf0-93bbc60d885e"

test/interpolation1D.jl

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using ClimaInterpolations
2+
using ClimaInterpolations.Interpolation1D
3+
import .Interpolation1D:
4+
interpolate, Linear, get_stencil, interpolate1d!, Flat, LinearExtrapolation
5+
using Statistics
6+
using BenchmarkTools
7+
using CairoMakie
8+
using Test
9+
10+
FT = Float64
11+
12+
xmin, xmax = FT(0), FT(2 * π)
13+
nsource, ntarget = 150, 200
14+
#nsource, ntarget = 15, 20
15+
xsource = Vector{FT}(range(xmin, xmax, length = nsource))
16+
#xtarget = Vector{FT}(range(xmin-1, xmax+1, length = ntarget))
17+
xtarget = Vector{FT}(range(xmin, xmax, length = ntarget))
18+
19+
fsource = sin.(xsource) # function defined on source grid
20+
ftarget = zeros(FT, ntarget) # allocated function on target grid
21+
22+
#extrapolation = LinearExtrapolation()
23+
extrapolation = Flat()
24+
@time interpolate1d!(ftarget, xsource, xtarget, fsource, Linear(), extrapolation)
25+
@time interpolate1d!(ftarget, xsource, xtarget, fsource, Linear(), extrapolation)
26+
@allocated interpolate1d!(ftarget, xsource, xtarget, fsource, Linear(), extrapolation)
27+
28+
bm_trial = @benchmark interpolate1d!(
29+
$ftarget,
30+
$xsource,
31+
$xtarget,
32+
$fsource,
33+
$Linear(),
34+
$extrapolation,
35+
)
36+
37+
@show (nsource, ntarget)
38+
@show bm_trial
39+
@show Statistics.median(bm_trial)
40+
41+
fig, ax, plt = scatterlines(xsource, fsource, color = :blue, marker = :star4)
42+
scatterlines!(ax, xtarget, ftarget, color = :green, marker = :circle)
43+
save("test.pdf", fig)
44+
# multiple 1D columns
45+
nlon, nlat = 2560, 1280
46+
#nlon, nlat = 5, 7
47+
xsourcecols = repeat(xsource, 1, nlon, nlat)
48+
xtargetcols = repeat(xtarget, 1, nlon, nlat)
49+
fsourcecols = repeat(fsource, 1, nlon, nlat)
50+
ftargetcols = zeros(ntarget, nlon, nlat)
51+
52+
@time interpolate1d!(
53+
ftargetcols,
54+
xsourcecols,
55+
xtargetcols,
56+
fsourcecols,
57+
Linear(),
58+
extrapolation,
59+
)
60+
@time interpolate1d!(
61+
ftargetcols,
62+
xsourcecols,
63+
xtargetcols,
64+
fsourcecols,
65+
Linear(),
66+
extrapolation,
67+
)
68+
69+
bm_trial_mcols = @benchmark interpolate1d!(
70+
$ftargetcols,
71+
$xsourcecols,
72+
$xtargetcols,
73+
$fsourcecols,
74+
$Linear(),
75+
$extrapolation,
76+
)
77+
78+
@show bm_trial_mcols
79+
@show Statistics.median(bm_trial_mcols)
80+
81+
@testset "testing interpolate1d! on multiple columns" begin
82+
@test ftargetcols[:, 1, 1] ftarget[:]
83+
@test ftargetcols[:, 25, 87] ftarget[:]
84+
end

0 commit comments

Comments
 (0)