Skip to content

Commit 5542d98

Browse files
committed
Add RollingDataset to close past forcing data.
1 parent 1a54359 commit 5542d98

3 files changed

Lines changed: 49 additions & 8 deletions

File tree

Wflow/src/Wflow.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ function Clock(config)
9393
end
9494

9595
function Clock(config, reader)
96-
nctimes = reader.dataset["time"][:]
96+
nctimes = reader.dataset_times
9797

9898
# if the timestep is not given, use the difference between netCDF time 1 and 2
9999
if isnothing(config.time.timestepsecs)

Wflow/src/io.jl

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
"NetCDF forcing files with only the currently selected file open."
2+
mutable struct RollingDataset{D <: NCDataset}
3+
paths::Vector{String}
4+
file_end_indices::Vector{Int}
5+
dataset::D
6+
file_index::Int
7+
end
8+
9+
function RollingDataset(paths::Vector{String})
10+
times_per_file = map(paths) do path
11+
NCDataset(path) do dataset
12+
dataset["time"][:]
13+
end
14+
end
15+
file_end_indices = cumsum(length.(times_per_file))
16+
times = reduce(vcat, times_per_file)
17+
dataset = NCDataset(first(paths))
18+
return RollingDataset(paths, file_end_indices, dataset, 1), times
19+
end
20+
21+
"Select the forcing dataset and local index for a global time index."
22+
function dataset_index!(dataset::RollingDataset, index::Int)
23+
file_index = searchsortedfirst(dataset.file_end_indices, index)
24+
checkbounds(dataset.paths, file_index)
25+
if file_index != dataset.file_index
26+
close(dataset.dataset)
27+
dataset.file_index = 0
28+
dataset.dataset = NCDataset(dataset.paths[file_index])
29+
dataset.file_index = file_index
30+
end
31+
previous_end =
32+
file_index == firstindex(dataset.file_end_indices) ? 0 :
33+
dataset.file_end_indices[file_index - 1]
34+
return dataset.dataset, index - previous_end
35+
end
36+
37+
Base.close(dataset::RollingDataset) = close(dataset.dataset)
38+
139
"""Turn "a.aa.aaa" into (:a, :aa, :aaa)"""
240
symbols(s::AbstractString) = Tuple(Symbol(x) for x in split(s, '.'))
341

@@ -7,7 +45,7 @@ param(obj, fields::AbstractString) = param(obj, symbols(fields))
745

846
"Extract a netCDF variable at a given time"
947
function get_at(
10-
ds::CFDataset,
48+
ds::RollingDataset,
1149
var::InputEntry,
1250
metadata,
1351
times::AbstractVector{<:TimeType},
@@ -21,6 +59,11 @@ function get_at(
2159
return get_at(ds, var, metadata, i, dt)
2260
end
2361

62+
function get_at(ds::RollingDataset, var::InputEntry, metadata, i::Int, dt::Float64)
63+
dataset, local_index = dataset_index!(ds, i)
64+
return get_at(dataset, var, metadata, local_index, dt)
65+
end
66+
2467
function get_at(ds::CFDataset, var::InputEntry, metadata, i::Int, dt::Float64)
2568
data = read_standardized(ds, variable_name(var), (x = :, y = :, time = i))
2669
apply_affine_transform!(data, var)
@@ -430,7 +473,7 @@ function add_time(ds, time)
430473
end
431474

432475
struct NCReader{T}
433-
dataset::CFDataset
476+
dataset::RollingDataset
434477
dataset_times::Vector{T}
435478
cyclic_dataset::Union{NCDataset, Nothing}
436479
cyclic_times::Dict{String, Vector{Tuple{Int, Int}}}
@@ -507,11 +550,10 @@ function NCReader(config)
507550
if isempty(dynamic_paths)
508551
error("No files found with name '$glob_path' in '$glob_dir'")
509552
end
510-
dataset = NCDataset(dynamic_paths; aggdim = "time", deferopen = false)
553+
dataset, nctimes = RollingDataset(dynamic_paths)
511554

512-
if haskey(dataset["time"].attrib, "_FillValue")
555+
if haskey(dataset.dataset["time"].attrib, "_FillValue")
513556
@warn "Time dimension contains `_FillValue` attribute, this is not in line with CF conventions."
514-
nctimes = dataset["time"][:]
515557
times_dropped = collect(skipmissing(nctimes))
516558
# check if length has changed (missing in time dimension are not allowed), and throw
517559
# an error if the lengths are different
@@ -522,7 +564,6 @@ function NCReader(config)
522564
nctimes_type = eltype(nctimes)
523565
end
524566
else
525-
nctimes = dataset["time"][:]
526567
nctimes_type = eltype(nctimes)
527568
end
528569

Wflow/test/io.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ end
5454
# mock a NCReader object
5555
ncpath = Wflow.input_path(config, config.input.path_forcing)
5656
ds = NCDataset(ncpath)
57-
reader = (; dataset = ds)
57+
reader = (; dataset_times = ds["time"][:])
5858

5959
clock = Wflow.Clock(config, reader)
6060

0 commit comments

Comments
 (0)