Output writers
AbstractOutputWriter
s save data to disk. Oceananigans
provides three ways to write output:
NetCDFOutputWriter
for output of arrays and scalars that uses NCDatasets.jlJLD2OutputWriter
for arbitrary julia data structures that uses JLD2.jlCheckpointer
that automatically saves as much model data as possible, using JLD2.jl
The Checkpointer
is discussed in detail on a separate section of the documentation.
Basic usage
NetCDFOutputWriter
and JLD2OutputWriter
require four inputs:
- The
model
from which output data is sourced (required to initialize theOutputWriter
). - A key-value pairing of output "names" and "output" objects.
JLD2OutputWriter
acceptsNamedTuple
s andDict
s;NetCDFOutputWriter
acceptsDict
s with string-valued keys. Output objects are eitherAbstractField
s or functions that return data when called viafunc(model)
. - A
schedule
on which output is written.TimeInterval
,IterationInterval
,WallTimeInterval
schedule periodic output according to the simulation time, simulation interval, or "wall time" (the physical time according to a clock on your wall). A fourthschedule
calledAveragedTimeInterval
specifies periodic output that is time-averaged over awindow
prior to being written. - The
filename
anddir
ectory.
Other important keyword arguments are
indices
for outputting subregions, two- and one-dimensional slices of fields. Specifies the indices to write to disk with aTuple
ofColon
,UnitRange
,orInt
elements. For example,indices = (:, :, 1)
implies outputing $x-y$-slices of the bottom-most index (k=1
). Defaults to(:, :, :)
, i.e., "all indices".with_halos :: Boolean
: whether to output the halos (true
) or only the interior points (false
; default).array_type
for specifying the type of the array that holds outputted field data. The default isArray{Float64}
, or arrays of single-precision floating point numbers.
Once an OutputWriter
is created, it can be used to write output by adding it the ordered dictionary simulation.output_writers
. prior to calling run!(simulation)
.
More specific detail about the NetCDFOutputWriter
and JLD2OutputWriter
is given below.
Oceananigans simulations will shorten the time step as needed to align model output with each output writer's schedule.
NetCDF output writer
Model data can be saved to NetCDF files along with associated metadata. The NetCDF output writer is generally used by passing it a dictionary of (label, field) pairs and any indices for slicing if you don't want to save the full 3D field.
Examples
Saving the u velocity field and temperature fields as full 3D fields, surface 2D slices, and 1D columns to separate NetCDF files:
using Oceananigans
grid = RectilinearGrid(size=(16, 16, 16), extent=(1, 1, 1))
model = NonhydrostaticModel(grid=grid, tracers=:c)
simulation = Simulation(model, Δt=12, stop_time=3600)
fields = Dict("u" => model.velocities.u, "c" => model.tracers.c)
simulation.output_writers[:field_writer] =
NetCDFOutputWriter(model, fields, filename="more_fields.nc", schedule=TimeInterval(60))
NetCDFOutputWriter scheduled on TimeInterval(1 minute):
├── filepath: build/model_setup/more_fields.nc
├── dimensions: zC(16), zF(17), xC(16), yF(16), xF(16), yC(16), time(0)
├── 2 outputs: (c, u)
└── array type: Array{Float64}
├── file_splitting: NoFileSplitting
└── file size: 14.9 KiB
simulation.output_writers[:surface_slice_writer] =
NetCDFOutputWriter(model, fields, filename="another_surface_xy_slice.nc",
schedule=TimeInterval(60), indices=(:, :, grid.Nz))
NetCDFOutputWriter scheduled on TimeInterval(1 minute):
├── filepath: build/model_setup/another_surface_xy_slice.nc
├── dimensions: zC(1), zF(1), xC(16), yF(16), xF(16), yC(16), time(0)
├── 2 outputs: (c, u)
└── array type: Array{Float64}
├── file_splitting: NoFileSplitting
└── file size: 14.9 KiB
simulation.output_writers[:averaged_profile_writer] =
NetCDFOutputWriter(model, fields,
filename = "another_averaged_z_profile.nc",
schedule = AveragedTimeInterval(60, window=20),
indices = (1, 1, :))
NetCDFOutputWriter scheduled on TimeInterval(1 minute):
├── filepath: build/model_setup/another_averaged_z_profile.nc
├── dimensions: zC(16), zF(17), xC(1), yF(1), xF(1), yC(1), time(0)
├── 2 outputs: (c, u) averaged on AveragedTimeInterval(window=20 seconds, stride=1, interval=1 minute)
└── array type: Array{Float64}
├── file_splitting: NoFileSplitting
└── file size: 17.6 KiB
NetCDFOutputWriter
also accepts output functions that write scalars and arrays to disk, provided that their dimensions
are provided:
using Oceananigans
Nx, Ny, Nz = 16, 16, 16
grid = RectilinearGrid(size=(Nx, Ny, Nz), extent=(1, 2, 3))
model = NonhydrostaticModel(grid=grid)
simulation = Simulation(model, Δt=1.25, stop_iteration=3)
f(model) = model.clock.time^2; # scalar output
g(model) = model.clock.time .* exp.(znodes(grid, Center())) # single-column profile output (vector)
xC, yF = xnodes(grid, Center()), ynodes(grid, Face())
XC = [xC[i] for i in 1:Nx, j in 1:Ny]
YF = [yF[j] for i in 1:Nx, j in 1:Ny]
h(model) = @. model.clock.time * sin(XC) * cos(YF) # x-y slice output (2D array)
outputs = Dict("scalar" => f, "profile" => g, "slice" => h)
dims = Dict("scalar" => (), "profile" => ("zC",), "slice" => ("xC", "yC"))
output_attributes = Dict(
"scalar" => Dict("longname" => "Some scalar", "units" => "bananas"),
"profile" => Dict("longname" => "Some vertical profile", "units" => "watermelons"),
"slice" => Dict("longname" => "Some slice", "units" => "mushrooms")
)
global_attributes = Dict("location" => "Bay of Fundy", "onions" => 7)
simulation.output_writers[:things] =
NetCDFOutputWriter(model, outputs,
schedule=IterationInterval(1), filename="things.nc", dimensions=dims, verbose=true,
global_attributes=global_attributes, output_attributes=output_attributes)
NetCDFOutputWriter scheduled on IterationInterval(1):
├── filepath: build/model_setup/things.nc
├── dimensions: zC(16), zF(17), xC(16), yF(16), xF(16), yC(16), time(0)
├── 3 outputs: (profile, slice, scalar)
└── array type: Array{Float64}
├── file_splitting: NoFileSplitting
└── file size: 17.8 KiB
NetCDFOutputWriter
can also be configured for outputs
that are interpolated or regridded to a different grid than model.grid
. To use this functionality, include the keyword argument grid = output_grid
.
using Oceananigans
using Oceananigans.Fields: interpolate!
grid = RectilinearGrid(size=(1, 1, 8), extent=(1, 1, 1));
model = NonhydrostaticModel(; grid)
coarse_grid = RectilinearGrid(size=(grid.Nx, grid.Ny, grid.Nz÷2), extent=(grid.Lx, grid.Ly, grid.Lz))
coarse_u = Field{Face, Center, Center}(coarse_grid)
interpolate_u(model) = interpolate!(coarse_u, model.velocities.u)
outputs = (; u = interpolate_u)
output_writer = NetCDFOutputWriter(model, outputs;
grid = coarse_grid,
filename = "coarse_u.nc",
schedule = IterationInterval(1))
NetCDFOutputWriter scheduled on IterationInterval(1):
├── filepath: build/model_setup/coarse_u.nc
├── dimensions: zC(4), zF(5), xC(1), yF(1), xF(1), yC(1), time(0)
├── 1 outputs: u
└── array type: Array{Float64}
├── file_splitting: NoFileSplitting
└── file size: 14.6 KiB
See NetCDFOutputWriter
for more information.
JLD2 output writer
JLD2 is a fast HDF5 compatible file format written in pure Julia. JLD2 files can be opened in Julia with the JLD2.jl package and in Python with the h5py package.
The JLD2OutputWriter
receives either a Dict
ionary or NamedTuple
containing name, output
pairs. The name
can be a symbol or string. The output
must either be an AbstractField
or a function called with func(model)
that returns arbitrary output. Whenever output needs to be written, the functions will be called and the output of the function will be saved to the JLD2 file.
Examples
Write out 3D fields for u, v, w, and a tracer c, along with a horizontal average:
using Oceananigans
using Oceananigans.Utils: hour, minute
model = NonhydrostaticModel(grid=RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1)), tracers=(:c,))
simulation = Simulation(model, Δt=12, stop_time=1hour)
function init_save_some_metadata!(file, model)
file["author"] = "Chim Riggles"
file["parameters/coriolis_parameter"] = 1e-4
file["parameters/density"] = 1027
return nothing
end
c_avg = Field(Average(model.tracers.c, dims=(1, 2)))
# Note that model.velocities is NamedTuple
simulation.output_writers[:velocities] = JLD2OutputWriter(model, model.velocities,
filename = "some_more_data.jld2",
schedule = TimeInterval(20minute),
init = init_save_some_metadata!)
JLD2OutputWriter scheduled on TimeInterval(20 minutes):
├── filepath: build/model_setup/some_more_data.jld2
├── 3 outputs: (u, v, w)
├── array type: Array{Float64}
├── including: [:grid, :coriolis, :buoyancy, :closure]
├── file_splitting: NoFileSplitting
└── file size: 30.9 KiB
and a time- and horizontal-average of tracer c
every 20 minutes of simulation time to a file called some_more_averaged_data.jld2
simulation.output_writers[:avg_c] = JLD2OutputWriter(model, (; c=c_avg),
filename = "some_more_averaged_data.jld2",
schedule = AveragedTimeInterval(20minute, window=5minute))
JLD2OutputWriter scheduled on TimeInterval(20 minutes):
├── filepath: build/model_setup/some_more_averaged_data.jld2
├── 1 outputs: c averaged on AveragedTimeInterval(window=5 minutes, stride=1, interval=20 minutes)
├── array type: Array{Float64}
├── including: [:grid, :coriolis, :buoyancy, :closure]
├── file_splitting: NoFileSplitting
└── file size: 19.7 KiB
See JLD2OutputWriter
for more information.
Time-averaged output
Time-averaged output is specified by setting the schedule
keyword argument for either NetCDFOutputWriter
or JLD2OutputWriter
to AveragedTimeInterval
.
With AveragedTimeInterval
, the time-average of $a$ is taken as a left Riemann sum corresponding to
\[\langle a \rangle = \frac{1}{T} \int_{t_i-T}^{t_i} a \, \mathrm{d} t \, ,\]
where $\langle a \rangle$ is the time-average of $a$, $T$ is the time-window
for averaging specified by the window
keyword argument to AveragedTimeInterval
, and the $t_i$ are discrete times separated by the time interval
. The $t_i$ specify both the end of the averaging window and the time at which output is written.
Example
Building an AveragedTimeInterval
that averages over a 1 day window, every 4 days,
using Oceananigans
using Oceananigans.Units
schedule = AveragedTimeInterval(4days, window=1day)
# output
AveragedTimeInterval(window=1 day, stride=1, interval=4 days)
An AveragedTimeInterval
schedule directs an output writer to time-average its outputs before writing them to disk:
using Oceananigans
using Oceananigans.Units
model = NonhydrostaticModel(grid=RectilinearGrid(size=(1, 1, 1), extent=(1, 1, 1)))
simulation = Simulation(model, Δt=10minutes, stop_time=30days)
simulation.output_writers[:velocities] = JLD2OutputWriter(model, model.velocities,
filename = "even_more_averaged_velocity_data.jld2",
schedule = AveragedTimeInterval(4days, window=1day, stride=2))
JLD2OutputWriter scheduled on TimeInterval(4 days):
├── filepath: build/model_setup/even_more_averaged_velocity_data.jld2
├── 3 outputs: (u, v, w) averaged on AveragedTimeInterval(window=1 day, stride=2, interval=4 days)
├── array type: Array{Float64}
├── including: [:grid, :coriolis, :buoyancy, :closure]
├── file_splitting: NoFileSplitting
└── file size: 28.9 KiB