@@ -12,7 +12,7 @@ using Oceananigans.Architectures: CPU, GPU, on_architecture
1212using Oceananigans. AbstractOperations: KernelFunctionOperation, AbstractOperation
1313using Oceananigans. BuoyancyFormulations: BuoyancyForce, BuoyancyTracer, SeawaterBuoyancy, LinearEquationOfState
1414using Oceananigans. Fields
15- using Oceananigans. Fields: Reduction, reduced_dimensions, reduced_location, location
15+ using Oceananigans. Fields: Reduction, reduced_dimensions, reduced_location, location, indices
1616using Oceananigans. Grids: Center, Face, Flat, Periodic, Bounded,
1717 AbstractGrid, RectilinearGrid, LatitudeLongitudeGrid, StaticVerticalDiscretization,
1818 topology, halo_size, xspacings, yspacings, zspacings, λspacings, φspacings,
@@ -88,7 +88,7 @@ already exist, they are validated to match the expected dimensions for the given
8888
8989Arguments:
9090- `ds`: NetCDF dataset
91- - `field`: AbstractField being written
91+ - `field`: AbstractField being written
9292- `all_dims`: Tuple of dimension names to create/validate
9393- `dimension_name_generator`: Function to generate dimension names
9494"""
@@ -103,7 +103,7 @@ function create_field_dimensions!(ds, field::AbstractField, all_dims, dimension_
103103 if " time" in all_dims && " time" ∉ keys (ds. dim)
104104 create_time_dimension! (ds)
105105 end
106-
106+
107107 return nothing
108108end
109109
@@ -162,6 +162,34 @@ function create_spatial_dimensions!(dataset, dims, attributes_dict; array_type=A
162162 end
163163end
164164
165+ """
166+ effective_reduced_dimensions(field)
167+
168+ Return dimensions that are effectively reduced, considering both location-based reduction
169+ (e.g. a `Nothing` location) and index-based reduction at boundaries (e.g. free surface
170+ height fields with :, :, Nz+1:Nz+1 indices).
171+ ```
172+ """
173+ function effective_reduced_dimensions (field)
174+ loc_reduced = reduced_dimensions (field)
175+
176+ idx_reduced = ()
177+ inds = indices (field)
178+ grid_size = size (field. grid)
179+
180+ for (dim, ind) in enumerate (inds)
181+ if ind isa UnitRange && length (ind) == 1
182+ index_value = first (ind)
183+ if index_value > grid_size[dim]
184+ idx_reduced = (idx_reduced... , dim)
185+ end
186+ end
187+ end
188+
189+ all_reduced = (loc_reduced... , idx_reduced... )
190+ return Tuple (unique (all_reduced))
191+ end
192+
165193# ####
166194# #### Gathering of grid dimensions
167195# ####
@@ -429,10 +457,13 @@ end
429457
430458function field_dimensions (field:: AbstractField , grid:: RectilinearGrid , dim_name_generator)
431459 LX, LY, LZ = location (field)
460+ TX, TY, TZ = topology (grid)
461+
462+ eff_reduced_dims = effective_reduced_dimensions (field)
432463
433- x_dim_name = dim_name_generator (" x" , grid, LX (), nothing , nothing , Val (:x ))
434- y_dim_name = dim_name_generator (" y" , grid, nothing , LY (), nothing , Val (:y ))
435- z_dim_name = dim_name_generator (" z" , grid, nothing , nothing , LZ (), Val (:z ))
464+ x_dim_name = ( 1 ∈ eff_reduced_dims || TX == Flat) ? " " : dim_name_generator (" x" , grid, LX (), nothing , nothing , Val (:x ))
465+ y_dim_name = ( 2 ∈ eff_reduced_dims || TY == Flat) ? " " : dim_name_generator (" y" , grid, nothing , LY (), nothing , Val (:y ))
466+ z_dim_name = ( 3 ∈ eff_reduced_dims || TZ == Flat) ? " " : dim_name_generator (" z" , grid, nothing , nothing , LZ (), Val (:z ))
436467
437468 x_dim_name = isempty (x_dim_name) ? tuple () : tuple (x_dim_name)
438469 y_dim_name = isempty (y_dim_name) ? tuple () : tuple (y_dim_name)
@@ -443,10 +474,13 @@ end
443474
444475function field_dimensions (field:: AbstractField , grid:: LatitudeLongitudeGrid , dim_name_generator)
445476 LΛ, LΦ, LZ = location (field)
477+ TΛ, TΦ, TZ = topology (grid)
478+
479+ eff_reduced_dims = effective_reduced_dimensions (field)
446480
447- λ_dim_name = dim_name_generator (" λ" , grid, LΛ (), nothing , nothing , Val (:x ))
448- φ_dim_name = dim_name_generator (" φ" , grid, nothing , LΦ (), nothing , Val (:y ))
449- z_dim_name = dim_name_generator (" z" , grid, nothing , nothing , LZ (), Val (:z ))
481+ λ_dim_name = ( 1 ∈ eff_reduced_dims || TΛ == Flat) ? " " : dim_name_generator (" λ" , grid, LΛ (), nothing , nothing , Val (:x ))
482+ φ_dim_name = ( 2 ∈ eff_reduced_dims || TΦ == Flat) ? " " : dim_name_generator (" φ" , grid, nothing , LΦ (), nothing , Val (:y ))
483+ z_dim_name = ( 3 ∈ eff_reduced_dims || TZ == Flat) ? " " : dim_name_generator (" z" , grid, nothing , nothing , LZ (), Val (:z ))
450484
451485 λ_dim_name = isempty (λ_dim_name) ? tuple () : tuple (λ_dim_name)
452486 φ_dim_name = isempty (φ_dim_name) ? tuple () : tuple (φ_dim_name)
@@ -1403,11 +1437,15 @@ drop_output_dims(output, data) = data # fallback
14031437drop_output_dims (output:: WindowedTimeAverage{<:Field} , data) = drop_output_dims (output. operand, data)
14041438
14051439function drop_output_dims (field:: Field , data)
1406- reduced_dims = reduced_dimensions (field)
1440+ eff_reduced_dims = effective_reduced_dimensions (field)
14071441 flat_dims = Tuple (i for (i, T) in enumerate (topology (field. grid)) if T == Flat)
1408- dims = (reduced_dims ... , flat_dims... )
1442+ dims = (eff_reduced_dims ... , flat_dims... )
14091443 dims = Tuple (Set (dims)) # ensure dims are unique
1410- return dropdims (data; dims)
1444+
1445+ # Only drop dimensions that exist in the data and are size 1
1446+ dims = filter (d -> d <= ndims (data) && size (data, d) == 1 , dims)
1447+
1448+ return isempty (dims) ? data : dropdims (data; dims= tuple (dims... ))
14111449end
14121450
14131451# ####
0 commit comments