Skip to content

Commit 2355d11

Browse files
committed
Make write_field! use the type of time
When running a simulation with `ITime`, the type of the time dimension in the NetCDF files should be `Float64` and not the type of the space.
1 parent 9ee9620 commit 2355d11

File tree

2 files changed

+76
-1
lines changed

2 files changed

+76
-1
lines changed

src/netcdf_writer.jl

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,10 +342,12 @@ function write_field!(writer::NetCDFWriter, field, diagnostic, u, p, t)
342342

343343
nc = writer.open_files[output_path]
344344

345+
# Save as associated float if t is ITime
346+
TT = typeof(float(t))
345347
# Define time coordinate
346348
add_time_maybe!(
347349
nc,
348-
FT;
350+
TT;
349351
units = "s",
350352
axis = "T",
351353
standard_name = "time",

test/writers.jl

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import ClimaCore.Fields
1111
import ClimaDiagnostics
1212
import ClimaDiagnostics.Writers
1313

14+
import ClimaUtilities.TimeManager: ITime
15+
1416
include("TestTools.jl")
1517

1618
# The temporary directory where we write the file cannot be in /tmp, it has
@@ -285,3 +287,74 @@ end
285287
show(stdout, MIME"text/plain"(), timing_ncdataset)
286288
println()
287289
end
290+
291+
@testset "NetCDFWriter write field time test" begin
292+
space = SphericalShellSpace(FT = Float32)
293+
field = Fields.coordinate_field(space).z
294+
295+
# Number of interpolation points
296+
NUM = 50
297+
298+
writer = Writers.NetCDFWriter(
299+
space,
300+
output_dir;
301+
num_points = (NUM, 2NUM, 3NUM),
302+
sync_schedule = ClimaDiagnostics.Schedules.DivisorSchedule(2),
303+
z_sampling_method = ClimaDiagnostics.Writers.FakePressureLevelsMethod(),
304+
)
305+
306+
u = (; field)
307+
# FIXME: We are hardcoding the start date
308+
p = (; start_date = Dates.DateTime(2010, 1))
309+
# `ITime` should save the times as `Float64`
310+
# Float32(1000 * 20995200.0) |> Dates.Millisecond is not equal to
311+
# 20_995_200_000 milliseconds, but it is true for Float64
312+
t = ITime(
313+
20_995_200,
314+
period = Dates.Second(1),
315+
epoch = Dates.DateTime(2010, 1),
316+
)
317+
318+
function compute!(out, u, p, t)
319+
if isnothing(out)
320+
return u.field
321+
else
322+
out .= u.field
323+
end
324+
end
325+
326+
diagnostic = ClimaDiagnostics.ScheduledDiagnostic(;
327+
variable = ClimaDiagnostics.DiagnosticVariable(;
328+
compute!,
329+
short_name = "ABC",
330+
),
331+
output_short_name = "timetest",
332+
output_long_name = "My Long Name",
333+
output_writer = writer,
334+
)
335+
Writers.interpolate_field!(writer, field, diagnostic, u, p, t)
336+
Writers.write_field!(writer, field, diagnostic, u, p, t)
337+
338+
# This is div(2^53, 1000), since 2^53 + 1 is the first integer that cannot be
339+
# represented exactly as a Float64 due to rounding error
340+
# Divide by 1000 because time conversion function will go through
341+
# milliseconds (e.g. see the conversion from seconds to dates in
342+
# write_field!)
343+
t = ITime(
344+
div(2^53, 1000),
345+
period = Dates.Second(1),
346+
epoch = Dates.DateTime(2010, 1),
347+
)
348+
Writers.interpolate_field!(writer, field, diagnostic, u, p, t)
349+
Writers.write_field!(writer, field, diagnostic, u, p, t)
350+
351+
NCDatasets.NCDataset(joinpath(output_dir, "timetest.nc")) do nc
352+
times = nc["time"][:]
353+
@test eltype(times) == Float64
354+
@test Dates.Second(Dates.Millisecond(round(1000 * times[1]))) ==
355+
Dates.Second(20_995_200)
356+
357+
@test Dates.Second(Dates.Millisecond(round(1000 * times[2]))) ==
358+
Dates.Second(div(2^53, 1000))
359+
end
360+
end

0 commit comments

Comments
 (0)