Skip to content

Commit

Permalink
Fix error handling in program filter_topo (ufs-community#553)
Browse files Browse the repository at this point in the history
Update error handler routine ("handle_err") to use "error stop" 
instead of "stop" to return non-zero error code on failure.
Add print of "FATAL ERROR" to standard output as per 
NCO requirements.

Increase length of file name variables to handle whole path names.

Move routines "handle_err" and "read_namelist" to a new module
(utils.F90) to facilitate unit testing. 

Create unit test for routine "read_namelist".

Fixes ufs-community#547.
  • Loading branch information
gsketefian authored Aug 12, 2021
1 parent 560d5c7 commit 529b168
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 66 deletions.
19 changes: 16 additions & 3 deletions sorc/grid_tools.fd/filter_topo.fd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
set(fortran_src
set(lib_src
utils.F90)

set(exe_src
filter_topo.F90)

if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$")
Expand All @@ -8,9 +11,19 @@ elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^(GNU)$")
endif()

set(exe_name filter_topo)
add_executable(${exe_name} ${fortran_src})

add_library(filter_topo_lib STATIC ${lib_src})
add_executable(${exe_name} ${exe_src})

set(mod_dir "${CMAKE_CURRENT_BINARY_DIR}/mod")
set_target_properties(filter_topo_lib PROPERTIES Fortran_MODULE_DIRECTORY ${mod_dir})
target_include_directories(filter_topo_lib INTERFACE ${mod_dir})

target_link_libraries(
${exe_name}
filter_topo_lib
PUBLIC
NetCDF::NetCDF_Fortran)

target_link_libraries(${exe_name} PRIVATE filter_topo_lib)

install(TARGETS ${exe_name} RUNTIME DESTINATION ${exec_dir})
64 changes: 2 additions & 62 deletions sorc/grid_tools.fd/filter_topo.fd/filter_topo.F90
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
!! @author Zhi Liang (GFDL) who packaged it into a standalone application.
program filter_topo

use utils

implicit none

Expand All @@ -29,28 +30,12 @@ program filter_topo
real, parameter :: big_number=1.d8
real, parameter :: tiny_number=1.d-8


real:: cd4 ! Dimensionless coeff for del-4 difussion (with FCT)
real:: peak_fac ! overshoot factor for the mountain peak
real:: max_slope ! max allowable terrain slope: 1 --> 45 deg

integer :: n_del2_weak

logical :: zs_filter = .true.
logical :: zero_ocean = .true. ! if true, no diffusive flux into water/ocean area
real :: res = 48. ! real value of the 'c' resolution
real :: stretch_fac = 1.0
logical :: nested = .false. &
,regional = .false.
integer :: grid_type = 0 ! gnomonic_ed
character(len=128) :: topo_file = "orog"
character(len=128) :: topo_field = "orog_filt"
character(len=128) :: mask_field = "slmsk"
character(len=128) :: grid_file = "atmos_mosaic.nc"
namelist /filter_topo_nml/ topo_file, topo_field, mask_field, grid_file, zero_ocean, &
zs_filter, stretch_fac, res, nested, grid_type, regional

integer :: stdunit = 6
integer :: ntiles = 0

real da_min
Expand Down Expand Up @@ -635,7 +620,7 @@ subroutine read_grid_file(regional)
real :: g1(2), g2(2), g3(2), g4(2), g5(2)
real :: p1(3), p3(3)
real :: p_lL(2), p_uL(2), p_lR(2), p_uR(2)
character(len=256) :: tile_file
character(len=512) :: tile_file
real, allocatable, dimension(:,:) :: tmpvar, geolon_c_nest, geolat_c_nest
real, allocatable, dimension(:,:,:) :: geolon_c, geolat_c
real, allocatable, dimension(:,:,:) :: geolon_t, geolat_t, cos_sg, grid3
Expand Down Expand Up @@ -1933,51 +1918,6 @@ subroutine del4_cubed_sphere(is, ie, js, je, isd, ied, jsd, jed, npx, npy, ntile

end subroutine del4_cubed_sphere

!> ???
!!
!! @param[in] status ???
!! @param[in] string ???
!! @author GFDL Programmer
subroutine handle_err(status, string)
integer, intent(in) :: status
character(len=*), intent(in) :: string
character(len=256) :: errmsg

if (status .ne. nf_noerr) then
errmsg = nf_strerror(status)
errmsg = trim(errmsg)//trim(string)
print *, trim(errmsg)
stop 'Stopped'
endif

end subroutine handle_err

!> Reads the namelist file, write namelist to log file.
!!
!!
!! @author GFDL Programmer
subroutine read_namelist

! read namelist
integer :: unit=7, io_status
logical :: opened

do
inquire( unit=unit, opened=opened )
if( .NOT.opened )exit
unit = unit + 1
if( unit.EQ.100 )call handle_err(-1, 'Unable to locate unit number.' )
end do
open( unit=unit, file='input.nml', iostat=io_status )
read( unit,filter_topo_nml, iostat=io_status )
close(unit)

if (io_status > 0) call handle_err(-1, 'Error reading input.nml')

write (stdunit, nml=filter_topo_nml)

end subroutine read_namelist

!> Check results of netCDF call.
!!
!! @param[in] status return code to check
Expand Down
90 changes: 90 additions & 0 deletions sorc/grid_tools.fd/filter_topo.fd/utils.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
!> @file
!! @brief Utility routines.
!! @author GFDL programmer

!> Module that contains general utility routines.
!!
!! @author GFDL programmer
module utils

implicit none

public

character(len=512) :: topo_file = "orog" !< Path/name of the topography (or orography) file.
character(len=128) :: topo_field = "orog_filt" !< NetCDF record name of the filtered
!! topography (or orography).
character(len=128) :: mask_field = "slmsk" !< NetCDF record name of the land/sea mask.
character(len=512) :: grid_file = "atmos_mosaic.nc" !< Path/name of the grid mosaic file.

logical :: zero_ocean = .true. !< If true, no diffusive flux into water/ocean
!! area (preserve islands).
logical :: nested = .false. !< If true, process a global grid with a nest.
logical :: regional = .false. !< If true, process a stand-alone regional grid.

integer :: grid_type = 0 !< Grid type. 0 for a gnomonic grid.

real :: stretch_fac = 1.0 !< Grid stretching factor.
real :: res = 48. !< The 'CRES' resolution.

contains

!> Read the program namelist file. Then, write the namelist
!! variables to standard output.
!!
!! @author GFDL Programmer
subroutine read_namelist

implicit none

integer :: stdunit = 6, unit=7, io_status
logical :: opened

namelist /filter_topo_nml/ topo_file, topo_field, mask_field, grid_file, zero_ocean, &
stretch_fac, res, nested, grid_type, regional

do
inquire( unit=unit, opened=opened )
if( .NOT.opened )exit
unit = unit + 1
if( unit.EQ.100 )call handle_err(-1, 'Unable to locate unit number.' )
end do

open( unit=unit, file='input.nml', iostat=io_status )
read( unit,filter_topo_nml, iostat=io_status )
close(unit)

if (io_status > 0) call handle_err(-1, 'Error reading input.nml')

write (stdunit, nml=filter_topo_nml)

end subroutine read_namelist

!> Prints an error message to standard output,
!! then halts program execution with a
!! bad status.
!!
!! @param[in] status Error status code.
!! @param[in] string Error message.
!! @author GFDL Programmer
subroutine handle_err(status, string)

implicit none

#include <netcdf.inc>

integer, intent(in) :: status
character(len=*), intent(in) :: string
character(len=256) :: errmsg

if (status .ne. nf_noerr) then
errmsg = nf_strerror(status)
errmsg = trim(errmsg) // " " // trim(string)
print *, "FATAL ERROR:"
print *, trim(errmsg)
error stop 'Stopped'
endif

end subroutine handle_err

end module utils
3 changes: 2 additions & 1 deletion tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
# Ed Hartnett 2/11/21

# Add the test subdirecotries.
add_subdirectory(filter_topo)
add_subdirectory(chgres_cube)
add_subdirectory(fre-nctools)
add_subdirectory(global_cycle)
add_subdirectory(sfc_climo_gen)
add_subdirectory(sfc_climo_gen)
23 changes: 23 additions & 0 deletions tests/filter_topo/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# This is the cmake build file for the tests directory of the
# UFS_UTILS project.
#
# George Gayno, Ed Hartnett

if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$")
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -r8 -assume byterecl")
elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^(GNU)$")
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -ffree-line-length-0 -fdefault-real-8")
endif()

include_directories(${PROJECT_SOURCE_DIR})

# Copy necessary test files from the source data directory to the
# build data directory.
execute_process( COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/data/input.nml ${CMAKE_CURRENT_BINARY_DIR}/input.nml)
execute_process( COMMAND ${CMAKE_COMMAND} -E copy
${CMAKE_CURRENT_SOURCE_DIR}/LSanSuppress.supp ${CMAKE_CURRENT_BINARY_DIR}/LSanSuppress.supp)

add_executable(ftst_read_filter_topo_nml ftst_readnml.F90)
add_test(NAME filter_topo-ftst_read_namelist COMMAND ftst_read_filter_topo_nml)
target_link_libraries(ftst_read_filter_topo_nml filter_topo_lib)
2 changes: 2 additions & 0 deletions tests/filter_topo/LSanSuppress.supp
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
leak:ESMCI
leak:esmf
12 changes: 12 additions & 0 deletions tests/filter_topo/data/input.nml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
&filter_topo_nml
topo_file="/dir1/dir2/orography.nc"
topo_field="orog_filter"
mask_field="landmask"
grid_file="/dir1/dir2/dir3/mosaic.nc"
zero_ocean=.false.
stretch_fac=2.0
res=96.
nested=.true.
grid_type=1
regional=.true.
/
34 changes: 34 additions & 0 deletions tests/filter_topo/ftst_readnml.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
! Unit test for filter_topo routine "read_namelist".
!
! Reads a sample namelist from file input.nml.
! If any namelist variable does not match expected values,
! the test fails.
!
! Author George Gayno 7/23/2021

program readnml

use utils

implicit none

print*, "Starting test of filter_topo routine read_namelist."
print*, "Testing with file input.nml..."

call read_namelist()

if (trim(topo_file) /= "/dir1/dir2/orography.nc") stop 2
if (trim(topo_field) /= "orog_filter") stop 4
if (trim(mask_field) /= "landmask") stop 6
if (trim(grid_file) /= "/dir1/dir2/dir3/mosaic.nc") stop 8
if (zero_ocean) stop 10
if (stretch_fac /= 2.0) stop 14
if (res /= 96.0) stop 14
if (.not. nested) stop 16
if (grid_type /= 1) stop 18
if (.not. regional) stop 20

print*, "OK"
print*, "SUCCESS!"

end program readnml

0 comments on commit 529b168

Please sign in to comment.