Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(0.96.0) Improve the NetCDFOutputWriter experience #4046

Open
wants to merge 40 commits into
base: main
Choose a base branch
from

Conversation

ali-ramadhan
Copy link
Member

@ali-ramadhan ali-ramadhan commented Jan 16, 2025

This PR updates the NetCDFOutputWriter to:

  • Properly work on RectilinearGrid and LatitudeLongitudeGrid (with correct and useful output attributes).
  • Save grid metrics with useful attributes.
  • Save immersed boundary information.
  • Properly support flat grids.
  • Work cleanly with LagrangianParticles output.
  • Allow for flexible dimension naming to satisfy desired naming conventions.
  • Write grid reconstruction metadata into a NetCDF group to support FieldTimeSeries construction from NetCDF (full support to be added in a subsequent PR).

Tests have been added for all these features. Thank you to @tomchor and @almacarolina for helpful discussions during this refactor!

There's still a little bit left to do, but if anyone has any thoughts or feedback and would like to leave a review I'd appreciate it! There are a lot of line additions but thankfully the changes are almost fully isolated to just two files.

TODO:

  • Output grid areas and volumes too? But maybe it would be nice to first have xareas, volumes, etc. via KernelFunctionOperation?
  • Further improve the docstring and documentation for NetCDFOutputWriter to highlight all features.
  • Use NetCDFOutputWriter + some fancier features in an example.
  • Figure out which tests are missing.
  • Watch out for failing tests/examples and fix them.

Some comments:

  • I'm hoping to merge this PR and immediately work on adding support for NetCDF-backed FieldTimeSeries. I was planning on working on it here (as the branch name suggests) but it will involve refactoring field_time_series.jl which seems best suited for a separate PR.
  • Supporting output of the free surface height is a bit hacky. Since it's a regular Field but is kind of a ReducedField we cannot dispatch on its type and work with it correctly. Will open an issue to discuss.
  • I'm tagging v0.96.0 since this PR significantly changes the dimension names used in NetCDF files produced by NetCDFOutputWriter.

Resolves #1334 (via the dimension name generator)
Resolves #2248
Resolves #2770 (Maybe? You can save u, v, w, T, S, and η in the same NetCDF file but it's a bit hacky, see above.)
Resolves #3997

This PR makes progress on issue #3935
This PR supercedes PR #2652

@ali-ramadhan
Copy link
Member Author

ali-ramadhan commented Jan 16, 2025

Here's what a NetCDF file looks like now in NCDatasets.jl and xarray to give an idea of the changes introduced by this PR.

NCDatasets.jl:

julia> ds = NCDataset("test/test_immersed_grid_latlon_no_halos_GPU.nc")
Dataset: test/test_immersed_grid_latlon_no_halos_GPU.nc
Group: /

Dimensions
   time = 6
   z_c = 16
   z_f = 17
   latitude_c = 16
   latitude_f = 17
   longitude_f = 17
   longitude_c = 16

Variables
  time   (6)
    Datatype:    Float64 (Float64)
    Dimensions:  time
    Attributes:
     units                = seconds
     long_name            = Time

  z_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  z_c
    Attributes:
     units                = m
     long_name            = Locations of the cell centers in the z-direction.

  z_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  z_f
    Attributes:
     units                = m
     long_name            = Locations of the cell faces in the z-direction.

  latitude_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  latitude_c
    Attributes:
     units                = degrees north
     long_name            = Locations of the cell centers in the meridional direction.

  latitude_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  latitude_f
    Attributes:
     units                = degrees north
     long_name            = Locations of the cell faces in the meridional direction.

  longitude_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f
    Attributes:
     units                = degrees east
     long_name            = Locations of the cell faces in the zonal direction.

  longitude_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c
    Attributes:
     units                = degrees east
     long_name            = Locations of the cell centers in the zonal direction.

  bottom_height   (16 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c

  dlatitude_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  latitude_c
    Attributes:
     units                = degrees
     long_name            = Angular spacings between the cell centers in the meridional direction.

  dlatitude_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  latitude_f
    Attributes:
     units                = degrees
     long_name            = Angular spacings between the cell faces in the meridional direction.

  dlongitude_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c
    Attributes:
     units                = degrees
     long_name            = Angular spacings between the cell centers in the zonal direction.

  dlongitude_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f
    Attributes:
     units                = degrees
     long_name            = Angular spacings between the cell faces in the zonal direction.

  dx_cc   (16 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the zonal direction between the cell located at (Center, Center).

  dx_cf   (16 × 17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_f
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the zonal direction between the cell located at (Center, Face).

  dx_fc   (17 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_c
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the zonal direction between the cell located at (Face, Center).

  dx_ff   (17 × 17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_f
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the zonal direction between the cell located at (Face, Face).

  dy_cc   (16 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the meridional direction between the cell located at (Center, Center).

  dy_cf   (16 × 17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_f
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the meridional direction between the cell located at (Center, Face).

  dy_fc   (17 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_c
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the meridional direction between the cell located at (Face, Center).

  dy_ff   (17 × 17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_f
    Attributes:
     units                = m
     long_name            = Geodesic spacings in the meridional direction between the cell located at (Face, Face).

  dz_c   (16)
    Datatype:    Float32 (Float32)
    Dimensions:  z_c
    Attributes:
     units                = m
     long_name            = Spacings between the cell faces (located at the cell centers) in the z-direction.

  dz_f   (17)
    Datatype:    Float32 (Float32)
    Dimensions:  z_f
    Attributes:
     units                = m
     long_name            = Spacings between the cell centers (located at the cell faces) in the z-direction.

  immersed_boundary_mask_ccc   (16 × 16 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c × z_c

  immersed_boundary_mask_ccf   (16 × 16 × 17)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c × z_f

  immersed_boundary_mask_cfc   (16 × 17 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_f × z_c

  immersed_boundary_mask_fcc   (17 × 16 × 16)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_c × z_c

  S   (16 × 16 × 16 × 6)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c × z_c × time
    Attributes:
     units                = practical salinity unit (psu)
     long_name            = Salinity

  T   (16 × 16 × 16 × 6)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c × z_c × time
    Attributes:
     units                = °C
     long_name            = Temperature

  u   (17 × 16 × 16 × 6)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_f × latitude_c × z_c × time
    Attributes:
     units                = m/s
     long_name            = Velocity in the zonal direction (+ = east).

  v   (16 × 17 × 16 × 6)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_f × z_c × time
    Attributes:
     units                = m/s
     long_name            = Velocity in the meridional direction (+ = north).

  w   (16 × 16 × 17 × 6)
    Datatype:    Float32 (Float32)
    Dimensions:  longitude_c × latitude_c × z_f × time
    Attributes:
     units                = m/s
     long_name            = Velocity in the vertical direction (+ = up).

Global attributes
  Julia                = This file was generated using Julia Version 1.10.7
Commit 4976d05258e (2024-11-26 15:57 UTC)
Build Info:
  Official https://julialang.org/ release
Platform Info:
  OS: Linux (x86_64-linux-gnu)
  CPU: 48 × AMD Ryzen Threadripper 7960X 24-Cores
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-15.0.7 (ORCJIT, znver3)
Threads: 1 default, 0 interactive, 1 GC (on 48 virtual cores)
Environment:
  JULIA_TEST_FAILFAST = true
  LD_PRELOAD = /usr/NX/lib/libnxegl.so
  JULIA_LOAD_PATH = @:/tmp/jl_JcvMoH
  GPU: NVIDIA GeForce RTX 4090

  Oceananigans         = This file was generated using Oceananigans v0.96.0
  date                 = This file was generated on 2025-01-15T17:53:38.863 local time (2025-01-16T00:53:38.863 UTC).
  interval             = 1
  output iteration interval = Output was saved every 1 iteration(s).
  schedule             = IterationInterval
Groups
  Dataset: test/test_immersed_grid_latlon_no_halos_GPU.nc
  Group: grid_reconstruction

  Dimensions
     φ_f = 17
     λ_f = 17
     z_f = 17

  Variables
    φ_f     (17)
      Datatype:    Float32 (Float32)
      Dimensions:  φ_f

    λ_f     (17)
      Datatype:    Float32 (Float32)
      Dimensions:  λ_f

    z_f     (17)
      Datatype:    Float32 (Float32)
      Dimensions:  z_f

  Global attributes
    Hx                   = 2
    Hy                   = 3
    Hz                   = 4
    Nx                   = 16
    Ny                   = 16
    Nz                   = 16
    TX                   = Bounded
    TY                   = Bounded
    TZ                   = Bounded
    eltype               = Float64
    immersed_boundary_type = GridFittedBottom
    type                 = LatitudeLongitudeGrid
    z_spacing            = regular
    λ_spacing            = regular
    φ_spacing            = regular

xarray:

In [2]: ds = xr.open_dataset("test/test_immersed_grid_latlon_no_halos_GPU.nc")

In [3]: ds
Out[3]: 
<xarray.Dataset> Size: 589kB
Dimensions:                     (time: 6, z_c: 16, z_f: 17, latitude_c: 16,
                                 latitude_f: 17, longitude_f: 17,
                                 longitude_c: 16)
Coordinates:
  * time                        (time) timedelta64[ns] 48B 00:00:00 ... 00:00...
  * z_c                         (z_c) float32 64B -968.8 -906.2 ... -31.25
  * z_f                         (z_f) float32 68B -1e+03 -937.5 ... -62.5 0.0
  * latitude_c                  (latitude_c) float32 64B -9.375 -8.125 ... 9.375
  * latitude_f                  (latitude_f) float32 68B -10.0 -8.75 ... 10.0
  * longitude_f                 (longitude_f) float32 68B -20.0 -17.5 ... 20.0
  * longitude_c                 (longitude_c) float32 64B -18.75 ... 18.75
Data variables: (12/24)
    bottom_height               (latitude_c, longitude_c) float32 1kB ...
    dlatitude_c                 (latitude_c) float32 64B ...
    dlatitude_f                 (latitude_f) float32 68B ...
    dlongitude_c                (longitude_c) float32 64B ...
    dlongitude_f                (longitude_f) float32 68B ...
    dx_cc                       (latitude_c, longitude_c) float32 1kB ...
    ...                          ...
    immersed_boundary_mask_fcc  (z_c, latitude_c, longitude_f) float32 17kB ...
    S                           (time, z_c, latitude_c, longitude_c) float32 98kB ...
    T                           (time, z_c, latitude_c, longitude_c) float32 98kB ...
    u                           (time, z_c, latitude_c, longitude_f) float32 104kB ...
    v                           (time, z_c, latitude_f, longitude_c) float32 104kB ...
    w                           (time, z_f, latitude_c, longitude_c) float32 104kB ...
Attributes:
    Julia:                      This file was generated using Julia Version 1...
    Oceananigans:               This file was generated using Oceananigans v0...
    date:                       This file was generated on 2025-01-15T17:53:3...
    interval:                   1
    output iteration interval:  Output was saved every 1 iteration(s).
    schedule:                   IterationInterval
In [4]: ds.longitude_f
Out[4]: 
<xarray.DataArray 'longitude_f' (longitude_f: 17)> Size: 68B
array([-20. , -17.5, -15. , -12.5, -10. ,  -7.5,  -5. ,  -2.5,   0. ,   2.5,
         5. ,   7.5,  10. ,  12.5,  15. ,  17.5,  20. ], dtype=float32)
Coordinates:
  * longitude_f  (longitude_f) float32 68B -20.0 -17.5 -15.0 ... 15.0 17.5 20.0
Attributes:
    units:      degrees east
    long_name:  Locations of the cell faces in the zonal direction.
In [5]: ds.u
Out[5]: 
<xarray.DataArray 'u' (time: 6, z_c: 16, latitude_c: 16, longitude_f: 17)> Size: 104kB
[26112 values with dtype=float32]
Coordinates:
  * time         (time) timedelta64[ns] 48B 00:00:00 ... 00:00:00.500000
  * z_c          (z_c) float32 64B -968.8 -906.2 -843.8 ... -156.2 -93.75 -31.25
  * latitude_c   (latitude_c) float32 64B -9.375 -8.125 -6.875 ... 8.125 9.375
  * longitude_f  (longitude_f) float32 68B -20.0 -17.5 -15.0 ... 15.0 17.5 20.0
Attributes:
    units:      m/s
    long_name:  Velocity in the zonal direction (+ = east).

Hmmm, looks like I forgot to save some attributes for immersed boundary related variables.

Comment on lines +204 to +205
Δxᶠᵃᵃ_name = dim_name_generator("dx", grid, f, nothing, nothing, Val(:x))
Δxᶜᵃᵃ_name = dim_name_generator("dx", grid, c, nothing, nothing, Val(:x))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that dx is hardcoded here. Should we allow for more flexibility here too since this is one of the motivations behind the PR?

Copy link
Member Author

@ali-ramadhan ali-ramadhan Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah so I suppose dx is the "canonical" name, but the dim_name_generator can be used to override this name!

For example, a custom dim_name_generator can be passed to the NetCDFOutputWriter constructor to change dx to Δx or delta_x before passing it back to Oceananigans.OutputWriters.default_dim_name (to keep all other behavior the same).

This is totally not obvious from the code (and the docstring) so I should add a test for this and probably another docstring example. It's how I was thinking we can satisfy desired naming conventions.

But happy to switch to another better design!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I figured that somewhere down in between this and the last comment haha. There's a comment somewhere about it. I think the way you're doing is great!

Comment on lines +321 to +334
function gather_immersed_boundary(grid::GFBIBG, indices, dim_name_generator)
op_mask_ccc = KernelFunctionOperation{Center, Center, Center}(peripheral_node, grid, Center(), Center(), Center())
op_mask_fcc = KernelFunctionOperation{Face, Center, Center}(peripheral_node, grid, Face(), Center(), Center())
op_mask_cfc = KernelFunctionOperation{Center, Face, Center}(peripheral_node, grid, Center(), Face(), Center())
op_mask_ccf = KernelFunctionOperation{Center, Center, Face}(peripheral_node, grid, Center(), Center(), Face())

return Dict(
"bottom_height" => Field(grid.immersed_boundary.bottom_height; indices),
"immersed_boundary_mask_ccc" => Field(op_mask_ccc; indices),
"immersed_boundary_mask_fcc" => Field(op_mask_fcc; indices),
"immersed_boundary_mask_cfc" => Field(op_mask_cfc; indices),
"immersed_boundary_mask_ccf" => Field(op_mask_ccf; indices)
)
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is assuming a GridFittedBottom, but it would be nice to extend it to GridFittedBoundary (the only difference is that GridFittedBoundary doesn't necessary have a bottom height).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! This function only dispatches on GridFittedBottom (via GFBIBG) but I need to also define gather_immersed_boundary for PartialCellBottom and GridFittedBoundary.

Comment on lines +405 to +413
xᶠᵃᵃ_name = dim_name_generator("x", grid, f, nothing, nothing, Val(:x))
xᶜᵃᵃ_name = dim_name_generator("x", grid, c, nothing, nothing, Val(:x))
yᵃᶠᵃ_name = dim_name_generator("y", grid, nothing, f, nothing, Val(:y))
yᵃᶜᵃ_name = dim_name_generator("y", grid, nothing, c, nothing, Val(:y))

Δxᶠᵃᵃ_name = dim_name_generator("dx", grid, f, nothing, nothing, Val(:x))
Δxᶜᵃᵃ_name = dim_name_generator("dx", grid, c, nothing, nothing, Val(:x))
Δyᵃᶠᵃ_name = dim_name_generator("dy", grid, nothing, f, nothing, Val(:y))
Δyᵃᶜᵃ_name = dim_name_generator("dy", grid, nothing, c, nothing, Val(:y))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as before. Should we avoid hardcoding these?

Comment on lines +415 to +418
xᶠᵃᵃ_attrs = Dict("long_name" => "Locations of the cell faces in the x-direction.", "units" => "m")
xᶜᵃᵃ_attrs = Dict("long_name" => "Locations of the cell centers in the x-direction.", "units" => "m")
yᵃᶠᵃ_attrs = Dict("long_name" => "Locations of the cell faces in the y-direction.", "units" => "m")
yᵃᶜᵃ_attrs = Dict("long_name" => "Locations of the cell centers in the y-direction.", "units" => "m")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
xᶠᵃᵃ_attrs = Dict("long_name" => "Locations of the cell faces in the x-direction.", "units" => "m")
xᶜᵃᵃ_attrs = Dict("long_name" => "Locations of the cell centers in the x-direction.", "units" => "m")
yᵃᶠᵃ_attrs = Dict("long_name" => "Locations of the cell faces in the y-direction.", "units" => "m")
yᵃᶜᵃ_attrs = Dict("long_name" => "Locations of the cell centers in the y-direction.", "units" => "m")
xᶠᵃᵃ_attrs = Dict("long_name" => "Cell face locations in the x-direction.", "units" => "m")
xᶜᵃᵃ_attrs = Dict("long_name" => "Cell center locations in the x-direction.", "units" => "m")
yᵃᶠᵃ_attrs = Dict("long_name" => "Cell face locations in the y-direction.", "units" => "m")
yᵃᶜᵃ_attrs = Dict("long_name" => "Cell center locations in the y-direction.", "units" => "m")

I always thought these names were pretty long and not super easy to read as axis labels in figures. I made them a bit shorter but I wonder if we can do better. Perhaps x node locations (faces) on so on? That way x is the first thing in the description, making it easier for the user/reader/viewer.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also we have always assumed SI units for the outputs. I wonder if it would be hard to include a flag to not do that.

Comment on lines +449 to +450
λᶠᵃᵃ_attrs = Dict("long_name" => "Locations of the cell faces in the zonal direction.", "units" => "degrees east")
λᶜᵃᵃ_attrs = Dict("long_name" => "Locations of the cell centers in the zonal direction.", "units" => "degrees east")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment here for the names and units.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I now understand that these are just the default ones! Somewhere down there must be an option to provide user-defined ones. Got it! Disregard the other comments about this,

Comment on lines +687 to +690
immersed_attrs = Dict(
"immersed_boundary_type" => string(nameof(typeof(ibg.immersed_boundary)))
)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

deflatelevel = 0,
part = 1,
file_splitting = NoFileSplitting(),
verbose = false)
dimension_name_generator = default_dim_name)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great way to do things. Maybe in the future we can include functions that already follow a given popular/useful convention. I think we should probably also provide one that uses the exact names Oceananigans uses (I assume that'll be needed for the integration with FieldTimeSeries?)

Comment on lines +1036 to +1039
outputs = Dict(
string(name) => construct_output(outputs[name], grid, indices, with_halos)
for name in keys(outputs)
)
Copy link
Collaborator

@tomchor tomchor Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably we should follow the conventions we already use in Oceananigans?

Suggested change
outputs = Dict(
string(name) => construct_output(outputs[name], grid, indices, with_halos)
for name in keys(outputs)
)
outputs = Dict(string(name) => construct_output(outputs[name], grid, indices, with_halos)
for name in keys(outputs)

Or in this case it might be better to even do a one-liner.

Comment on lines +1179 to +1190
define_output_variable!(
dataset,
materialized,
name,
array_type,
deflatelevel,
attributes,
dimensions,
filepath, # for better error messages
dimension_name_generator,
false # time_dependent = false
)
Copy link
Collaborator

@tomchor tomchor Jan 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, maybe we should keep consistency with the rest of Oceananigans formatting.

Suggested change
define_output_variable!(
dataset,
materialized,
name,
array_type,
deflatelevel,
attributes,
dimensions,
filepath, # for better error messages
dimension_name_generator,
false # time_dependent = false
)
define_output_variable!(dataset,
materialized,
name,
array_type,
deflatelevel,
attributes,
dimensions,
filepath, # for better error messages
dimension_name_generator,
false # time_dependent = false)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with this comment generally, we can start a discussion to format the code differently throughout, but either way I think we should strive to format consistently.

@tomchor
Copy link
Collaborator

tomchor commented Jan 17, 2025

I haven't checked the tests yet, but so far it's looking great! I'll try to check the tests tomorrow.

@glwagner
Copy link
Member

Supporting output of the free surface height is a bit hacky. Since it's a regular Field but is kind of a ReducedField we cannot dispatch on its type and work with it correctly. Will open an issue to discuss.

It's not a ReducedField, its a WindowedField. But properly supporting WindowedField is intrinsic to NetCDF output writing without halos so there should be a general solution to this.

@glwagner
Copy link
Member

I'm tagging v0.96.0 since this PR significantly changes the dimension names used in NetCDF files produced by NetCDFOutputWriter.

I'm not sure a FieldTimeSeries refactor is necessary (note that we also support NetCDF FieldTimeSeries on ClimaOcean, so I don't entirely understand why refactoring is necessary). However, in the case that such a refactor bumps the version again, would it be prudent to be more conservative about version bumping here?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants