Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add fortran code for ice or ocn post #25

Merged
merged 4 commits into from
Oct 20, 2023

Conversation

DeniseWorthen
Copy link
Contributor

This code is verified to reproduce the original NCL scripts w/in ~O10-8, with the exception of the ocean field speed which is now re-calculated from the remapped SSU and SSV fields.

The code will remap either ocean or ice model history files via a run-time flag do_ocnpost set according to the ftype value in the nml file. It is assumed that the model history file is present in the run directory with the name ftype.nc, ie either ocean.nc or ice.nc.

The model history file will be remapped to three rectilinear resolutions, 1/4 deg, 1/2 deg and 1/deg. The output files will be named, for example, ftype.0p25.nc for the 1/4 deg case.

A debug flag is available in the nml file. If set, information will be sent to ftype.post.log to assist debugging. Intermediate netCDF files will also be created during the remapping process.

The required ESMF weights are obtained from the location specified in wgtsdir. The same weights are used for either the ocean or ice case. The current weights in /scratch1/NCEPDEV/climate/climpara/S2S/FIX/fix_UFSp6/fix_reg2grb2/ need to be updated with the weights generated by the UFS_UTILS cpld_gridgen utility after the PR noted above.

Two run directories are available showing how the code works at /scratch2/NCEPDEV/stmp1/Denise.Worthen/ForRahul

@HenryRWinterbottom HenryRWinterbottom self-assigned this Oct 14, 2023

end subroutine ocnvars_typedefine

subroutine icevars_typedefine
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing should be hard coded. Any options, including variable names to be used, should be read in either via a FORTRAN namelist or a CSV file. Hard-coding features limits the capabilities of the application.

!set defaults
outvars(:)%input_var_name=''
outvars(:)%var_grid = 'Ct'
outvars(:)%var_remapmethod = 'bilinear'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if a variable requires a different type of interpolation type (e.g., nearest-neighbor)? This should not be hard coded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

State variables should be remapped with linear interpolation. Fluxes could be remapped with nearest neighbor. Is this something desired for MOM6 or CICE6 remapped fields?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DeniseWorthen What happens if an additional variable is needed in the future and requires nearest-neighbor interpolation? How do you do this without needing to rebuild the entire application?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@HenryWinterbottom-NOAA We can address the customization as an improvement activity.
For now, let us focus on this improved functionality that can be leveraged

integer :: ii = 0

!set defaults
outvars(:)%input_var_name=''
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entire subroutine needs to be defined via a namelist or CSV file. Nothing should be hard coded as it limits the capabilities of the software.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand the comments regarding generality. Variables in MOM6/CICE6 output have specified names, on specified grid locations. MOM6 temperature is never written in the output file on anything other than the center grid locations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @HenryWinterbottom-NOAA's point is to make this configurable so that one can add/remove variables without having to rebuild executables. It separates action (code) from options (configuration).

This can be addressed later as an improvement activity.

@@ -0,0 +1,577 @@
program ocnicepost
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The netCDF interface should be modified to use the https://github.com/NOAA-EMC/NCEPLIBS-ncio. It is operationally supported code and the netCDF interface is redundant.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file ocnicepost.F90 is too long and thus difficult to follow. The applications within need to be modified such that they are within standalone modules and subroutines to reduce the bloat of this code.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re. ncio, I think we can accept code without nceplibs-ncio. It may make things easier to read, but it requires a template to write. So it doesn't fully satisfy the needs of this program.

integer, parameter :: ndest = 3
integer, parameter, dimension(ndest) :: nxrs = (/1440, 720, 360/)
integer, parameter, dimension(ndest) :: nyrs = (/ 721, 361, 181/)
character(len=4), dimension(ndest) :: dstgrds = (/'0p25', '0p5 ', '1p0 '/)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hard coding of variables is not supported. The hard coded attributes in this instance should be read into the program via either a FORTRAN namelist or a CSV file.

!----------------------------------------------------------
! write a bare netcdf file of a 2D packed field
!----------------------------------------------------------
subroutine dumpnc2d(fname, vname, dims, nflds, field)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be accomplished via ncio.

!----------------------------------------------------------
! handle netcdf errors
!----------------------------------------------------------
subroutine handle_err(ierr,string)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments regarding ncio.

!----------------------------------------------------------
! write a bare netcdf file of an unpacked 2D field
!----------------------------------------------------------
subroutine dumpnc1d(fname, vname, dims, field)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments regarding ncio.

!----------------------------------------------------------
! write a bare netcdf file of an unpacked 3D field
!----------------------------------------------------------
subroutine dumpnc3dk(fname, vname, dims, field)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments regarding ncio.

!----------------------------------------------------------
! write a bare netcdf file of a packed 3D field
!----------------------------------------------------------
subroutine dumpnc3d(fname, vname, dims, nk, nflds, field)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comments regarding ncio.

Comment on lines 41 to 48
ii = ii + 1; outvars(ii)%input_var_name = 'SSH'
ii = ii + 1; outvars(ii)%input_var_name = 'SST'
ii = ii + 1; outvars(ii)%input_var_name = 'SSS'
ii = ii + 1; outvars(ii)%input_var_name = 'speed'
!ii = ii + 1; outvars(ii)%input_var_name = 'mld'
ii = ii + 1; outvars(ii)%input_var_name = 'ePBL'
ii = ii + 1; outvars(ii)%input_var_name = 'MLD_003'
ii = ii + 1; outvars(ii)%input_var_name = 'MLD_0125'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DeniseWorthen You are hard coding variables below (see above). Hard coding paths, variables, etc., that can be read via an external file is not permitted.

Copy link
Contributor

@aerorahul aerorahul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the PR.
A few comments that would help with the code.

I agree w/ @HenryWinterbottom-NOAA, the main program could be better organized, but I understand and appreciate the contribution when it was not your responsibility.

Comment on lines 17 to 20
integer, parameter :: ndest = 3
integer, parameter, dimension(ndest) :: nxrs = (/1440, 720, 360/)
integer, parameter, dimension(ndest) :: nyrs = (/ 721, 361, 181/)
character(len=4), dimension(ndest) :: dstgrds = (/'0p25', '0p5 ', '1p0 '/)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we make this namelist configurable so that the number of and the destination grid is not hard-wired.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The number of destination grids is dependent on the source grid in the sense that you don't remap the 1/2 deg tripole to the 1/4deg rectilinear. So for 1/4 deg tripole, you have 3 destination grids, for 1/2 deg tripole there are 2 destination grids and for 1deg tripole there is 1 destination grid. We've never set up a remapping of the 5deg tripole, because there was never any intention of anyone looking at that output.

The dimensions of the destination grids can be set based on whether it is a 1/4 deg, 1/2deg or 1 deg. The grid dimensions of those destination grids are fixed though. They are no more variable than the dimensions of the 1/4deg tripole grid.

! --------------------------------------------------------

nvalid = 0
rc = nf90_open(trim(input_file), nf90_nowrite, ncid)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we please wrap error checking so that the netCDF calls here and below terminate the program in the event of an error?

An example is:

subroutine nc_check(status)
  integer, intent ( in) :: status
  
    if(status /= nf90_noerr) then 
      write(6, '(a)') 'FATAL ERROR: ' // trim(nf90_strerror(status))
      stop status
    end if
end subroutine nc_check

and then

call nc_check(nf90_open(trim(input_file), nf90_nowrite, ncid))

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally do not prefer this style of checking, but I can use it if preferred here.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, but we need to be able to check the return code rc to be non-zero and exit if it is.
I was merely providing a typical example used in a lot of our codes so it feels familiar.
However, feel free to use whatever you prefer.

Comment on lines 151 to 152
rc = nf90_inq_varid(ncid, 'temp', varid)
rc = nf90_get_var(ncid, varid, tmp3d)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use getfield?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getfield is not used so that I can retain the fill value, which I use to define the 3-D interpolation mask.

character(len=120) :: input_file, wgtsfile, output_file

! source grid, tripole 1/4 deg, 40 vertical levels
integer, parameter :: nxt = 1440, nyt = 1080, nlevs = 40
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the input file required to be 1/4 degree? Will this program work for MOM6/CICE6 output at any other resolution e.g. 5 degree?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The required weights are generated for 1/4 tripole->(rect 1/4deg, 1/2deg, 1deg), the 1/2 tripole -> (rect 1/2deg, 1deg) and 1deg tripole>rect 1deg. This initial code was intended as a demonstration of how the original NCL scripts could be rewritten in fortran. The NCL scripts could do any of the three tripole resolutions.

The other resolutions can all be added as variations to the fortran version. As noted above however, the 5deg ocean output was never intended as being used for anything other than plumbing. Are you suggesting that the 5deg tripole output will be used for some purpose? Or do you want it for plumbing in this case also?

The destination grid resolutions themselves are fixed. That is, the weights are pre-generated and work only for a rectilinear 1/4deg of 1440x721, for example The code is not expected to operate between completely arbitrary destination and sources.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed this offline.
We will put in place checks to ensure that the target grid resolution does not exceed the input grid resolution; i.e. a 5-deg tripolar input will only produce 5-deg rectilinear output. 1/4-deg tripolar input can produce 1/4, 1/2, 1, 5-deg rectillinear outputs. This will be namelist configurable rather than looping over in the code.

@@ -0,0 +1,577 @@
program ocnicepost
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DeniseWorthen
At a minimum, please add a few lines of what this code does, what the inputs are, etc.
Note that the weight files have hard-wired names down in this code. Please be sure to document that.
Also include the authorship, so users can know who to ask questions in the case an error is encountered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok

* add csv files to set source field info
* restrict destination grid to a single resolution
@DeniseWorthen
Copy link
Contributor Author

The code has been restructured. Per conversation with @aerorahul, looping over destination grids has been removed. Samples of the input nml and csv files are found in staged directories /scratch2/NCEPDEV/stmp1/Denise.Worthen/ForRahul.

The code does still hard-wire the name of the time and vertical axis in the source file. The implementation of netcdf-error checking and making the time axis and vertical grid names configurable are relatively minor changes and have not been implemented at this time.

Weights are not yet available for mapping the 5-deg tripole or for remapping to a 5-deg rectilinear but there should be no restriction on the code being able to do that once weights are available.

@aerorahul aerorahul self-requested a review October 20, 2023 17:30
Copy link
Contributor

@aerorahul aerorahul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

add fortran code to remap tripole ocean and ice output to rectilinear
3 participants