p_prep_obs.F90 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. ! File : p_prep_obs.F90
  2. !
  3. ! Created: unknown
  4. !
  5. ! Author: unknown
  6. !
  7. ! Purpose: Read data from different data sources and convert it to
  8. ! type(measurement).
  9. !
  10. ! Description: The code calls different subroutines for particular types of
  11. ! input data, depending on the source, observation type and
  12. ! format. The output is the array of type(measurement) that
  13. ! contains, in particular, pivot points and bilinear
  14. ! interpolation coefficients for each observation. This array
  15. ! is written to "observations.uf" in binary format.
  16. !
  17. ! Modifications: 30/01/2008 - Pavel Sakov gave a trim (formatted) -- sorry
  18. ! for that, could not stand -- and modified to allow in-situ
  19. ! argo data from ifremer.
  20. ! 02/09/2008 - Pavel Sakov added superobing for SST and SLA data
  21. ! 17/08/2010 PS - turned (3D) superobing on for Argo obs
  22. ! 09/11/2012 Geir Arne Waagbo: Added support for OSISAF ice drift obs
  23. program p_prep_obs
  24. use mod_measurement
  25. use mod_grid
  26. use m_read_CLS_header
  27. use m_read_CLS_data
  28. use m_read_CLS_SST_grid
  29. use m_read_MET_SST_grid
  30. use m_read_CLS_TSLA_grid
  31. use m_read_CLS_SST
  32. use m_read_CLS_SSH
  33. use m_read_CLS_SLA
  34. use m_read_CLS_TSLA
  35. use m_read_MET_SST
  36. use m_read_CERSAT_data
  37. use m_read_OSISAF_data
  38. use m_read_ifremer_argo
  39. use m_read_jpl_hice
  40. use m_read_FFI_glider
  41. use m_read_metno_icec
  42. use m_get_def_wet_point
  43. use m_write_wet_file
  44. use m_get_mod_grid
  45. use m_parse_blkdat
  46. use m_read_amsr_norsex
  47. use m_superobs
  48. use m_uobs
  49. implicit none
  50. integer, parameter :: STRLEN = 512
  51. type (measurement), allocatable :: data(:)
  52. type (measurement), allocatable :: obs(:)
  53. type (grid) :: gr
  54. integer :: nx, ny
  55. real, allocatable, dimension(:,:) :: depths, modlat, modlon
  56. integer, parameter :: maxobs = 5000000
  57. character(STRLEN) :: fname, fnamehdr, dataformat, producer
  58. character(len=3) :: form
  59. character(len=5) :: obstype
  60. character(len=1) :: offset
  61. integer :: nrobs
  62. integer :: grpoints, k
  63. real :: factor, var
  64. real :: rdummy, mindx, meandx
  65. logical :: data_eq_obs
  66. ! superobs
  67. logical :: dosuperob
  68. logical :: is3d
  69. integer :: nrsobs
  70. type(measurement), allocatable :: sobs(:)
  71. integer :: i
  72. integer :: nthisobs
  73. integer, allocatable, dimension(:) :: thisobs
  74. gr = default_grid
  75. data_eq_obs = .false.
  76. open(10, file = 'infile.data')
  77. read(10, '(a)') producer
  78. read(10, '(a)') obstype
  79. read(10, '(a)') fnamehdr
  80. read(10, '(a)') fname
  81. close(10)
  82. print *, 'Data producer: ', trim(producer)
  83. print *, 'Data to be processed for TOPAZ: ', trim(obstype)
  84. print *, 'Filenames to be processed are: "', trim(fnamehdr), '" "', trim(fname), '"'
  85. print *, 'Result of processing is stored in temporary file "observation.uf"'
  86. ! Get grid dimensions from blkdat.input
  87. !
  88. call parse_blkdat('idm ', 'integer', rdummy, nx)
  89. call parse_blkdat('jdm ', 'integer', rdummy, ny)
  90. allocate(depths(nx, ny))
  91. allocate(modlon(nx, ny))
  92. allocate(modlat(nx, ny))
  93. dosuperob = .false.
  94. is3d = .false.
  95. ! Fill the "data" array by calling subroutines specific for the producer
  96. ! and observation type
  97. !
  98. if (trim(producer) == 'Reynolds') then
  99. if (trim(obstype) == 'SST') then
  100. dosuperob = .true.
  101. call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
  102. grpoints = gr % nx * gr % ny
  103. allocate(data(grpoints))
  104. allocate(obs(maxobs))
  105. call read_CLS_data(fname, obstype, dataformat, gr, form, data, factor, var)
  106. print*, 'Reynolds- ', obstype, ' data has been scaled by a factor = ', factor
  107. else
  108. stop 'ERROR: Reynolds only produce SST'
  109. endif
  110. else if (trim(Producer) == 'MET') then
  111. if (trim(obstype) == 'SST') then
  112. dosuperob = .true.
  113. call read_MET_SST_grid(fnamehdr, gr)
  114. grpoints = gr % nx * gr % ny
  115. allocate(data(grpoints))
  116. allocate(obs(maxobs))
  117. call read_MET_SST(fname, gr, data)
  118. else
  119. stop 'ERROR: OSTIA (MET) only produces SST'
  120. endif
  121. else if (trim(Producer) == 'NSIDC-AMSR') then
  122. if (trim(obstype) == 'ICEC') then
  123. dosuperob = .true.
  124. call read_amsr_norsex(fname, gr, data, obstype)
  125. allocate (obs(maxobs))
  126. else
  127. print *, 'No ',obstype, ' data from:', Producer
  128. stop 'ERROR: p_prep_obs'
  129. endif
  130. else if (trim(Producer) == 'METNO') then
  131. if (trim(obstype) == 'ICEC') then
  132. dosuperob = .true.
  133. call read_metno_icec_repro(fname, data, gr)
  134. allocate (obs(size(data)))
  135. elseif (index(obstype,'idrf')>0) then
  136. print *, 'OSISAF Ice Drift: ', obstype
  137. offset = obstype(5:5)
  138. print *, 'Offset: ', offset ! The number of days before analysis day
  139. dosuperob = .false.
  140. call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
  141. grpoints = gr % nx ! NB - 2 vector components - irregular grid
  142. allocate(data(grpoints))
  143. allocate(obs(maxobs))
  144. call read_OSISAF_data(trim(fname), gr, data, grpoints, var, offset)
  145. print *, producer, obstype, 'data has been scaled by a factor = ', factor
  146. else
  147. print *, 'There can be no ', obstype,' data from', Producer
  148. stop
  149. endif
  150. elseif (trim(producer) == 'CLS') then
  151. if (trim(obstype) == 'SLA') then
  152. dosuperob = .true.
  153. ! call read_CLS_SST_grid() here because SST data grid has the same
  154. ! structure
  155. call read_CLS_SST_grid(fnamehdr, gr)
  156. grpoints = gr % nx * gr % ny
  157. allocate(data(grpoints))
  158. allocate(obs(maxobs))
  159. call read_CLS_SLA(fname, gr, data)
  160. elseif (trim(obstype) == 'SSH') then
  161. dosuperob = .true.
  162. call read_CLS_SST_grid(fnamehdr, gr)
  163. grpoints = gr % nx * gr % ny
  164. allocate(data(grpoints))
  165. allocate(obs(maxobs))
  166. call read_CLS_SSH(fname, gr, data)
  167. elseif (trim(obstype) == 'SST') then
  168. dosuperob = .true.
  169. call read_CLS_SST_grid(fnamehdr, gr)
  170. grpoints = gr % nx * gr % ny
  171. allocate(data(grpoints))
  172. allocate(obs(maxobs))
  173. call read_CLS_SST(fname, gr, data)
  174. elseif (trim(obstype) == 'TSLA') then
  175. dosuperob = .true.
  176. call read_CLS_TSLA_grid(fnamehdr, gr)
  177. print *, 'read_CLS_TSLA_grid finished, total # of obs = ', gr % nx
  178. grpoints = gr % nx
  179. allocate(data(grpoints))
  180. allocate(obs(maxobs))
  181. call read_CLS_TSLA(fname,gr,data)
  182. else
  183. print *, 'data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
  184. stop 'ERROR: p_prep_obs'
  185. endif
  186. else if (trim(producer) == 'NSIDC') then
  187. if (trim(obstype) == 'ICEC') then
  188. dosuperob = .true.
  189. call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
  190. grpoints = gr % nx * gr % ny
  191. allocate(data(grpoints))
  192. allocate(obs(maxobs))
  193. call read_CLS_data(fname, obstype, dataformat, gr, form, data, factor, var)
  194. print *, producer, obstype, 'data has been scaled by a factor = ', factor
  195. else
  196. print *, 'no data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
  197. stop 'ERROR: p_prep_obs'
  198. endif
  199. else if (trim(producer) == 'CERSAT') then
  200. if (trim(obstype) == 'idrft') then
  201. dosuperob = .false.
  202. call read_CLS_header(fnamehdr, gr, dataformat, form, factor, var)
  203. grpoints = gr % nx ! NB - 2 vector components - irregular grid
  204. allocate(data(grpoints))
  205. allocate(obs(maxobs))
  206. call read_CERSAT_data(trim(fname), gr, data, grpoints, var)
  207. print *, producer, obstype, 'data has been scaled by a factor = ', factor
  208. else
  209. print *, 'no data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
  210. stop 'ERROR: p_prep_obs'
  211. endif
  212. elseif (trim(producer) == 'IFREMER') then
  213. dosuperob = .true.
  214. is3d = .true.
  215. read(fnamehdr, *) var
  216. print *, 'variance =', var
  217. call read_ifremer_argo(fname, obstype, var, nx, ny, data)
  218. ! PS: This is a flag to denote that read_ifremer_argo() takes care of
  219. ! filling type(measurement) array "data" in a correct way, and it should
  220. ! not be re-processed by calling get_def_wet_point(). This may not match
  221. ! the ideology behind the workflow adopted in this module and may be
  222. ! changed in future.
  223. !
  224. data_eq_obs = .true.
  225. elseif (trim(producer) == 'JPL') then
  226. dosuperob = .true.
  227. is3d = .false.
  228. read(fnamehdr, *) var
  229. print *, 'variance = ', var
  230. call read_jpl_hice(fname, obstype, var, nx, ny, data)
  231. ! see the comment for producer = IFREMER
  232. data_eq_obs = .true.
  233. elseif (trim(producer) == 'FFI') then
  234. dosuperob = .true.
  235. is3d = .true.
  236. read(fnamehdr, *) var
  237. print *, 'variance =', var
  238. call read_FFI_glider(fname, obstype, var, nx, ny, data)
  239. data_eq_obs = .true.
  240. elseif (trim(producer) == 'MYO') then
  241. if (trim(obstype) == 'TSLA') then
  242. dosuperob = .true.
  243. call read_MYO_TSLA_grid(fnamehdr, gr)
  244. print *, 'read_CLS_TSLA_grid finished, total # of obs = ', gr % nx
  245. grpoints = gr % nx
  246. allocate(data(grpoints))
  247. allocate(obs(maxobs))
  248. call read_MYO_TSLA(fnamehdr,fname,gr,data)
  249. print *, 'read_MYO_TSLA finished, SIZE(data) = ', SIZE(data)
  250. else
  251. print *, 'data of type "', trim(obstype),'" from producer "', producer, '" is not handled'
  252. stop 'ERROR: p_prep_obs'
  253. endif
  254. else
  255. print *, 'unknown producer ', trim(producer), ' in "infile.data"'
  256. stop 'ERROR: p_prep_obs'
  257. endif
  258. ! Read position and depth from model grid
  259. !
  260. call get_mod_grid(modlon, modlat, depths, mindx, meandx, nx, ny)
  261. if (.not. data_eq_obs) then
  262. ! Compute bilinear coefficients
  263. ! Extract the defined and wet data points
  264. ! Write locations to ijfile to be used in TECPLOT
  265. !
  266. call get_def_wet_point(obs, data, gr, depths, modlat, modlon, nrobs, nx, ny)
  267. else
  268. call check_forland(data, depths, size(data), nx, ny)
  269. nrobs = size(data)
  270. allocate(obs(nrobs))
  271. obs = data
  272. end if
  273. deallocate(data)
  274. if (trim(obstype) == 'TSLA') then
  275. call set_re_TSLA(nrobs, obs, nx, ny, modlon, modlat)
  276. end if
  277. where (obs % d + 1.0 == obs % d)
  278. obs % status = .false.
  279. end where
  280. ! Superob dense 2D data
  281. !
  282. if (dosuperob) then
  283. allocate(sobs(nrobs))
  284. call superob(obstype, nrobs, obs, nx, ny, modlon, modlat, nrsobs, sobs, is3d)
  285. deallocate(obs)
  286. allocate(obs(nrsobs))
  287. obs = sobs(1 : nrsobs)
  288. nrobs = nrsobs
  289. deallocate(sobs)
  290. end if
  291. if (nrobs .ge. maxobs) then
  292. print *, 'max No. of data reached, increase it!'
  293. stop 'ERROR: p_prep_obs'
  294. elseif (nrobs .le. 1) then
  295. print *, 'less than one observation in the whole dataset'
  296. !PS 4/9/2011 stop 'ERROR: p_prep_obs: Not worth the money'
  297. end if
  298. ! Write data to the binary file "observations.uf"
  299. !
  300. call write_wet_file(obs, nrobs)
  301. call uobs_get(obs(1 : nrobs) % id, nrobs, .true.)
  302. allocate(thisobs(nrobs))
  303. do i = 1, nuobs
  304. nthisobs = 0
  305. do k = 1, nrobs
  306. if (trim(unique_obs(i)) == trim(obs(k) % id)) then
  307. nthisobs = nthisobs + 1
  308. thisobs(nthisobs) = k
  309. end if
  310. end do
  311. if (nthisobs > 0) then
  312. call obs2nc(nthisobs, obs(thisobs(1 : nthisobs)))
  313. end if
  314. end do
  315. deallocate(thisobs)
  316. print *, 'Last observation:'
  317. print '(a)',' obs var id lon lat depth ipiv jpiv nsup'//&
  318. ' 4-bilin-coeffs active orig (i,j) dp age orig_id'
  319. print '(2g10.2,a6,3f6.1,3i6,4f5.1,l5,2i7,f7.1,2i5)', obs(nrobs)
  320. deallocate(obs)
  321. deallocate(depths)
  322. deallocate(modlon)
  323. deallocate(modlat)
  324. print *, 'prep_obs: end of processing'
  325. end program p_prep_obs
  326. subroutine obs2nc(nobs, obs)
  327. use mod_measurement
  328. use nfw_mod
  329. implicit none
  330. integer, parameter :: STRLEN = 512
  331. integer, intent(in) :: nobs
  332. type(measurement), intent(in) :: obs(nobs)
  333. character(STRLEN) :: fname
  334. integer :: ncid, obsdimid(1), lon_id, lat_id, depth_id, d_id, var_id, age_id
  335. integer :: n_id, ipiv_id, jpiv_id
  336. integer :: n(nobs)
  337. ! Create netcdf file of observations
  338. !
  339. write(fname, '(a, a, a)') 'observations-', trim(obs(1) % id), '.nc'
  340. print *, 'dumping observations to "', trim(fname), '"'
  341. call nfw_create(fname, nf_clobber, ncid)
  342. call nfw_def_dim(fname, ncid, 'nobs', nobs, obsdimid(1))
  343. call nfw_def_var(fname, ncid, 'lon', nf_float, 1, obsdimid(1), lon_id)
  344. call nfw_def_var(fname, ncid, 'lat', nf_float, 1, obsdimid(1), lat_id)
  345. call nfw_def_var(fname, ncid, 'depth', nf_float, 1, obsdimid(1), depth_id)
  346. call nfw_def_var(fname, ncid, 'd', nf_float, 1, obsdimid(1), d_id)
  347. call nfw_def_var(fname, ncid, 'var', nf_float, 1, obsdimid(1), var_id)
  348. call nfw_def_var(fname, ncid, 'age', nf_int, 1, obsdimid(1), age_id)
  349. call nfw_def_var(fname, ncid, 'n', nf_int, 1, obsdimid(1), n_id)
  350. call nfw_def_var(fname, ncid, 'ipiv', nf_int, 1, obsdimid(1), ipiv_id)
  351. call nfw_def_var(fname, ncid, 'jpiv', nf_int, 1, obsdimid(1), jpiv_id)
  352. call nfw_enddef(fname, ncid)
  353. call nfw_put_var_double(fname, ncid, lon_id, obs(1:nobs) % lon)
  354. call nfw_put_var_double(fname, ncid, lat_id, obs(1:nobs) % lat)
  355. call nfw_put_var_double(fname, ncid, depth_id, obs(1:nobs) % depth)
  356. call nfw_put_var_double(fname, ncid, d_id, obs(1:nobs) % d)
  357. call nfw_put_var_double(fname, ncid, var_id, obs(1:nobs) % var)
  358. call nfw_put_var_int(fname, ncid, age_id, obs(1:nobs) % date)
  359. call nfw_put_var_int(fname, ncid, ipiv_id, obs(1:nobs) % ipiv)
  360. call nfw_put_var_int(fname, ncid, jpiv_id, obs(1:nobs) % jpiv)
  361. n = int(obs(1:nobs) % h)
  362. call nfw_put_var_int(fname, ncid, n_id, n)
  363. call nfw_close(fname, ncid)
  364. end subroutine obs2nc
  365. subroutine check_forland(data, depths, nrobs, ni, nj)
  366. use mod_measurement
  367. type (measurement), intent(inout), dimension(nrobs) :: data
  368. real, dimension(ni, nj), intent(in) :: depths
  369. integer, intent(in) :: nrobs
  370. integer, intent(in) :: ni, nj
  371. integer :: o, imin, jmin, imax, jmax, nmasked
  372. nmasked = 0
  373. do o = 1, nrobs
  374. imin = max(1, data(o) % ipiv - 1)
  375. jmin = max(1, data(o) % jpiv - 1)
  376. imax = min(ni, data(o) % ipiv + 2)
  377. jmax = min(nj, data(o) % jpiv + 2)
  378. if (any(depths(imin:imax,jmin:jmax) < 10.0 .or. depths(imin:imax,jmin:jmax) == depths(imin:imax,jmin:jmax) + 1.0)) then
  379. data(o) % status = .false.
  380. nmasked = nmasked + 1
  381. end if
  382. end do
  383. print *, " check_forland(): ", nmasked, "obs close to land masked"
  384. end subroutine check_forland