obs_readmdt.F90 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. MODULE obs_readmdt
  2. !!======================================================================
  3. !! *** MODULE obs_readmdt ***
  4. !! Observation diagnostics: Read the MDT for SLA data (skeleton for now)
  5. !!======================================================================
  6. !! History : ! 2007-03 (K. Mogensen) Initial skeleton version
  7. !! ! 2007-04 (E. Remy) migration and improvement from OPAVAR
  8. !!----------------------------------------------------------------------
  9. !!----------------------------------------------------------------------
  10. !! obs_rea_mdt : Driver for reading MDT
  11. !! obs_offset_mdt : Remove the offset between the model MDT and the used one
  12. !!----------------------------------------------------------------------
  13. USE wrk_nemo ! Memory Allocation
  14. USE par_kind ! Precision variables
  15. USE par_oce ! Domain parameters
  16. USE in_out_manager ! I/O manager
  17. USE obs_surf_def ! Surface observation definitions
  18. USE obs_inter_sup ! Interpolation support routines
  19. USE obs_inter_h2d ! 2D interpolation
  20. USE obs_utils ! Various observation tools
  21. USE iom_nf90 ! IOM NetCDF
  22. USE netcdf ! NetCDF library
  23. USE lib_mpp ! MPP library
  24. USE dom_oce, ONLY : & ! Domain variables
  25. & tmask, tmask_i, e1t, e2t, gphit, glamt
  26. USE obs_const, ONLY : obfillflt ! Fillvalue
  27. USE oce , ONLY : sshn ! Model variables
  28. IMPLICIT NONE
  29. PRIVATE
  30. PUBLIC obs_rea_mdt ! called by ?
  31. PUBLIC obs_offset_mdt ! called by ?
  32. INTEGER , PUBLIC :: nmsshc = 1 ! MDT correction scheme
  33. REAL(wp), PUBLIC :: mdtcorr = 1.61_wp ! User specified MDT correction
  34. REAL(wp), PUBLIC :: mdtcutoff = 65.0_wp ! MDT cutoff for computed correction
  35. !!----------------------------------------------------------------------
  36. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  37. !! $Id: obs_readmdt.F90 3294 2012-01-28 16:44:18Z rblod $
  38. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  39. !!----------------------------------------------------------------------
  40. CONTAINS
  41. SUBROUTINE obs_rea_mdt( kslano, sladata, k2dint )
  42. !!---------------------------------------------------------------------
  43. !!
  44. !! *** ROUTINE obs_rea_mdt ***
  45. !!
  46. !! ** Purpose : Read from file the MDT data (skeleton)
  47. !!
  48. !! ** Method :
  49. !!
  50. !! ** Action :
  51. !!----------------------------------------------------------------------
  52. USE iom
  53. !
  54. INTEGER , INTENT(IN) :: kslano ! Number of SLA Products
  55. TYPE(obs_surf), DIMENSION(kslano), INTENT(inout) :: sladata ! SLA data
  56. INTEGER , INTENT(in) :: k2dint ! ?
  57. !
  58. CHARACTER(LEN=12), PARAMETER :: cpname = 'obs_rea_mdt'
  59. CHARACTER(LEN=20), PARAMETER :: mdtname = 'slaReferenceLevel.nc'
  60. INTEGER :: jslano ! Data set loop variable
  61. INTEGER :: jobs ! Obs loop variable
  62. INTEGER :: jpimdt, jpjmdt ! Number of grid point in lat/lon for the MDT
  63. INTEGER :: iico, ijco ! Grid point indicies
  64. INTEGER :: i_nx_id, i_ny_id, i_file_id, i_var_id, i_stat
  65. INTEGER :: nummdt
  66. !
  67. REAL(wp), DIMENSION(1) :: zext, zobsmask
  68. REAL(wp), DIMENSION(2,2,1) :: zweig
  69. !
  70. REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: zmask, zmdtl, zglam, zgphi
  71. INTEGER , DIMENSION(:,:,:), ALLOCATABLE :: igrdi, igrdj
  72. !
  73. REAL(wp), POINTER, DIMENSION(:,:) :: z_mdt, mdtmask
  74. REAL(wp) :: zlam, zphi, zfill, zinfill ! local scalar
  75. !!----------------------------------------------------------------------
  76. CALL wrk_alloc(jpi,jpj,z_mdt,mdtmask)
  77. IF(lwp)WRITE(numout,*)
  78. IF(lwp)WRITE(numout,*) ' obs_rea_mdt : Read MDT for referencing altimeter anomalies'
  79. IF(lwp)WRITE(numout,*) ' ------------- '
  80. CALL iom_open( mdtname, nummdt ) ! Open the file
  81. ! ! Get the MDT data
  82. CALL iom_get ( nummdt, jpdom_data, 'sossheig', z_mdt(:,:), 1 )
  83. CALL iom_close(nummdt) ! Close the file
  84. ! Read in the fill value
  85. zinfill = 0.0
  86. i_stat = nf90_open( mdtname, nf90_nowrite, nummdt )
  87. i_stat = nf90_inq_varid( nummdt, 'sossheig', i_var_id )
  88. i_stat = nf90_get_att( nummdt, i_var_id, "_FillValue",zinfill)
  89. zfill = zinfill
  90. i_stat = nf90_close( nummdt )
  91. ! setup mask based on tmask and MDT mask
  92. ! set mask to 0 where the MDT is set to fillvalue
  93. WHERE(z_mdt(:,:) /= zfill) ; mdtmask(:,:) = tmask(:,:,1)
  94. ELSE WHERE ; mdtmask(:,:) = 0
  95. END WHERE
  96. ! Remove the offset between the MDT used with the sla and the model MDT
  97. IF( nmsshc == 1 .OR. nmsshc == 2 ) CALL obs_offset_mdt( z_mdt, zfill )
  98. ! Intepolate the MDT already on the model grid at the observation point
  99. DO jslano = 1, kslano
  100. ALLOCATE( &
  101. & igrdi(2,2,sladata(jslano)%nsurf), &
  102. & igrdj(2,2,sladata(jslano)%nsurf), &
  103. & zglam(2,2,sladata(jslano)%nsurf), &
  104. & zgphi(2,2,sladata(jslano)%nsurf), &
  105. & zmask(2,2,sladata(jslano)%nsurf), &
  106. & zmdtl(2,2,sladata(jslano)%nsurf) &
  107. & )
  108. DO jobs = 1, sladata(jslano)%nsurf
  109. igrdi(1,1,jobs) = sladata(jslano)%mi(jobs)-1
  110. igrdj(1,1,jobs) = sladata(jslano)%mj(jobs)-1
  111. igrdi(1,2,jobs) = sladata(jslano)%mi(jobs)-1
  112. igrdj(1,2,jobs) = sladata(jslano)%mj(jobs)
  113. igrdi(2,1,jobs) = sladata(jslano)%mi(jobs)
  114. igrdj(2,1,jobs) = sladata(jslano)%mj(jobs)-1
  115. igrdi(2,2,jobs) = sladata(jslano)%mi(jobs)
  116. igrdj(2,2,jobs) = sladata(jslano)%mj(jobs)
  117. END DO
  118. CALL obs_int_comm_2d( 2, 2, sladata(jslano)%nsurf, igrdi, igrdj, glamt , zglam )
  119. CALL obs_int_comm_2d( 2, 2, sladata(jslano)%nsurf, igrdi, igrdj, gphit , zgphi )
  120. CALL obs_int_comm_2d( 2, 2, sladata(jslano)%nsurf, igrdi, igrdj, mdtmask, zmask )
  121. CALL obs_int_comm_2d( 2, 2, sladata(jslano)%nsurf, igrdi, igrdj, z_mdt , zmdtl )
  122. DO jobs = 1, sladata(jslano)%nsurf
  123. zlam = sladata(jslano)%rlam(jobs)
  124. zphi = sladata(jslano)%rphi(jobs)
  125. CALL obs_int_h2d_init( 1, 1, k2dint, zlam, zphi, &
  126. & zglam(:,:,jobs), zgphi(:,:,jobs), &
  127. & zmask(:,:,jobs), zweig, zobsmask )
  128. CALL obs_int_h2d( 1, 1, zweig, zmdtl(:,:,jobs), zext )
  129. sladata(jslano)%rext(jobs,2) = zext(1)
  130. ! mark any masked data with a QC flag
  131. IF( zobsmask(1) == 0 ) sladata(jslano)%nqc(jobs) = 11
  132. END DO
  133. DEALLOCATE( &
  134. & igrdi, &
  135. & igrdj, &
  136. & zglam, &
  137. & zgphi, &
  138. & zmask, &
  139. & zmdtl &
  140. & )
  141. END DO
  142. CALL wrk_dealloc(jpi,jpj,z_mdt,mdtmask)
  143. !
  144. END SUBROUTINE obs_rea_mdt
  145. SUBROUTINE obs_offset_mdt( mdt, zfill )
  146. !!---------------------------------------------------------------------
  147. !!
  148. !! *** ROUTINE obs_offset_mdt ***
  149. !!
  150. !! ** Purpose : Compute a correction term for the MDT on the model grid
  151. !! !!!!! IF it is on the model grid
  152. !!
  153. !! ** Method : Compute the mean difference between the model and the
  154. !! used MDT and remove the offset.
  155. !!
  156. !! ** Action :
  157. !!----------------------------------------------------------------------
  158. REAL(wp), DIMENSION(jpi,jpj), INTENT(inout) :: mdt ! MDT used on the model grid
  159. REAL(wp) , INTENT(in ) :: zfill
  160. !
  161. INTEGER :: ji, jj
  162. REAL(wp) :: zdxdy, zarea, zeta1, zeta2, zcorr_mdt, zcorr_bcketa, zcorr ! local scalar
  163. REAL(wp), POINTER, DIMENSION(:,:) :: zpromsk
  164. CHARACTER(LEN=14), PARAMETER :: cpname = 'obs_offset_mdt'
  165. !!----------------------------------------------------------------------
  166. CALL wrk_alloc( jpi,jpj, zpromsk )
  167. ! Initialize the local mask, for domain projection
  168. ! Also exclude mdt points which are set to missing data
  169. DO ji = 1, jpi
  170. DO jj = 1, jpj
  171. zpromsk(ji,jj) = tmask_i(ji,jj)
  172. IF ( ( gphit(ji,jj) .GT. mdtcutoff ) &
  173. &.OR.( gphit(ji,jj) .LT. -mdtcutoff ) &
  174. &.OR.( mdt(ji,jj) .EQ. zfill ) ) &
  175. & zpromsk(ji,jj) = 0.0
  176. END DO
  177. END DO
  178. ! Compute MSSH mean over [0,360] x [-mdtcutoff,mdtcutoff]
  179. zarea = 0.0
  180. zeta1 = 0.0
  181. zeta2 = 0.0
  182. DO jj = 1, jpj
  183. DO ji = 1, jpi
  184. zdxdy = e1t(ji,jj) * e2t(ji,jj) * zpromsk(ji,jj)
  185. zarea = zarea + zdxdy
  186. zeta1 = zeta1 + mdt(ji,jj) * zdxdy
  187. zeta2 = zeta2 + sshn (ji,jj) * zdxdy
  188. END DO
  189. END DO
  190. IF( lk_mpp) CALL mpp_sum( zeta1 )
  191. IF( lk_mpp) CALL mpp_sum( zeta2 )
  192. IF( lk_mpp) CALL mpp_sum( zarea )
  193. zcorr_mdt = zeta1 / zarea
  194. zcorr_bcketa = zeta2 / zarea
  195. ! Define correction term
  196. zcorr = zcorr_mdt - zcorr_bcketa
  197. ! Correct spatial mean of the MSSH
  198. IF( nmsshc == 1 ) mdt(:,:) = mdt(:,:) - zcorr
  199. ! User defined value : 1.6 m for the Rio MDT compared to ORCA2 MDT
  200. IF( nmsshc == 2 ) mdt(:,:) = mdt(:,:) - mdtcorr
  201. IF(lwp) THEN
  202. WRITE(numout,*)
  203. WRITE(numout,*) ' obs_readmdt : mdtcutoff = ', mdtcutoff
  204. WRITE(numout,*) ' ----------- zcorr_mdt = ', zcorr_mdt
  205. WRITE(numout,*) ' zcorr_bcketa = ', zcorr_bcketa
  206. WRITE(numout,*) ' zcorr = ', zcorr
  207. WRITE(numout,*) ' nmsshc = ', nmsshc
  208. ENDIF
  209. IF ( nmsshc == 0 ) WRITE(numout,*) ' MSSH correction is not applied'
  210. IF ( nmsshc == 1 ) WRITE(numout,*) ' MSSH correction is applied'
  211. IF ( nmsshc == 2 ) WRITE(numout,*) ' User defined MSSH correction'
  212. CALL wrk_dealloc( jpi,jpj, zpromsk )
  213. !
  214. END SUBROUTINE obs_offset_mdt
  215. !!======================================================================
  216. END MODULE obs_readmdt