1
1
using Oceananigans: location
2
- using Oceananigans. Grids: node, on_architecture
2
+ using Oceananigans. Grids: AbstractGrid, node, on_architecture
3
3
using Oceananigans. Fields: interpolate!, interpolate, location, instantiated_location
4
4
using Oceananigans. OutputReaders: Cyclical, TotallyInMemory, AbstractInMemoryBackend, FlavorOfFTS, time_indices
5
5
using Oceananigans. Utils: Time
35
35
Adapt. adapt_structure (to, b:: ECCONetCDFBackend{N, C} ) where {N, C} = ECCONetCDFBackend {N, C} (b. start, b. length, nothing , nothing )
36
36
37
37
"""
38
- ECCONetCDFBackend(length; on_native_grid = false, inpainting = NearestNeighborInpainting(Inf))
38
+ ECCONetCDFBackend(length; on_native_grid= false, inpainting= NearestNeighborInpainting(Inf))
39
39
40
40
Represent an ECCO FieldTimeSeries backed by ECCO native netCDF files.
41
41
Each time instance is stored in an individual file.
51
51
Base. length (backend:: ECCONetCDFBackend ) = backend. length
52
52
Base. summary (backend:: ECCONetCDFBackend ) = string (" ECCONetCDFBackend(" , backend. start, " , " , backend. length, " )" )
53
53
54
- const ECCONetCDFFTS {N} = FlavorOfFTS{<: Any , <: Any , <: Any , <: Any , <: ECCONetCDFBackend{N} } where N
54
+ const ECCOFieldTimeSeries {N} = FlavorOfFTS{<: Any , <: Any , <: Any , <: Any , <: ECCONetCDFBackend{N} } where N
55
55
56
56
new_backend (b:: ECCONetCDFBackend{native, cache_data} , start, length) where {native, cache_data} =
57
57
ECCONetCDFBackend {native, cache_data} (start, length, b. inpainting, b. metadata)
58
58
59
59
on_native_grid (:: ECCONetCDFBackend{native} ) where native = native
60
60
cache_inpainted_data (:: ECCONetCDFBackend{native, cache_data} ) where {native, cache_data} = cache_data
61
61
62
- function set! (fts:: ECCONetCDFFTS )
62
+ function set! (fts:: ECCOFieldTimeSeries )
63
63
backend = fts. backend
64
64
inpainting = backend. inpainting
65
65
cache_data = cache_inpainted_data (backend)
@@ -103,12 +103,10 @@ function ECCO_times(metadata; start_time = first(metadata).dates)
103
103
end
104
104
105
105
"""
106
- ECCO_field_time_series(metadata::ECCOMetadata;
107
- grid = nothing,
108
- architecture = isnothing(grid) ? CPU() : architecture(grid),
109
- time_indices_in_memory = 2,
110
- time_indexing = Cyclical(),
111
- inpainting_iterations = prod(size(metadata)),
106
+ ECCOFieldTimeSeries(metadata::ECCOMetadata [, arch_or_grid=CPU() ];
107
+ time_indices_in_memory = 2,
108
+ time_indexing = Cyclical(),
109
+ inpainting = nothing)
112
110
113
111
Create a field time series object for ECCO data.
114
112
@@ -117,13 +115,12 @@ Arguments
117
115
118
116
- `metadata`: `ECCOMetadata` containing information about the ECCO dataset.
119
117
118
+ - `arch_or_grid`: Either a grid to interpolate ECCO data to, or an `arch`itecture
119
+ to use for the native ECCO grid. Default: CPU().
120
+
120
121
Keyword Arguments
121
122
=================
122
123
123
- - `grid`: where ECCO data is interpolated. If `nothing`, the native `ECCO` grid is used.
124
-
125
- - `architecture`: where data is stored. Should only be set if `isnothing(grid)`.
126
-
127
124
- `time_indices_in_memory`: The number of time indices to keep in memory. Default: 2.
128
125
129
126
- `time_indexing`: The time indexing scheme to use. Default: `Cyclical()`.
@@ -136,49 +133,47 @@ Keyword Arguments
136
133
Default: `true`.
137
134
138
135
"""
139
- function ECCO_field_time_series (metadata:: ECCOMetadata ;
140
- architecture = CPU (),
141
- time_indices_in_memory = 2 ,
142
- time_indexing = Cyclical (),
143
- inpainting = NearestNeighborInpainting (prod (size (metadata))),
144
- cache_inpainted_data = true ,
145
- grid = nothing )
136
+ function ECCOFieldTimeSeries (metadata:: ECCOMetadata , architecture:: AbstractArchitecture = CPU (); kw... )
137
+ download_dataset (metadata)
138
+ ftmp = empty_ECCO_field (first (metadata); architecture)
139
+ grid = ftmp. grid
140
+ return ECCOFieldTimeSeries (metadata, grid; kw... )
141
+ end
142
+
143
+ function ECCOFieldTimeSeries (metadata:: ECCOMetadata , grid:: AbstractGrid ;
144
+ time_indices_in_memory = 2 ,
145
+ time_indexing = Cyclical (),
146
+ inpainting = nothing ,
147
+ cache_inpainted_data = true )
146
148
147
149
# Make sure all the required individual files are downloaded
148
150
download_dataset (metadata)
149
151
150
152
inpainting isa Int && (inpainting = NearestNeighborInpainting (inpainting))
151
-
152
- ftmp = empty_ECCO_field (first (metadata); architecture)
153
- on_native_grid = isnothing (grid)
154
- on_native_grid && (grid = ftmp. grid)
153
+ backend = ECCONetCDFBackend (time_indices_in_memory, metadata; on_native_grid, inpainting, cache_inpainted_data)
155
154
156
155
times = ECCO_times (metadata)
157
156
loc = LX, LY, LZ = location (metadata)
158
157
boundary_conditions = FieldBoundaryConditions (grid, loc)
159
-
160
- backend = ECCONetCDFBackend (time_indices_in_memory, metadata; on_native_grid, inpainting, cache_inpainted_data)
161
-
162
158
fts = FieldTimeSeries {LX, LY, LZ} (grid, times; backend, time_indexing, boundary_conditions)
163
159
set! (fts)
164
160
165
161
return fts
166
162
end
167
163
168
- ECCO_field_time_series (variable_name:: Symbol , version= ECCO4Monthly (); kw... ) =
169
- ECCO_field_time_series (ECCOMetadata (variable_name, all_ECCO_dates (version), version); kw... )
164
+ ECCOFieldTimeSeries (variable_name:: Symbol , version= ECCO4Monthly (); kw... ) =
165
+ ECCOFieldTimeSeries (ECCOMetadata (variable_name, all_ECCO_dates (version), version); kw... )
170
166
171
167
# Variable names for restoreable data
172
168
struct Temperature end
173
169
struct Salinity end
174
170
struct UVelocity end
175
171
struct VVelocity end
176
172
177
- oceananigans_fieldname = Dict (
178
- :temperature => Temperature (),
179
- :salinity => Salinity (),
180
- :u_velocity => UVelocity (),
181
- :v_velocity => VVelocity ())
173
+ const oceananigans_fieldnames = Dict (:temperature => Temperature (),
174
+ :salinity => Salinity (),
175
+ :u_velocity => UVelocity (),
176
+ :v_velocity => VVelocity ())
182
177
183
178
@inline Base. getindex (fields, i, j, k, :: Temperature ) = @inbounds fields. T[i, j, k]
184
179
@inline Base. getindex (fields, i, j, k, :: Salinity ) = @inbounds fields. S[i, j, k]
@@ -192,14 +187,14 @@ Base.summary(::VVelocity) = "v_velocity"
192
187
193
188
struct ECCORestoring{FTS, G, M, V, N}
194
189
field_time_series :: FTS
195
- grid :: G
190
+ native_grid :: G
196
191
mask :: M
197
192
variable_name :: V
198
193
rate :: N
199
194
end
200
195
201
196
Adapt. adapt_structure (to, p:: ECCORestoring ) = ECCORestoring (Adapt. adapt (to, p. field_time_series),
202
- Adapt. adapt (to, p. grid ),
197
+ Adapt. adapt (to, p. native_grid ),
203
198
Adapt. adapt (to, p. mask),
204
199
Adapt. adapt (to, p. variable_name),
205
200
Adapt. adapt (to, p. rate))
@@ -212,20 +207,20 @@ Adapt.adapt_structure(to, p::ECCORestoring) = ECCORestoring(Adapt.adapt(to, p.fi
212
207
213
208
# Possibly interpolate ECCO data from the ECCO grid to simulation grid.
214
209
# Otherwise, simply extract the pre-interpolated data from p.field_time_series.
215
- backend = p. field_time_series. backend
216
- interpolating = on_native_grid (backend)
217
- ψ_ecco = maybe_interpolate (Val (interpolating), p. field_time_series, i, j, k, p. grid, grid, time)
210
+ if p. native_grid isa Nothing
211
+ ψ_ecco = @inbounds p. field_time_series[i, j, k, time]
212
+ else
213
+ ψ_ecco = interpolate_to_grid (p. field_time_series, i, j, k, p. native_grid, grid, time)
214
+ end
218
215
219
216
ψ = @inbounds fields[i, j, k, p. variable_name]
220
217
μ = stateindex (p. mask, i, j, k, grid, clock. time, loc)
221
- ω = p. rate
218
+ r = p. rate
222
219
223
- return ω * μ * (ψ_ecco - ψ)
220
+ return r * μ * (ψ_ecco - ψ)
224
221
end
225
222
226
- @inline maybe_interpolate (:: Val{false} , fts, i, j, k, native_grid, grid, time) = @inbounds fts[i, j, k, time]
227
-
228
- @inline function maybe_interpolate (:: Val{true} , fts, i, j, k, native_grid, grid, time)
223
+ @inline function interpolate_to_grid (fts, i, j, k, native_grid, grid, time)
229
224
times = fts. times
230
225
data = fts. data
231
226
time_indexing = fts. time_indexing
@@ -238,40 +233,47 @@ end
238
233
end
239
234
240
235
"""
241
- ECCORestoring([arch=CPU(),]
242
- variable_name::Symbol;
243
- version=ECCO4Monthly(),
244
- dates=all_ECCO_dates(version),
245
- dates = all_ECCO_dates(version),
236
+ ECCORestoring(variable_name::Symbol, [ arch_or_grid = CPU(), ];
237
+ version = ECCO4Monthly(),
238
+ dates = all_ECCO_dates(version),
246
239
time_indices_in_memory = 2,
247
240
time_indexing = Cyclical(),
248
241
mask = 1,
249
242
rate = 1,
250
- grid = nothing,
251
- inpainting = NearestNeighborInpainting(prod(size(metadata))),
243
+ inpainting = NearestNeighborInpainting(Inf),
252
244
cache_inpainted_data = true)
253
245
254
- Create a forcing term that restores to values stored in an ECCO field time series.
246
+ Build a forcing term that restores to values stored in an ECCO field time series.
255
247
The restoring is applied as a forcing on the right hand side of the evolution equations calculated as
256
248
257
- ```julia
258
- F = mask ⋅ rate ⋅ (ECCO_variable - simulation_variable[i, j, k] )
249
+ ```math
250
+ Fψ = r μ (ψ_{ECCO} - ψ )
259
251
```
260
- where `ECCO_variable` is linearly interpolated in space and time from the ECCO dataset of choice to the
261
- simulation grid and time.
252
+
253
+ where ``μ`` is the mask, ``r`` is the restoring rate, ``ψ`` is the simulation variable,
254
+ and the ECCO variable ``ψ_ECCO`` is linearly interpolated in space and time from the
255
+ ECCO dataset of choice to the simulation grid and time.
262
256
263
257
Arguments
264
258
=========
265
259
266
- - `arch`: The architecture. Typically `CPU()` or `GPU()`. Default: `CPU()`.
267
-
268
260
- `variable_name`: The name of the variable to restore. Choices include:
269
- * `:temperature`,
270
- * `:salinity`,
271
- * `:u_velocity`,
272
- * `:v_velocity`,
273
- * `:sea_ice_thickness`,
274
- * `:sea_ice_area_fraction`.
261
+ * `:temperature`,
262
+ * `:salinity`,
263
+ * `:u_velocity`,
264
+ * `:v_velocity`,
265
+ * `:sea_ice_thickness`,
266
+ * `:sea_ice_area_fraction`.
267
+
268
+ Note that `ECCOMetadata` may be provided as the first argument instead
269
+ of `variable_name`. In this case the `version` and `dates` kwargs (described below)
270
+ cannot be provided.
271
+
272
+ - `arch_or_grid`: Either the architecture of the simulation, or a grid on which the ECCO data
273
+ is pre-interpolated when loaded. If an `arch`itecture is provided, such as
274
+ `arch_or_grid = CPU()` or `arch_or_grid = GPU()`, ECCO data
275
+ will be interpolated on-the-fly when the forcing tendency is computed.
276
+ Default: CPU().
275
277
276
278
Keyword Arguments
277
279
=================
@@ -280,77 +282,58 @@ Keyword Arguments
280
282
281
283
- `dates`: The dates to use for the ECCO dataset. Default: `all_ECCO_dates(version)`.
282
284
283
- - `time_indices_in_memory`: The number of time indices to keep in memory; trade-off between performance
284
- and memory footprint.
285
+ - `time_indices_in_memory`: The number of time indices to keep in memory. The number is chosen based on
286
+ a trade-off between increased performance (more indices in memory) and reduced
287
+ memory footprint (fewer indices in memory). Default: 2.
285
288
286
- - `time_indexing`: The time indexing scheme for the field time series≥
289
+ - `time_indexing`: The time indexing scheme for the field time series.
287
290
288
291
- `mask`: The mask value. Can be a function of `(x, y, z, time)`, an array, or a number.
289
292
290
293
- `rate`: The restoring rate, i.e., the inverse of the restoring timescale (in s⁻¹).
291
294
292
- - `time_indices_in_memory:` how many time instances are loaded in memory; the remaining are loaded lazily.
293
-
294
295
- `inpainting`: inpainting algorithm, see [`inpaint_mask!`](@ref). Default: `NearestNeighborInpainting(Inf)`.
295
296
296
- - `grid`: If `isnothing(grid)`, ECCO data is interpolated on-the-fly to the simulation grid.
297
- If `!isnothing(grid)`, ECCO data is pre-interpolated to `grid`.
298
- Default: nothing.
299
-
300
297
- `cache_inpainted_data`: If `true`, the data is cached to disk after inpainting for later retrieving.
301
298
Default: `true`.
302
-
303
- It is possible to also pass an `ECCOMetadata` type as the first argument without the need for the
304
- `variable_name` argument and the `version` and `dates` keyword arguments.
305
299
"""
306
- function ECCORestoring (arch :: AbstractArchitecture ,
307
- variable_name :: Symbol ;
308
- version= ECCO4Monthly (),
309
- dates= all_ECCO_dates (version),
300
+ function ECCORestoring (variable_name :: Symbol ,
301
+ arch_or_grid = CPU () ;
302
+ version = ECCO4Monthly (),
303
+ dates = all_ECCO_dates (version),
310
304
kw... )
311
305
312
306
metadata = ECCOMetadata (variable_name, dates, version)
313
- return ECCORestoring (arch, metadata ; kw... )
307
+ return ECCORestoring (metadata, arch_or_grid ; kw... )
314
308
end
315
309
316
- function ECCORestoring (arch :: AbstractArchitecture ,
317
- metadata :: ECCOMetadata ;
310
+ function ECCORestoring (metadata :: ECCOMetadata ,
311
+ arch_or_grid = CPU () ;
318
312
rate,
319
313
mask = 1 ,
320
- grid = nothing ,
321
314
time_indices_in_memory = 2 , # Not more than this if we want to use GPU!
322
315
time_indexing = Cyclical (),
323
316
inpainting = NearestNeighborInpainting (Inf ),
324
317
cache_inpainted_data = true )
325
318
326
- # Validate architecture
327
- if ! isnothing (grid) && architecture (grid) != arch
328
- throw (ArgumentError (" The architecture of ECCORestoring must match the architecture of the grid." ))
329
- end
330
-
331
- fts = ECCO_field_time_series (metadata;
332
- grid,
333
- architecture = arch,
334
- time_indices_in_memory,
335
- time_indexing,
336
- inpainting,
337
- cache_inpainted_data)
319
+ fts = ECCOFieldTimeSeries (metadata, arch_or_grid;
320
+ time_indices_in_memory,
321
+ time_indexing,
322
+ inpainting,
323
+ cache_inpainted_data)
338
324
339
325
# Grab the correct Oceananigans field to restore
340
326
variable_name = metadata. name
341
- field_name = oceananigans_fieldname [variable_name]
327
+ field_name = oceananigans_fieldnames [variable_name]
342
328
343
329
# If we pass the grid we do not need to interpolate
344
330
# so we can save parameter space by setting the native grid to nothing
345
- native_grid = isnothing (grid) ? fts. grid : nothing
331
+ on_native_grid = arch_or_grid isa AbstractArchitecture
332
+ maybe_native_grid = on_native_grid ? fts. grid : nothing
346
333
347
- return ECCORestoring (fts, native_grid , mask, field_name, rate)
334
+ return ECCORestoring (fts, maybe_native_grid , mask, field_name, rate)
348
335
end
349
336
350
- # Make sure we can call ECCORestoring with architecture as the first positional argument
351
- ECCORestoring (variable_name:: Symbol ; kw... ) = ECCORestoring (CPU (), variable_name; kw... )
352
- ECCORestoring (metadata:: ECCOMetadata ; kw... ) = ECCORestoring (CPU (), metadata; kw... )
353
-
354
337
function Base. show (io:: IO , p:: ECCORestoring )
355
338
print (io, " ECCORestoring:" , ' \n ' ,
356
339
" ├── restored variable: " , summary (p. variable_name), ' \n ' ,
0 commit comments