diff --git a/Manifest.toml b/Manifest.toml index 2f12da2251..e051b089b1 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -32,6 +32,12 @@ git-tree-sha1 = "62847acab40e6855a9b5905ccb99c2b5cf6b3ebb" uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" version = "0.2.0" +[[CFTime]] +deps = ["Dates", "Printf"] +git-tree-sha1 = "90eddf050a4d4b35520f87b9ba82302643706a1e" +uuid = "179af706-886a-5703-950a-314cd64e0468" +version = "0.0.3" + [[CSTParser]] deps = ["Tokenize"] git-tree-sha1 = "c69698c3d4a7255bc1b4bc2afc09f59db910243b" @@ -135,12 +141,6 @@ git-tree-sha1 = "8fba6ddaf66b45dec830233cea0aae43eb1261ad" uuid = "1a297f60-69ca-5386-bcde-b61e274b549b" version = "0.6.4" -[[Formatting]] -deps = ["Printf"] -git-tree-sha1 = "aef8983c0f77c84ae77ced1bb3ecf5ab7d687700" -uuid = "59287772-0a20-5a39-b81b-1366585eb4c0" -version = "0.4.0" - [[GPUArrays]] deps = ["Adapt", "FFTW", "FillArrays", "LinearAlgebra", "Printf", "Random", "Serialization", "StaticArrays", "Test"] git-tree-sha1 = "77e27264276fe97a7e7fb928bf8999a145abc018" @@ -198,21 +198,26 @@ version = "0.5.1" deps = ["Base64"] uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" +[[Missings]] +git-tree-sha1 = "29858ce6c8ae629cf2d733bffa329619a1c843d0" +uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" +version = "0.4.2" + [[Mmap]] uuid = "a63ad114-7e13-5084-954f-fe012c677804" +[[NCDatasets]] +deps = ["BinDeps", "CFTime", "Compat", "CondaBinDeps", "DataStructures", "Dates", "Libdl", "Missings", "Printf", "Random"] +git-tree-sha1 = "21f833cf06f4e0128726b25aa2fc662b7d66d1bd" +uuid = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" +version = "0.9.3" + [[NNlib]] deps = ["Libdl", "LinearAlgebra", "Requires", "Statistics", "TimerOutputs"] git-tree-sha1 = "0c667371391fc6bb31f7f12f96a56a17098b3de8" uuid = "872c559c-99b0-510c-b3b7-b6c96a88d5cd" version = "0.6.0" -[[NetCDF]] -deps = ["BinDeps", "CondaBinDeps", "Formatting", "Libdl"] -git-tree-sha1 = "fce0c7962fb14b8cf2f33ea77885f3b7c7e1485e" -uuid = "30363a11-5582-574a-97bb-aa9a979735b9" -version = "0.8.0" - [[OffsetArrays]] git-tree-sha1 = "1af2f79c7eaac3e019a0de41ef63335ff26a0a57" uuid = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" diff --git a/Project.toml b/Project.toml index 126c15836f..57ea51c48a 100644 --- a/Project.toml +++ b/Project.toml @@ -14,7 +14,7 @@ FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" GPUifyLoops = "ba82f77b-6841-5d2e-bd9f-4daf811aec27" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -NetCDF = "30363a11-5582-574a-97bb-aa9a979735b9" +NCDatasets = "85f8d34a-cbdd-5861-8df4-14fed0d494ab" OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881" OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" diff --git a/examples/netcdf_ouput_example.jl b/examples/netcdf_ouput_example.jl new file mode 100644 index 0000000000..a9c48259db --- /dev/null +++ b/examples/netcdf_ouput_example.jl @@ -0,0 +1,78 @@ +using Oceananigans, Printf + +#### +#### Model set-up +#### + +Nx, Ny, Nz = 16, 16, 16 # No. of grid points in x, y, and z, respectively. +Lx, Ly, Lz = 100, 100, 100 # Length of the domain in x, y, and z, respectively (m). +tf = 5000 # Length of the simulation (s) + +model = Model(grid=RegularCartesianGrid(N=(Nx, Ny, Nz), L=(Lx, Ly, Lz)), + closure=ConstantIsotropicDiffusivity()) + +# Add a cube-shaped warm temperature anomaly that takes up the middle 50% +# of the domain volume. +i1, i2 = round(Int, Nx/4), round(Int, 3Nx/4) +j1, j2 = round(Int, Ny/4), round(Int, 3Ny/4) +k1, k2 = round(Int, Nz/4), round(Int, 3Nz/4) +model.tracers.T.data[i1:i2, j1:j2, k1:k2] .+= 0.01 + +#### +#### Set up output +#### + +write_grid(model) + +outputs = Dict("u" => model.velocities.u, + "v" => model.velocities.v, + "w" => model.velocities.w, + "T" => model.tracers.T, + "S" => model.tracers.S) + +outputattrib = Dict("u" => ["longname" => "Velocity in the x-direction", "units" => "m/s"], + "v" => ["longname" => "Velocity in the y-direction", "units" => "m/s"], + "w" => ["longname" => "Velocity in the z-direction", "units" => "m/s"], + "T" => ["longname" => "Temperature", "units" => "K"], + "S" => ["longname" => "Salinity", "units" => "g/kg"]) + +globalattrib = Dict("f" => 1e-4, "name" => "Thermal bubble expt 1") + +# The following writer saves a yz plane at xC[5] for all fields that +# have xC as their dimension and at xF[6] for all fields that have xF +# as their dimension. Ranges also can be specified (e.g. xC=2:10) +subsetwriter = NetCDFOutputWriter(model, outputs; + interval=10, filename="dump_subset.nc", + outputattrib=outputattrib, + globalattrib=globalattrib, + xC=5, xF=6) +push!(model.output_writers, subsetwriter) + +# The following writer saves a data from the entire domain +globalwriter = NetCDFOutputWriter(model, outputs, interval=10, + filename="dump_global.nc") +push!(model.output_writers, globalwriter) + +#### +#### Run the simulation +#### + +function terse_message(model, walltime, Δt) + cfl = Δt / Oceananigans.cell_advection_timescale(model) + return @sprintf("i: %d, t: %.4f s, Δt: %.1f s, cfl: %.3f, wall time: %s\n", + model.clock.iteration, model.clock.time, Δt, cfl, prettytime(walltime)) +end + +# A wizard for managing the simulation time-step. +wizard = TimeStepWizard(cfl=0.2, Δt=10.0, max_change=1.1, max_Δt=50.0) + +# Run the model +while model.clock.time < tf + update_Δt!(wizard, model) + walltime = @elapsed time_step!(model, 10, wizard.Δt) + @printf "%s" terse_message(model, walltime, wizard.Δt) +end + +# Close the NetCDFOutputWriter +OWClose(subsetwriter) +OWClose(globalwriter) diff --git a/src/Oceananigans.jl b/src/Oceananigans.jl index 66b36566ae..ae11c5176e 100644 --- a/src/Oceananigans.jl +++ b/src/Oceananigans.jl @@ -48,9 +48,9 @@ export Model, BasicModel, ChannelModel, BasicChannelModel, # Model output writers - NetCDFOutputWriter, Checkpointer, restore_from_checkpoint, read_output, JLD2OutputWriter, FieldOutput, FieldOutputs, + write_grid, NetCDFOutputWriter, # Model diagnostics HorizontalAverage, NaNChecker, @@ -77,7 +77,7 @@ using StaticArrays, OffsetArrays, JLD2, - NetCDF + NCDatasets import CUDAapi, diff --git a/src/output_writers.jl b/src/output_writers.jl index 3cfc590ad1..7faed74563 100644 --- a/src/output_writers.jl +++ b/src/output_writers.jl @@ -9,7 +9,7 @@ ext(fw::AbstractOutputWriter) = throw("Extension for $(typeof(fw)) is not implem saveproperty!(file, location, p::Number) = file[location] = p saveproperty!(file, location, p::AbstractRange) = file[location] = collect(p) saveproperty!(file, location, p::AbstractArray) = file[location] = Array(p) -saveproperty!(file, location, p::AbstractField) = file[location] = Array(p.data.parent) +saveproperty!(file, location, p::AbstractField) = file[location] = Array(p.data.parent) saveproperty!(file, location, p::Function) = @warn "Cannot save Function property into $location" saveproperty!(file, location, p) = [saveproperty!(file, location * "/$subp", getproperty(p, subp)) for subp in propertynames(p)] @@ -176,7 +176,7 @@ function write_output(model, fw::JLD2OutputWriter) verbose && @info @sprintf("Writing done: time=%s, size=%s, Δsize=%s", prettytime((t1-t0)/1e9), pretty_filesize(newsz), pretty_filesize(newsz-sz)) - return + return nothing end """ @@ -194,7 +194,7 @@ function jld2output!(path, iter, time, data, kwargs) file["timeseries/$name/$iter"] = datum end end - return + return nothing end function start_next_file(model::Model, fw::JLD2OutputWriter) @@ -266,126 +266,215 @@ end #### NetCDF output writer #### -"A type for writing NetCDF output." -Base.@kwdef mutable struct NetCDFOutputWriter <: AbstractOutputWriter - dir :: AbstractString = "." - prefix :: AbstractString = "" - frequency :: Int = 1 - padding :: Int = 9 - naming_scheme :: Symbol = :iteration - compression :: Int = 3 - async :: Bool = false -end +""" + netcdf_spatial_dimensions(::field) -ext(fw::NetCDFOutputWriter) = ".nc" +Returns the dimensions associated with a field. -function filename(fw, name, iteration) - if fw.naming_scheme == :iteration - fw.prefix * name * lpad(iteration, fw.padding, "0") * ext(fw) - elseif fw.naming_scheme == :file_number - file_num = Int(iteration / fw.frequency) - fw.prefix * name * lpad(file_num, fw.padding, "0") * ext(fw) - else - throw(ArgumentError("Invalid naming scheme: $(fw.naming_scheme)")) - end +Examples +======== + +julia> netcdf_spatial_dimensions(model.velocities.u) +("xF", "yC", "zC") + +julia> netcdf_spatial_dimensions(model.tracers.T) +("xC", "yC", "zC") +""" +function netcdf_spatial_dimensions(field::Field{LX, LY, LZ}) where {LX, LY, LZ} + xdim(LX), ydim(LY), zdim(LZ) end -function write_output(model::Model, fw::NetCDFOutputWriter) - fields = Dict( +xdim(::Type{Face}) = "xF" +xdim(::Type{Cell}) = "xC" +ydim(::Type{Face}) = "yF" +ydim(::Type{Cell}) = "yC" +zdim(::Type{Face}) = "zF" +zdim(::Type{Cell}) = "zC" + +# This function converts an integer to a range, and nothing to a Colon +get_slice(n::Integer) = n:n +get_slice(n::UnitRange) = n +get_slice(n::Nothing) = Colon() + +""" + write_grid(model; filename="grid.nc", mode="c", + compression=0, attributes=Dict(), slice_kw...) + +Writes a grid.nc file that contains all the dimensions of the domain. + +Keyword arguments +================= + + - `filename::String` : File name to be saved under + - `mode::String` : Netcdf file is opened in either clobber ("c") or append ("a") mode (Default: "c" ) + - `compression::Int` : Defines the compression level of data (0-9, default 0) + - `attributes::Dict` : Attributes (default: Dict()) +""" +function write_grid(model; filename="./grid.nc", mode="c", + compression=0, attributes=Dict(), slice_kw...) + dimensions = Dict( "xC" => collect(model.grid.xC), "yC" => collect(model.grid.yC), "zC" => collect(model.grid.zC), - "xF" => collect(model.grid.xF), - "yF" => collect(model.grid.yF), - "zF" => collect(model.grid.zF), - "u" => Array(parentdata(model.velocities.u)), - "v" => Array(parentdata(model.velocities.v)), - "w" => Array(parentdata(model.velocities.w)), - "T" => Array(parentdata(model.tracers.T)), - "S" => Array(parentdata(model.tracers.S)) + "xF" => collect(model.grid.xF)[1:end-1], + "yF" => collect(model.grid.yF)[1:end-1], + "zF" => collect(model.grid.zF)[1:end-1] + ) + dim_attrib = Dict( + "xC" => ["longname" => "Locations of the cell centers in the x-direction.", "units" => "m"], + "yC" => ["longname" => "Locations of the cell centers in the y-direction.", "units" => "m"], + "zC" => ["longname" => "Locations of the cell centers in the z-direction.", "units" => "m"], + "xF" => ["longname" => "Locations of the cell faces in the x-direction.", "units" => "m"], + "yF" => ["longname" => "Locations of the cell faces in the y-direction.", "units" => "m"], + "zF" => ["longname" => "Locations of the cell faces in the z-direction.", "units" => "m"] ) - if fw.async - # Execute asynchronously on worker 2. - i = model.clock.iteration - @async remotecall(write_output_netcdf, 2, fw, fields, i) - else - write_output_netcdf(fw, fields, model.clock.iteration) + # Applies slices to the dimensions d + for (d, slice) in slice_kw + if String(d) in keys(dimensions) + dimensions[String(d)] = dimensions[String(d)][get_slice(slice)] + end end - return + # Writes the sliced dimensions to the specified netcdf file + Dataset(filename, mode, attrib=attributes) do ds + for (dimname, dimarray) in dimensions + defVar(ds, dimname, dimarray, (dimname,), + compression=compression, attrib=dim_attrib[dimname]) + end + end + return nothing end -function write_output_netcdf(fw::NetCDFOutputWriter, fields, iteration) - xC, yC, zC = fields["xC"], fields["yC"], fields["zC"] - xF, yF, zF = fields["xF"], fields["yF"], fields["zF"] - u, v, w = fields["u"], fields["v"], fields["w"] - T, S = fields["T"], fields["S"] +""" + NetCDFOutputWriter <: AbstractOutputWriter - xC_attr = Dict("longname" => "Locations of the cell centers in the x-direction.", "units" => "m") - yC_attr = Dict("longname" => "Locations of the cell centers in the y-direction.", "units" => "m") - zC_attr = Dict("longname" => "Locations of the cell centers in the z-direction.", "units" => "m") +An output writer for writing to NetCDF files. +""" +mutable struct NetCDFOutputWriter <: AbstractOutputWriter + filename :: String + dataset :: Any + outputs :: Dict + interval :: Union{Nothing, AbstractFloat} + frequency :: Union{Nothing, Int} + clobber :: Bool + slices :: Dict + len_time_dimension :: Int + previous :: Float64 +end - xF_attr = Dict("longname" => "Locations of the cell faces in the x-direction.", "units" => "m") - yF_attr = Dict("longname" => "Locations of the cell faces in the y-direction.", "units" => "m") - zF_attr = Dict("longname" => "Locations of the cell faces in the z-direction.", "units" => "m") +""" + NetCDFOutputWriter(model, outputs; interval=nothing, frequency=nothing, filename=".", + clobber=true, global_attributes=Dict(), output_attributes=nothing, slice_kw...) - u_attr = Dict("longname" => "Velocity in the x-direction", "units" => "m/s") - v_attr = Dict("longname" => "Velocity in the y-direction", "units" => "m/s") - w_attr = Dict("longname" => "Velocity in the z-direction", "units" => "m/s") - T_attr = Dict("longname" => "Temperature", "units" => "K") - S_attr = Dict("longname" => "Salinity", "units" => "g/kg") +Construct a `NetCDFOutputWriter` that writes `label, field` pairs in `outputs` (which can be a +`Dict` or `NamedTuple`) to a NC file, where `label` is a symbol that labels the output and +`field` is a field from the model (e.g. `model.velocities.u`). - filepath = joinpath(fw.dir, filename(fw, "", iteration)) +Keyword arguments +================= - if fw.async - println("[Worker $(Distributed.myid()): NetCDFOutputWriter] Writing fields to disk: $filepath") - end + - `filename::String` : Directory to save output to. Default: "." (current working directory). + - `frequency::Int` : Save output every `n` model iterations. + - `interval::Int` : Save output every `t` units of model clock time. + - `clobber::Bool` : Remove existing files if their filenames conflict. Default: `false`. + - `compression::Int` : Determines the compression level of data (0-9, default 0) + - `global_attributes::Dict` : Dict of model properties to save with every file (deafult: Dict()) + - `output_attributes::Dict` : Dict of attributes to be saved with each field variable (reasonable + defaults are provided for velocities, temperature, and salinity) + - `slice_kw` : `dimname = Union{OrdinalRange, Integer}` will slice the dimension `dimname`. + All other keywords are ignored. + e.g. `xC = 3:10` will only produce output along the dimension `xC` between + indices 3 and 10 for all fields with `xC` as one of their dimensions. + `xC = 1` is treated like `xC = 1:1`. + Multiple dimensions can be sliced in one call. Not providing slices writes + output over the entire domain. +""" + +function NetCDFOutputWriter(model, outputs; interval=nothing, frequency=nothing, filename=".", + clobber=true, global_attributes=Dict(), output_attributes=nothing, compression=0, slice_kw...) + + validate_interval(interval, frequency) + + mode = clobber ? "c" : "a" + + # Initiates the output file with dimensions + write_grid(model; filename=filename, mode=mode, + compression=compression, attrib=global_attributes, slice_kw...) + + # Opens the same output file for writing fields from the user-supplied variable outputs + dataset = Dataset(filename, "a") + + # Creates an unliimited dimension "Time" + defDim(dataset, "Time", Inf); sync(dataset) + defVar(dataset, "Time", Float64, ("Time",)); sync(dataset) + len_time_dimension = 0 # Number of time-steps so far - isfile(filepath) && rm(filepath) + if isa(output_attributes, Nothing) + output_attributes = Dict("u" => Dict("longname" => "Velocity in the x-direction", "units" => "m/s"), + "v" => Dict("longname" => "Velocity in the y-direction", "units" => "m/s"), + "w" => Dict("longname" => "Velocity in the z-direction", "units" => "m/s"), + "T" => Dict("longname" => "Temperature", "units" => "K"), + "S" => Dict("longname" => "Salinity", "units" => "g/kg")) + end - nccreate(filepath, "u", "xF", xC, xC_attr, - "yC", yC, yC_attr, - "zC", zC, zC_attr, - atts=u_attr, compress=fw.compression) + # Initiates empty Float32 arrays for fields from the user-supplied variable outputs + for (fieldname, field) in outputs + dtype = eltype(parentdata(field)) + defVar(dataset, fieldname, dtype, (netcdf_spatial_dimensions(field)...,"Time"), + compression=compression, attrib=output_attributes[fieldname]) + end + sync(dataset) - nccreate(filepath, "v", "xC", xC, xC_attr, - "yF", yC, yC_attr, - "zC", zC, zC_attr, - atts=v_attr, compress=fw.compression) + # Stores slices for the dimensions of each output field + slices = Dict{String, Vector{Union{OrdinalRange,Colon}}}() + for (fieldname, field) in outputs + slices[fieldname] = slice(field; slice_kw...) + end - nccreate(filepath, "w", "xC", xC, xC_attr, - "yC", yC, yC_attr, - "zF", zC, zC_attr, - atts=w_attr, compress=fw.compression) + return NetCDFOutputWriter(filename, dataset, outputs, interval, + frequency, clobber, slices, len_time_dimension, 0.0) +end - nccreate(filepath, "T", "xC", xC, xC_attr, - "yC", yC, yC_attr, - "zC", zC, zC_attr, - atts=T_attr, compress=fw.compression) - nccreate(filepath, "S", "xC", xC, xC_attr, - "yC", yC, yC_attr, - "zC", zC, zC_attr, - atts=S_attr, compress=fw.compression) +# Closes the outputwriter +Base.close(fw::NetCDFOutputWriter) = close(fw.dataset) - ncwrite(u, filepath, "u") - ncwrite(v, filepath, "v") - ncwrite(w, filepath, "w") - ncwrite(T, filepath, "T") - ncwrite(S, filepath, "S") +function read_output(fw::NetCDFOutputWriter, fieldname) + ds = Dataset(fw.filename,"r") + field = ds[fieldname][:,:,:,end] + close(ds) + return field +end - ncclose(filepath) +""" + slice(field; slice_kw...) - return +For internal use only. Returns a slice for a field based on its dimensions and the supplied slices in `slice_kw`. +""" +function slice(field; slice_kw...) + slice_array = Vector{Union{AbstractRange,Colon}}() + for dim in netcdf_spatial_dimensions(field) + slice = get_slice(haskey(slice_kw, Symbol(dim)) ? slice_kw[Symbol(dim)] : nothing) + push!(slice_array, slice) + end + return slice_array end -function read_output(fw::NetCDFOutputWriter, field_name, iter) - filepath = joinpath(fw.dir, filename(fw, "", iter)) - field_data = ncread(filepath, field_name) - ncclose(filepath) - return field_data +""" + write_output(model, OutputWriter) + +For internal user only. Writes output to the netcdf file at specified intervals. Increments the `Time` dimension every time an output is written to the file. +""" +function write_output(model, fw::NetCDFOutputWriter) + fw.len_time_dimension += 1 + fw.dataset["Time"][fw.len_time_dimension] = model.clock.time + for (fieldname, field) in fw.outputs + fw.dataset[fieldname][:,:,:,fw.len_time_dimension] = view(parentdata(field), fw.slices[fieldname]...) + end + sync(fw.dataset) + return nothing end #### @@ -532,3 +621,4 @@ function restore_from_checkpoint(filepath; kwargs=Dict()) return model end + diff --git a/test/regression_tests/thermal_bubble_regression_test.jl b/test/regression_tests/thermal_bubble_regression_test.jl index 9ea5182703..76bc728c04 100644 --- a/test/regression_tests/thermal_bubble_regression_test.jl +++ b/test/regression_tests/thermal_bubble_regression_test.jl @@ -17,20 +17,25 @@ function run_thermal_bubble_regression_test(arch) k1, k2 = round(Int, Nz/4), round(Int, 3Nz/4) model.tracers.T.data[i1:i2, j1:j2, k1:k2] .+= 0.01 - nc_writer = NetCDFOutputWriter(dir=joinpath(dirname(@__FILE__), "data"), - prefix="thermal_bubble_regression_", - frequency=10, padding=2) - - # Uncomment to include a NetCDF output writer that produces the regression. - # push!(model.output_writers, nc_writer) + outputs = Dict("v"=>model.velocities.v, + "u"=>model.velocities.u, + "w"=>model.velocities.w, + "T"=>model.tracers.T, + "S"=>model.tracers.S) + nc_writer = NetCDFOutputWriter(model, outputs, + filename="thermal_bubble_regression_test.nc", + frequency=10) + push!(model.output_writers, nc_writer) time_step!(model, 10, Δt) - u = read_output(nc_writer, "u", 10) - v = read_output(nc_writer, "v", 10) - w = read_output(nc_writer, "w", 10) - T = read_output(nc_writer, "T", 10) - S = read_output(nc_writer, "S", 10) + close(nc_writer) + + u = read_output(nc_writer, "u") + v = read_output(nc_writer, "v") + w = read_output(nc_writer, "w") + T = read_output(nc_writer, "T") + S = read_output(nc_writer, "S") field_names = ["u", "v", "w", "T", "S"] fields = [model.velocities.u, model.velocities.v, model.velocities.w, model.tracers.T, model.tracers.S] diff --git a/test/test_output_writers.jl b/test/test_output_writers.jl index 483a37bb36..2ac0f27b6e 100644 --- a/test/test_output_writers.jl +++ b/test/test_output_writers.jl @@ -17,22 +17,57 @@ function run_thermal_bubble_netcdf_tests(arch) k1, k2 = round(Int, Nz/4), round(Int, 3Nz/4) model.tracers.T.data[i1:i2, j1:j2, k1:k2] .+= 0.01 - nc_writer = NetCDFOutputWriter(dir=".", prefix="test_", frequency=10, padding=1) + outputs = Dict("v"=>model.velocities.v, + "u"=>model.velocities.u, + "w"=>model.velocities.w, + "T"=>model.tracers.T, + "S"=>model.tracers.S) + nc_writer = NetCDFOutputWriter(model, outputs, + filename="dumptest.nc", + frequency=10) push!(model.output_writers, nc_writer) + xC_slice = 1:10 + xF_slice = 2:11 + yC_slice = 10:15 + yF_slice = 1 + zC_slice = 10 + zF_slice = 9:11 + nc_sliced_writer = NetCDFOutputWriter(model, outputs, + filename="dumptestsliced.nc", + frequency=10, + xC=xC_slice, xF=xF_slice, yC=yC_slice, + yF=yF_slice, zC=zC_slice, zF=zF_slice) + push!(model.output_writers, nc_sliced_writer) + time_step!(model, 10, Δt) - u = read_output(nc_writer, "u", 10) - v = read_output(nc_writer, "v", 10) - w = read_output(nc_writer, "w", 10) - T = read_output(nc_writer, "T", 10) - S = read_output(nc_writer, "S", 10) + close(nc_writer) + close(nc_sliced_writer) + + u = read_output(nc_writer, "u") + v = read_output(nc_writer, "v") + w = read_output(nc_writer, "w") + T = read_output(nc_writer, "T") + S = read_output(nc_writer, "S") @test all(u .≈ Array(parentdata(model.velocities.u))) @test all(v .≈ Array(parentdata(model.velocities.v))) @test all(w .≈ Array(parentdata(model.velocities.w))) @test all(T .≈ Array(parentdata(model.tracers.T))) @test all(S .≈ Array(parentdata(model.tracers.S))) + + u_sliced = read_output(nc_sliced_writer, "u") + v_sliced = read_output(nc_sliced_writer, "v") + w_sliced = read_output(nc_sliced_writer, "w") + T_sliced = read_output(nc_sliced_writer, "T") + S_sliced = read_output(nc_sliced_writer, "S") + + @test all(u_sliced .≈ Array(parentdata(model.velocities.u))[xF_slice, yC_slice, zC_slice]) + @test all(v_sliced .≈ Array(parentdata(model.velocities.v))[xC_slice, yF_slice, zC_slice]) + @test all(w_sliced .≈ Array(parentdata(model.velocities.w))[xC_slice, yC_slice, zF_slice]) + @test all(T_sliced .≈ Array(parentdata(model.tracers.T))[xC_slice, yC_slice, zC_slice]) + @test all(S_sliced .≈ Array(parentdata(model.tracers.S))[xC_slice, yC_slice, zC_slice]) end function run_jld2_file_splitting_tests(arch) diff --git a/test/test_regression.jl b/test/test_regression.jl index e7c0f6fbfe..4a34c6ef83 100644 --- a/test/test_regression.jl +++ b/test/test_regression.jl @@ -1,4 +1,3 @@ - include("regression_tests/thermal_bubble_regression_test.jl") include("regression_tests/rayleigh_benard_regression_test.jl") include("regression_tests/ocean_large_eddy_simulation_regression_test.jl")