Output writers
Saving model data to disk can be done in a flexible manner using output writers. The two main output writers currently implemented are a NetCDF output writer (relying on NCDatasets.jl) and a JLD2 output writer (relying on JLD2.jl).
Output writers are stored as a list of output writers in simulation.output_writers
. Output writers can be specified at model creation time or be specified at any later time and appended (or assigned with a key value pair) to simulation.output_writers
.
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.
The following example shows how to construct NetCDF output writers for two different kinds of outputs (3D fields and slices) along with output attributes
using Oceananigans, Oceananigans.OutputWriters
grid = RegularCartesianGrid(size=(16, 16, 16), extent=(1, 1, 1));
model = IncompressibleModel(grid=grid);
simulation = Simulation(model, Δt=12, stop_time=3600);
fields = Dict("u" => model.velocities.u, "T" => model.tracers.T);
simulation.output_writers[:field_writer] =
NetCDFOutputWriter(model, fields, filename="output_fields.nc", time_interval=60)
# output
NetCDFOutputWriter (time_interval=60): output_fields.nc
├── dimensions: zC(16), zF(17), xC(16), yF(16), xF(16), yC(16), time(0)
└── 2 outputs: ["T", "u"]
simulation.output_writers[:surface_slice_writer] =
NetCDFOutputWriter(model, fields, filename="output_surface_xy_slice.nc",
time_interval=60, zC=grid.Nz, zF=grid.Nz+1)
# output
NetCDFOutputWriter (time_interval=60): output_surface_xy_slice.nc
├── dimensions: zC(1), zF(1), xC(16), yF(16), xF(16), yC(16), time(0)
└── 2 outputs: ["T", "u"]
Writing a scalar, profile, and slice to NetCDF:
using Oceananigans, Oceananigans.OutputWriters
grid = RegularCartesianGrid(size=(16, 16, 16), extent=(1, 2, 3));
model = IncompressibleModel(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(Cell, grid)); # vector/profile output
h(model) = model.clock.time .* ( sin.(xnodes(Cell, grid, reshape=true)[:, :, 1])
.* cos.(ynodes(Face, grid, reshape=true)[:, :, 1])); # xy slice output
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[:stuff] =
NetCDFOutputWriter(model, outputs,
iteration_interval=1, filename="stuff.nc", dimensions=dims, verbose=true,
global_attributes=global_attributes, output_attributes=output_attributes)
# output
NetCDFOutputWriter (iteration_interval=1): stuff.nc
├── dimensions: zC(16), zF(17), xC(16), yF(16), xF(16), yC(16), time(0)
└── 3 outputs: ["profile", "slice", "scalar"]
See NetCDFOutputWriter
for more details and options.
JLD2 output writer
JLD2 is a an HDF5 compatible file format written in pure Julia and is generally pretty fast. JLD2 files can be opened in Python with the h5py package.
The JLD2 output writer is generally used by passing it a dictionary or named tuple of (label, function) pairs where the functions have a single input model
. Whenever output needs to be written, the functions will be called and the output of the function will be saved to the JLD2 file. For example, to write out 3D fields for w and T and a horizontal average of T every 1 hour of simulation time to a file called some_data.jld2
using Oceananigans
using Oceananigans.OutputWriters
using Oceananigans.Utils: hour, minute
model = IncompressibleModel(grid=RegularCartesianGrid(size=(16, 16, 16), extent=(1, 1, 1)))
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
end
T_avg = Average(model.tracers.T, dims=(1, 2))
outputs = Dict(
:w => model -> model.velocities.u,
:T => model -> model.tracers.T,
:T_avg => model -> T_avg(model)
)
jld2_writer = JLD2OutputWriter(model, outputs, init=init_save_some_metadata, interval=20minute, prefix="some_data")
push!(simulation.output_writers, jld2_writer)
See JLD2OutputWriter
for more details and options.