Shared registration body for register_2d/_3d/_segment_2d/_segment_3d.
(i0, j0, nx, ny, nz) are FILE-side start/count (already resolved
by the caller — plain global-offset slicing for the base
variants, degenerate-axis geometry for the segment variants).
| Type | Intent | Optional | Attributes | Name | ||
|---|---|---|---|---|---|---|
| class(ocean_data_input_t), | intent(inout) | :: | this | |||
| character(len=*), | intent(in) | :: | file | |||
| character(len=*), | intent(in) | :: | var | |||
| logical, | intent(in) | :: | is_3d | |||
| integer, | intent(in) | :: | i0 | |||
| integer, | intent(in) | :: | j0 | |||
| integer, | intent(in) | :: | nx | |||
| integer, | intent(in) | :: | ny | |||
| integer, | intent(in) | :: | nz | |||
| integer, | intent(in) | :: | dest_i0 | |||
| integer, | intent(in) | :: | dest_j0 | |||
| integer, | intent(in) | :: | dest_n1 | |||
| integer, | intent(in) | :: | dest_n2 | |||
| integer, | intent(in) | :: | dest_n3 | |||
| character(len=*), | intent(in), | optional | :: | time_mode | ||
| real(kind=wp), | intent(in), | optional | :: | cycle_period | ||
| real(kind=wp), | intent(in), | optional | :: | t_offset | ||
| real(kind=wp), | intent(in), | optional | :: | t_scale | ||
| real(kind=wp), | intent(in), | optional | :: | scale | ||
| real(kind=wp), | intent(in), | optional | :: | add_offset | ||
| integer, | intent(in), | optional | :: | oor | ||
| integer, | intent(out) | :: | id | |||
| integer, | intent(in), | optional | :: | edge | ||
| integer, | intent(out), | optional | :: | ierr |
Non-zero ( |
| Type | Visibility | Attributes | Name | Initial | |||
|---|---|---|---|---|---|---|---|
| integer, | private | :: | d1 | ||||
| integer, | private | :: | d2 | ||||
| integer, | private | :: | dt | ||||
| integer, | private | :: | dz | ||||
| integer, | private | :: | expect_nd | ||||
| integer, | private | :: | k | ||||
| integer, | private | :: | local_ierr | ||||
| integer, | private | :: | ncid | ||||
| integer, | private | :: | nt | ||||
| integer, | private | :: | status | ||||
| real(kind=wp), | private | :: | t_scale_eff | ||||
| integer, | private | :: | tdimid | ||||
| integer, | private | :: | tvarid | ||||
| logical, | private | :: | units_ok | ||||
| character(len=:), | private, | allocatable | :: | units_str | |||
| integer, | private | :: | var_dimids(4) | ||||
| integer, | private | :: | var_ndims | ||||
| integer, | private | :: | varid |
subroutine register_common(this, file, var, is_3d, i0, j0, nx, ny, nz, & dest_i0, dest_j0, dest_n1, dest_n2, dest_n3, & time_mode, cycle_period, t_offset, t_scale, scale, add_offset, & oor, id, edge, ierr) !! Shared registration body for register_2d/_3d/_segment_2d/_segment_3d. !! `(i0, j0, nx, ny, nz)` are FILE-side start/count (already resolved !! by the caller — plain global-offset slicing for the base !! variants, degenerate-axis geometry for the segment variants). class(ocean_data_input_t), intent(inout) :: this character(len=*), intent(in) :: file, var logical, intent(in) :: is_3d integer, intent(in) :: i0, j0, nx, ny, nz integer, intent(in) :: dest_i0, dest_j0, dest_n1, dest_n2, dest_n3 character(len=*), intent(in), optional :: time_mode real(wp), intent(in), optional :: cycle_period, t_offset, t_scale, scale, add_offset integer, intent(in), optional :: oor integer, intent(out) :: id integer, intent(in), optional :: edge integer, intent(out), optional :: ierr !! Non-zero (`OCEAN_STATUS_ERR_SETUP`/`OCEAN_STATUS_ERR_IO`) on a !! registry/file/dimension failure when present; absent behaves !! as today (`error stop`). integer :: ncid, varid, tvarid, tdimid, status integer :: var_ndims integer :: var_dimids(4) integer :: expect_nd, d1, d2, dz, dt, nt character(len=:), allocatable :: units_str logical :: units_ok real(wp) :: t_scale_eff integer :: k integer :: local_ierr if (present(ierr)) ierr = OCEAN_STATUS_OK if (this%nfields >= this%nfields_max) then call fail("ocean_data_input: registry full (max_fields = "// & to_string(this%nfields_max)//"); raise &ocean_data_nml max_fields", & ierr, OCEAN_STATUS_ERR_SETUP) return end if call nc_open_read(trim(file), ncid, ierr=local_ierr) if (.not. reg_io_ok(local_ierr, ierr)) return call nc_check(nf90_inq_varid(ncid, trim(var), varid), & "ocean_data_input: finding variable '"//trim(var)//"' in "//trim(file), local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return call nc_check(nf90_inquire_variable(ncid, varid, ndims=var_ndims, & dimids=var_dimids(1:merge(4, 3, is_3d))), & "ocean_data_input: querying variable '"//trim(var)//"'", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return expect_nd = merge(4, 3, is_3d) if (var_ndims /= expect_nd) then call nc_close(ncid) call fail("ocean_data_input: '"//trim(var)//"' in "//trim(file)// & " has "//to_string(var_ndims)//" dims; expected "// & to_string(expect_nd)//" (x,y[,z],t) — Fortran storage order required, "// & "no in-core transpose (regrid/reorder the file)", ierr, OCEAN_STATUS_ERR_IO) return end if call nc_check(nf90_inquire_dimension(ncid, var_dimids(1), len=d1), & "ocean_data_input: dim 1", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return call nc_check(nf90_inquire_dimension(ncid, var_dimids(2), len=d2), & "ocean_data_input: dim 2", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return if (is_3d) then call nc_check(nf90_inquire_dimension(ncid, var_dimids(3), len=dz), & "ocean_data_input: dim 3 (z)", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return call nc_check(nf90_inquire_dimension(ncid, var_dimids(4), len=dt), & "ocean_data_input: dim 4 (t)", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return else dz = 1 call nc_check(nf90_inquire_dimension(ncid, var_dimids(3), len=dt), & "ocean_data_input: dim 3 (t)", local_ierr) if (.not. reg_io_ok(local_ierr, ierr, ncid)) return end if if (present(edge)) then ! Degenerate-axis fail-loud check (§5.7.1): the horizontal ! extent this registration claims is 1 (a segment file) must ! actually BE 1 in the file. if (nx == 1 .and. d1 /= 1) then call nc_close(ncid) call fail("ocean_data_input: segment '"//trim(var)//"' edge "// & to_string(edge)//" expects a degenerate x axis (extent 1); "// & "file has extent "//to_string(d1), ierr, OCEAN_STATUS_ERR_IO) return end if if (ny == 1 .and. d2 /= 1) then call nc_close(ncid) call fail("ocean_data_input: segment '"//trim(var)//"' edge "// & to_string(edge)//" expects a degenerate y axis (extent 1); "// & "file has extent "//to_string(d2), ierr, OCEAN_STATUS_ERR_IO) return end if end if if (.not. dims_geometry_ok(var_ndims, expect_nd, d1, d2, i0 + nx - 1, j0 + ny - 1)) then call nc_close(ncid) call fail("ocean_data_input: '"//trim(var)//"' in "//trim(file)// & " horizontal dims too small for this rank's slab: file ("// & to_string(d1)//","//to_string(d2)//"), need offset+extent ("// & to_string(i0 + nx - 1)//","//to_string(j0 + ny - 1)//")", ierr, OCEAN_STATUS_ERR_IO) return end if if (is_3d .and. dz /= nz) then call nc_close(ncid) call fail("ocean_data_input: '"//trim(var)//"' in "//trim(file)// & " has "//to_string(dz)//" z-levels; caller expects nz_src = "// & to_string(nz), ierr, OCEAN_STATUS_ERR_IO) return end if nt = dt if (nt < 1) then call nc_close(ncid) call fail("ocean_data_input: '"//trim(var)//"' in "//trim(file)//" has no time records", & ierr, OCEAN_STATUS_ERR_IO) return end if ! Time axis: the time DIMENSION and its coordinate VARIABLE share ! the CF name by convention; try that, then fall back to "time". tdimid = var_dimids(expect_nd) call resolve_time_var(ncid, tdimid, tvarid, status) if (status /= nf90_noerr) then call nc_close(ncid) call fail("ocean_data_input: no time coordinate variable found for '"// & trim(var)//"' in "//trim(file), ierr, OCEAN_STATUS_ERR_IO) return end if id = this%nfields + 1 this%nfields = id associate (fld => this%fields(id)) fld%active = .true. fld%ncid = ncid fld%varid = varid fld%is_3d = is_3d fld%nx = nx fld%ny = ny fld%nz = merge(nz, 1, is_3d) fld%i0 = i0 fld%j0 = j0 fld%dest_i0 = dest_i0 fld%dest_j0 = dest_j0 fld%dest_n1 = dest_n1 fld%dest_n2 = dest_n2 fld%dest_n3 = dest_n3 fld%nt = nt fld%scale = 1.0_wp if (present(scale)) fld%scale = scale fld%add_offset = 0.0_wp if (present(add_offset)) fld%add_offset = add_offset fld%t_offset = 0.0_wp if (present(t_offset)) fld%t_offset = t_offset fld%cycle_period = 0.0_wp if (present(cycle_period)) fld%cycle_period = cycle_period fld%oor = DATA_OOR_ERROR if (present(oor)) fld%oor = oor fld%time_mode = DATA_TIME_LINEAR if (present(time_mode)) fld%time_mode = data_input_time_mode_from_string(time_mode) if (fld%time_mode == DATA_TIME_CYCLIC .and. fld%cycle_period <= 0.0_wp) then fld%active = .false. this%nfields = this%nfields - 1 call nc_close(ncid) call fail("ocean_data_input: '"//trim(var)//"' time_mode='cyclic' requires "// & "cycle_period > 0", ierr, OCEAN_STATUS_ERR_SETUP) return end if allocate (fld%t_axis(nt)) call nc_get_var_1d(ncid, tvarid, fld%t_axis) t_scale_eff = 1.0_wp if (present(t_scale)) then t_scale_eff = t_scale else call nc_get_att_text(ncid, tvarid, "units", units_str, units_ok) if (units_ok) then call data_input_time_scale_from_units(trim(units_str), t_scale_eff, units_ok) end if ! units_ok = .false. (absent/unrecognised attribute) silently ! keeps the seconds-default — the common case for a ! model-native file with no CF units attribute. end if fld%t_axis = fld%t_axis*t_scale_eff do k = 2, nt if (fld%t_axis(k) <= fld%t_axis(k - 1)) then call logger%error("ocean_data_input: '"//trim(var)//"' time axis not "// & "monotonically increasing at record "//to_string(k)//" ("// & to_string(fld%t_axis(k))//" <= "//to_string(fld%t_axis(k - 1))//")") error stop "ocean_data_input: non-monotonic time axis" end if end do allocate (fld%f0(fld%nx, fld%ny, fld%nz)) allocate (fld%f1(fld%nx, fld%ny, fld%nz)) if (fld%time_mode == DATA_TIME_STATIC) then call data_input_read_slab_impl(fld, 1) fld%f1 = fld%f0 fld%rec0 = 1 fld%rec1 = 1 fld%w = 0.0_wp end if end associate end subroutine register_common