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)"""
240symbols (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"
947function 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)
2260end
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+
2467function 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)
430473end
431474
432475struct 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
0 commit comments