From dd7774afc2829eb4f8b924d75687658ad8b1adaf Mon Sep 17 00:00:00 2001 From: noel Date: Sun, 7 Jun 2026 19:53:42 -0700 Subject: [PATCH 1/2] fix various PIO warnings --- .../eam/src/chemistry/utils/tracer_data.F90 | 22 ++++++-- components/eam/src/control/cam_history.F90 | 32 ++++++++--- components/eam/src/physics/cam/phys_prop.F90 | 24 +++++++-- components/eam/src/utils/cam_grid_support.F90 | 6 ++- components/elm/src/main/histFileMod.F90 | 53 +++++++++--------- components/elm/src/main/histGPUMod.F90 | 2 +- components/elm/src/main/ncdio_pio.F90.in | 54 ++++++++++++++++--- components/elm/src/main/restFileMod.F90 | 3 +- .../src/framework/mpas_stream_manager.F | 5 +- .../Registry_seaice_conservation_check.xml | 8 +-- driver-mct/main/seq_io_mod.F90 | 48 +++++++++++------ driver-moab/main/seq_io_mod.F90 | 36 ++++++++----- 12 files changed, 210 insertions(+), 83 deletions(-) diff --git a/components/eam/src/chemistry/utils/tracer_data.F90 b/components/eam/src/chemistry/utils/tracer_data.F90 index 62ccbcef8a25..e3ef7d7e6c85 100644 --- a/components/eam/src/chemistry/utils/tracer_data.F90 +++ b/components/eam/src/chemistry/utils/tracer_data.F90 @@ -32,7 +32,7 @@ module tracer_data pio_put_att, pio_put_var, & pio_get_var, pio_get_att, pio_nowrite, pio_inq_dimlen, & pio_inq_vardimid, pio_inq_dimlen, pio_closefile, & - pio_inquire_variable + pio_inquire_variable, pio_inq_varndims implicit none @@ -1669,6 +1669,7 @@ subroutine read_za_trc_linoz( fid, vid, loc_arr, strt, cnt, file, order ,vid_srf type(var_desc_t), intent(in), optional :: vid_srf integer :: cnt_srf(2) integer :: strt_srf(2) + integer :: srf_ndims !! type(interp_type) :: lat_wgts real(r8) :: to_lats(pcols), to_lons(pcols), wrk(pcols) @@ -1716,7 +1717,14 @@ subroutine read_za_trc_linoz( fid, vid, loc_arr, strt, cnt, file, order ,vid_srf if (present(vid_srf)) then !!padding for clim terms allocate(wrksrf(cnt(1)), stat=ierr ) - ierr = pio_get_var( fid, vid_srf, strt_srf, cnt_srf, wrksrf ) + !! Use only as many start/count elements as the variable has dims + !! to avoid PIO warnings when the surface variable is 1D. + ierr = pio_inq_varndims(fid, vid_srf, srf_ndims) + if (srf_ndims >= 2) then + ierr = pio_get_var( fid, vid_srf, strt_srf, cnt_srf, wrksrf ) + else + ierr = pio_get_var( fid, vid_srf, strt_srf(1:1), cnt_srf(1:1), wrksrf ) + end if !!surface padding wrk2d(:,file%nlev)=wrksrf deallocate(wrksrf) @@ -1774,6 +1782,7 @@ subroutine read_zasrf_trc_linoz( fid, vid, loc_arr, strt, cnt, file) integer :: c, k, ierr, ncols integer :: cnt_srf(2) integer :: strt_srf(2) + integer :: srf_ndims !! nullify(wrk_in) allocate( wrk(cnt(1)), stat=ierr ) @@ -1789,7 +1798,14 @@ subroutine read_zasrf_trc_linoz( fid, vid, loc_arr, strt, cnt, file) !! !for surface variable with the dimension of (time,lat) or (time,1) !for (time) it is also set like (time,1) - ierr = pio_get_var( fid, vid, strt_srf, cnt_srf, wrk ) + !! Use only as many start/count elements as the variable has dims + !! to avoid PIO warnings when the surface variable is 1D. + ierr = pio_inq_varndims(fid, vid, srf_ndims) + if (srf_ndims >= 2) then + ierr = pio_get_var( fid, vid, strt_srf, cnt_srf, wrk ) + else + ierr = pio_get_var( fid, vid, strt_srf(1:1), cnt_srf(1:1), wrk ) + end if !! if(associated(wrk_in)) then wrk_in = reshape( wrk(:),(/file%nlat/)) diff --git a/components/eam/src/control/cam_history.F90 b/components/eam/src/control/cam_history.F90 index 1d7d84245c77..84826697c9bd 100644 --- a/components/eam/src/control/cam_history.F90 +++ b/components/eam/src/control/cam_history.F90 @@ -103,7 +103,7 @@ module cam_history ! The size of these parameters should match the assignments in restart_vars_setnames and restart_dims_setnames below ! integer, parameter :: restartvarcnt = 38 - integer, parameter :: restartdimcnt = 10 + integer, parameter :: restartdimcnt = 11 type(rvar_id) :: restartvars(restartvarcnt) type(rdim_id) :: restartdims(restartdimcnt) integer, parameter :: ptapes_dim_ind = 1 @@ -116,6 +116,7 @@ module cam_history integer, parameter :: maxvarmdims_dim_ind = 8 integer, parameter :: registeredmdims_dim_ind = 9 integer, parameter :: max_hcoordname_len_dim_ind = 10 + integer, parameter :: avgflag_len_dim_ind = 11 integer :: nfmaster = 0 ! number of fields in master field list integer :: nflds(ptapes) ! number of fields per tape @@ -1099,9 +1100,10 @@ subroutine restart_vars_setnames() rvindex = rvindex + 1 restartvars(rvindex)%name = 'avgflag' restartvars(rvindex)%type = pio_char - restartvars(rvindex)%ndims = 2 - restartvars(rvindex)%dims(1) = maxnflds_dim_ind - restartvars(rvindex)%dims(2) = ptapes_dim_ind + restartvars(rvindex)%ndims = 3 + restartvars(rvindex)%dims(1) = avgflag_len_dim_ind + restartvars(rvindex)%dims(2) = maxnflds_dim_ind + restartvars(rvindex)%dims(3) = ptapes_dim_ind rvindex = rvindex + 1 restartvars(rvindex)%name = 'sampling_seq' @@ -1263,6 +1265,9 @@ subroutine restart_dims_setnames() restartdims(max_hcoordname_len_dim_ind)%name = 'max_hcoordname_len' restartdims(max_hcoordname_len_dim_ind)%len = max_hcoordname_len + restartdims(avgflag_len_dim_ind)%name = 'avgflag_len' + restartdims(avgflag_len_dim_ind)%len = 1 + end subroutine restart_dims_setnames @@ -1517,11 +1522,11 @@ subroutine write_restart_history ( File, & ierr = pio_put_var(File, numlev_desc,start,tape(t)%hlist(f)%field%numlev) ierr = pio_put_var(File, hwrt_prec_desc,start,tape(t)%hlist(f)%hwrt_prec) + ierr = pio_put_var(File, avgflag_desc,startc,tape(t)%hlist(f)%avgflag) ierr = pio_put_var(File, sseq_desc,startc,tape(t)%hlist(f)%field%sampling_seq) ierr = pio_put_var(File, longname_desc,startc,tape(t)%hlist(f)%field%long_name) ierr = pio_put_var(File, standardname_desc,startc,tape(t)%hlist(f)%field%standard_name) ierr = pio_put_var(File, units_desc,startc,tape(t)%hlist(f)%field%units) - ierr = pio_put_var(File, avgflag_desc,start, tape(t)%hlist(f)%avgflag) ierr = pio_put_var(File, fillval_desc,start, tape(t)%hlist(f)%field%fillvalue) ierr = pio_put_var(File, meridional_complement_desc,start, tape(t)%hlist(f)%field%meridional_complement) @@ -1583,7 +1588,7 @@ end subroutine write_restart_history subroutine read_restart_history (File) use pio, only: pio_inq_dimid - use pio, only: pio_inq_varid, pio_inq_dimname + use pio, only: pio_inq_varid, pio_inq_dimname, pio_inq_varndims use cam_pio_utils, only: cam_pio_openfile, cam_pio_closefile use cam_pio_utils, only: cam_pio_var_info use ioFileMod, only: getfil @@ -1836,11 +1841,22 @@ subroutine read_restart_history (File) ierr = pio_get_var(File,fillval_desc, (/f,t/), tape(t)%hlist(f)%field%fillvalue) ierr = pio_get_var(File,meridional_complement_desc, (/f,t/), tape(t)%hlist(f)%field%meridional_complement) ierr = pio_get_var(File,zonal_complement_desc, (/f,t/), tape(t)%hlist(f)%field%zonal_complement) - ierr = pio_get_var(File,avgflag_desc, (/f,t/), tape(t)%hlist(f)%avgflag) + ! avgflag: new restarts store it as 3D (avgflag_len=1, maxnflds, ptapes) to satisfy + ! PIO's convention that the first Fortran dim is the string length. Old restarts + ! stored it as 2D (maxnflds, ptapes) without a leading string-length dim, which + ! caused spurious PIO buffer-size warnings. Support both layouts here. + ierr = pio_inq_varndims(File, avgflag_desc, ndims) + if (ndims == 3) then + ierr = pio_get_var(File,avgflag_desc, (/1,f,t/), tape(t)%hlist(f)%avgflag) + else + ierr = pio_get_var(File,avgflag_desc, (/f,t/), tape(t)%hlist(f)%avgflag) + end if ierr = pio_get_var(File,longname_desc, (/1,f,t/), tape(t)%hlist(f)%field%long_name) tape(t)%hlist(f)%field%standard_name = '' ierr = pio_get_var(File,standardname_desc, (/1,f,t/), tape(t)%hlist(f)%field%standard_name) + call strip_null(tape(t)%hlist(f)%field%standard_name) ierr = pio_get_var(File,units_desc, (/1,f,t/), tape(t)%hlist(f)%field%units) + call strip_null(tape(t)%hlist(f)%field%units) tape(t)%hlist(f)%field%sampling_seq(1:max_chars) = ' ' ierr = pio_get_var(File,sseq_desc, (/1,f,t/), tape(t)%hlist(f)%field%sampling_seq) call strip_null(tape(t)%hlist(f)%field%sampling_seq) @@ -4151,7 +4167,7 @@ subroutine h_define (t, restart) 'h_define: cannot define long_name for '//trim(fname_tmp)) str = tape(t)%hlist(f)%field%standard_name - if (str /= ' ') then + if (len_trim(str) > 0) then ierr=pio_put_att (tape(t)%File, varid, 'standard_name', trim(str)) call cam_pio_handle_error(ierr, & 'h_define: cannot define standard_name for '//trim(fname_tmp)) diff --git a/components/eam/src/physics/cam/phys_prop.F90 b/components/eam/src/physics/cam/phys_prop.F90 index 65961bf89ec9..c78b3d29dcdb 100644 --- a/components/eam/src/physics/cam/phys_prop.F90 +++ b/components/eam/src/physics/cam/phys_prop.F90 @@ -16,7 +16,8 @@ module phys_prop use cam_pio_utils, only: cam_pio_openfile use pio, only: file_desc_t, var_desc_t, pio_get_var, pio_inq_varid, & pio_inq_dimlen, pio_inq_dimid , pio_nowrite, pio_closefile, & - pio_seterrorhandling, PIO_BCAST_ERROR, PIO_INTERNAL_ERROR, PIO_NOERR + pio_seterrorhandling, PIO_BCAST_ERROR, PIO_INTERNAL_ERROR, PIO_NOERR, & + pio_inq_varndims use cam_logfile, only: iulog use cam_abortutils, only: endrun @@ -587,7 +588,8 @@ subroutine insoluble_optics_init(phys_prop, nc_id) integer :: sw_ext_id, sw_ssa_id, sw_asm_id, lw_ext_id integer :: swbands, nbnd integer :: ierr ! error flag - integer :: start(2), count(2) + integer :: ndims + integer, allocatable :: start(:), count(:) !------------------------------------------------------------------------------------ allocate (phys_prop%sw_nonhygro_ext(nswbands)) @@ -615,14 +617,28 @@ subroutine insoluble_optics_init(phys_prop, nc_id) ierr = pio_inq_varid(nc_id, 'asm_sw', sw_asm_id) ierr = pio_inq_varid(nc_id, 'abs_lw', lw_ext_id) + ! Query ndims from file so start/count match exactly, avoiding warnings + ! from SCORPIO when array size differs from variable rank. The band + ! dimension is always the last (or only) dimension; all leading dimensions + ! are singleton and get start=1, count=1. + ierr = pio_inq_varndims(nc_id, sw_ext_id, ndims) + allocate(start(ndims), count(ndims)) start = 1 - count=(/1,swbands/) + count = 1 + count(ndims) = swbands ierr = pio_get_var(nc_id, sw_ext_id, start, count, phys_prop%sw_nonhygro_ext) ierr = pio_get_var(nc_id, sw_ssa_id, start, count, phys_prop%sw_nonhygro_ssa) ierr = pio_get_var(nc_id, sw_asm_id, start, count, phys_prop%sw_nonhygro_asm) - count = (/1,nbnd/) + deallocate(start, count) + + ierr = pio_inq_varndims(nc_id, lw_ext_id, ndims) + allocate(start(ndims), count(ndims)) + start = 1 + count = 1 + count(ndims) = nbnd ierr = pio_get_var(nc_id, lw_ext_id, start, count, phys_prop%lw_abs) + deallocate(start, count) ! read refractive index data if available call refindex_aer_init(phys_prop, nc_id) diff --git a/components/eam/src/utils/cam_grid_support.F90 b/components/eam/src/utils/cam_grid_support.F90 index bc147321b325..348f54173840 100644 --- a/components/eam/src/utils/cam_grid_support.F90 +++ b/components/eam/src/utils/cam_grid_support.F90 @@ -574,8 +574,10 @@ subroutine write_horiz_coord_attr(this, File, dimid_out) ierr=pio_put_att(File, this%vardesc, 'long_name', trim(this%long_name)) call cam_pio_handle_error(ierr, 'Error writing "long_name" attr in write_horiz_coord_attr') ! units - ierr=pio_put_att(File, this%vardesc, 'units', trim(this%units)) - call cam_pio_handle_error(ierr, 'Error writing "units" attr in write_horiz_coord_attr') + if (len_trim(this%units) > 0) then + ierr=pio_put_att(File, this%vardesc, 'units', trim(this%units)) + call cam_pio_handle_error(ierr, 'Error writing "units" attr in write_horiz_coord_attr') + end if end if ! We define the variable if (present(dimid_out)) then diff --git a/components/elm/src/main/histFileMod.F90 b/components/elm/src/main/histFileMod.F90 index b0906e931fa3..e9afeec6556d 100644 --- a/components/elm/src/main/histFileMod.F90 +++ b/components/elm/src/main/histFileMod.F90 @@ -49,6 +49,7 @@ module histFileMod integer , public, parameter :: max_flds = 2500 ! max number of history fields integer , public, parameter :: max_namlen = 64 ! maximum number of characters for field name integer , private, parameter :: hist_dim_name_length = 16 ! lenngth of character strings in dimension names + integer , private, parameter :: hist_date_str_len = 8 ! length of date/time strings (cdate, ctime from getdatetime) ! Possible ways to treat multi-layer snow fields at times when no snow is present in a ! given layer. Note that the public parameters are the only ones that can be used by @@ -181,10 +182,10 @@ module histFileMod integer :: num1d_out ! size of hbuf first dimension (all nodes) integer :: num2d ! size of hbuf second dimension (e.g. number of vertical levels) integer :: hpindex ! history pointer index - character(len=8) :: p2c_scale_type ! scale factor when averaging pft to column - character(len=8) :: c2l_scale_type ! scale factor when averaging column to landunit - character(len=8) :: l2g_scale_type ! scale factor when averaging landunit to gridcell - character(len=8) :: t2g_scale_type ! scale factor when averaging topounit to gridcell + character(len=hist_dim_name_length) :: p2c_scale_type ! scale factor when averaging pft to column + character(len=hist_dim_name_length) :: c2l_scale_type ! scale factor when averaging column to landunit + character(len=hist_dim_name_length) :: l2g_scale_type ! scale factor when averaging landunit to gridcell + character(len=hist_dim_name_length) :: t2g_scale_type ! scale factor when averaging topounit to gridcell integer :: no_snow_behavior ! for multi-layer snow fields, flag saying how to treat times when a given snow layer is absent end type field_info @@ -251,7 +252,8 @@ module histFileMod type(file_desc_t) :: ncid_hist(max_tapes) ! file ids for history restart files integer :: time_dimid ! time dimension id integer :: hist_interval_dimid ! time bounds dimension id - integer :: strlen_dimid ! string dimension id + integer :: strlen_dimid ! string dimension id (length hist_dim_name_length) + integer :: strlen_dt_dimid ! date/time string dimension id (length hist_date_str_len) ! ! Time Constant variable names and filename ! @@ -1048,10 +1050,10 @@ subroutine hist_update_hbuf_field_1d (t, f, bounds) character(len=hist_dim_name_length) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] character(len=hist_dim_name_length) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] character(len=1) :: avgflag ! time averaging flag - character(len=8) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column - character(len=8) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits - character(len=8) :: l2g_scale_type ! scale type for subgrid averaging of landunits to gridcells - character(len=8) :: t2g_scale_type ! scale type for subgrid averaging of topounits to gridcells + character(len=hist_dim_name_length) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column + character(len=hist_dim_name_length) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits + character(len=hist_dim_name_length) :: l2g_scale_type ! scale type for subgrid averaging of landunits to gridcells + character(len=hist_dim_name_length) :: t2g_scale_type ! scale type for subgrid averaging of topounits to gridcells real(r8), pointer :: hbuf(:,:) ! history buffer integer , pointer :: nacs(:,:) ! accumulation counter real(r8), pointer :: field(:) ! clm 1d pointer field @@ -1300,10 +1302,10 @@ subroutine hist_update_hbuf_field_2d (t, f, bounds, num2d) character(len=hist_dim_name_length) :: type1d ! 1d clm pointerr type ["gridcell","landunit","column","pft"] character(len=hist_dim_name_length) :: type1d_out ! 1d history buffer type ["gridcell","landunit","column","pft"] character(len=1) :: avgflag ! time averaging flag - character(len=8) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column - character(len=8) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits - character(len=8) :: l2g_scale_type ! scale type for subgrid averaging of landunits to gridcells - character(len=8) :: t2g_scale_type ! scale type for subgrid averaging of topounits to gridcells + character(len=hist_dim_name_length) :: p2c_scale_type ! scale type for subgrid averaging of pfts to column + character(len=hist_dim_name_length) :: c2l_scale_type ! scale type for subgrid averaging of columns to landunits + character(len=hist_dim_name_length) :: l2g_scale_type ! scale type for subgrid averaging of landunits to gridcells + character(len=hist_dim_name_length) :: t2g_scale_type ! scale type for subgrid averaging of topounits to gridcells integer :: no_snow_behavior ! for multi-layer snow fields, behavior to use when a given layer is absent real(r8), pointer :: hbuf(:,:) ! history buffer integer , pointer :: nacs(:,:) ! accumulation counter @@ -1928,6 +1930,7 @@ subroutine htape_create (t, histrest) call ncd_defdim(lnfid, subs_name(n), subs_dim(n), dimid) end do call ncd_defdim(lnfid, 'string_length', hist_dim_name_length, strlen_dimid) + call ncd_defdim(lnfid, 'string_date_len', hist_date_str_len, strlen_dt_dimid) call ncd_defdim( lnfid, 'levdcmp', nlevdecomp_full, dimid) call ncd_defdim( lnfid, 'levtrc', nlevtrc_full, dimid) @@ -2109,7 +2112,7 @@ subroutine htape_timeconst3D(t, & character(len=max_chars) :: standard_name ! variable CF standard_name character(len=max_namlen):: varname ! variable name character(len=max_namlen):: units ! variable units - character(len=8) :: l2g_scale_type ! scale type for subgrid averaging of landunits to grid cells + character(len=hist_dim_name_length) :: l2g_scale_type ! scale type for subgrid averaging of landunits to grid cells ! real(r8), pointer :: histi(:,:) ! temporary real(r8), pointer :: histo(:,:) ! temporary @@ -2648,7 +2651,7 @@ subroutine htape_timeconst(t, mode) call ncd_defvar(nfid(t), 'time_bounds', ncd_double, 2, dim2id, varid, & long_name = 'history time interval endpoints') - dim2id(1) = strlen_dimid; dim2id(2) = time_dimid + dim2id(1) = strlen_dt_dimid; dim2id(2) = time_dimid call ncd_defvar(nfid(t), 'date_written', ncd_char, 2, dim2id, varid) call ncd_defvar(nfid(t), 'time_written', ncd_char, 2, dim2id, varid) @@ -4497,11 +4500,11 @@ subroutine hist_addfld1d (fname, units, avgflag, long_name, type1d_out, standard integer :: hpindex ! history buffer pointer index character(len=hist_dim_name_length) :: l_type1d ! 1d data type character(len=hist_dim_name_length) :: l_type1d_out ! 1d output type - character(len=8) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column - character(len=8) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits - character(len=8) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells - character(len=8) :: scale_type_t2g ! scale type for subgrid averaging of topounits to gridcells - type(bounds_type):: bounds ! boudns + character(len=hist_dim_name_length) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column + character(len=hist_dim_name_length) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits + character(len=hist_dim_name_length) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells + character(len=hist_dim_name_length) :: scale_type_t2g ! scale type for subgrid averaging of topounits to gridcells + type(bounds_type):: bounds ! boudns character(len=16):: l_default ! local version of 'default' character(len=max_namlen) :: lstandard_name ! local standard name character(len=*),parameter :: subname = 'hist_addfld1d' @@ -4744,11 +4747,11 @@ subroutine hist_addfld2d (fname, type2d, units, avgflag, long_name, type1d_out, integer :: hpindex ! history buffer index character(len=hist_dim_name_length) :: l_type1d ! 1d data type character(len=hist_dim_name_length) :: l_type1d_out ! 1d output type - character(len=8) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column - character(len=8) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits - character(len=8) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells - character(len=8) :: scale_type_t2g ! scale type for subgrid averaging of topounits to gridcells - type(bounds_type):: bounds + character(len=hist_dim_name_length) :: scale_type_p2c ! scale type for subgrid averaging of pfts to column + character(len=hist_dim_name_length) :: scale_type_c2l ! scale type for subgrid averaging of columns to landunits + character(len=hist_dim_name_length) :: scale_type_l2g ! scale type for subgrid averaging of landunits to gridcells + character(len=hist_dim_name_length) :: scale_type_t2g ! scale type for subgrid averaging of topounits to gridcells + type(bounds_type):: bounds character(len=16):: l_default ! local version of 'default' character(len=max_namlen) :: lstandard_name ! local standard name character(len=*),parameter :: subname = 'hist_addfld2d' diff --git a/components/elm/src/main/histGPUMod.F90 b/components/elm/src/main/histGPUMod.F90 index 43522b97c4fc..bf9b02020be4 100644 --- a/components/elm/src/main/histGPUMod.F90 +++ b/components/elm/src/main/histGPUMod.F90 @@ -46,7 +46,7 @@ module histGPUMod integer, pointer :: p2c_scale_type => null() ! scale factor when averaging pft to column integer, pointer :: c2l_scale_type => null() ! scale factor when averaging column to landunit integer, pointer :: l2g_scale_type => null() ! scale factor when averaging landunit to gridcell - character(len=8), pointer :: t2g_scale_type => null() ! scale factor when averaging topounit to gridcell + character(len=16), pointer :: t2g_scale_type => null() ! scale factor when averaging topounit to gridcell integer, pointer :: no_snow_behavior => null() ! for multi-layer snow fields, flag saying how to treat times when a given snow layer is absent ! character(len=1), pointer :: avgflag => null() ! time averaging flag diff --git a/components/elm/src/main/ncdio_pio.F90.in b/components/elm/src/main/ncdio_pio.F90.in index 6fbaba0b7108..fd62595e7aeb 100644 --- a/components/elm/src/main/ncdio_pio.F90.in +++ b/components/elm/src/main/ncdio_pio.F90.in @@ -180,7 +180,12 @@ contains subroutine ncd_pio_openfile(file, fname, mode) ! ! !DESCRIPTION: - ! Open a NetCDF PIO file + ! Open a NetCDF PIO file. Detects HDF5/NetCDF4 files (magic bytes + ! \x89HDF) and opens them with PIO_IOTYPE_NETCDF4P instead of + ! PIO_IOTYPE_PNETCDF to avoid PIO warnings about unsupported formats. + ! + ! !USES: + use pio, only : pio_iotype_pnetcdf, pio_iotype_netcdf4p ! ! !ARGUMENTS: class(file_desc_t) , intent(inout) :: file ! Output PIO file handle @@ -188,10 +193,43 @@ contains integer , intent(in) :: mode ! file mode ! ! !LOCAL VARIABLES: - integer :: ierr + integer :: ierr + integer :: my_io_type ! iotype selected for this open + integer :: iunit ! Fortran unit for header read + integer :: ios ! I/O status + logical :: is_hdf5 ! .true. if file has HDF5 magic bytes + character :: hdr(8) ! first 8 bytes of file + ! HDF5 magic: 0x89 'H' 'D' 'F' 0x0D 0x0A 0x1A 0x0A + character, parameter :: hdf5_magic(8) = & + (/ char(137), 'H', 'D', 'F', char(13), char(10), char(26), char(10) /) !----------------------------------------------------------------------- - ierr = pio_openfile(pio_subsystem, file, io_type, fname, mode) + ! Detect HDF5/NetCDF4 format on the master process and broadcast result + is_hdf5 = .false. + if (masterproc) then + iunit = getavu() + open(unit=iunit, file=trim(fname), form='unformatted', access='stream', & + status='old', iostat=ios) + if (ios == 0) then + read(iunit, iostat=ios) hdr + if (ios == 0) then + is_hdf5 = all(hdr == hdf5_magic) + end if + end if + call relavu(iunit) ! closes (if open) and frees the unit + end if + call MPI_Bcast(is_hdf5, 1, MPI_LOGICAL, 0, mpicom, ierr) + + my_io_type = io_type + if (is_hdf5 .and. my_io_type == pio_iotype_pnetcdf) then + my_io_type = pio_iotype_netcdf4p + if (pio_iotask_rank(pio_subsystem)==0) then + write(iulog,*) 'ncd_pio_openfile: detected NetCDF4/HDF5 file, ', & + 'switching from pnetcdf to netcdf4p iotype for ', trim(fname) + end if + end if + + ierr = pio_openfile(pio_subsystem, file, my_io_type, fname, mode) if(ierr/= PIO_NOERR) then call shr_sys_abort('ncd_pio_openfile ERROR: Failed to open file') @@ -999,10 +1037,12 @@ contains ! Add attributes ! if (present(long_name)) then - call ncd_putatt(ncid, varid, 'long_name', trim(long_name)) + if (len_trim(long_name) > 0) then + call ncd_putatt(ncid, varid, 'long_name', trim(long_name)) + end if end if if (present(standard_name)) then - if (standard_name /= ' ') then + if (len_trim(standard_name) > 0) then call ncd_putatt(ncid, varid, 'standard_name', trim(standard_name)) end if end if @@ -1036,7 +1076,9 @@ contains call ncd_putatt(ncid, varid, 'comment', trim(comment)) end if if (present(units)) then - call ncd_putatt(ncid, varid, 'units', trim(units)) + if (len_trim(units) > 0) then + call ncd_putatt(ncid, varid, 'units', trim(units)) + end if end if if (present(cell_method)) then str = 'time: ' // trim(cell_method) diff --git a/components/elm/src/main/restFileMod.F90 b/components/elm/src/main/restFileMod.F90 index 291178b98233..d3663cd8df26 100644 --- a/components/elm/src/main/restFileMod.F90 +++ b/components/elm/src/main/restFileMod.F90 @@ -1004,7 +1004,8 @@ subroutine restFile_dimset( ncid ) call ncd_putatt(ncid, NCD_GLOBAL, 'case_title' , trim(ctitle)) call ncd_putatt(ncid, NCD_GLOBAL, 'case_id' , trim(caseid)) call ncd_putatt(ncid, NCD_GLOBAL, 'surface_dataset', trim(fsurdat)) - call ncd_putatt(ncid, NCD_GLOBAL, 'flanduse_timeseries', trim(get_flanduse_timeseries())) + if (len_trim(get_flanduse_timeseries()) > 0) & + call ncd_putatt(ncid, NCD_GLOBAL, 'flanduse_timeseries', trim(get_flanduse_timeseries())) call ncd_putatt(ncid, NCD_GLOBAL, 'title', 'ELM Restart information') if (create_glacier_mec_landunit) then call ncd_putatt(ncid, ncd_global, 'created_glacier_mec_landunits', 'true') diff --git a/components/mpas-framework/src/framework/mpas_stream_manager.F b/components/mpas-framework/src/framework/mpas_stream_manager.F index d50168038c86..0d78e894dc87 100644 --- a/components/mpas-framework/src/framework/mpas_stream_manager.F +++ b/components/mpas-framework/src/framework/mpas_stream_manager.F @@ -4337,7 +4337,10 @@ end subroutine gen_random call mpas_writeStreamAtt(stream % stream, itr % memberName, intAtt, syncVal=.false., ierr=local_ierr) else if ( itr % dataType == MPAS_POOL_CHARACTER ) then call mpas_pool_get_config(stream % att_pool, itr % memberName, charAtt) - call mpas_writeStreamAtt(stream % stream, itr % memberName, charAtt, syncVal=.false., ierr=local_ierr) + local_ierr = MPAS_STREAM_NOERR + if (len_trim(charAtt) > 0) then + call mpas_writeStreamAtt(stream % stream, itr % memberName, charAtt, syncVal=.false., ierr=local_ierr) + end if else if ( itr % dataType == MPAS_POOL_LOGICAL ) then call mpas_pool_get_config(stream % att_pool, itr % memberName, logAtt) if (logAtt) then diff --git a/components/mpas-seaice/src/analysis_members/Registry_seaice_conservation_check.xml b/components/mpas-seaice/src/analysis_members/Registry_seaice_conservation_check.xml index 3be754ebea1f..548768a925c6 100644 --- a/components/mpas-seaice/src/analysis_members/Registry_seaice_conservation_check.xml +++ b/components/mpas-seaice/src/analysis_members/Registry_seaice_conservation_check.xml @@ -40,13 +40,13 @@ - - - @@ -307,7 +307,7 @@ 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"internal_dname",trim(dname)) if (present(tavg)) then if (tavg) then @@ -787,9 +789,11 @@ subroutine seq_io_write_avs(filename,gsmap,AVS,dname,whead,wdata,nx,ny,nt,fillva rcode = pio_def_var(cpl_io_file(lfile_ind),trim(name1),PIO_DOUBLE,dimid,varid) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"_FillValue",lfillvalue) end if - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"internal_dname",trim(dname)) if (present(tavg)) then if (tavg) then @@ -1024,9 +1028,11 @@ subroutine seq_io_write_avscomp(filename, comp, flow, dname, & rcode = pio_def_var(cpl_io_file(lfile_ind),trim(name1),PIO_DOUBLE,dimid,varid) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"_FillValue",lfillvalue) end if - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"internal_dname",trim(dname)) if (present(tavg)) then if (tavg) then @@ -1158,9 +1164,11 @@ subroutine seq_io_write_int(filename,idata,dname,whead,wdata,file_ind) ! rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',1,dimid(1)) ! rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,dimid,varid) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -1235,9 +1243,11 @@ subroutine seq_io_write_int1d(filename,idata,dname,whead,wdata,file_ind) lnx = size(idata) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -1313,9 +1323,11 @@ subroutine seq_io_write_r8(filename,rdata,dname,whead,wdata,file_ind) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_DOUBLE,varid) if(rcode==PIO_NOERR) then - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) end if endif @@ -1389,9 +1401,11 @@ subroutine seq_io_write_r81d(filename,rdata,dname,whead,wdata,file_ind) lnx = size(rdata) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_DOUBLE,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -1466,9 +1480,11 @@ subroutine seq_io_write_char(filename,rdata,dname,whead,wdata,file_ind) lnx = len(charvar) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_len',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_CHAR,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif diff --git a/driver-moab/main/seq_io_mod.F90 b/driver-moab/main/seq_io_mod.F90 index 2c57b8ec158b..285de0088715 100644 --- a/driver-moab/main/seq_io_mod.F90 +++ b/driver-moab/main/seq_io_mod.F90 @@ -436,9 +436,11 @@ subroutine seq_io_write_int(filename,idata,dname,whead,wdata,file_ind) ! rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',1,dimid(1)) ! rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,dimid,varid) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -513,9 +515,11 @@ subroutine seq_io_write_int1d(filename,idata,dname,whead,wdata,file_ind) lnx = size(idata) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_INT,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -591,9 +595,11 @@ subroutine seq_io_write_r8(filename,rdata,dname,whead,wdata,file_ind) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_DOUBLE,varid) if(rcode==PIO_NOERR) then - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) end if endif @@ -667,9 +673,11 @@ subroutine seq_io_write_r81d(filename,rdata,dname,whead,wdata,file_ind) lnx = size(rdata) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_nx',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_DOUBLE,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -744,9 +752,11 @@ subroutine seq_io_write_char(filename,rdata,dname,whead,wdata,file_ind) lnx = len(charvar) rcode = pio_def_dim(cpl_io_file(lfile_ind),trim(dname)//'_len',lnx,dimid(1)) rcode = pio_def_var(cpl_io_file(lfile_ind),trim(dname),PIO_CHAR,dimid,varid) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) if (lwdata) call seq_io_enddef(filename, file_ind=lfile_ind) endif @@ -1057,9 +1067,11 @@ subroutine seq_io_write_moab_tags(filename, mbxid, dname, tag_list, whead,wdata, rcode = pio_def_var(cpl_io_file(lfile_ind),trim(name1),PIO_DOUBLE,dimid,varid) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"_FillValue",lfillvalue) end if - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) + if (len_trim(cunit) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"units",trim(cunit)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"long_name",trim(lname)) - rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) + if (len_trim(sname) > 0) & + rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"standard_name",trim(sname)) rcode = pio_put_att(cpl_io_file(lfile_ind),varid,"internal_dname",trim(dname)) !-------tcraig endif From fd8fd4c916ade5e69fbd614a330c73cb6f896089 Mon Sep 17 00:00:00 2001 From: noel Date: Tue, 9 Jun 2026 06:15:35 -0700 Subject: [PATCH 2/2] revert a change regarding auto-detecting --- components/elm/src/main/ncdio_pio.F90.in | 44 ++---------------------- 1 file changed, 3 insertions(+), 41 deletions(-) diff --git a/components/elm/src/main/ncdio_pio.F90.in b/components/elm/src/main/ncdio_pio.F90.in index fd62595e7aeb..79529fcbc6a8 100644 --- a/components/elm/src/main/ncdio_pio.F90.in +++ b/components/elm/src/main/ncdio_pio.F90.in @@ -180,12 +180,7 @@ contains subroutine ncd_pio_openfile(file, fname, mode) ! ! !DESCRIPTION: - ! Open a NetCDF PIO file. Detects HDF5/NetCDF4 files (magic bytes - ! \x89HDF) and opens them with PIO_IOTYPE_NETCDF4P instead of - ! PIO_IOTYPE_PNETCDF to avoid PIO warnings about unsupported formats. - ! - ! !USES: - use pio, only : pio_iotype_pnetcdf, pio_iotype_netcdf4p + ! Open a NetCDF PIO file ! ! !ARGUMENTS: class(file_desc_t) , intent(inout) :: file ! Output PIO file handle @@ -193,43 +188,10 @@ contains integer , intent(in) :: mode ! file mode ! ! !LOCAL VARIABLES: - integer :: ierr - integer :: my_io_type ! iotype selected for this open - integer :: iunit ! Fortran unit for header read - integer :: ios ! I/O status - logical :: is_hdf5 ! .true. if file has HDF5 magic bytes - character :: hdr(8) ! first 8 bytes of file - ! HDF5 magic: 0x89 'H' 'D' 'F' 0x0D 0x0A 0x1A 0x0A - character, parameter :: hdf5_magic(8) = & - (/ char(137), 'H', 'D', 'F', char(13), char(10), char(26), char(10) /) + integer :: ierr !----------------------------------------------------------------------- - ! Detect HDF5/NetCDF4 format on the master process and broadcast result - is_hdf5 = .false. - if (masterproc) then - iunit = getavu() - open(unit=iunit, file=trim(fname), form='unformatted', access='stream', & - status='old', iostat=ios) - if (ios == 0) then - read(iunit, iostat=ios) hdr - if (ios == 0) then - is_hdf5 = all(hdr == hdf5_magic) - end if - end if - call relavu(iunit) ! closes (if open) and frees the unit - end if - call MPI_Bcast(is_hdf5, 1, MPI_LOGICAL, 0, mpicom, ierr) - - my_io_type = io_type - if (is_hdf5 .and. my_io_type == pio_iotype_pnetcdf) then - my_io_type = pio_iotype_netcdf4p - if (pio_iotask_rank(pio_subsystem)==0) then - write(iulog,*) 'ncd_pio_openfile: detected NetCDF4/HDF5 file, ', & - 'switching from pnetcdf to netcdf4p iotype for ', trim(fname) - end if - end if - - ierr = pio_openfile(pio_subsystem, file, my_io_type, fname, mode) + ierr = pio_openfile(pio_subsystem, file, io_type, fname, mode) if(ierr/= PIO_NOERR) then call shr_sys_abort('ncd_pio_openfile ERROR: Failed to open file')