ooo_read.F90 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. MODULE ooo_read
  2. !!==================================================================
  3. !! *** MODULE ooo_read ***
  4. !! Read routines : I/O for offline obs_oper
  5. !!==================================================================
  6. USE mppini
  7. USE lib_mpp
  8. USE in_out_manager
  9. USE par_kind, ONLY: lc
  10. USE netcdf
  11. USE oce, ONLY: tsn, sshn
  12. USE dom_oce, ONLY: nlci, nlcj, nimpp, njmpp, tmask
  13. USE par_oce, ONLY: jpi, jpj, jpk
  14. USE obs_fbm, ONLY: fbimdi, fbrmdi, fbsp, fbdp
  15. USE ooo_data
  16. IMPLICIT NONE
  17. PRIVATE
  18. PUBLIC ooo_rea_dri
  19. !! $Id: ooo_read.F90 2355 2015-05-20 07:11:50Z ufla $
  20. CONTAINS
  21. SUBROUTINE ooo_rea_dri(kfile)
  22. !!------------------------------------------------------------------------
  23. !! *** ooo_rea_dri ***
  24. !!
  25. !! Purpose : To choose appropriate read method
  26. !! Method :
  27. !!
  28. !! Author : A. Ryan Oct 2013
  29. !!
  30. !!------------------------------------------------------------------------
  31. INTEGER, INTENT(IN) :: &
  32. & kfile !: File number
  33. CHARACTER(len=lc) :: &
  34. & cdfilename, & !: File name
  35. & cmatchname !: Match name
  36. INTEGER :: &
  37. & kindex !: File index to read
  38. !! Filename, index and match-up kind
  39. cdfilename = TRIM(ooo_files(kfile))
  40. cmatchname = TRIM(cl4_vars(kfile))
  41. kindex = nn_ooo_idx(kfile)
  42. !! Update model fields
  43. !! Class 4 variables: forecast, persistence,
  44. !! nrt_analysis, best_estimate
  45. !! Feedback variables: empty string
  46. IF ( (TRIM(cmatchname) == 'forecast') .OR. &
  47. & (TRIM(cmatchname) == 'persistence') .OR. &
  48. & (TRIM(cmatchname) == 'nrt_analysis') .OR. &
  49. & (TRIM(cmatchname) == 'best_estimate').OR. &
  50. & (TRIM(cmatchname) == '') ) THEN
  51. CALL ooo_read_file(TRIM(cdfilename), kindex)
  52. CALL ooo_read_juld(TRIM(cdfilename), kindex, cl4_modjuld)
  53. ELSE IF (TRIM(cmatchname) == 'climatology') THEN
  54. WRITE(numout,*) 'Interpolating climatologies'
  55. ELSE IF (TRIM(cmatchname) == 'altimeter') THEN
  56. CALL ooo_read_altbias(TRIM(cdfilename))
  57. CALL ooo_read_juld(TRIM(cdfilename), kindex, cl4_modjuld)
  58. END IF
  59. END SUBROUTINE ooo_rea_dri
  60. SUBROUTINE ooo_read_altbias(filename)
  61. !!------------------------------------------------------------------------
  62. !! *** ooo_read_altbias ***
  63. !!
  64. !! Purpose : To read altimeter bias and set tn,sn to missing values
  65. !! Method : Use subdomain indices to create start and count matrices
  66. !! for netcdf read.
  67. !!
  68. !! Author : A. Ryan Sept 2012
  69. !!------------------------------------------------------------------------
  70. CHARACTER(len=*), INTENT(IN) :: filename
  71. INTEGER :: ncid, &
  72. & varid,&
  73. & istat,&
  74. & ntimes,&
  75. & tdim, &
  76. & xdim, &
  77. & ydim, &
  78. & zdim
  79. INTEGER :: ii, ij, ik
  80. INTEGER, DIMENSION(3) :: start_s, &
  81. & count_s
  82. REAL(fbdp), DIMENSION(:,:), ALLOCATABLE :: temp_sshn
  83. REAL(fbdp) :: fill_val
  84. IF (TRIM(filename) == 'nofile') THEN
  85. tsn(:,:,:,:) = fbrmdi
  86. sshn(:,:) = fbrmdi
  87. ELSE
  88. ! Open Netcdf file to find dimension id
  89. istat = nf90_open(trim(filename),nf90_nowrite,ncid)
  90. istat = nf90_inq_dimid(ncid,'x',xdim)
  91. istat = nf90_inq_dimid(ncid,'y',ydim)
  92. istat = nf90_inq_dimid(ncid,'deptht',zdim)
  93. istat = nf90_inq_dimid(ncid,'time',tdim)
  94. istat = nf90_inquire_dimension(ncid, tdim, len=ntimes)
  95. ! Allocate temporary temperature array
  96. ALLOCATE(temp_sshn(nlci,nlcj))
  97. ! Create start and count arrays
  98. start_s = (/ nimpp, njmpp, 1 /)
  99. count_s = (/ nlci, nlcj, 1 /)
  100. ! Altimeter bias
  101. istat = nf90_inq_varid(ncid,'altbias',varid)
  102. istat = nf90_get_att(ncid, varid, '_FillValue', fill_val)
  103. istat = nf90_get_var(ncid, varid, temp_sshn, start_s, count_s)
  104. WHERE(temp_sshn(:,:) == fill_val) temp_sshn(:,:) = fbrmdi
  105. ! Initialise tsn, sshn to fbrmdi
  106. tsn(:,:,:,:) = fbrmdi
  107. sshn(:,:) = fbrmdi
  108. ! Fill sshn with altimeter bias
  109. sshn(1:nlci,1:nlcj) = temp_sshn(:,:) * tmask(1:nlci,1:nlcj,1)
  110. ! Remove halo from tmask, sshn to prevent double obs counting
  111. IF (jpi > nlci) THEN
  112. tmask(nlci+1:,:,:) = 0
  113. sshn(nlci+1:,:) = 0
  114. END IF
  115. IF (jpj > nlcj) THEN
  116. tmask(:,nlcj+1:,:) = 0
  117. sshn(:,nlcj+1:) = 0
  118. END IF
  119. ! Deallocate arrays
  120. DEALLOCATE(temp_sshn)
  121. ! Close netcdf file
  122. istat = nf90_close(ncid)
  123. END IF
  124. END SUBROUTINE ooo_read_altbias
  125. SUBROUTINE ooo_read_file(filename, ifcst)
  126. !!------------------------------------------------------------------------
  127. !! *** ooo_read_file ***
  128. !!
  129. !! Purpose : To fill tn and sn with dailymean field from netcdf files
  130. !! Method : Use subdomain indices to create start and count matrices
  131. !! for netcdf read.
  132. !!
  133. !! Author : A. Ryan Oct 2010
  134. !!------------------------------------------------------------------------
  135. INTEGER, INTENT(IN) :: ifcst
  136. CHARACTER(len=*), INTENT(IN) :: filename
  137. INTEGER :: ncid, &
  138. & varid,&
  139. & istat,&
  140. & ntimes,&
  141. & tdim, &
  142. & xdim, &
  143. & ydim, &
  144. & zdim
  145. INTEGER :: ii, ij, ik
  146. INTEGER, DIMENSION(4) :: start_n, &
  147. & count_n
  148. INTEGER, DIMENSION(3) :: start_s, &
  149. & count_s
  150. REAL(fbdp), DIMENSION(:,:,:),ALLOCATABLE :: temp_tn, &
  151. & temp_sn
  152. REAL(fbdp), DIMENSION(:,:), ALLOCATABLE :: temp_sshn
  153. REAL(fbdp) :: fill_val
  154. ! DEBUG
  155. INTEGER :: istage
  156. IF (TRIM(filename) == 'nofile') THEN
  157. tsn(:,:,:,:) = fbrmdi
  158. sshn(:,:) = fbrmdi
  159. ELSE
  160. WRITE(numout,*) "Opening :", TRIM(filename)
  161. ! Open Netcdf file to find dimension id
  162. istat = nf90_open(path=TRIM(filename), mode=nf90_nowrite, ncid=ncid)
  163. IF ( istat /= nf90_noerr ) THEN
  164. WRITE(numout,*) "WARNING: Could not open ", trim(filename)
  165. WRITE(numout,*) "ERROR: ", nf90_strerror(istat)
  166. ENDIF
  167. istat = nf90_inq_dimid(ncid,'x',xdim)
  168. istat = nf90_inq_dimid(ncid,'y',ydim)
  169. istat = nf90_inq_dimid(ncid,'deptht',zdim)
  170. istat = nf90_inq_dimid(ncid,'time_counter',tdim)
  171. istat = nf90_inquire_dimension(ncid, tdim, len=ntimes)
  172. IF (ifcst .LE. ntimes) THEN
  173. ! Allocate temporary temperature array
  174. ALLOCATE(temp_tn(nlci,nlcj,jpk))
  175. ALLOCATE(temp_sn(nlci,nlcj,jpk))
  176. ALLOCATE(temp_sshn(nlci,nlcj))
  177. ! Set temp_tn, temp_sn to 0.
  178. temp_tn(:,:,:) = fbrmdi
  179. temp_sn(:,:,:) = fbrmdi
  180. temp_sshn(:,:) = fbrmdi
  181. ! Create start and count arrays
  182. start_n = (/ nimpp, njmpp, 1, ifcst /)
  183. count_n = (/ nlci, nlcj, jpk, 1 /)
  184. start_s = (/ nimpp, njmpp, ifcst /)
  185. count_s = (/ nlci, nlcj, 1 /)
  186. ! Read information into temporary arrays
  187. ! retrieve varid and read in temperature
  188. istat = nf90_inq_varid(ncid,'votemper',varid)
  189. istat = nf90_get_att(ncid, varid, '_FillValue', fill_val)
  190. istat = nf90_get_var(ncid, varid, temp_tn, start_n, count_n)
  191. WHERE(temp_tn(:,:,:) == fill_val) temp_tn(:,:,:) = fbrmdi
  192. ! retrieve varid and read in salinity
  193. istat = nf90_inq_varid(ncid,'vosaline',varid)
  194. istat = nf90_get_att(ncid, varid, '_FillValue', fill_val)
  195. istat = nf90_get_var(ncid, varid, temp_sn, start_n, count_n)
  196. WHERE(temp_sn(:,:,:) == fill_val) temp_sn(:,:,:) = fbrmdi
  197. ! retrieve varid and read in SSH
  198. istat = nf90_inq_varid(ncid,'sossheig',varid)
  199. IF (istat /= nf90_noerr) THEN
  200. ! Altimeter bias
  201. istat = nf90_inq_varid(ncid,'altbias',varid)
  202. END IF
  203. istat = nf90_get_att(ncid, varid, '_FillValue', fill_val)
  204. istat = nf90_get_var(ncid, varid, temp_sshn, start_s, count_s)
  205. WHERE(temp_sshn(:,:) == fill_val) temp_sshn(:,:) = fbrmdi
  206. ! Initialise tsn, sshn to fbrmdi
  207. tsn(:,:,:,:) = fbrmdi
  208. sshn(:,:) = fbrmdi
  209. ! Mask out missing data index
  210. tsn(1:nlci,1:nlcj,1:jpk,1) = temp_tn(:,:,:) * tmask(1:nlci,1:nlcj,1:jpk)
  211. tsn(1:nlci,1:nlcj,1:jpk,2) = temp_sn(:,:,:) * tmask(1:nlci,1:nlcj,1:jpk)
  212. sshn(1:nlci,1:nlcj) = temp_sshn(:,:) * tmask(1:nlci,1:nlcj,1)
  213. ! Remove halo from tmask, tsn, sshn to prevent double obs counting
  214. IF (jpi > nlci) THEN
  215. tmask(nlci+1:,:,:) = 0
  216. tsn(nlci+1:,:,:,1) = 0
  217. tsn(nlci+1:,:,:,2) = 0
  218. sshn(nlci+1:,:) = 0
  219. END IF
  220. IF (jpj > nlcj) THEN
  221. tmask(:,nlcj+1:,:) = 0
  222. tsn(:,nlcj+1:,:,1) = 0
  223. tsn(:,nlcj+1:,:,2) = 0
  224. sshn(:,nlcj+1:) = 0
  225. END IF
  226. ! Deallocate arrays
  227. DEALLOCATE(temp_tn, temp_sn, temp_sshn)
  228. ELSE
  229. ! Mark all as missing data
  230. tsn(:,:,:,:) = fbrmdi
  231. sshn(:,:) = fbrmdi
  232. ENDIF
  233. ! Close netcdf file
  234. WRITE(numout,*) "Closing :", TRIM(filename)
  235. istat = nf90_close(ncid)
  236. END IF
  237. END SUBROUTINE ooo_read_file
  238. SUBROUTINE ooo_read_juld(filename, ifcst, julian)
  239. USE calendar
  240. !!--------------------------------------------------------------------
  241. !! *** ooo_read_juld ***
  242. !!
  243. !! Purpose : To read model julian day information from file
  244. !! Author : A. Ryan Nov 2010
  245. !!--------------------------------------------------------------------
  246. !! Routine arguments
  247. CHARACTER(len=*), INTENT(IN) :: filename
  248. INTEGER, INTENT(IN) :: ifcst
  249. REAL, INTENT(OUT) :: julian !: Julian day
  250. !! Local variables
  251. INTEGER :: year, & !: Date information
  252. & month, &
  253. & day, &
  254. & hour, &
  255. & minute,&
  256. & second
  257. INTEGER :: istat, & !: Netcdf variables
  258. & ncid, &
  259. & dimid, &
  260. & varid, &
  261. & ntime
  262. REAL,DIMENSION(:),ALLOCATABLE :: r_sec !: Remainder seconds
  263. CHARACTER(len=120) :: time_str !: time string
  264. time_str=''
  265. !! Read in time_counter and remainder seconds
  266. istat = nf90_open(trim(filename),nf90_nowrite,ncid)
  267. istat = nf90_inq_dimid(ncid,'time_counter',dimid)
  268. IF (istat /= nf90_noerr) THEN
  269. istat = nf90_inq_dimid(ncid,'time',dimid)
  270. ENDIF
  271. istat = nf90_inquire_dimension(ncid,dimid,len=ntime)
  272. istat = nf90_inq_varid(ncid,'time_counter',varid)
  273. IF (istat /= nf90_noerr) THEN
  274. istat = nf90_inq_dimid(ncid,'time',dimid)
  275. ENDIF
  276. istat = nf90_get_att(ncid,varid,'units',time_str)
  277. ALLOCATE(r_sec(ntime))
  278. istat = nf90_get_var(ncid,varid, r_sec)
  279. istat = nf90_close(ncid)
  280. !! Fill yyyy-mm-dd hh:mm:ss
  281. !! format(('seconds since ', I4.4,'-',I2.2,'-',I2.2,' ',I2.2,':',I2.2,':',I2.2))
  282. 100 format((14x, I4.4,1x,I2.2,1x,I2.2,1x,I2.2,1x,I2.2,1x,I2.2))
  283. READ( time_str, 100 ) year, month, day, hour, minute, second
  284. CALL ymds2ju(year, month, day, r_sec(ifcst), julian)
  285. !! To take a comment from the ymds2ju subroutine
  286. !- In the case of the Gregorian calendar we have chosen to use
  287. !- the Lilian day numbers. This is the day counter which starts
  288. !- on the 15th October 1582.
  289. !- This is the day at which Pope Gregory XIII introduced the
  290. !- Gregorian calendar.
  291. !- Compared to the true Julian calendar, which starts some
  292. !- 7980 years ago, the Lilian days are smaler and are dealt with
  293. !- easily on 32 bit machines. With the true Julian days you can only
  294. !- the fraction of the day in the real part to a precision of
  295. !- a 1/4 of a day with 32 bits.
  296. !! The obs operator routines prefer to calculate Julian days since
  297. !! 01/01/1950 00:00:00
  298. !! In order to convert to the 1950 version we must adjust by the number
  299. !! of days between 15th October 1582 and 1st Jan 1950
  300. julian = julian - 134123.
  301. DEALLOCATE(r_sec)
  302. END SUBROUTINE ooo_read_juld
  303. END MODULE ooo_read