From e17b8d8136e4b1582826d2aba7fdee88c1344fbf Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 26 Sep 2024 12:41:38 -0500 Subject: [PATCH 01/20] Separate the namelist read routine and netcdf error routines into their own library. Write a unit test for the namelist read routine. Fixes #944. --- sorc/ocean_merge.fd/CMakeLists.txt | 16 ++++--- ..._lake_ocnmsk.f90 => merge_lake_ocnmsk.F90} | 44 ------------------- sorc/ocean_merge.fd/namelist.F90 | 29 ++++++++++++ sorc/ocean_merge.fd/utils.F90 | 13 ++++++ tests/CMakeLists.txt | 1 + tests/ocean_merge/CMakeLists.txt | 21 +++++++++ tests/ocean_merge/data/input.nml | 8 ++++ tests/ocean_merge/ftst_read_nml.F90 | 29 ++++++++++++ 8 files changed, 111 insertions(+), 50 deletions(-) rename sorc/ocean_merge.fd/{merge_lake_ocnmsk.f90 => merge_lake_ocnmsk.F90} (81%) create mode 100644 sorc/ocean_merge.fd/namelist.F90 create mode 100644 sorc/ocean_merge.fd/utils.F90 create mode 100644 tests/ocean_merge/CMakeLists.txt create mode 100644 tests/ocean_merge/data/input.nml create mode 100644 tests/ocean_merge/ftst_read_nml.F90 diff --git a/sorc/ocean_merge.fd/CMakeLists.txt b/sorc/ocean_merge.fd/CMakeLists.txt index 60d0a6b46..e5d1e4b10 100644 --- a/sorc/ocean_merge.fd/CMakeLists.txt +++ b/sorc/ocean_merge.fd/CMakeLists.txt @@ -1,6 +1,5 @@ -list(APPEND fortran_src - merge_lake_ocnmsk.f90 -) +set(lib_src utils.F90 namelist.F90) +set(exe_src merge_lake_ocnmsk.F90) if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$") set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} -r8 -i4 -convert big_endian") @@ -12,12 +11,17 @@ elseif(CMAKE_Fortran_COMPILER_ID MATCHES "^(GNU)$") endif() set(exe_name ocean_merge) -add_executable(${exe_name} ${fortran_src}) + +add_library(om_lib STATIC ${lib_src}) +add_executable(${exe_name} ${exe_src}) + target_link_libraries( - ${exe_name} - + om_lib + PUBLIC NetCDF::NetCDF_Fortran) +target_link_libraries(${exe_name} PRIVATE om_lib) + install(TARGETS ${exe_name}) # If doxygen documentation we enabled, build it. diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.f90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 similarity index 81% rename from sorc/ocean_merge.fd/merge_lake_ocnmsk.f90 rename to sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index 9cba4088d..e8bf1b639 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.f90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -138,47 +138,3 @@ program merge_lake_ocnmsk write(*,'(a,i8,a,i8,a)') 'total lake point ',lake_pt,' where ',nodp_pt,' has no depth' end program merge_lake_ocnmsk - -!> Handle netCDF errors. -!! -!! @param[in] ret NetCDF return code. -!! @author Shan Sun -subroutine handle_err (ret) - use netcdf - integer, intent(in) :: ret - - if (ret /= NF90_NOERR) then - write(6,*) nf90_strerror (ret) - stop 999 - end if -end subroutine handle_err - -!> Read program namelist. -!! -!! @param[out] ocean_mask_dir Directory containing MOM6 ocean mask file. -!! @param[out] lake_mask_dir Directory containing the lake mask file. -!! @param[out] out_dir Directory where output file will be written. -!! @param[out] atmres Atmosphere grid resolution. -!! @param[out] ocnres Ocean grid resolution. -!! @param[out] binary_lake or fractional lake -!! @author Rahul Mahajan -!! @author Sanath Kumar -subroutine read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_lake) - - integer :: unit=7, io_status - - character(len=120), intent(out) :: ocean_mask_dir - character(len=120), intent(out) :: lake_mask_dir - character(len=120), intent(out) :: out_dir - character(len=10), intent(out) :: atmres,ocnres - integer, intent(out):: binary_lake - - namelist/mask_nml/ocean_mask_dir, lake_mask_dir, atmres, ocnres,out_dir,binary_lake - open(unit=unit, file='input.nml', iostat=io_status ) - read(unit,mask_nml, iostat=io_status ) - close(unit) - if (io_status > 0) then - print *,'Error reading input.nml' - call handle_err(-1) - end if -end subroutine read_nml diff --git a/sorc/ocean_merge.fd/namelist.F90 b/sorc/ocean_merge.fd/namelist.F90 new file mode 100644 index 000000000..3db2c1ad5 --- /dev/null +++ b/sorc/ocean_merge.fd/namelist.F90 @@ -0,0 +1,29 @@ +!> Read program namelist. +!! +!! @param[out] ocean_mask_dir Directory containing MOM6 ocean mask file. +!! @param[out] lake_mask_dir Directory containing the lake mask file. +!! @param[out] out_dir Directory where output file will be written. +!! @param[out] atmres Atmosphere grid resolution. +!! @param[out] ocnres Ocean grid resolution. +!! @param[out] binary_lake or fractional lake +!! @author Rahul Mahajan +!! @author Sanath Kumar +subroutine read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_lake) + + integer :: unit=7, io_status + + character(len=120), intent(out) :: ocean_mask_dir + character(len=120), intent(out) :: lake_mask_dir + character(len=120), intent(out) :: out_dir + character(len=10), intent(out) :: atmres,ocnres + integer, intent(out):: binary_lake + + namelist/mask_nml/ocean_mask_dir, lake_mask_dir, atmres, ocnres,out_dir,binary_lake + open(unit=unit, file='input.nml', iostat=io_status ) + read(unit,mask_nml, iostat=io_status ) + close(unit) + if (io_status > 0) then + print *,'Error reading input.nml' + call handle_err(-1) + end if +end subroutine read_nml diff --git a/sorc/ocean_merge.fd/utils.F90 b/sorc/ocean_merge.fd/utils.F90 new file mode 100644 index 000000000..570f03cfa --- /dev/null +++ b/sorc/ocean_merge.fd/utils.F90 @@ -0,0 +1,13 @@ +!> Handle netCDF errors. +!! +!! @param[in] ret NetCDF return code. +!! @author Shan Sun +subroutine handle_err (ret) + use netcdf + integer, intent(in) :: ret + + if (ret /= NF90_NOERR) then + write(6,*) nf90_strerror (ret) + stop 999 + end if +end subroutine handle_err diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 95b28c8fe..a08411c3f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,3 +42,4 @@ add_subdirectory(sfc_climo_gen) add_subdirectory(cpld_gridgen) add_subdirectory(emcsfc_snow2mdl) add_subdirectory(ocnice_prep) +add_subdirectory(ocean_merge) diff --git a/tests/ocean_merge/CMakeLists.txt b/tests/ocean_merge/CMakeLists.txt new file mode 100644 index 000000000..24d4c1a8a --- /dev/null +++ b/tests/ocean_merge/CMakeLists.txt @@ -0,0 +1,21 @@ +# This is the cmake build file for the tests directory of the +# UFS_UTILS project. +# +# George Gayno + +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() + +# 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) + +add_executable(ftst_read_nml ftst_read_nml.F90) +target_link_libraries(ftst_read_nml om_lib) + +add_test(NAME ocean_merge-ftst_read_nml COMMAND ftst_read_nml) diff --git a/tests/ocean_merge/data/input.nml b/tests/ocean_merge/data/input.nml new file mode 100644 index 000000000..9a2c16208 --- /dev/null +++ b/tests/ocean_merge/data/input.nml @@ -0,0 +1,8 @@ + &mask_nml + ocean_mask_dir="/ocean/mask/dir" + ocnres="mx025" + lake_mask_dir="/lake/mask/dir" + atmres="C96" + out_dir="/out/dir" + binary_lake=1 + / diff --git a/tests/ocean_merge/ftst_read_nml.F90 b/tests/ocean_merge/ftst_read_nml.F90 new file mode 100644 index 000000000..3765c2b10 --- /dev/null +++ b/tests/ocean_merge/ftst_read_nml.F90 @@ -0,0 +1,29 @@ +! Unit test for the read_nml routine. + + program read_namelist + + implicit none + + character(len=120) :: ocean_mask_dir + character(len=120) :: lake_mask_dir + character(len=120) :: out_dir + character(len=10) :: atmres,ocnres + + integer :: binary_lake + + print*,"Call routine read_nml." + + call read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_lake) + + if (trim(ocean_mask_dir) /= "/ocean/mask/dir") stop 2 + if (trim(lake_mask_dir) /= "/lake/mask/dir") stop 4 + if (trim(atmres) /= "C96") stop 6 + if (trim(ocnres) /= "mx025") stop 8 + if (trim(out_dir) /= "/out/dir") stop 8 + if (binary_lake /= 1) stop 10 + + print*, "OK" + + print*, "SUCCESS!" + + end program read_namelist From b204a0583f7483b57fbba8fbbff3adfd807033c7 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 26 Sep 2024 13:35:02 -0500 Subject: [PATCH 02/20] Remove some commented out code. Fixes #944. --- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index e8bf1b639..3659dca5d 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -34,7 +34,6 @@ program merge_lake_ocnmsk integer :: lake_pt,vlat real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) - call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) print *, pth1 @@ -58,21 +57,11 @@ program merge_lake_ocnmsk call handle_err (nf90_inq_varid(ncid, 'land_frac', v1id)) call handle_err (nf90_get_var (ncid, v1id, ocn_frac, start=start, count=count)) - !write(flnm,'(3a,i1,a)') trim(pth2),trim(atmres),'_orog_data.tile',tile,'.nc' write(flnm,'(4a,i1,a)') trim(pth2),'oro.',trim(atmres),'.tile',tile,'.nc' print *,' flnm2=',trim(flnm) call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) write(6,*) 'flnm_lake=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts - !if (tile==1) then - ! call handle_err (nf90_inq_dimid (ncid, 'lat', latid)) - ! call handle_err (nf90_inq_dimid (ncid, 'lon', lonid)) - ! call handle_err (nf90_inquire_dimension (ncid, latid, len=lat)) - ! call handle_err (nf90_inquire_dimension (ncid, lonid, len=lon)) - ! write(6,*) 'lat=',lat,'lon=',lon - ! start(1:2) = (/1,1/) - ! count(1:2) = (/lon,lat/) - !end if call handle_err (nf90_inq_varid(ncid, 'lake_frac', v2id)) call handle_err (nf90_inq_varid(ncid, 'lake_depth',v3id)) call handle_err (nf90_inq_varid(ncid, 'geolat' ,vlat)) @@ -103,7 +92,6 @@ program merge_lake_ocnmsk else lake_depth(i,j)=0. end if -! slmsk(i,j) = ceiling(land_frac(i,j))! "ceiling is used for orog smoothing" slmsk(i,j) = nint(land_frac(i,j)) ! nint got the land pts correct end do end do @@ -128,12 +116,6 @@ program merge_lake_ocnmsk call handle_err (nf90_put_var (ncid4, v4id,slmsk)) call handle_err (nf90_close(ncid4)) -! do i=1,48 -! do j=1,48 -! write(*,'(2i4,4f6.1)') i,j,land_frac(i,j),lake_frac(i,j),lake_depth(i,j),slmsk(i,j) -! end do -! end do - end do ! tile write(*,'(a,i8,a,i8,a)') 'total lake point ',lake_pt,' where ',nodp_pt,' has no depth' From d89bb2657b7e2b23f1e3e485c2b52aba81b2b585 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 26 Sep 2024 14:51:15 -0500 Subject: [PATCH 03/20] Move the merging algorithm to its own routne. Fixes #944. --- sorc/ocean_merge.fd/merge.F90 | 51 +++++++++++++++++++++++ sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 36 ++-------------- 2 files changed, 55 insertions(+), 32 deletions(-) create mode 100644 sorc/ocean_merge.fd/merge.F90 diff --git a/sorc/ocean_merge.fd/merge.F90 b/sorc/ocean_merge.fd/merge.F90 new file mode 100644 index 000000000..2de4c8db7 --- /dev/null +++ b/sorc/ocean_merge.fd/merge.F90 @@ -0,0 +1,51 @@ + subroutine merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + implicit none + + integer, intent(in) :: lon, lat, binary_lake + + real, intent(in) :: lat2d(lon,lat) + real, intent(in) :: ocn_frac(lon,lat) + real, intent(inout) :: lake_frac(lon,lat) + real, intent(inout) :: lake_depth(lon,lat) + real, intent(inout) :: land_frac(lon,lat) + real, intent(out) :: slmsk(lon,lat) + + real, parameter :: min_land=1.e-4, def_lakedp=10. + + integer :: i, j, nodp_pt, lake_pt + + nodp_pt=0 + lake_pt=0 + + do i=1,lon + do j=1,lat + if (binary_lake.eq.1) lake_frac(i,j)=nint(lake_frac(i,j)) ! using integer lake_frac + if (lat2d(i,j).le.-60.) lake_frac(i,j)=0. ! ignore lakes on Antarctica + land_frac(i,j)=1.-ocn_frac(i,j) + if (land_frac(i,j) < min_land) land_frac(i,j)=0. ! ignore land < min_land + if (land_frac(i,j) > 1.-min_land) land_frac(i,j)=1. ! ignore water < min_land + if (1.-land_frac(i,j) > 0.) lake_frac(i,j)=0. ! ocn dominates + + if (lake_frac(i,j) > 0.) then + lake_pt=lake_pt+1 ! calculating total lake points + if (binary_lake.eq.1) then + land_frac(i,j)=0. + else + land_frac(i,j)=1.-lake_frac(i,j) + end if + if (lake_depth(i,j) <= 0.) then + lake_depth(i,j)=def_lakedp ! set missing lake depth to default value + nodp_pt=nodp_pt+1 ! calculating total lake points without depth + end if + else + lake_depth(i,j)=0. + end if + slmsk(i,j) = nint(land_frac(i,j)) ! nint got the land pts correct + end do + end do + + write(*,'(a,i8,a,i8,a)') 'total lake point ',lake_pt,' where ',nodp_pt,' has no depth' + + end subroutine merge diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index 3659dca5d..0d6339b06 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -22,7 +22,6 @@ program merge_lake_ocnmsk character(len=120) :: pth1 character(len=120) :: pth2,pth3 character(len=10) :: atmres,ocnres - real, parameter :: min_land=1.e-4, def_lakedp=10. ! this variable is now renamed as binary_lake and is passed in from the name ! list ! logical, parameter :: int_lake=.true. @@ -30,15 +29,14 @@ program merge_lake_ocnmsk integer :: binary_lake character(len=250) :: flnm - integer :: ncid,ndims,nvars,natts,lat,lon,v1id,v2id,v3id,v4id,start(2),count(2),i,j,latid,lonid,ncid4, dims(2),tile,nodp_pt - integer :: lake_pt,vlat + integer :: ncid,ndims,nvars,natts,lat,lon,v1id,v2id,v3id,v4id,start(2),count(2),latid,lonid,ncid4, dims(2),tile + integer :: vlat real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) print *, pth1 - nodp_pt=0 - lake_pt=0 + do tile=1,6 write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) @@ -69,32 +67,7 @@ program merge_lake_ocnmsk call handle_err (nf90_get_var (ncid, v3id, lake_depth,start=start, count=count)) call handle_err (nf90_get_var (ncid, vlat, lat2d, start=start, count=count)) - do i=1,lon - do j=1,lat - if (binary_lake.eq.1) lake_frac(i,j)=nint(lake_frac(i,j)) ! using integer lake_frac - if (lat2d(i,j).le.-60.) lake_frac(i,j)=0. ! ignore lakes on Antarctica - land_frac(i,j)=1.-ocn_frac(i,j) - if (land_frac(i,j) < min_land) land_frac(i,j)=0. ! ignore land < min_land - if (land_frac(i,j) > 1.-min_land) land_frac(i,j)=1. ! ignore water < min_land - if (1.-land_frac(i,j) > 0.) lake_frac(i,j)=0. ! ocn dominates - - if (lake_frac(i,j) > 0.) then - lake_pt=lake_pt+1 ! calculating total lake points - if (binary_lake.eq.1) then - land_frac(i,j)=0. - else - land_frac(i,j)=1.-lake_frac(i,j) - end if - if (lake_depth(i,j) <= 0.) then - lake_depth(i,j)=def_lakedp ! set missing lake depth to default value - nodp_pt=nodp_pt+1 ! calculating total lake points without depth - end if - else - lake_depth(i,j)=0. - end if - slmsk(i,j) = nint(land_frac(i,j)) ! nint got the land pts correct - end do - end do + call merge(lon, lat, binary_lake, lat2d, ocn_frac, lake_frac, lake_depth, land_frac, slmsk) write(flnm,'(4a,i1,a)') trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' print *,'output=',trim(flnm) @@ -117,6 +90,5 @@ program merge_lake_ocnmsk call handle_err (nf90_close(ncid4)) end do ! tile - write(*,'(a,i8,a,i8,a)') 'total lake point ',lake_pt,' where ',nodp_pt,' has no depth' end program merge_lake_ocnmsk From 70c12335a748f5f4fbe2865ee40dec2fe4977a94 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 27 Sep 2024 08:11:15 -0500 Subject: [PATCH 04/20] Create an initial unit test for the 'merge' routine. Fixes #944. --- sorc/ocean_merge.fd/CMakeLists.txt | 2 +- sorc/ocean_merge.fd/merge.F90 | 2 +- tests/ocean_merge/CMakeLists.txt | 4 ++ tests/ocean_merge/ftst_merge.F90 | 64 ++++++++++++++++++++++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/ocean_merge/ftst_merge.F90 diff --git a/sorc/ocean_merge.fd/CMakeLists.txt b/sorc/ocean_merge.fd/CMakeLists.txt index e5d1e4b10..e363478d1 100644 --- a/sorc/ocean_merge.fd/CMakeLists.txt +++ b/sorc/ocean_merge.fd/CMakeLists.txt @@ -1,4 +1,4 @@ -set(lib_src utils.F90 namelist.F90) +set(lib_src merge.F90 utils.F90 namelist.F90) set(exe_src merge_lake_ocnmsk.F90) if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$") diff --git a/sorc/ocean_merge.fd/merge.F90 b/sorc/ocean_merge.fd/merge.F90 index 2de4c8db7..febb78514 100644 --- a/sorc/ocean_merge.fd/merge.F90 +++ b/sorc/ocean_merge.fd/merge.F90 @@ -9,7 +9,7 @@ subroutine merge(lon, lat, binary_lake, lat2d, ocn_frac, & real, intent(in) :: ocn_frac(lon,lat) real, intent(inout) :: lake_frac(lon,lat) real, intent(inout) :: lake_depth(lon,lat) - real, intent(inout) :: land_frac(lon,lat) + real, intent(out) :: land_frac(lon,lat) real, intent(out) :: slmsk(lon,lat) real, parameter :: min_land=1.e-4, def_lakedp=10. diff --git a/tests/ocean_merge/CMakeLists.txt b/tests/ocean_merge/CMakeLists.txt index 24d4c1a8a..6f1bec5bc 100644 --- a/tests/ocean_merge/CMakeLists.txt +++ b/tests/ocean_merge/CMakeLists.txt @@ -18,4 +18,8 @@ execute_process( COMMAND ${CMAKE_COMMAND} -E copy add_executable(ftst_read_nml ftst_read_nml.F90) target_link_libraries(ftst_read_nml om_lib) +add_executable(ftst_merge ftst_merge.F90) +target_link_libraries(ftst_merge om_lib) + add_test(NAME ocean_merge-ftst_read_nml COMMAND ftst_read_nml) +add_test(NAME ocean_merge-ftst_merge COMMAND ftst_merge) diff --git a/tests/ocean_merge/ftst_merge.F90 b/tests/ocean_merge/ftst_merge.F90 new file mode 100644 index 000000000..173f2e417 --- /dev/null +++ b/tests/ocean_merge/ftst_merge.F90 @@ -0,0 +1,64 @@ +! Unit test for the merge routine. + + program ftst_merge + + implicit none + + integer, parameter :: lon = 1 + integer, parameter :: lat = 1 + + integer :: binary_lake + + real :: lat2d(lon,lat) + real :: ocn_frac(lon,lat) + real :: lake_frac(lon,lat) + real :: lake_depth(lon,lat) + real :: land_frac(lon,lat) + real :: slmsk(lon,lat) + + print*,"Begin test of merge routine" + +! test point 1 + + binary_lake = 0 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = .75 + lake_frac(1,1) = 0.0 + lake_depth(1,1) = 0.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 1 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + +! test point 2 + + binary_lake = 0 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = 0.0 + lake_frac(1,1) = .75 + lake_depth(1,1) = 100.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 2 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + print*, "OK" + + print*, "SUCCESS!" + + end program ftst_merge From 610c7602da82cac945c5f77455e3bd66d6f31744 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 27 Sep 2024 08:34:44 -0500 Subject: [PATCH 05/20] Add doxygen to the 'merge' routine. Fixes #944. --- sorc/ocean_merge.fd/merge.F90 | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/sorc/ocean_merge.fd/merge.F90 b/sorc/ocean_merge.fd/merge.F90 index febb78514..138ea5144 100644 --- a/sorc/ocean_merge.fd/merge.F90 +++ b/sorc/ocean_merge.fd/merge.F90 @@ -1,3 +1,21 @@ +!> Determine the water mask by merging the lake mask with the mapped ocean +!! mask from MOM6. Both are on the FV3 grid. During merge, the ocean mask +!! dominates the lake mask if there is a conflict. After the merge, the remaining +!! non-water fraction is the land fraction. +!! +!! @param[in] lon The "east/west" dimension of the model grid. +!! @param[in] lat The "north/south" dimension of the model grid. +!! @param[in] binary_lake When '1', lake fraction is either 0 or 1. Otherwise, it is a fraction. +!! @param[in] lat2d Latitude of the model grid points. +!! @param[in] ocn_frac Fraction of the grid point that is ocean. +!! @param[inout] lake_frac Fraction of the grid point that is lake. +!! @param[inout] lake_depth Lake depth. +!! @param[out] land_frac Fraction of the grid point that is land. +!! @param[out] slmsk Land/sea mask. '1' if less than 50% land. Otherwise, '1'. +!! +!! @author Shan Sun +!! @author Rahul Mahajan +!! @author Sanath Kumar subroutine merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) From e8e8343b83299aaeae4d189467d530cfa263e974 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 27 Sep 2024 10:27:40 -0500 Subject: [PATCH 06/20] Add more test points to the 'merge' unit test. Fixes #944. --- tests/ocean_merge/ftst_merge.F90 | 152 ++++++++++++++++++++++++++++++- 1 file changed, 147 insertions(+), 5 deletions(-) diff --git a/tests/ocean_merge/ftst_merge.F90 b/tests/ocean_merge/ftst_merge.F90 index 173f2e417..4cd3082a3 100644 --- a/tests/ocean_merge/ftst_merge.F90 +++ b/tests/ocean_merge/ftst_merge.F90 @@ -9,6 +9,7 @@ program ftst_merge integer :: binary_lake + real, parameter :: epsilon=0.00001 real :: lat2d(lon,lat) real :: ocn_frac(lon,lat) real :: lake_frac(lon,lat) @@ -18,11 +19,102 @@ program ftst_merge print*,"Begin test of merge routine" -! test point 1 +! Test point 1 + +! Some ocean. No lake. + + print*,'Test point 1.' + + binary_lake = 0 ! keep fractional lake. + lat2d(1,1) = 30.0 ! point at 30N. + ocn_frac(1,1) = .75 ! .75 ocean/.25 land + lake_frac(1,1) = 0.0 ! no lake. + lake_depth(1,1) = 0.0 ! no lake. + land_frac(1,1) = -99. ! based on ocn_frac, should be .25. + slmsk(1,1) = -99. ! should be zero (nint of land_frac) + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 2 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 2 + if ( abs(land_frac(1,1) - .25) > epsilon) stop 2 + if ( abs(slmsk(1,1) - 0.) > epsilon) stop 2 + +! test point 2 + +! No ocean. Some lake. + + binary_lake = 0 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = 0.0 + lake_frac(1,1) = .75 + lake_depth(1,1) = 100.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 2 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + +! test point 3 + +! Some lake and some ocean. Ocean should dominate. + + binary_lake = 0 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = .45 + lake_frac(1,1) = .75 + lake_depth(1,1) = 100.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 3 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + +! test point 4 + +! No ocean. Some lake. Lake has a missing depth that should +! be given a default value. + + binary_lake = 0 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = 0.0 + lake_frac(1,1) = .75 + lake_depth(1,1) = -9. + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 4 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + +! Test point 5 +! Some ocean (but very small percentage). No lake. +! The ocean is removed and point becomes all land. binary_lake = 0 lat2d(1,1) = 30.0 - ocn_frac(1,1) = .75 + ocn_frac(1,1) = 1.e-6 lake_frac(1,1) = 0.0 lake_depth(1,1) = 0.0 land_frac(1,1) = -99. @@ -31,17 +123,42 @@ program ftst_merge call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 1 ' + print*,'test point 5 ' print*,'ocn_frac ',ocn_frac(1,1) print*,'lake_frac ',lake_frac(1,1) print*,'lake_depth ',lake_depth(1,1) print*,'land_frac ',land_frac(1,1) print*,'slmsk ', slmsk(1,1) -! test point 2 +! Test point 6 +! Some ocean (almost all ocean). Some lake. +! The ocean is set to 1.0 and there is no land. binary_lake = 0 lat2d(1,1) = 30.0 + ocn_frac(1,1) = 0.99999 + lake_frac(1,1) = 0.24 + lake_depth(1,1) = 50.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 6 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + +! test point 7 + +! No ocean. Some lake, but near Antarctica. +! Lake to be removed. + + binary_lake = 0 + lat2d(1,1) = -70.0 ocn_frac(1,1) = 0.0 lake_frac(1,1) = .75 lake_depth(1,1) = 100.0 @@ -51,12 +168,37 @@ program ftst_merge call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 2 ' + print*,'test point 7 ' print*,'ocn_frac ',ocn_frac(1,1) print*,'lake_frac ',lake_frac(1,1) print*,'lake_depth ',lake_depth(1,1) print*,'land_frac ',land_frac(1,1) print*,'slmsk ', slmsk(1,1) + +! test point 8 + +! No ocean. Some lake. Assume binary yes/no lake. + + binary_lake = 1 + lat2d(1,1) = 30.0 + ocn_frac(1,1) = 0.0 + lake_frac(1,1) = .15 + lake_depth(1,1) = 100.0 + land_frac(1,1) = -99. + slmsk(1,1) = -99. + + call merge(lon, lat, binary_lake, lat2d, ocn_frac, & + lake_frac, lake_depth, land_frac, slmsk) + + print*,'test point 8 ' + print*,'ocn_frac ',ocn_frac(1,1) + print*,'lake_frac ',lake_frac(1,1) + print*,'lake_depth ',lake_depth(1,1) + print*,'land_frac ',land_frac(1,1) + print*,'slmsk ', slmsk(1,1) + + + print*, "OK" print*, "SUCCESS!" From c9d9a96e18800b458e417f086b9a82ed66a783e7 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 27 Sep 2024 14:44:18 -0500 Subject: [PATCH 07/20] Finish unit test for 'merge' routine. Fixes #944. --- tests/ocean_merge/ftst_merge.F90 | 231 +++++++++++++++---------------- 1 file changed, 115 insertions(+), 116 deletions(-) diff --git a/tests/ocean_merge/ftst_merge.F90 b/tests/ocean_merge/ftst_merge.F90 index 4cd3082a3..f0d5b0ab2 100644 --- a/tests/ocean_merge/ftst_merge.F90 +++ b/tests/ocean_merge/ftst_merge.F90 @@ -20,18 +20,17 @@ program ftst_merge print*,"Begin test of merge routine" ! Test point 1 - -! Some ocean. No lake. +! Some ocean. No lake. Ocean info retained. print*,'Test point 1.' - binary_lake = 0 ! keep fractional lake. - lat2d(1,1) = 30.0 ! point at 30N. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. ocn_frac(1,1) = .75 ! .75 ocean/.25 land - lake_frac(1,1) = 0.0 ! no lake. - lake_depth(1,1) = 0.0 ! no lake. - land_frac(1,1) = -99. ! based on ocn_frac, should be .25. - slmsk(1,1) = -99. ! should be zero (nint of land_frac) + lake_frac(1,1) = 0.0 ! No lake. + lake_depth(1,1) = 0.0 ! No lake. + land_frac(1,1) = -99. ! Based on ocn_frac, should be .25. + slmsk(1,1) = -99. ! Should be zero (nint of land_frac) call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) @@ -41,163 +40,163 @@ program ftst_merge if ( abs(land_frac(1,1) - .25) > epsilon) stop 2 if ( abs(slmsk(1,1) - 0.) > epsilon) stop 2 -! test point 2 +! Test point 2 +! No ocean. Some lake. Lake info retained. -! No ocean. Some lake. + print*,'Test point 2.' - binary_lake = 0 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = 0.0 - lake_frac(1,1) = .75 - lake_depth(1,1) = 100.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. + ocn_frac(1,1) = 0.0 ! 0 ocean/1 land. + lake_frac(1,1) = .75 ! Some lake. + lake_depth(1,1) = 100.0 ! Lake depth. + land_frac(1,1) = -99. ! Should be .25 + slmsk(1,1) = -99. ! Should be zero (nint of land_frac). call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 2 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) + if ( abs(lake_frac(1,1) - .75) > epsilon) stop 4 + if ( abs(lake_depth(1,1) - 100.) > epsilon) stop 4 + if ( abs(land_frac(1,1) - .25) > epsilon) stop 4 + if ( abs(slmsk(1,1) - 0.) > epsilon) stop 4 -! test point 3 +! Test point 3 +! Some lake and some ocean. Ocean should dominate. Lake +! should be removed. -! Some lake and some ocean. Ocean should dominate. + print*,'Test point 3.' - binary_lake = 0 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = .45 - lake_frac(1,1) = .75 - lake_depth(1,1) = 100.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. + ocn_frac(1,1) = .45 ! Some ocean. + lake_frac(1,1) = .75 ! Some lake. + lake_depth(1,1) = 100.0 ! Lake depth + land_frac(1,1) = -99. ! Should be 1 minus ocn_frac + slmsk(1,1) = -99. ! Should be 1 (nint of land_frac). call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 3 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 6 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 6 + if ( abs(land_frac(1,1) - .55) > epsilon) stop 6 + if ( abs(slmsk(1,1) - 1.) > epsilon) stop 6 -! test point 4 +! Test point 4 +! No ocean. Some lake. Lake will be retainted. Lake has +! a missing depth that should be given a default value. -! No ocean. Some lake. Lake has a missing depth that should -! be given a default value. + print*,'Test point 4.' - binary_lake = 0 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = 0.0 - lake_frac(1,1) = .75 - lake_depth(1,1) = -9. - land_frac(1,1) = -99. - slmsk(1,1) = -99. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. + ocn_frac(1,1) = 0.0 ! No ocean. + lake_frac(1,1) = .75 ! Some lake. + lake_depth(1,1) = -9. ! Lake depth is missing. + land_frac(1,1) = -99. ! Should be 1 minus lake_frac + slmsk(1,1) = -99. ! Should be 0 (nint of land_frac). call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 4 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) + if ( abs(lake_frac(1,1) - .75) > epsilon) stop 8 + if ( abs(lake_depth(1,1) - 10.) > epsilon) stop 8 + if ( abs(land_frac(1,1) - .25) > epsilon) stop 8 + if ( abs(slmsk(1,1) - 0.) > epsilon) stop 8 ! Test point 5 ! Some ocean (but very small percentage). No lake. -! The ocean is removed and point becomes all land. +! The ocean % is below the min threshold, so it will be +! removed and the point becomes all land. + + print*,'Test point 5.' - binary_lake = 0 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = 1.e-6 - lake_frac(1,1) = 0.0 - lake_depth(1,1) = 0.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. + ocn_frac(1,1) = 1.e-6 ! Very small % of ocean. + lake_frac(1,1) = 0.0 ! No lake. + lake_depth(1,1) = 0.0 ! No lake. + land_frac(1,1) = -99. ! Should be 1. + slmsk(1,1) = -99. ! Should be 1. call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 5 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 10 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 10 + if ( abs(land_frac(1,1) - 1.) > epsilon) stop 10 + if ( abs(slmsk(1,1) - 1.) > epsilon) stop 10 ! Test point 6 -! Some ocean (almost all ocean). Some lake. -! The ocean is set to 1.0 and there is no land. +! Almost all ocean. Some lake. Since the ocean % +! is very close to 1, it will be rounded up to +! exactly 1. Since ocean dominates, the lake +! will be removed. - binary_lake = 0 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = 0.99999 - lake_frac(1,1) = 0.24 - lake_depth(1,1) = 50.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + print*,'Test point 6.' + + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N + ocn_frac(1,1) = 0.99999 ! Very high % of ocean. + lake_frac(1,1) = 0.24 ! Some lake. + lake_depth(1,1) = 50.0 ! Lake depth. + land_frac(1,1) = -99. ! Should be 0. + slmsk(1,1) = -99. ! Should be 0. call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 6 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 12 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 12 + if ( abs(land_frac(1,1) - 0.) > epsilon) stop 12 + if ( abs(slmsk(1,1) - 0.) > epsilon) stop 12 -! test point 7 +! Test point 7 +! No ocean. Some lake, but it is near Antarctica. +! Lakes near Antarctica are to be removed. Point +! becomes all land. -! No ocean. Some lake, but near Antarctica. -! Lake to be removed. + print*,'Test point 7.' - binary_lake = 0 - lat2d(1,1) = -70.0 - ocn_frac(1,1) = 0.0 - lake_frac(1,1) = .75 - lake_depth(1,1) = 100.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + binary_lake = 0 ! Keep fractional lake. + lat2d(1,1) = -70.0 ! Point at 70S. + ocn_frac(1,1) = 0.0 ! No ocean. + lake_frac(1,1) = .75 ! Some lake. + lake_depth(1,1) = 100.0 ! Lake depth. + land_frac(1,1) = -99. ! Should be 1. + slmsk(1,1) = -99. ! Should be 1. call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 7 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) - -! test point 8 + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 14 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 14 + if ( abs(land_frac(1,1) - 1.) > epsilon) stop 14 + if ( abs(slmsk(1,1) - 1.) > epsilon) stop 14 +! Test point 8 ! No ocean. Some lake. Assume binary yes/no lake. +! In this case, the lake fraction will become zero and +! the land fraction will become 1. - binary_lake = 1 - lat2d(1,1) = 30.0 - ocn_frac(1,1) = 0.0 - lake_frac(1,1) = .15 - lake_depth(1,1) = 100.0 - land_frac(1,1) = -99. - slmsk(1,1) = -99. + print*,'Test point 8.' + + binary_lake = 1 ! Keep fractional lake. + lat2d(1,1) = 30.0 ! Point at 30N. + ocn_frac(1,1) = 0.0 ! No ocean. + lake_frac(1,1) = .15 ! Less than 50% lake. + lake_depth(1,1) = 100.0 ! Lake depth. + land_frac(1,1) = -99. ! Should be 1. + slmsk(1,1) = -99. ! Should be 1. call merge(lon, lat, binary_lake, lat2d, ocn_frac, & lake_frac, lake_depth, land_frac, slmsk) - print*,'test point 8 ' - print*,'ocn_frac ',ocn_frac(1,1) - print*,'lake_frac ',lake_frac(1,1) - print*,'lake_depth ',lake_depth(1,1) - print*,'land_frac ',land_frac(1,1) - print*,'slmsk ', slmsk(1,1) - - + if ( abs(lake_frac(1,1) - 0.) > epsilon) stop 16 + if ( abs(lake_depth(1,1) - 0.) > epsilon) stop 16 + if ( abs(land_frac(1,1) - 1.) > epsilon) stop 16 + if ( abs(slmsk(1,1) - 1.) > epsilon) stop 16 print*, "OK" From f013a59a9bf54e7de636a47a6ffcff2cec37af73 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Tue, 1 Oct 2024 08:29:02 -0500 Subject: [PATCH 08/20] Move write of output file to its own routine. Fixes #944. --- sorc/ocean_merge.fd/CMakeLists.txt | 2 +- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 23 ++-------- sorc/ocean_merge.fd/read_write.F90 | 56 +++++++++++++++++++++++ 3 files changed, 60 insertions(+), 21 deletions(-) create mode 100644 sorc/ocean_merge.fd/read_write.F90 diff --git a/sorc/ocean_merge.fd/CMakeLists.txt b/sorc/ocean_merge.fd/CMakeLists.txt index e363478d1..b2f5f1ac4 100644 --- a/sorc/ocean_merge.fd/CMakeLists.txt +++ b/sorc/ocean_merge.fd/CMakeLists.txt @@ -1,4 +1,4 @@ -set(lib_src merge.F90 utils.F90 namelist.F90) +set(lib_src read_write.F90 merge.F90 utils.F90 namelist.F90) set(exe_src merge_lake_ocnmsk.F90) if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$") diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index 0d6339b06..ea3e8ef13 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -29,7 +29,7 @@ program merge_lake_ocnmsk integer :: binary_lake character(len=250) :: flnm - integer :: ncid,ndims,nvars,natts,lat,lon,v1id,v2id,v3id,v4id,start(2),count(2),latid,lonid,ncid4, dims(2),tile + integer :: ncid,ndims,nvars,natts,lat,lon,v1id,v2id,v3id,start(2),count(2),latid,lonid,tile integer :: vlat real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) @@ -69,25 +69,8 @@ program merge_lake_ocnmsk call merge(lon, lat, binary_lake, lat2d, ocn_frac, lake_frac, lake_depth, land_frac, slmsk) - write(flnm,'(4a,i1,a)') trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' - print *,'output=',trim(flnm) - call handle_err (nf90_create (path=trim(pth3)//trim(flnm), & - cmode=or(NF90_CLOBBER, NF90_64BIT_OFFSET), ncid=ncid4)) ! netcdf3 - - call handle_err (nf90_def_dim (ncid4,'lon', lon, dims(1))) - call handle_err (nf90_def_dim (ncid4,'lat', lat, dims(2))) - call handle_err (nf90_def_var (ncid4,'land_frac', nf90_float, dims(1:2), v1id)) - call handle_err (nf90_def_var (ncid4,'lake_frac', nf90_float, dims(1:2), v2id)) - call handle_err (nf90_def_var (ncid4,'lake_depth',nf90_float, dims(1:2), v3id)) - call handle_err (nf90_def_var (ncid4,'slmsk', nf90_float, dims(1:2), v4id)) - - call handle_err (nf90_enddef (ncid4)) - - call handle_err (nf90_put_var (ncid4, v1id,land_frac)) - call handle_err (nf90_put_var (ncid4, v2id,lake_frac)) - call handle_err (nf90_put_var (ncid4, v3id,lake_depth)) - call handle_err (nf90_put_var (ncid4, v4id,slmsk)) - call handle_err (nf90_close(ncid4)) + call write_data(atmres,ocnres,pth3,tile,lon,lat,land_frac, & + lake_frac,lake_depth,slmsk) end do ! tile diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 new file mode 100644 index 000000000..78dd75d5d --- /dev/null +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -0,0 +1,56 @@ +!> Write the merged data to a NetCDF file. Each tile is in +!! its own file. +!! +!! @param[in] atmres Atmospheric resolution. +!! @param[in] ocnres Ocean resolution. +!! @param[in] pth3 Diretory path to output file. +!! @param[in] tile Tile number. +!! @param[in] lon E/W dimension of tile. +!! @param[in] lat N/S dimension of tile. +!! @param[in] land_frac Land fraction. +!! @param[in] lake_frac Lake fraction. +!! @param[in] lake_depth Lake depth. +!! @param[in] slmsk Land/sea mask. +!! +!! @author Shan Sun +!! @author Rahul Mahajan +!! @author Sanath Kumar + subroutine write_data(atmres,ocnres,pth3,tile,lon,lat,land_frac, & + lake_frac,lake_depth,slmsk) + + use netcdf + + implicit none + + character(len=*), intent(in) :: atmres, ocnres, pth3 + + integer, intent(in) :: tile, lon, lat + + real, intent(in) :: land_frac(lon,lat), lake_frac(lon,lat) + real, intent(in) :: lake_depth(lon,lat), slmsk(lon,lat) + + character(len=250) :: flnm + + integer :: ncid4, dims(2), v1id, v2id, v3id, v4id + + write(flnm,'(4a,i1,a)') trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' + print *,'output data to file= ',trim(flnm) + call handle_err (nf90_create (path=trim(pth3)//trim(flnm), & + cmode=or(NF90_CLOBBER, NF90_64BIT_OFFSET), ncid=ncid4)) ! netcdf3 + + call handle_err (nf90_def_dim (ncid4,'lon', lon, dims(1))) + call handle_err (nf90_def_dim (ncid4,'lat', lat, dims(2))) + call handle_err (nf90_def_var (ncid4,'land_frac', nf90_float, dims(1:2), v1id)) + call handle_err (nf90_def_var (ncid4,'lake_frac', nf90_float, dims(1:2), v2id)) + call handle_err (nf90_def_var (ncid4,'lake_depth',nf90_float, dims(1:2), v3id)) + call handle_err (nf90_def_var (ncid4,'slmsk', nf90_float, dims(1:2), v4id)) + + call handle_err (nf90_enddef (ncid4)) + + call handle_err (nf90_put_var (ncid4, v1id,land_frac)) + call handle_err (nf90_put_var (ncid4, v2id,lake_frac)) + call handle_err (nf90_put_var (ncid4, v3id,lake_depth)) + call handle_err (nf90_put_var (ncid4, v4id,slmsk)) + call handle_err (nf90_close(ncid4)) + + end subroutine write_data From c64161b37f62eb10f95d6880fa121adb2dc0c6ac Mon Sep 17 00:00:00 2001 From: George Gayno Date: Tue, 1 Oct 2024 12:55:53 -0500 Subject: [PATCH 09/20] Move read of lake mask file to its own routine. Fixes #944. --- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 16 ++-------- sorc/ocean_merge.fd/read_write.F90 | 37 +++++++++++++++++++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index ea3e8ef13..fc58d13b3 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -29,8 +29,7 @@ program merge_lake_ocnmsk integer :: binary_lake character(len=250) :: flnm - integer :: ncid,ndims,nvars,natts,lat,lon,v1id,v2id,v3id,start(2),count(2),latid,lonid,tile - integer :: vlat + integer :: ncid,ndims,nvars,natts,lat,lon,v1id,start(2),count(2),latid,lonid,tile real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) @@ -55,17 +54,8 @@ program merge_lake_ocnmsk call handle_err (nf90_inq_varid(ncid, 'land_frac', v1id)) call handle_err (nf90_get_var (ncid, v1id, ocn_frac, start=start, count=count)) - write(flnm,'(4a,i1,a)') trim(pth2),'oro.',trim(atmres),'.tile',tile,'.nc' - print *,' flnm2=',trim(flnm) - call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) - call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) - write(6,*) 'flnm_lake=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts - call handle_err (nf90_inq_varid(ncid, 'lake_frac', v2id)) - call handle_err (nf90_inq_varid(ncid, 'lake_depth',v3id)) - call handle_err (nf90_inq_varid(ncid, 'geolat' ,vlat)) - call handle_err (nf90_get_var (ncid, v2id, lake_frac, start=start, count=count)) - call handle_err (nf90_get_var (ncid, v3id, lake_depth,start=start, count=count)) - call handle_err (nf90_get_var (ncid, vlat, lat2d, start=start, count=count)) + call read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & + lake_depth,lat2d) call merge(lon, lat, binary_lake, lat2d, ocn_frac, lake_frac, lake_depth, land_frac, slmsk) diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index 78dd75d5d..6869b1876 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -1,3 +1,40 @@ + subroutine read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & + lake_depth,lat2d) + + use netcdf + + implicit none + + character(len=*), intent(in) :: pth2, atmres + + integer, intent(in) :: tile, lon, lat + + real, intent(out) :: lake_frac(lon,lat) + real, intent(out) :: lake_depth(lon,lat) + real, intent(out) :: lat2d(lon,lat) + + character(len=250) :: flnm + + integer :: ncid, ndims, nvars, natts + integer :: v2id, v3id, vlat + integer :: start(2), count(2) + + write(flnm,'(4a,i1,a)') trim(pth2),'oro.',trim(atmres),'.tile',tile,'.nc' + print *,' flnm2=',trim(flnm) + call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) + call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) + write(6,*) 'flnm_lake=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts + call handle_err (nf90_inq_varid(ncid, 'lake_frac', v2id)) + call handle_err (nf90_inq_varid(ncid, 'lake_depth',v3id)) + call handle_err (nf90_inq_varid(ncid, 'geolat' ,vlat)) + start(1:2) = (/1,1/) + count(1:2) = (/lon,lat/) + call handle_err (nf90_get_var (ncid, v2id, lake_frac, start=start, count=count)) + call handle_err (nf90_get_var (ncid, v3id, lake_depth,start=start, count=count)) + call handle_err (nf90_get_var (ncid, vlat, lat2d, start=start, count=count)) + call handle_err (nf90_close (ncid)) + + end subroutine read_lake_mask !> Write the merged data to a NetCDF file. Each tile is in !! its own file. !! From b4188b94fffd374d03862e0d4a06bef0768814ee Mon Sep 17 00:00:00 2001 From: George Gayno Date: Wed, 9 Oct 2024 15:24:30 -0500 Subject: [PATCH 10/20] All unit test for routine read_lake_mask. Fixes #944. --- tests/ocean_merge/CMakeLists.txt | 7 ++++ tests/ocean_merge/data/oro.C48.tile1.nc | Bin 0 -> 15042 bytes tests/ocean_merge/ftst_read_lake_mask.F90 | 42 ++++++++++++++++++++++ 3 files changed, 49 insertions(+) create mode 100644 tests/ocean_merge/data/oro.C48.tile1.nc create mode 100644 tests/ocean_merge/ftst_read_lake_mask.F90 diff --git a/tests/ocean_merge/CMakeLists.txt b/tests/ocean_merge/CMakeLists.txt index 6f1bec5bc..513f9fb57 100644 --- a/tests/ocean_merge/CMakeLists.txt +++ b/tests/ocean_merge/CMakeLists.txt @@ -15,11 +15,18 @@ endif() 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}/data/oro.C48.tile1.nc ${CMAKE_CURRENT_BINARY_DIR}/oro.C48.tile1.nc) + add_executable(ftst_read_nml ftst_read_nml.F90) target_link_libraries(ftst_read_nml om_lib) add_executable(ftst_merge ftst_merge.F90) target_link_libraries(ftst_merge om_lib) +add_executable(ftst_read_lake_mask ftst_read_lake_mask.F90) +target_link_libraries(ftst_read_lake_mask om_lib) + add_test(NAME ocean_merge-ftst_read_nml COMMAND ftst_read_nml) add_test(NAME ocean_merge-ftst_merge COMMAND ftst_merge) +add_test(NAME ocean_merge-ftst_read_lake_mask COMMAND ftst_read_lake_mask) diff --git a/tests/ocean_merge/data/oro.C48.tile1.nc b/tests/ocean_merge/data/oro.C48.tile1.nc new file mode 100644 index 0000000000000000000000000000000000000000..64366c35552b25a8915ad75d815de6782a8dd892 GIT binary patch literal 15042 zcmeHN4Qv$06`u3i#&!=v{vaWsOb}6QYK}W|xY)){edjYKF*fC#s--B$`flypVDCD+ zdpNXJNl+3W@@`h)6|Xwr}yGD4kVlU!$aiR72>4!-?*W zwsj>lzw0YmD2V<_)%KYyW#Nd*E3cCEsuJeI((KuIeYXU!jJ3;*1!}P1X94&tWh`l? zmL(n6Hc~E|4e|g95@*;8M+tljb3dzqKWNJsj%(Rl7~XOl{E)3DtMl%Z%XyfGmo?Va zH-_qYU8pY7$j#Iyhc8L<0nM$AEU%5M;I8htK{F-tIw({XbY9*V2^Ds>%-R(VwG9z& z*;X*tP#<)S0X!()xAY%rmY#)VOr1nX-aTUl2Oh@|czOwDcQpCfgfKS%b)gKhS46+(@O* zy)$RGG#K;wgh5JtKA+SoX&2Og6)N}g8?Mjmdu|1ryA{SL6UOsbN#kk4Sd2ZSM!$N# z=-{tn1en4+@JVF#gGfRZvCh^+LMQ{lfYxeTy(Zq3Sl!)~OvG9{;|e9q{MZfbD>H_} zphjmYlyvECD%}@pGX{%;lGLS>N-bym#!}fi;TZ$4__IeN zI7(o>L}HmTa_gG7nAoR*Tfh*o$>Cq)%HC;XP&b90d$TS#EqAnOvt}Dw?|>fUlp-wt z#as4|w;Y+4@{en|lNZZ!M-{fFWI5p{Ca~O$;T=~9od>1P15)QH%d*pkslh51s-LM; z->+K(u$(Z{++*n-C(wY?Z?k&#aP9Vryv-KjT}xoO(P|@`71osv`2?%43fHB7vFvf; z%MzCdufdU}!^8Z)<2evVK0mt(mJc|Aq*^{PkN(CuTW}EwVN8@`8Oq z`mw3!RP?g3lquDO*=~|%uaag5+x90-ZBQ3R$4v``?9^Pt&8GE0HP-VUCu?lnJ_MOmV0mVrs(>2E}>-g!a>9^Q*wNeL{&|)Q3QUuy;Cs<<}8h)q_S(0^% z*QvVJz*=cH<&M+3ld_E=7mhMwW#aaUb~elb%}m2-Cd>^pZKTj&^M2b%^OQa?06XNc zwuSfE)*w$=VBpuU2J<$9`8gG$!9(*na=w< zWh2AM0T<_lOBo@GCLYi>={&6uxtYNAxY78TIu@b(6<{b+oP)Zn+kxlt?1_hdaVjhX z&V!1#S9A0G0c8>f9^n|Yw>Vs zkXP$>r9dXE)`i1^fIc46oFPLqc|zBqr!$nb4J+%w6M+rq?IFtv%25E6w$2CiK9^_B zR7NxV^>pyn*m`^Vf%(KFp64P0bE`UnJvlird;Yfn8L-j?NK?io=xI`1(n(O@vd`91 z=#&BrCx#}SAo6@AzH_1T5KI~|pGW7K?zYtlUJYmrFM-SQ8a`xO=`1{gW{1+??9zM~ zp3=BGZ1GNTgpTGCgVV^}jLvUa7vsagXcJuwRu6;Kg=#qZPUKqE8C%jGODqdvD>O6- zs$*sC6s$eX)dcj1HHW8cUEH>J3y)=Vv;WR4Aie`G{oLx~x2E$5lQ?0X%DPrx zUvnt9Jk-Q{;WTY;Nn&erc-yb4o|=BVJ8-7QROpB&e>%J1j@Y_fif}+?6FK4oi&s2H zt>>3d8SjrsyiejY9gs?TVlyobi?|szGx{?veMiDlSW$vx_+=XRz3OK^t%o_cayNeCFf zVXwDBZ?v!LSj%Pzdtj79C5nv9P)>Czo!roBm?)PuhNt9@lR&0?PdPM)qxZrP^*#9V zor|J99c{2910Nna($)8e>1=0Z-}p*rHN$Ap9QNbm_qQ+zudr*`cRu=M z7yB9%7qGq$x1?CBpsqX+%dnTAIG^n;f81n;pm+^?Z2#_U4A;T6Z09$>x}7~M7=HWw zpLepWp*V-#a5`l`p_u-+G$8Cx!4U{&fOK;dY@jG1k%zbhfS+a{QKHr*Q`X0`rbrSv z`Jp8saAk@l0i>RbnF7(8hmIU3hGKqEG=Mvz3@iPj;GrzA;+%WlTo4a|;S3Bqo8bA< zgq^E8zfsjNmV2siH;!I$1y028TL|M}+9vg z+lVvb1Yt4sZW=N|!m_uHqQyG*ZCVxU?nJs6Oz~iqkatKlj=FK8Kdw+t=q5Vx6U>QD z`~+~K6F=1{Cw>)Y7$=W=4Q_%a7mAwO-HL??M9 zH)G!>0fTCPbAfadg)8!dGg;y-rP8mL@K;4KJf9g85nkhbTK4a^y2IP@Jh68TB9@=P4Px) zFp6^Tp1of{2?DP%h=}_k{vE=2(7Jegd|kXN7Eg+JP(1{6&~Esy4c;=328Qxq_OS|V zm+>0T@JmaI#Zca@f;KAT!-#?EdsJ|P>W`@44AqyY;0x6kC?HWiE+SnNb%#jToA*5q zB26)Qt#Wu;t%CZ&IZ!MO)o|w2t8aNFc)CGOW24MO^sY=;>q12DP_bSKFqm}mRL!I6 zX5%uiWYKAr3?bl^4C8X|tW3V?m7up#3b;{b7dWzs5jn2}7>Rr72jx546NxyZ7g;`d zCv+Nbf8y!)e}nnt$t!uuv`UW4!z($)95;6V=th*_;;nYl1g&CTKGsAzNl`F z1RH{NwV8C^^5$?b90`VMd(M=%ceF(recq4vdgP$~`TS?C%nx7LQViHvirU8HhtD)A zLhCEVn_()KALZuVU@5)H5e=3}8uFD=)Vo~1gCL1~oT zG9&sS(4Pf*576&d^s}pHL_a8?JHUS~I%9X=JiWhBIQ(Sqb thresh) stop 2 + if (abs(lake_depth(5,2)-68.3817) > thresh) stop 4 + if (abs(lake_frac(4,3)-1.0) > thresh) stop 6 + if (abs(lake_frac(4,4)-0.0) > thresh) stop 8 + if (abs(lat2d(1,4)-0.399218) > thresh) stop 10 + if (abs(lat2d(6,1)-(-1.87402)) > thresh) stop 12 + + print*,"OK" + + print*,"SUCCESS" + + end program read_lake_info From b4d66517d8945fa8e3daf32d8635813eb9a01859 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 18 Oct 2024 16:15:07 -0500 Subject: [PATCH 11/20] Place the read of the model grid dimensions in its own routine. Fixes #944. --- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 10 ++----- sorc/ocean_merge.fd/read_write.F90 | 34 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index fc58d13b3..c6ea8f6f2 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -29,7 +29,7 @@ program merge_lake_ocnmsk integer :: binary_lake character(len=250) :: flnm - integer :: ncid,ndims,nvars,natts,lat,lon,v1id,start(2),count(2),latid,lonid,tile + integer :: ncid,lat,lon,v1id,start(2),count(2),tile real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) @@ -37,14 +37,10 @@ program merge_lake_ocnmsk print *, pth1 do tile=1,6 + call read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) + write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) - call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) - write(6,*) 'flnm_ocn=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts - call handle_err (nf90_inq_dimid (ncid, 'grid_xt', latid)) ! RM: lon is no longer in this file; try grid_xt - call handle_err (nf90_inq_dimid (ncid, 'grid_yt', lonid)) ! RM: lat is no longer in this file; try grid_tyt - call handle_err (nf90_inquire_dimension (ncid, latid, len=lat)) - call handle_err (nf90_inquire_dimension (ncid, lonid, len=lon)) if (tile==1) then write(6,*) 'lat=',lat,'lon=',lon allocate (lake_frac(lon,lat),lake_depth(lon,lat),land_frac(lon,lat),ocn_frac(lon,lat),slmsk(lon,lat),lat2d(lon,lat)) diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index 6869b1876..3032092d3 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -1,3 +1,37 @@ + subroutine read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) + + use netcdf + + implicit none + + character(len=*), intent(in) :: pth1 + character(len=*), intent(in) :: atmres + character(len=*), intent(in) :: ocnres + + integer, intent(in) :: tile + integer, intent(out) :: lon, lat + + character(len=250) :: flnm + + integer :: ncid, ndims, nvars, natts + integer :: latid, lonid + + write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' + + call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) + call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) + call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) + write(6,*) 'flnm_ocn=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts + call handle_err (nf90_inq_dimid (ncid, 'grid_xt', latid)) ! RM: lon is no longer in this file; try grid_xt + call handle_err (nf90_inq_dimid (ncid, 'grid_yt', lonid)) ! RM: lat is no longer in this file; try grid_yt + call handle_err (nf90_inquire_dimension (ncid, latid, len=lat)) + call handle_err (nf90_inquire_dimension (ncid, lonid, len=lon)) + call handle_err (nf90_close (ncid)) + + print*,'- in new routine ',lon, lat + + end subroutine read_grid_dims + subroutine read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & lake_depth,lat2d) From 7d4f128494aa88e9cfb8fa71e67894ab9ee4843a Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 14 Nov 2024 13:08:49 -0600 Subject: [PATCH 12/20] Place read of ocean fraction file in its own routine. Fixes #944. --- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 20 ++++++------ sorc/ocean_merge.fd/read_write.F90 | 37 +++++++++++++++++++++++ 2 files changed, 46 insertions(+), 11 deletions(-) diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index c6ea8f6f2..e4cf92b63 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -15,7 +15,6 @@ !! @author Rahul Mahajan !! @author Sanath Kumar program merge_lake_ocnmsk - use netcdf implicit none @@ -28,8 +27,7 @@ program merge_lake_ocnmsk ! all instances of int_lake was changed to binary_lake integer :: binary_lake - character(len=250) :: flnm - integer :: ncid,lat,lon,v1id,start(2),count(2),tile + integer :: lat,lon,tile real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) @@ -37,18 +35,16 @@ program merge_lake_ocnmsk print *, pth1 do tile=1,6 + call read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) - write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' - call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) if (tile==1) then write(6,*) 'lat=',lat,'lon=',lon - allocate (lake_frac(lon,lat),lake_depth(lon,lat),land_frac(lon,lat),ocn_frac(lon,lat),slmsk(lon,lat),lat2d(lon,lat)) - start(1:2) = (/1,1/) - count(1:2) = (/lon,lat/) - end if - call handle_err (nf90_inq_varid(ncid, 'land_frac', v1id)) - call handle_err (nf90_get_var (ncid, v1id, ocn_frac, start=start, count=count)) + allocate (lake_frac(lon,lat),lake_depth(lon,lat),land_frac(lon,lat), & + ocn_frac(lon,lat),slmsk(lon,lat),lat2d(lon,lat)) + endif + + call read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) call read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & lake_depth,lat2d) @@ -60,4 +56,6 @@ program merge_lake_ocnmsk end do ! tile + deallocate (lake_frac,lake_depth,land_frac,ocn_frac,slmsk,lat2d) + end program merge_lake_ocnmsk diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index 3032092d3..888b24864 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -32,6 +32,43 @@ subroutine read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) end subroutine read_grid_dims + subroutine read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) + + use netcdf + + implicit none + + character(len=*), intent(in) :: pth1 + character(len=*), intent(in) :: atmres + character(len=*), intent(in) :: ocnres + + integer, intent(in) :: lat + integer, intent(in) :: lon + integer, intent(in) :: tile + + real, intent(out) :: ocn_frac(lon,lat) + + character(len=300) :: flnm + + integer :: ncid, v1id, start(2), count(2) + + write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' + + print*,'in new routine ',trim(flnm) + + start(1:2) = (/1,1/) + count(1:2) = (/lon,lat/) + + call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) + +! The file record is named 'land_frac', but the data is ocean fraction. + + call handle_err (nf90_inq_varid(ncid, 'land_frac', v1id)) + call handle_err (nf90_get_var (ncid, v1id, ocn_frac, start=start, count=count)) + call handle_err (nf90_close (ncid)) + + end subroutine read_ocean_frac + subroutine read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & lake_depth,lat2d) From f96db7b858ed2798b84c101290137b389fb2853d Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 14 Nov 2024 14:45:48 -0600 Subject: [PATCH 13/20] Complete doxygen in read_write.F90. Add some diagnostic print. Fixes #944. --- sorc/ocean_merge.fd/read_write.F90 | 50 +++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 7 deletions(-) diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index 888b24864..63c254cdb 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -1,3 +1,14 @@ +!> Read the grid dimensions from a NetCDF file. +!! +!! @param[in] pth1 Directory path to file. +!! @param[in] atmres Atmospheric resolution. +!! @param[in] ocnres Ocean resolution. +!! @param[in] tile Tile number. +!! @param[out] lon E/W dimension of tile. +!! @param[out] lat N/S dimension of tile. +!! +!! @author Shan Sun +!! @author Rahul Mahajan subroutine read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) use netcdf @@ -18,20 +29,33 @@ subroutine read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' + print*,'- READ GRID DIMESIONS FROM: ',trim(flnm) + call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) - write(6,*) 'flnm_ocn=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts call handle_err (nf90_inq_dimid (ncid, 'grid_xt', latid)) ! RM: lon is no longer in this file; try grid_xt call handle_err (nf90_inq_dimid (ncid, 'grid_yt', lonid)) ! RM: lat is no longer in this file; try grid_yt call handle_err (nf90_inquire_dimension (ncid, latid, len=lat)) call handle_err (nf90_inquire_dimension (ncid, lonid, len=lon)) call handle_err (nf90_close (ncid)) - print*,'- in new routine ',lon, lat + print*,'- DIMENSIONS ARE: ',lon, lat end subroutine read_grid_dims +!> Read the ocean fraction from a NetCDF file. +!! +!! @param[in] pth1 Directory path to file. +!! @param[in] atmres Atmospheric resolution. +!! @param[in] ocnres Ocean resolution. +!! @param[in] tile Tile number. +!! @param[in] lon E/W dimension of tile. +!! @param[in] lat N/S dimension of tile. +!! @param[out] ocn_frac ocean fraction +!! +!! @author Shan Sun +!! @author Rahul Mahajan subroutine read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) use netcdf @@ -54,7 +78,7 @@ subroutine read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) write(flnm,'(5a,i1,a)') trim(pth1),trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' - print*,'in new routine ',trim(flnm) + print*,'-READ OCEAN FRACTION FROM: ',trim(flnm) start(1:2) = (/1,1/) count(1:2) = (/lon,lat/) @@ -69,6 +93,19 @@ subroutine read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) end subroutine read_ocean_frac +!> Read lake fraction, lake depth and latitude from a NetCDF file. +!! +!! @param[in] pth2 Directory path to file. +!! @param[in] atmres Atmospheric resolution. +!! @param[in] tile Tile number. +!! @param[in] lon E/W dimension of tile. +!! @param[in] lat N/S dimension of tile. +!! @param[out] lake_frac Lake fraction +!! @param[out] lake_depth Lake depth +!! @param[out] lat2d Latitude +!! +!! @author Shan Sun +!! @author Rahul Mahajan subroutine read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & lake_depth,lat2d) @@ -91,10 +128,9 @@ subroutine read_lake_mask(pth2,atmres,tile,lon,lat,lake_frac, & integer :: start(2), count(2) write(flnm,'(4a,i1,a)') trim(pth2),'oro.',trim(atmres),'.tile',tile,'.nc' - print *,' flnm2=',trim(flnm) + print *,'- READ LAKE DEPTH, FRACTION AND LATITUDE FROM: ',trim(flnm) call handle_err (nf90_open (flnm, NF90_NOWRITE, ncid)) call handle_err (nf90_inquire (ncid, ndimensions=ndims, nvariables=nvars, nattributes=natts)) - write(6,*) 'flnm_lake=',flnm,' ncid=',ncid, ' ndims=',ndims, 'nvars=',nvars,' natts=',natts call handle_err (nf90_inq_varid(ncid, 'lake_frac', v2id)) call handle_err (nf90_inq_varid(ncid, 'lake_depth',v3id)) call handle_err (nf90_inq_varid(ncid, 'geolat' ,vlat)) @@ -111,7 +147,7 @@ end subroutine read_lake_mask !! !! @param[in] atmres Atmospheric resolution. !! @param[in] ocnres Ocean resolution. -!! @param[in] pth3 Diretory path to output file. +!! @param[in] pth3 Directory path to output file. !! @param[in] tile Tile number. !! @param[in] lon E/W dimension of tile. !! @param[in] lat N/S dimension of tile. @@ -142,7 +178,7 @@ subroutine write_data(atmres,ocnres,pth3,tile,lon,lat,land_frac, & integer :: ncid4, dims(2), v1id, v2id, v3id, v4id write(flnm,'(4a,i1,a)') trim(atmres),'.',trim(ocnres),'.tile',tile,'.nc' - print *,'output data to file= ',trim(flnm) + print *,'- OUTPUT DATA TO FILE: ',trim(flnm) call handle_err (nf90_create (path=trim(pth3)//trim(flnm), & cmode=or(NF90_CLOBBER, NF90_64BIT_OFFSET), ncid=ncid4)) ! netcdf3 From e4a2f33f569edbe04440f69e4dc50f40d65b48fa Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 14 Nov 2024 14:47:20 -0600 Subject: [PATCH 14/20] Add unit test for 'read_ocean_frac'. Fixes #944. --- tests/ocean_merge/CMakeLists.txt | 7 ++++ tests/ocean_merge/data/C48.mx500.tile1.nc | Bin 0 -> 1272 bytes tests/ocean_merge/ftst_read_ocean_frac.F90 | 37 +++++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/ocean_merge/data/C48.mx500.tile1.nc create mode 100644 tests/ocean_merge/ftst_read_ocean_frac.F90 diff --git a/tests/ocean_merge/CMakeLists.txt b/tests/ocean_merge/CMakeLists.txt index 513f9fb57..6057e61a3 100644 --- a/tests/ocean_merge/CMakeLists.txt +++ b/tests/ocean_merge/CMakeLists.txt @@ -18,6 +18,9 @@ execute_process( COMMAND ${CMAKE_COMMAND} -E copy execute_process( COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/data/oro.C48.tile1.nc ${CMAKE_CURRENT_BINARY_DIR}/oro.C48.tile1.nc) +execute_process( COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_CURRENT_SOURCE_DIR}/data/C48.mx500.tile1.nc ${CMAKE_CURRENT_BINARY_DIR}/C48.mx500.tile1.nc) + add_executable(ftst_read_nml ftst_read_nml.F90) target_link_libraries(ftst_read_nml om_lib) @@ -27,6 +30,10 @@ target_link_libraries(ftst_merge om_lib) add_executable(ftst_read_lake_mask ftst_read_lake_mask.F90) target_link_libraries(ftst_read_lake_mask om_lib) +add_executable(ftst_read_ocean_frac ftst_read_ocean_frac.F90) +target_link_libraries(ftst_read_ocean_frac om_lib) + add_test(NAME ocean_merge-ftst_read_nml COMMAND ftst_read_nml) add_test(NAME ocean_merge-ftst_merge COMMAND ftst_merge) add_test(NAME ocean_merge-ftst_read_lake_mask COMMAND ftst_read_lake_mask) +add_test(NAME ocean_merge-ftst_read_ocean_frac COMMAND ftst_read_ocean_frac) diff --git a/tests/ocean_merge/data/C48.mx500.tile1.nc b/tests/ocean_merge/data/C48.mx500.tile1.nc new file mode 100644 index 0000000000000000000000000000000000000000..d3999075f4ef31be86cd7367d44199495e9fb120 GIT binary patch literal 1272 zcmZ>EabseD04^W}VzZ|gWv0YemViWA;rt3PpAE?80b;PajLhPa{Gv)A7tB8!l2NMQ zmtUq}Xrf?fY-MC_WniXYWME`srI44LU96y+q5w9zqD05gT*t^rp(M4qL@zHHOdA0i zTxbTES{WE)GoZ3W$H-F0*jPcoJijR0NIx$>F;PDyQ9nIBu`(}Tzc{fhRX@}%I6gGQ z(~ zB?VUc`gzIudc|paK#e*I&iN@wGU=Hm8Kp^j$@#e;MIfvRvWFXpnSmG*2aqs_#SbG$ z0Th7Z;RA%tqyeOn5}s4^qD|ZS@S0dQp?_8X)y^wZk@p)Vs>OH3O-)UnH{#r2c5#!gi4Q$y1!& zK*>3yPVAoWF|+Oa_O8t>VAb^_Jk|Jssd z2U5RzF2_-zdj4Zr4t2d%!3u9@@aIcTleD<31+?4Y%aP4VT09}c?z>LNCnUv$tjpC9bozQ#c>eIMu7 ziYy1czA2p|v)di?R=>1!{UhL@w|@fjt8JVP2A_;vv-#y542Ae4JDFJ>40Rr{+i?AG zFm!7F#dfmO!7%8-{6y9w2gBIQU(-tVI2b+Xdin7FIR|6rmQyL7D;s|JFMgdoAmGRmkOF9JX?PPll;IG&RBLBgaonvlH0`Nn@BKTpdi`krT1LtK*hp zs)UHxzyA*cU!eLp?T?&f*H52fLqPo-xIITs9@*9^`z&j`Cr`AZ@;~K U)k0tW`SzRj1!FgCjDqP00N$K}jsO4v literal 0 HcmV?d00001 diff --git a/tests/ocean_merge/ftst_read_ocean_frac.F90 b/tests/ocean_merge/ftst_read_ocean_frac.F90 new file mode 100644 index 000000000..ec35621ab --- /dev/null +++ b/tests/ocean_merge/ftst_read_ocean_frac.F90 @@ -0,0 +1,37 @@ +! Unit test for the read_ocean_frac routine. +! +! Reads a 6x5 version of the ocean mask file and +! checks values from the ocean fraction record. +! If differences exceed a threshold, then the test fails. +! + program read_ocean_info + + implicit none + + integer, parameter :: lon = 6 + integer, parameter :: lat = 5 + integer, parameter :: tile = 1 + + character(len=3) :: pth1="./" + character(len=3) :: atmres="C48" + character(len=5) :: ocnres="mx500" + + real, parameter :: thresh = 0.001 + real :: ocn_frac(lon,lat) + + print*,"Call routine read_ocean_frac." + + call read_ocean_frac(pth1,atmres,ocnres,tile,lon,lat,ocn_frac) + + print*,"Check records." + + if (abs(ocn_frac(1,1)-1.0) > thresh) stop 2 + if (abs(ocn_frac(6,5)-0.0) > thresh) stop 4 + if (abs(ocn_frac(4,5)-0.0917) > thresh) stop 6 + if (abs(ocn_frac(3,1)-0.162347) > thresh) stop 8 + + print*,"OK" + + print*,"SUCCESS" + + end program read_ocean_info From 8c79cbe3d9b959a3eb27960969460bce92b3442a Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 14 Nov 2024 15:19:08 -0600 Subject: [PATCH 15/20] Minor updates. Fixes #944. --- sorc/ocean_merge.fd/merge.F90 | 4 ++-- sorc/ocean_merge.fd/namelist.F90 | 4 +++- sorc/ocean_merge.fd/read_write.F90 | 18 +++++++++--------- sorc/ocean_merge.fd/utils.F90 | 1 + 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/sorc/ocean_merge.fd/merge.F90 b/sorc/ocean_merge.fd/merge.F90 index 138ea5144..f8eda3d1b 100644 --- a/sorc/ocean_merge.fd/merge.F90 +++ b/sorc/ocean_merge.fd/merge.F90 @@ -9,9 +9,9 @@ !! @param[in] lat2d Latitude of the model grid points. !! @param[in] ocn_frac Fraction of the grid point that is ocean. !! @param[inout] lake_frac Fraction of the grid point that is lake. -!! @param[inout] lake_depth Lake depth. +!! @param[inout] lake_depth Lake depth in meters. !! @param[out] land_frac Fraction of the grid point that is land. -!! @param[out] slmsk Land/sea mask. '1' if less than 50% land. Otherwise, '1'. +!! @param[out] slmsk Land/sea mask. '0' if less than 50% land. Otherwise, '1'. !! !! @author Shan Sun !! @author Rahul Mahajan diff --git a/sorc/ocean_merge.fd/namelist.F90 b/sorc/ocean_merge.fd/namelist.F90 index 3db2c1ad5..f6b019da8 100644 --- a/sorc/ocean_merge.fd/namelist.F90 +++ b/sorc/ocean_merge.fd/namelist.F90 @@ -5,11 +5,13 @@ !! @param[out] out_dir Directory where output file will be written. !! @param[out] atmres Atmosphere grid resolution. !! @param[out] ocnres Ocean grid resolution. -!! @param[out] binary_lake or fractional lake +!! @param[out] binary_lake or fractional lake. !! @author Rahul Mahajan !! @author Sanath Kumar subroutine read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_lake) + implicit none + integer :: unit=7, io_status character(len=120), intent(out) :: ocean_mask_dir diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index 63c254cdb..a2ff5336f 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -2,7 +2,7 @@ !! !! @param[in] pth1 Directory path to file. !! @param[in] atmres Atmospheric resolution. -!! @param[in] ocnres Ocean resolution. +!! @param[in] ocnres Ocean resolution in decimal percent. !! @param[in] tile Tile number. !! @param[out] lon E/W dimension of tile. !! @param[out] lat N/S dimension of tile. @@ -52,7 +52,7 @@ end subroutine read_grid_dims !! @param[in] tile Tile number. !! @param[in] lon E/W dimension of tile. !! @param[in] lat N/S dimension of tile. -!! @param[out] ocn_frac ocean fraction +!! @param[out] ocn_frac ocean fraction in decimal percent. !! !! @author Shan Sun !! @author Rahul Mahajan @@ -100,9 +100,9 @@ end subroutine read_ocean_frac !! @param[in] tile Tile number. !! @param[in] lon E/W dimension of tile. !! @param[in] lat N/S dimension of tile. -!! @param[out] lake_frac Lake fraction -!! @param[out] lake_depth Lake depth -!! @param[out] lat2d Latitude +!! @param[out] lake_frac Lake fraction in decimal percent. +!! @param[out] lake_depth Lake depth in meters. +!! @param[out] lat2d Latitude in degrees. !! !! @author Shan Sun !! @author Rahul Mahajan @@ -151,10 +151,10 @@ end subroutine read_lake_mask !! @param[in] tile Tile number. !! @param[in] lon E/W dimension of tile. !! @param[in] lat N/S dimension of tile. -!! @param[in] land_frac Land fraction. -!! @param[in] lake_frac Lake fraction. -!! @param[in] lake_depth Lake depth. -!! @param[in] slmsk Land/sea mask. +!! @param[in] land_frac Land fraction in decimal percent. +!! @param[in] lake_frac Lake fraction in decimal percent. +!! @param[in] lake_depth Lake depth in meters. +!! @param[in] slmsk Land/sea mask - 0-non-land; 1-land. !! !! @author Shan Sun !! @author Rahul Mahajan diff --git a/sorc/ocean_merge.fd/utils.F90 b/sorc/ocean_merge.fd/utils.F90 index 570f03cfa..af62ae3cc 100644 --- a/sorc/ocean_merge.fd/utils.F90 +++ b/sorc/ocean_merge.fd/utils.F90 @@ -4,6 +4,7 @@ !! @author Shan Sun subroutine handle_err (ret) use netcdf + implicit none integer, intent(in) :: ret if (ret /= NF90_NOERR) then From 4327472d9740286c7db785fb98c1305e38cc2549 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 15 Nov 2024 09:31:35 -0600 Subject: [PATCH 16/20] Minor updates to program comments and print statements. Fixes #944. --- sorc/ocean_merge.fd/merge.F90 | 2 +- sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 | 13 ++++++------- sorc/ocean_merge.fd/namelist.F90 | 6 ++++-- sorc/ocean_merge.fd/read_write.F90 | 8 ++++---- sorc/ocean_merge.fd/utils.F90 | 4 +++- 5 files changed, 18 insertions(+), 15 deletions(-) diff --git a/sorc/ocean_merge.fd/merge.F90 b/sorc/ocean_merge.fd/merge.F90 index f8eda3d1b..36c007436 100644 --- a/sorc/ocean_merge.fd/merge.F90 +++ b/sorc/ocean_merge.fd/merge.F90 @@ -64,6 +64,6 @@ subroutine merge(lon, lat, binary_lake, lat2d, ocn_frac, & end do end do - write(*,'(a,i8,a,i8,a)') 'total lake point ',lake_pt,' where ',nodp_pt,' has no depth' + write(*,'(a,i8,a,i8,a)') 'Total lake point ',lake_pt,' where ',nodp_pt,' has no depth' end subroutine merge diff --git a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 index e4cf92b63..ee2bccf6e 100644 --- a/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 +++ b/sorc/ocean_merge.fd/merge_lake_ocnmsk.F90 @@ -21,18 +21,15 @@ program merge_lake_ocnmsk character(len=120) :: pth1 character(len=120) :: pth2,pth3 character(len=10) :: atmres,ocnres - ! this variable is now renamed as binary_lake and is passed in from the name - ! list - ! logical, parameter :: int_lake=.true. - ! all instances of int_lake was changed to binary_lake - integer :: binary_lake + integer :: binary_lake integer :: lat,lon,tile + real, allocatable :: lake_frac(:,:),lake_depth(:,:),land_frac(:,:),ocn_frac(:,:),slmsk(:,:),lat2d(:,:) + print*,"- BEGIN OCEAN MERGE PROGRAM." + call read_nml(pth1, pth2, atmres, ocnres, pth3,binary_lake) - - print *, pth1 do tile=1,6 @@ -58,4 +55,6 @@ program merge_lake_ocnmsk deallocate (lake_frac,lake_depth,land_frac,ocn_frac,slmsk,lat2d) + print*,"- NORMAL TERMINATION." + end program merge_lake_ocnmsk diff --git a/sorc/ocean_merge.fd/namelist.F90 b/sorc/ocean_merge.fd/namelist.F90 index f6b019da8..f66896eae 100644 --- a/sorc/ocean_merge.fd/namelist.F90 +++ b/sorc/ocean_merge.fd/namelist.F90 @@ -5,7 +5,9 @@ !! @param[out] out_dir Directory where output file will be written. !! @param[out] atmres Atmosphere grid resolution. !! @param[out] ocnres Ocean grid resolution. -!! @param[out] binary_lake or fractional lake. +!! @param[out] binary_lake When '1', treat lake fraction as either 0 or 1. Otherwise, +!! it is a fraction. +!! !! @author Rahul Mahajan !! @author Sanath Kumar subroutine read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_lake) @@ -25,7 +27,7 @@ subroutine read_nml(ocean_mask_dir, lake_mask_dir, atmres,ocnres,out_dir,binary_ read(unit,mask_nml, iostat=io_status ) close(unit) if (io_status > 0) then - print *,'Error reading input.nml' + print *,'FATAL ERROR reading input.nml' call handle_err(-1) end if end subroutine read_nml diff --git a/sorc/ocean_merge.fd/read_write.F90 b/sorc/ocean_merge.fd/read_write.F90 index a2ff5336f..b445c525b 100644 --- a/sorc/ocean_merge.fd/read_write.F90 +++ b/sorc/ocean_merge.fd/read_write.F90 @@ -1,4 +1,4 @@ -!> Read the grid dimensions from a NetCDF file. +!> Read the grid dimensions from the MOM6 ocean mask NetCDF file. !! !! @param[in] pth1 Directory path to file. !! @param[in] atmres Atmospheric resolution. @@ -44,7 +44,7 @@ subroutine read_grid_dims(pth1, atmres, ocnres, tile, lon, lat) end subroutine read_grid_dims -!> Read the ocean fraction from a NetCDF file. +!> Read the ocean fraction from the MOM6 ocean NetCDF file. !! !! @param[in] pth1 Directory path to file. !! @param[in] atmres Atmospheric resolution. @@ -95,7 +95,7 @@ end subroutine read_ocean_frac !> Read lake fraction, lake depth and latitude from a NetCDF file. !! -!! @param[in] pth2 Directory path to file. +!! @param[in] pth2 Directory path to the file. !! @param[in] atmres Atmospheric resolution. !! @param[in] tile Tile number. !! @param[in] lon E/W dimension of tile. @@ -152,7 +152,7 @@ end subroutine read_lake_mask !! @param[in] lon E/W dimension of tile. !! @param[in] lat N/S dimension of tile. !! @param[in] land_frac Land fraction in decimal percent. -!! @param[in] lake_frac Lake fraction in decimal percent. +!! @param[in] lake_frac Lake fraction. !! @param[in] lake_depth Lake depth in meters. !! @param[in] slmsk Land/sea mask - 0-non-land; 1-land. !! diff --git a/sorc/ocean_merge.fd/utils.F90 b/sorc/ocean_merge.fd/utils.F90 index af62ae3cc..22e2fadbd 100644 --- a/sorc/ocean_merge.fd/utils.F90 +++ b/sorc/ocean_merge.fd/utils.F90 @@ -1,4 +1,5 @@ -!> Handle netCDF errors. +!> Check NetCDF return code. If an error is indicated, +!! stop program. !! !! @param[in] ret NetCDF return code. !! @author Shan Sun @@ -8,6 +9,7 @@ subroutine handle_err (ret) integer, intent(in) :: ret if (ret /= NF90_NOERR) then + write(6,*) '- FATAL ERROR.' write(6,*) nf90_strerror (ret) stop 999 end if From bda77cd276b49f7c259973ab6b37fc2d08080066 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Fri, 15 Nov 2024 09:48:23 -0600 Subject: [PATCH 17/20] Minor updates to unit tests. Fixes #944. --- tests/ocean_merge/ftst_merge.F90 | 4 +++- tests/ocean_merge/ftst_read_lake_mask.F90 | 2 +- tests/ocean_merge/ftst_read_nml.F90 | 9 ++++++--- tests/ocean_merge/ftst_read_ocean_frac.F90 | 2 +- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/ocean_merge/ftst_merge.F90 b/tests/ocean_merge/ftst_merge.F90 index f0d5b0ab2..6d9c40728 100644 --- a/tests/ocean_merge/ftst_merge.F90 +++ b/tests/ocean_merge/ftst_merge.F90 @@ -1,5 +1,7 @@ ! Unit test for the merge routine. - +! +! Test several combinations of lake and ocean attributes +! and check the 'merged' value for correctness. program ftst_merge implicit none diff --git a/tests/ocean_merge/ftst_read_lake_mask.F90 b/tests/ocean_merge/ftst_read_lake_mask.F90 index e345607cc..3754455cc 100644 --- a/tests/ocean_merge/ftst_read_lake_mask.F90 +++ b/tests/ocean_merge/ftst_read_lake_mask.F90 @@ -1,6 +1,6 @@ ! Unit test for the read_lake_mask routine. ! -! Reads a 6x4 version of the lake mask file and +! Reads a 6x4 version of the lake mask NetCDF file and ! checks values from the lake fraction, lake depth ! and latitude records. If differences exceed a ! threshold, then the test fails. diff --git a/tests/ocean_merge/ftst_read_nml.F90 b/tests/ocean_merge/ftst_read_nml.F90 index 3765c2b10..d10017e0c 100644 --- a/tests/ocean_merge/ftst_read_nml.F90 +++ b/tests/ocean_merge/ftst_read_nml.F90 @@ -1,5 +1,8 @@ ! Unit test for the read_nml routine. - +! +! Read a sample namelist and check the data in each +! variable against expected values. +! program read_namelist implicit none @@ -19,8 +22,8 @@ program read_namelist if (trim(lake_mask_dir) /= "/lake/mask/dir") stop 4 if (trim(atmres) /= "C96") stop 6 if (trim(ocnres) /= "mx025") stop 8 - if (trim(out_dir) /= "/out/dir") stop 8 - if (binary_lake /= 1) stop 10 + if (trim(out_dir) /= "/out/dir") stop 10 + if (binary_lake /= 1) stop 12 print*, "OK" diff --git a/tests/ocean_merge/ftst_read_ocean_frac.F90 b/tests/ocean_merge/ftst_read_ocean_frac.F90 index ec35621ab..3e83377ed 100644 --- a/tests/ocean_merge/ftst_read_ocean_frac.F90 +++ b/tests/ocean_merge/ftst_read_ocean_frac.F90 @@ -1,6 +1,6 @@ ! Unit test for the read_ocean_frac routine. ! -! Reads a 6x5 version of the ocean mask file and +! Reads a 6x5 version of the MOM6 ocean mask file and ! checks values from the ocean fraction record. ! If differences exceed a threshold, then the test fails. ! From aff1a41820592a999e850d295c99dd0c130108be Mon Sep 17 00:00:00 2001 From: George Gayno Date: Mon, 18 Nov 2024 12:58:47 -0600 Subject: [PATCH 18/20] Update ocean_merge unit test CMakeLists.txt file to recognize IntelLLVM. Fixes #944. --- cmake/mpiexec.hercules | 2 +- tests/ocean_merge/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/mpiexec.hercules b/cmake/mpiexec.hercules index 332b33e29..23bec1047 100755 --- a/cmake/mpiexec.hercules +++ b/cmake/mpiexec.hercules @@ -6,7 +6,7 @@ # $2+ - Executable and its arguments # -ACCOUNT= +ACCOUNT=fv3-cpu QOS=debug NP=$1 diff --git a/tests/ocean_merge/CMakeLists.txt b/tests/ocean_merge/CMakeLists.txt index 6057e61a3..2aaa785b9 100644 --- a/tests/ocean_merge/CMakeLists.txt +++ b/tests/ocean_merge/CMakeLists.txt @@ -3,7 +3,7 @@ # # George Gayno -if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel)$") +if(CMAKE_Fortran_COMPILER_ID MATCHES "^(Intel|IntelLLVM)$") 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") From afb59a4942a6716772b43b16fef76c6bff7c7277 Mon Sep 17 00:00:00 2001 From: George Gayno Date: Tue, 19 Nov 2024 20:42:57 +0000 Subject: [PATCH 19/20] Update the c96.uniform grid_gen regression test to invoke the ocean_merge step. Fixes #944. --- reg_tests/grid_gen/c96.uniform.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reg_tests/grid_gen/c96.uniform.sh b/reg_tests/grid_gen/c96.uniform.sh index 2be0ba3ca..f5e29aeee 100755 --- a/reg_tests/grid_gen/c96.uniform.sh +++ b/reg_tests/grid_gen/c96.uniform.sh @@ -17,6 +17,7 @@ export add_lake=true export lake_data_srce=MODISP_GLDBV3 export lake_cutoff=0.50 export binary_lake=1 +export ocn=500 NCCMP=${NCCMP:-$(which nccmp)} @@ -41,7 +42,7 @@ echo "Ending at: " `date` # Compare output to baseline set of data. #----------------------------------------------------------------------------- -cd $out_dir/C96 +cd $out_dir/C96.mx500 test_failed=0 for files in *tile*.nc ./sfc/*tile*.nc From 6364736448b237524e5d307a03268979b53c1b7e Mon Sep 17 00:00:00 2001 From: George Gayno Date: Thu, 21 Nov 2024 18:14:12 +0000 Subject: [PATCH 20/20] Slight adjustment to ftst_read_nml.F90 test based on reviewer comments. Fixes #944. --- tests/ocean_merge/data/input.nml | 2 +- tests/ocean_merge/ftst_read_nml.F90 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ocean_merge/data/input.nml b/tests/ocean_merge/data/input.nml index 9a2c16208..ab86929b0 100644 --- a/tests/ocean_merge/data/input.nml +++ b/tests/ocean_merge/data/input.nml @@ -1,6 +1,6 @@ &mask_nml ocean_mask_dir="/ocean/mask/dir" - ocnres="mx025" + ocnres="mx500" lake_mask_dir="/lake/mask/dir" atmres="C96" out_dir="/out/dir" diff --git a/tests/ocean_merge/ftst_read_nml.F90 b/tests/ocean_merge/ftst_read_nml.F90 index d10017e0c..9ccb3156d 100644 --- a/tests/ocean_merge/ftst_read_nml.F90 +++ b/tests/ocean_merge/ftst_read_nml.F90 @@ -21,7 +21,7 @@ program read_namelist if (trim(ocean_mask_dir) /= "/ocean/mask/dir") stop 2 if (trim(lake_mask_dir) /= "/lake/mask/dir") stop 4 if (trim(atmres) /= "C96") stop 6 - if (trim(ocnres) /= "mx025") stop 8 + if (trim(ocnres) /= "mx500") stop 8 if (trim(out_dir) /= "/out/dir") stop 10 if (binary_lake /= 1) stop 12