subroutine nc_emit_post_fire(diag, ivar, t)
!! Post-fire emit hook. Appends one slice + time value for the
!! var that just fired. Bound to `diag%emit_post_fire` by
!! `open_stream`.
class(*), intent(inout) :: diag
integer, intent(in) :: ivar
real(wp), intent(in) :: t
integer :: n1, n2, n3, ti
select type (d => diag)
class is (ocean_diag_t)
if (.not. d%nc_stream%is_open) return
if (ivar < 1 .or. ivar > d%nvars) return
associate (v => d%vars(ivar))
if (v%nc_varid < 0) return
v%nc_time_index = v%nc_time_index + 1
ti = v%nc_time_index
call nc_check(nf90_put_var(d%nc_stream%ncid, v%nc_time_varid, &
[t], start=[ti], count=[1]), &
"writing diag time coord for "//trim(v%name))
n3 = size(v%output_buffer, 3)
if (d%nc_stream%xtype == NC_R4 .and. allocated(d%nc_stream%stage)) then
! Convert fp64 -> fp32 in the shared host staging buffer,
! then hand real32 data to a real32 variable. Handing the
! fp64 buffer straight to an NF90_FLOAT variable would also
! "work" (netcdf converts internally) but doubles the bytes
! crossing into the library — the whole point of the knob is
! the byte count, so the conversion is ours to do.
n1 = size(v%output_buffer, 1)
n2 = size(v%output_buffer, 2)
d%nc_stream%stage(1:n1, 1:n2, 1:n3) = &
real(v%output_buffer(1:n1, 1:n2, 1:n3), real32)
if (n3 == 1) then
call nc_put_var_3d_slice_r4(d%nc_stream%ncid, v%nc_varid, &
d%nc_stream%stage(1:n1, 1:n2, 1), ti)
else
call nc_put_var_4d_slice_r4(d%nc_stream%ncid, v%nc_varid, &
d%nc_stream%stage(1:n1, 1:n2, 1:n3), ti)
end if
else if (n3 == 1) then
call nc_put_var_3d_slice(d%nc_stream%ncid, v%nc_varid, &
v%output_buffer(:, :, 1), ti)
else
call nc_put_var_4d_slice(d%nc_stream%ncid, v%nc_varid, &
v%output_buffer, ti)
end if
! Flush the HDF5 metadata cache so frames survive an abort
! (e.g. the h-guard ERROR STOP): without this, a killed run
! leaves every record dim at 0 and the written data orphaned.
call nc_check(nf90_sync(d%nc_stream%ncid), &
"syncing diag stream after "//trim(v%name))
end associate
end select
end subroutine nc_emit_post_fire