From 860f87de3fe050847b4876d302cade9ce13aad63 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 04:23:51 +0000 Subject: [PATCH 1/4] Rename the min/max variables to valid_min/valid_max Fortran has no way to reach an intrinsic that a local name has shadowed, so any scoping unit with a variable called min or max simply cannot call MIN() or MAX(). mpp_io has five such routines, and the shadowing is invisible at the point of failure: gfortran does not say "you shadowed an intrinsic", it says "Unclassifiable statement" on the line that tried to use it. Renamed, in mpp_io_mod and the fms_io/oda_tools code that calls it: mpp_write_meta_axis_r1d min -> valid_min mpp_write_meta_axis_i1d min -> valid_min mpp_write_meta_field min, max -> valid_min, valid_max mpp_modify_field_meta min, max -> valid_min, valid_max mpp_get_field_atts min, max -> valid_min, valid_max register_restart_axis_r1d min -> valid_min validtype %min, %max -> %valid_min, %valid_max fieldtype %min, %max -> %valid_min, %valid_max fms_io ax_type %min -> %valid_min valid_min and valid_max are not invented names: these variables exist to carry the CF attributes that the same routines already write as the string literals 'valid_min' and 'valid_max'. The declaration now matches the attribute it produces. The component renames are cosmetic -- a component does not shadow anything -- but validtype and fieldtype are PRIVATE-component types whose min/max are only reachable inside mpp_io_mod, so the rename is contained, and leaving field%min next to a valid_min dummy would be worse than either alone. API impact, audited rather than assumed. Dummy-argument names are visible to keyword callers. Every keyword caller of the affected routines in FMS is updated here -- 11 call sites in fms/fms_io.F90, fms/fms_io_unstructured_register_restart_axis.inc, fms/fms_io_unstructured_save_restart.inc and oda_tools/write_ocean_data.F90. MOM5 outside its vendored src/shared has *zero* keyword min=/max= callers of mpp_write_meta, mpp_modify_field_meta, mpp_get_field_atts or register_restart_axis, so re-vendoring src/shared is the whole of the MOM5 change. Positional callers are unaffected either way. Deliberately NOT renamed: the integer min variables in time_manager.F90, time_interp_external.F90 and oda_core_ecda.F90. Those hold minutes. They do shadow the intrinsic in their own scopes, but valid_min would be a lie; the right name there is 'minute' and it is a separate change. No behaviour change: this is a pure rename, and the CF attribute strings written to the files are untouched. This commit is self-contained and applies to the mom5 branch on its own. Applied on top of the parallel-netCDF series it also makes MAX() reachable in mpp_write_meta_field, which is what the chunking loop there had to work around by hand. --- fms/fms_io.F90 | 12 +-- ..._io_unstructured_register_restart_axis.inc | 4 +- fms/fms_io_unstructured_save_restart.inc | 4 +- mpp/include/mpp_io_misc.inc | 4 +- mpp/include/mpp_io_read.inc | 4 +- mpp/include/mpp_io_util.inc | 48 ++++++------ mpp/include/mpp_io_write.inc | 78 +++++++++---------- mpp/mpp_io.F90 | 10 +-- oda_tools/write_ocean_data.F90 | 14 ++-- 9 files changed, 89 insertions(+), 89 deletions(-) diff --git a/fms/fms_io.F90 b/fms/fms_io.F90 index acff993d7c..fe2b4b8a19 100644 --- a/fms/fms_io.F90 +++ b/fms/fms_io.F90 @@ -196,7 +196,7 @@ module fms_io_mod character(len=128) :: calendar = '' integer :: sense !Orientation of z axis definition integer :: dimlen !max dim of elements across global domain - real :: min !valid min for real axis data + real :: valid_min !valid min for real axis data integer :: imin !valid min for integer axis data integer,allocatable :: idx(:) !compressed io-domain index vector integer,allocatable :: nelems(:) !num elements for each rank in io domain @@ -1237,14 +1237,14 @@ end subroutine write_data_3d_new ! This routine will register an integer restart file axis ! !------------------------------------------------------------------------------- -subroutine register_restart_axis_r1d(fileObj,filename,fieldname,data,cartesian,units,longname,sense,min,calendar) +subroutine register_restart_axis_r1d(fileObj,filename,fieldname,data,cartesian,units,longname,sense,valid_min,calendar) type(restart_file_type), intent(inout) :: fileObj character(len=*), intent(in) :: filename, fieldname real, intent(in), target :: data(:) character(len=*), intent(in) :: cartesian character(len=*), optional, intent(in) :: units, longname integer, optional, intent(in) :: sense - real, optional, intent(in) :: min !valid min for real axis data + real, optional, intent(in) :: valid_min !valid min for real axis data character(len=*), optional, intent(in) :: calendar integer :: idx @@ -1280,7 +1280,7 @@ subroutine register_restart_axis_r1d(fileObj,filename,fieldname,data,cartesian,u fileObj%axes(idx)%dimlen = -1 ! This is not a compressed axis if(PRESENT(units)) fileObj%axes(idx)%units = units if(PRESENT(longname)) fileObj%axes(idx)%longname = longname - if(PRESENT(min)) fileObj%axes(idx)%min = min + if(PRESENT(valid_min)) fileObj%axes(idx)%valid_min = valid_min if(idx == TIDX) then if(PRESENT(calendar)) fileObj%axes(idx)%calendar = trim(calendar) endif @@ -2669,7 +2669,7 @@ subroutine save_compressed_restart(fileObj,restartpath,append,time_level) if(ALLOCATED(axis%idx)) then call mpp_def_dim(unit,trim(axis%dimlen_name),axis%dimlen,trim(axis%dimlen_lname), (/(i,i=1,axis%dimlen)/)) call mpp_write_meta(unit,c_axis,axis%name,axis%units,axis%longname, & - data=axis%idx,compressed=axis%compressed,min=axis%imin) + data=axis%idx,compressed=axis%compressed,valid_min=axis%imin) c_axis_defined = .TRUE. else c_axis_defined = .FALSE. @@ -2679,7 +2679,7 @@ subroutine save_compressed_restart(fileObj,restartpath,append,time_level) if (ALLOCATED(axis%idx)) then call mpp_def_dim(unit,trim(axis%dimlen_name),axis%dimlen,trim(axis%dimlen_lname), (/(i,i=1,axis%dimlen)/)) call mpp_write_meta(unit,h_axis,axis%name,axis%units,axis%longname, & - data=axis%idx,compressed=axis%compressed,min=axis%imin) + data=axis%idx,compressed=axis%compressed,valid_min=axis%imin) h_axis_defined = .TRUE. else h_axis_defined = .FALSE. diff --git a/fms/fms_io_unstructured_register_restart_axis.inc b/fms/fms_io_unstructured_register_restart_axis.inc index f7b691e3a7..0690d189a5 100644 --- a/fms/fms_io_unstructured_register_restart_axis.inc +++ b/fms/fms_io_unstructured_register_restart_axis.inc @@ -221,9 +221,9 @@ subroutine fms_io_unstructured_register_restart_axis_r1D(fileObj, & !Store the minimum value allowed for the axis. if (present(fmin)) then - fileObj%axes(axis_index)%min = fmin + fileObj%axes(axis_index)%valid_min = fmin else - fileObj%axes(axis_index)%min = 0 + fileObj%axes(axis_index)%valid_min = 0 endif !Store the calendar for the axis. This is only done for the time dimension. diff --git a/fms/fms_io_unstructured_save_restart.inc b/fms/fms_io_unstructured_save_restart.inc index 3e39cb75c0..9c363cb71f 100644 --- a/fms/fms_io_unstructured_save_restart.inc +++ b/fms/fms_io_unstructured_save_restart.inc @@ -350,7 +350,7 @@ subroutine fms_io_unstructured_save_restart(fileObj, & axis%longname, & data=axis%idx, & compressed=axis%compressed, & - min=axis%imin) + valid_min=axis%imin) axis => null() c_axis_defined = .true. else @@ -373,7 +373,7 @@ subroutine fms_io_unstructured_save_restart(fileObj, & axis%longname, & data=axis%idx, & compressed=axis%compressed, & - min=axis%imin) + valid_min=axis%imin) axis => null() h_axis_defined = .true. else diff --git a/mpp/include/mpp_io_misc.inc b/mpp/include/mpp_io_misc.inc index 1d15009ed0..562a7e9bcd 100644 --- a/mpp/include/mpp_io_misc.inc +++ b/mpp/include/mpp_io_misc.inc @@ -115,8 +115,8 @@ default_field%ndim = -1 default_field%checksum = 0 !largest possible 4-byte reals - default_field%min = -huge(1._4) - default_field%max = huge(1._4) + default_field%valid_min = -huge(1._4) + default_field%valid_max = huge(1._4) default_field%missing = MPP_FILL_DOUBLE ! now using netcdf:NF_FILL_DOUBLE instead of -1e36 default_field%fill = MPP_FILL_DOUBLE ! now using netcdf:NF_FILL_DOUBLE instead of -1e36 default_field%scale = 1.0 diff --git a/mpp/include/mpp_io_read.inc b/mpp/include/mpp_io_read.inc index c83b594725..776a635339 100644 --- a/mpp/include/mpp_io_read.inc +++ b/mpp/include/mpp_io_read.inc @@ -1048,8 +1048,8 @@ case('packing') mpp_file(unit)%Var(nv)%pack=mpp_file(unit)%Var(nv)%Att(j)%fatt(1) case('valid_range') - mpp_file(unit)%Var(nv)%min=mpp_file(unit)%Var(nv)%Att(j)%fatt(1) - mpp_file(unit)%Var(nv)%max=mpp_file(unit)%Var(nv)%Att(j)%fatt(2) + mpp_file(unit)%Var(nv)%valid_min=mpp_file(unit)%Var(nv)%Att(j)%fatt(1) + mpp_file(unit)%Var(nv)%valid_max=mpp_file(unit)%Var(nv)%Att(j)%fatt(2) case('checksum') checksum_char = mpp_file(unit)%Var(nv)%Att(j)%catt ! Scan checksum attribute for , delimiter. If found implies multiple time levels. diff --git a/mpp/include/mpp_io_util.inc b/mpp/include/mpp_io_util.inc index f9bdc245f6..b0cf128613 100644 --- a/mpp/include/mpp_io_util.inc +++ b/mpp/include/mpp_io_util.inc @@ -92,13 +92,13 @@ end subroutine mpp_get_global_atts !##################################################################### - subroutine mpp_get_field_atts(field, name, units, longname, min, max, missing, ndim, siz, axes, atts, & + subroutine mpp_get_field_atts(field, name, units, longname, valid_min, valid_max, missing, ndim, siz, axes, atts, & valid, scale, add, checksum) type(fieldtype), intent(in) :: field character(len=*), intent(out), optional :: name, units character(len=*), intent(out), optional :: longname - real, intent(out), optional :: min,max,missing + real, intent(out), optional :: valid_min,valid_max,missing integer, intent(out), optional :: ndim integer, intent(out), dimension(:), optional :: siz type(validtype), intent(out), optional :: valid @@ -114,8 +114,8 @@ if (PRESENT(name)) name = field%name if (PRESENT(units)) units = field%units if (PRESENT(longname)) longname = field%longname - if (PRESENT(min)) min = field%min - if (PRESENT(max)) max = field%max + if (PRESENT(valid_min)) valid_min = field%valid_min + if (PRESENT(valid_max)) valid_max = field%valid_max if (PRESENT(missing)) missing = field%missing if (PRESENT(ndim)) ndim = field%ndim if (PRESENT(atts)) then @@ -615,7 +615,7 @@ integer :: valid_T, scale_T ! types of attributes v%is_range = .true. - v%min = -HUGE(v%min); v%max = HUGE(v%max) + v%valid_min = -HUGE(v%valid_min); v%valid_max = HUGE(v%valid_max) if (f%natt == 0) return ! find indices of relevant attributes irange = mpp_find_att(f%att,'valid_range') @@ -637,55 +637,55 @@ ! examine possible range attributes valid_T = 0 if (irange>0) then - v%min = f%att(irange)%fatt(1) - v%max = f%att(irange)%fatt(2) + v%valid_min = f%att(irange)%fatt(1) + v%valid_max = f%att(irange)%fatt(2) valid_T = f%att(irange)%type else if (imax>0.or.imin>0) then if(imax>0) then - v%max = f%att(imax)%fatt(1) + v%valid_max = f%att(imax)%fatt(1) valid_T = max(valid_T,f%att(imax)%type) endif if(imin>0) then - v%min = f%att(imin)%fatt(1) + v%valid_min = f%att(imin)%fatt(1) valid_T = max(valid_T,f%att(imin)%type) endif else if (imissing > 0) then v%is_range = .false. ! here we always scale, since missing_value is supposed to be in ! external representation - v%min = f%att(imissing)%fatt(1)*f%scale + f%add + v%valid_min = f%att(imissing)%fatt(1)*f%scale + f%add else if (ifill>0) then !z1l ifdef is added in to be able to compile without using use_netCDF. #ifdef use_netCDF ! define min and max according to _FillValue if(f%att(ifill)%fatt(1)>0) then ! if _FillValue is positive, then it defines valid maximum - v%max = f%att(ifill)%fatt(1) + v%valid_max = f%att(ifill)%fatt(1) select case(f%type) case (NF_BYTE,NF_SHORT,NF_INT) - v%max = v%max-1 + v%valid_max = v%valid_max-1 case (NF_FLOAT) - v%max = nearest(nearest(real(v%max,4),-1.0),-1.0) + v%valid_max = nearest(nearest(real(v%valid_max,4),-1.0),-1.0) case (NF_DOUBLE) - v%max = nearest(nearest(real(v%max,8),-1.0),-1.0) + v%valid_max = nearest(nearest(real(v%valid_max,8),-1.0),-1.0) end select ! always do the scaling, as the _FillValue is in external ! representation - v%max = v%max*f%scale + f%add + v%valid_max = v%valid_max*f%scale + f%add else ! if _FillValue is negative or zero, then it defines valid minimum - v%min = f%att(ifill)%fatt(1) + v%valid_min = f%att(ifill)%fatt(1) select case(f%type) case (NF_BYTE,NF_SHORT,NF_INT) - v%min = v%min+1 + v%valid_min = v%valid_min+1 case (NF_FLOAT) - v%min = nearest(nearest(real(v%min,4),+1.0),+1.0) + v%valid_min = nearest(nearest(real(v%valid_min,4),+1.0),+1.0) case (NF_DOUBLE) - v%min = nearest(nearest(real(v%min,8),+1.0),+1.0) + v%valid_min = nearest(nearest(real(v%valid_min,8),+1.0),+1.0) end select ! always do the scaling, as the _FillValue is in external ! representation - v%min = v%min*f%scale + f%add + v%valid_min = v%valid_min*f%scale + f%add endif #endif endif @@ -697,10 +697,10 @@ ! brances, because in this case all irange, imin, and imax are less then 0 if(.not.((valid_T == scale_T).and.(scale_T>f%type))) then if(irange>0 .or. imin>0) then - v%min = v%min*f%scale + f%add + v%valid_min = v%valid_min*f%scale + f%add endif if(irange>0 .or. imax>0) then - v%max = v%max*f%scale + f%add + v%valid_max = v%valid_max*f%scale + f%add endif endif @@ -712,9 +712,9 @@ type(validtype), intent(in) :: v ! validator if (v%is_range) then - mpp_is_valid = (v%min<=x).and.(x<=v%max) + mpp_is_valid = (v%valid_min<=x).and.(x<=v%valid_max) else - mpp_is_valid = x/=v%min + mpp_is_valid = x/=v%valid_min endif end function mpp_is_valid diff --git a/mpp/include/mpp_io_write.inc b/mpp/include/mpp_io_write.inc index 3564e8579b..a64f7d3753 100644 --- a/mpp/include/mpp_io_write.inc +++ b/mpp/include/mpp_io_write.inc @@ -46,7 +46,7 @@ ! character(len=128) :: units ! ! character(len=256) :: longname ! ! character(len=256) :: standard_name !CF standard name ! -! real :: min, max, missing, fill, scale, add ! +! real :: valid_min, valid_max, missing, fill, scale, add ! ! type(axistype), pointer :: axis(:) ! ! integer :: id ! ! end type fieldtype ! @@ -114,12 +114,12 @@ ! Only one time axis is allowed per file. ! ! ! ! subroutine mpp_write_meta_field( unit, field, axes, name, units, longname ! -! stanadard_name, min, max, missing, fill, scale, add, pack) ! +! stanadard_name, valid_min, valid_max, missing, fill, scale, add, ! ! integer, intent(in) :: unit ! ! type(fieldtype), intent(out) :: field ! ! type(axistype), intent(in) :: axes(:) ! ! character(len=*), intent(in) :: name, units, longname, standard_name ! -! real, intent(in), optional :: min, max, missing, fill, scale, add ! +! real, intent(in), optional :: valid_min, valid_max, missing, fill, ! ! integer, intent(in), optional :: pack ! ! ! ! This form defines a field. Metadata corresponding to the type ! @@ -352,7 +352,7 @@ - subroutine mpp_write_meta_axis_r1d( unit, axis, name, units, longname, cartesian, sense, domain, data, min, calendar) + subroutine mpp_write_meta_axis_r1d( unit, axis, name, units, longname, cartesian, sense, domain, data, valid_min, calendar) !load the values in an axistype (still need to call mpp_write) !write metadata attributes for axis !it is declared intent(inout) so you can nullify pointers in the incoming object if needed @@ -364,7 +364,7 @@ integer, intent(in), optional :: sense type(domain1D), intent(in), optional :: domain real, intent(in), optional :: data(:) - real, intent(in), optional :: min + real, intent(in), optional :: valid_min character(len=*), intent(in), optional :: calendar integer :: is, ie, isg, ieg @@ -520,8 +520,8 @@ ! silently ignore values of sense other than +/-1. end if end if - if( PRESENT(min) ) then - call mpp_write_meta( unit, axis%id, 'valid_min', rval=min) + if( PRESENT(valid_min) ) then + call mpp_write_meta( unit, axis%id, 'valid_min', rval=valid_min) axis%natt = axis%natt + 1 endif if( mpp_file(unit)%threading.EQ.MPP_MULTI .AND. mpp_file(unit)%fileset.EQ.MPP_MULTI .AND. domain_exist )then @@ -537,7 +537,7 @@ return end subroutine mpp_write_meta_axis_r1d - subroutine mpp_write_meta_axis_i1d(unit, axis, name, units, longname, data, min, compressed) + subroutine mpp_write_meta_axis_i1d(unit, axis, name, units, longname, data, valid_min, compressed) !load the values in an axistype (still need to call mpp_write) !write metadata attributes for axis !it is declared intent(inout) so you can nullify pointers in the incoming object if needed @@ -546,7 +546,7 @@ type(axistype), intent(inout) :: axis character(len=*), intent(in) :: name, units, longname integer, intent(in) :: data(:) - integer, intent(in), optional :: min + integer, intent(in), optional :: valid_min character(len=*), intent(in), optional :: compressed integer :: istat @@ -595,8 +595,8 @@ call mpp_write_meta( unit, axis%id, 'compress', cval=axis%compressed) axis%natt = axis%natt + 1 endif - if( PRESENT(min) ) then - call mpp_write_meta( unit, axis%id, 'valid_min', ival=min) + if( PRESENT(valid_min) ) then + call mpp_write_meta( unit, axis%id, 'valid_min', ival=valid_min) axis%natt = axis%natt + 1 endif if( verbose )print '(a,2i6,x,a,2i3)', 'MPP_WRITE_META: Wrote axis metadata, pe, unit, axis%name, axis%id, axis%did=', & @@ -674,13 +674,13 @@ subroutine mpp_write_meta_field( unit, field, axes, name, units, longname,& - min, max, missing, fill, scale, add, pack, time_method, standard_name, checksum) + valid_min, valid_max, missing, fill, scale, add, pack, time_method, standard_name, checksum) !define field: must have already called mpp_write_meta(axis) for each axis integer, intent(in) :: unit type(fieldtype), intent(inout) :: field type(axistype), intent(in) :: axes(:) character(len=*), intent(in) :: name, units, longname - real, intent(in), optional :: min, max, missing, fill, scale, add + real, intent(in), optional :: valid_min, valid_max, missing, fill, scale, add integer, intent(in), optional :: pack character(len=*), intent(in), optional :: time_method character(len=*), intent(in), optional :: standard_name @@ -755,8 +755,8 @@ end if end do !attributes - if( PRESENT(min) ) field%min = min - if( PRESENT(max) ) field%max = max + if( PRESENT(valid_min) ) field%valid_min = valid_min + if( PRESENT(valid_max) ) field%valid_max = valid_max if( PRESENT(scale) ) field%scale = scale if( PRESENT(add) ) field%add = add if( PRESENT(standard_name)) field%standard_name = standard_name @@ -822,26 +822,26 @@ call mpp_write_meta( unit, field%id, 'units', cval=field%units) endif !all real attributes must be written as packed - if( PRESENT(min) .AND. PRESENT(max) )then + if( PRESENT(valid_min) .AND. PRESENT(valid_max) )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_range', rval=(/min,max/), pack=pack ) + call mpp_write_meta( unit, field%id, 'valid_range', rval=(/valid_min,valid_max/), pack=pack ) else - a = nint((min-add)/scale) - b = nint((max-add)/scale) + a = nint((valid_min-add)/scale) + b = nint((valid_max-add)/scale) call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=pack ) end if - else if( PRESENT(min) )then + else if( PRESENT(valid_min) )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=pack ) + call mpp_write_meta( unit, field%id, 'valid_min', rval=field%valid_min, pack=pack ) else - a = nint((min-add)/scale) + a = nint((valid_min-add)/scale) call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=pack ) end if - else if( PRESENT(max) )then + else if( PRESENT(valid_max) )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=pack ) + call mpp_write_meta( unit, field%id, 'valid_max', rval=field%valid_max, pack=pack ) else - a = nint((max-add)/scale) + a = nint((valid_max-add)/scale) call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=pack ) end if end if @@ -1467,26 +1467,26 @@ call mpp_write_meta( unit, field%id, 'units', cval=field%units ) endif !all real attributes must be written as packed - if( (field%min.NE.default_field%min) .AND. (field%max.NE.default_field%max) )then + if( (field%valid_min.NE.default_field%valid_min) .AND. (field%valid_max.NE.default_field%valid_max) )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_range', rval=(/field%min,field%max/), pack=field%pack ) + call mpp_write_meta( unit, field%id, 'valid_range', rval=(/field%valid_min,field%valid_max/), pack=field%pack ) else - a = nint((field%min-field%add)/field%scale) - b = nint((field%max-field%add)/field%scale) + a = nint((field%valid_min-field%add)/field%scale) + b = nint((field%valid_max-field%add)/field%scale) call mpp_write_meta( unit, field%id, 'valid_range', rval=(/a, b /), pack=field%pack ) end if - else if( field%min.NE.default_field%min )then + else if( field%valid_min.NE.default_field%valid_min )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_min', rval=field%min, pack=field%pack ) + call mpp_write_meta( unit, field%id, 'valid_min', rval=field%valid_min, pack=field%pack ) else - a = nint((field%min-field%add)/field%scale) + a = nint((field%valid_min-field%add)/field%scale) call mpp_write_meta( unit, field%id, 'valid_min', rval=a, pack=field%pack ) end if - else if( field%max.NE.default_field%max )then + else if( field%valid_max.NE.default_field%valid_max )then if( field%pack.EQ.1 .OR. field%pack.EQ.2 )then - call mpp_write_meta( unit, field%id, 'valid_max', rval=field%max, pack=field%pack ) + call mpp_write_meta( unit, field%id, 'valid_max', rval=field%valid_max, pack=field%pack ) else - a = nint((field%max-field%add)/field%scale) + a = nint((field%valid_max-field%add)/field%scale) call mpp_write_meta( unit, field%id, 'valid_max', rval=a, pack=field%pack ) end if end if @@ -1538,18 +1538,18 @@ return end subroutine mpp_modify_axis_meta - subroutine mpp_modify_field_meta( field, name, units, longname, min, max, missing, axes ) + subroutine mpp_modify_field_meta( field, name, units, longname, valid_min, valid_max, missing, axes ) type(fieldtype), intent(inout) :: field character(len=*), intent(in), optional :: name, units, longname - real, intent(in), optional :: min, max, missing + real, intent(in), optional :: valid_min, valid_max, missing type(axistype), dimension(:), intent(inout), optional :: axes if (PRESENT(name)) field%name = trim(name) if (PRESENT(units)) field%units = trim(units) if (PRESENT(longname)) field%longname = trim(longname) - if (PRESENT(min)) field%min = min - if (PRESENT(max)) field%max = max + if (PRESENT(valid_min)) field%valid_min = valid_min + if (PRESENT(valid_max)) field%valid_max = valid_max if (PRESENT(missing)) field%missing = missing ! if (PRESENT(axes)) then ! axis%len = size(data(:)) diff --git a/mpp/mpp_io.F90 b/mpp/mpp_io.F90 index b8ae07a905..b941e45f50 100644 --- a/mpp/mpp_io.F90 +++ b/mpp/mpp_io.F90 @@ -165,7 +165,7 @@ ! character(len=128) :: name ! character(len=128) :: units ! character(len=256) :: longname -! real :: min, max, missing, fill, scale, add +! real :: valid_min, valid_max, missing, fill, scale, add ! integer :: pack ! type(axistype), dimension(:), pointer :: axes ! integer, dimension(:), pointer :: size @@ -443,7 +443,7 @@ module mpp_io_mod type :: validtype private logical :: is_range ! if true, then the data represent the valid range - real :: min,max ! boundaries of the valid range or missing value + real :: valid_min,valid_max ! boundaries of the valid range or missing value end type validtype type :: fieldtype @@ -452,7 +452,7 @@ module mpp_io_mod character(len=128) :: units character(len=256) :: longname character(len=256) :: standard_name ! CF standard name - real :: min, max, missing, fill, scale, add + real :: valid_min, valid_max, missing, fill, scale, add integer :: pack integer(LONG_KIND), dimension(3) :: checksum type(axistype), pointer :: axes(:) =>NULL() !axes associated with field size, time_axis_index redundantly @@ -729,7 +729,7 @@ module mpp_io_mod ! ! ! ! The second form defines a field. Metadata corresponding to the type @@ -780,7 +780,7 @@ module mpp_io_mod ! ! ! -! +! ! ! ! diff --git a/oda_tools/write_ocean_data.F90 b/oda_tools/write_ocean_data.F90 index b3a0d7cd4d..f05c790516 100644 --- a/oda_tools/write_ocean_data.F90 +++ b/oda_tools/write_ocean_data.F90 @@ -125,20 +125,20 @@ function open_profile_file(name, nvar, grid_lon, grid_lat,thread,fset) call mpp_write_meta(unit,lon_field,(/station_axis/),& 'longitude','degrees_E','longitude',& - min=-1.0,max=361.0) + valid_min=-1.0,valid_max=361.0) call mpp_write_meta(unit,lat_field,(/station_axis/),& 'latitude','degrees_N','latitude',& - min=-91.0,max=91.0) + valid_min=-91.0,valid_max=91.0) call mpp_write_meta(unit,profile_flag_field,(/station_axis/),& 'profile_flag','none','profile_flag',& - min=0.0,max=10.0,missing=missing_value) + valid_min=0.0,valid_max=10.0,missing=missing_value) if (nvar_out .eq. 2) call mpp_write_meta(unit,profile_flag_s_field,(/station_axis/),& 'profile_flag_s','none','profile_flag for salt',& - min=0.0,max=10.0,missing=missing_value) + valid_min=0.0,valid_max=10.0,missing=missing_value) write(time_units,'(a,i4.4,a,i2.2,a,i2.2,a)') 'days since ',ref_yr,'-',ref_mon,'-',ref_day,' 00:00:00' @@ -187,16 +187,16 @@ function open_profile_file(name, nvar, grid_lon, grid_lat,thread,fset) units='degrees_C' call mpp_write_meta(unit,data_t_field,(/depth_axis,station_axis/),& 'temp',trim(units),'in-situ temperature',& - min=-10.0,max=50.0,missing=missing_value) + valid_min=-10.0,valid_max=50.0,missing=missing_value) units='g/kg' if (nvar_out .eq. 2) call mpp_write_meta(unit,data_s_field,(/depth_axis,station_axis/),& 'salt',trim(units),'salinity',& - min=0.0,max=50.0,missing=missing_value) + valid_min=0.0,valid_max=50.0,missing=missing_value) call mpp_write_meta(unit,depth_field,(/depth_axis,station_axis/),& 'depth','meters','depth of obs',& - min=0.0,max=7000.0,missing=missing_value) + valid_min=0.0,valid_max=7000.0,missing=missing_value) From 30ca9be6208de478ecb44e872d6e561de6e4d159 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 20 Aug 2026 05:02:53 +0000 Subject: [PATCH 2/4] Rename the minutes variables from min to minutes in the time routines Companion to the valid_min/valid_max rename, covering the other family of min shadowing in this tree. These variables hold minutes, so valid_min would have been wrong for them; minutes is the name the surrounding code already uses. time_manager/time_manager.F90 date_to_string program test (#ifdef test_time_manager) time_interp/time_interp_external.F90 time_interp_external_3d time_interp_external_0d oda_tools/oda_core_ecda.F90 get_obs Every one is an unpacking of get_date(time, yr, mo, day, hr, min, sec) into locals. While the local is called min, the MIN intrinsic is unreachable in that scoping unit, and gfortran reports an attempt to use it only as "Unclassifiable statement" on the line that tried. Unlike the valid_min/valid_max rename there is no API surface here at all: all four declarations are plain locals, not dummy arguments, so no caller anywhere can name them and nothing outside these three files can see the change. The values are passed to get_date and increment_date positionally. time_manager already uses minutes as the dummy-argument name in increment_date, increment_date_private and decrement_date, so this makes the module self-consistent rather than introducing a new convention. No program unit that declares min also declares minutes, so there is no collision -- checked per scoping unit, not per file. The time_manager 'program test' block sits behind #ifdef test_time_manager and is not built by default; it was syntax-checked separately with -Dtest_time_manager, clean both before and after this change. No behaviour change: a pure rename of local variables, with no format string, attribute or output text touched. The ' min=' label in format 11 stays as it is -- that is display text, not an identifier. This commit is independent of the parallel-netCDF series and applies to the mom5 branch on its own. --- oda_tools/oda_core_ecda.F90 | 4 ++-- time_interp/time_interp_external.F90 | 12 ++++++------ time_manager/time_manager.F90 | 26 +++++++++++++------------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/oda_tools/oda_core_ecda.F90 b/oda_tools/oda_core_ecda.F90 index 6ee1a08248..a1ba6b0e6d 100644 --- a/oda_tools/oda_core_ecda.F90 +++ b/oda_tools/oda_core_ecda.F90 @@ -1739,7 +1739,7 @@ subroutine get_obs(model_time, Prof, nprof) integer, intent(inout) :: nprof integer :: i, k, kk, k_interval - integer :: yr, mon, day, hr, min, sec + integer :: yr, mon, day, hr, minutes, sec integer :: stdout_unit type(time_type) :: tdiff @@ -1748,7 +1748,7 @@ subroutine get_obs(model_time, Prof, nprof) stdout_unit = stdout() write (UNIT=stdout_unit, FMT='("Gathering profiles for current analysis time")') - call get_date(model_time, yr, mon, day, hr, min, sec) + call get_date(model_time, yr, mon, day, hr, minutes, sec) write (UNIT=stdout_unit, FMT='("Current YYYY/MM/DD = ",I4,"/",I2,"/",I2)') yr, mon, day do i=1, no_prf diff --git a/time_interp/time_interp_external.F90 b/time_interp/time_interp_external.F90 index 343e839404..c12c982815 100644 --- a/time_interp/time_interp_external.F90 +++ b/time_interp/time_interp_external.F90 @@ -716,7 +716,7 @@ subroutine time_interp_external_3d(index, time, data, interp,verbose,horz_interp integer :: nx, ny, nz, interp_method, t1, t2 integer :: i1, i2, isc, iec, jsc, jec, mod_time - integer :: yy, mm, dd, hh, min, ss + integer :: yy, mm, dd, hh, minutes, ss character(len=256) :: err_msg, filename integer :: isw, iew, jsw, jew, nxw, nyw @@ -821,9 +821,9 @@ subroutine time_interp_external_3d(index, time, data, interp,verbose,horz_interp endif w1 = 1.0-w2 if (verb) then - call get_date(time,yy,mm,dd,hh,min,ss) + call get_date(time,yy,mm,dd,hh,minutes,ss) write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') & - 'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',min,':',ss + 'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',minutes,':',ss write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2 endif @@ -871,7 +871,7 @@ subroutine time_interp_external_0d(index, time, data, verbose) integer :: t1, t2 integer :: i1, i2, mod_time - integer :: yy, mm, dd, hh, min, ss + integer :: yy, mm, dd, hh, minutes, ss character(len=256) :: err_msg, filename real :: w1,w2 @@ -913,9 +913,9 @@ subroutine time_interp_external_0d(index, time, data, verbose) endif w1 = 1.0-w2 if (verb) then - call get_date(time,yy,mm,dd,hh,min,ss) + call get_date(time,yy,mm,dd,hh,minutes,ss) write(outunit,'(a,i4,a,i2,a,i2,1x,i2,a,i2,a,i2)') & - 'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',min,':',ss + 'target time yyyy/mm/dd hh:mm:ss= ',yy,'/',mm,'/',dd,hh,':',minutes,':',ss write(outunit,*) 't1, t2, w1, w2= ', t1, t2, w1, w2 endif call load_record_0d(field(index),t1) diff --git a/time_manager/time_manager.F90 b/time_manager/time_manager.F90 index b3c724eeec..f16a69944f 100644 --- a/time_manager/time_manager.F90 +++ b/time_manager/time_manager.F90 @@ -3272,12 +3272,12 @@ function date_to_string(time, err_msg) character(len=*), intent(out), optional :: err_msg character(len=128) :: err_msg_local character(len=15) :: date_to_string - integer :: yr,mon,day,hr,min,sec + integer :: yr,mon,day,hr,minutes,sec if(present(err_msg)) err_msg = '' - call get_date(time,yr,mon,day,hr,min,sec) + call get_date(time,yr,mon,day,hr,minutes,sec) if (yr <= 9999) then - write(date_to_string,'(I4.4,I2.2,I2.2,".",I2.2,I2.2,I2.2)') yr, mon, day, hr, min, sec + write(date_to_string,'(I4.4,I2.2,I2.2,".",I2.2,I2.2,I2.2)') yr, mon, day, hr, minutes, sec else write(err_msg_local, '(a,i4.4,a)') 'year = ', yr, ' should be less than 10000' if(error_handler('function date_to_string', err_msg_local, err_msg)) return @@ -3428,7 +3428,7 @@ program test type(time_type) :: Time, time1, time2 real :: xx - integer :: yr, mo, day, hr, min, sec, ticks + integer :: yr, mo, day, hr, minutes, sec, ticks integer :: year, month, dday, days_this_month integer :: days_per_month(12) = (/31,28,31,30,31,30,31,31,30,31,30,31/) logical :: leap @@ -3687,8 +3687,8 @@ program test if(err_msg /= '') then write(outunit,'(a)') 'test of decrement_date fails '//trim(err_msg) else - call get_date(time2, yr, mo, day, hr, min, sec, ticks) - write(outunit,20) yr, mo, day, hr, min, sec, ticks + call get_date(time2, yr, mo, day, hr, minutes, sec, ticks) + write(outunit,20) yr, mo, day, hr, minutes, sec, ticks endif enddo enddo @@ -3697,13 +3697,13 @@ program test do icode=0,242 day = modulo(icode/81,3) - 1 hr = modulo(icode/27,3) - 1 - min = modulo(icode/9, 3) - 1 + minutes = modulo(icode/9, 3) - 1 sec = modulo(icode/3, 3) - 1 ticks = modulo(icode ,3) - 1 - write(outunit,11) day, hr, min, sec, ticks - time2 = increment_date(time1, 0, 0, day, hr, min, sec, ticks, err_msg) - call get_date(time2, yr, mo, day, hr, min, sec, ticks) - write(outunit,20) yr, mo, day, hr, min, sec, ticks + write(outunit,11) day, hr, minutes, sec, ticks + time2 = increment_date(time1, 0, 0, day, hr, minutes, sec, ticks, err_msg) + call get_date(time2, yr, mo, day, hr, minutes, sec, ticks) + write(outunit,20) yr, mo, day, hr, minutes, sec, ticks enddo enddo endif @@ -3783,7 +3783,7 @@ program test endif call set_calendar_type(GREGORIAN) Time = set_time(seconds=2, days=1, ticks=1) - call get_date(Time, yr, mo, day, hr, min, sec, err_msg=err_msg) + call get_date(Time, yr, mo, day, hr, minutes, sec, err_msg=err_msg) if(err_msg == '') then write(outunit,'(a)') 'test10.2 fails' else @@ -3952,7 +3952,7 @@ program test if(leap .and. month == 2) days_this_month = 29 do dday=1,days_this_month Time = set_date(year, month, dday, 0, 0, 0) - call get_date(Time, yr, mo, day, hr, min, sec) + call get_date(Time, yr, mo, day, hr, minutes, sec) write(outunit,100) yr, mo, day, leap_year(Time), days_in_month(Time), days_in_year(Time) enddo enddo From 193a6d392749c78d20222f23c8e096cb951a689b Mon Sep 17 00:00:00 2001 From: Manodeep Sinha Date: Tue, 25 Aug 2026 21:42:38 +1000 Subject: [PATCH 3/4] Fix up missing vars in comments to prevent future confusion (per review comment) --- mpp/include/mpp_io_write.inc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mpp/include/mpp_io_write.inc b/mpp/include/mpp_io_write.inc index a64f7d3753..897d7cadff 100644 --- a/mpp/include/mpp_io_write.inc +++ b/mpp/include/mpp_io_write.inc @@ -119,7 +119,8 @@ ! type(fieldtype), intent(out) :: field ! ! type(axistype), intent(in) :: axes(:) ! ! character(len=*), intent(in) :: name, units, longname, standard_name ! -! real, intent(in), optional :: valid_min, valid_max, missing, fill, ! +! real, intent(in), optional :: valid_min, valid_max, missing, fill, | +! scale, add ! ! integer, intent(in), optional :: pack ! ! ! ! This form defines a field. Metadata corresponding to the type ! From 29c00acda4e8de3f256a80940de4a57c964824c7 Mon Sep 17 00:00:00 2001 From: Manodeep Sinha Date: Wed, 26 Aug 2026 13:11:08 +1000 Subject: [PATCH 4/4] The missing 'pack' - finally fixed as per review --- mpp/include/mpp_io_write.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/mpp/include/mpp_io_write.inc b/mpp/include/mpp_io_write.inc index 897d7cadff..da5b867b9e 100644 --- a/mpp/include/mpp_io_write.inc +++ b/mpp/include/mpp_io_write.inc @@ -115,6 +115,7 @@ ! ! ! subroutine mpp_write_meta_field( unit, field, axes, name, units, longname ! ! stanadard_name, valid_min, valid_max, missing, fill, scale, add, ! +! pack) ! ! integer, intent(in) :: unit ! ! type(fieldtype), intent(out) :: field ! ! type(axistype), intent(in) :: axes(:) !