m_read_ifremer_argo.F90 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. ! File: m_read_ifremer_argo.F90
  2. !
  3. ! Created: 25 Jan 2008
  4. !
  5. ! Author: Pavel Sakov
  6. ! NERSC
  7. !
  8. ! Purpose: Read Argo data from NetCDF files from IFREMER into TOPAZ
  9. ! system.
  10. !
  11. ! Description: Data file(s) are defined by the string in the 4th line of
  12. ! "infile.data". It should have the following format:
  13. ! <BEGIN>
  14. ! IFREMER
  15. ! SAL | TEM
  16. ! <obs. error variance>
  17. ! <File name(s) or a wildcard>
  18. ! <END>
  19. ! After that:
  20. ! 1. all profiles are read into two arrays,
  21. ! pres(1 : nlev, 1 : nprof) and v(1 : nlev, 1 : nprof), where
  22. ! nprof is the total number of profiles in all files, and
  23. ! nlev is the maximum number of horizontal levels for all
  24. ! profiles;
  25. ! 2. bad data (with qc flags other than '1' or '2' is discarded;
  26. ! 3. dry or outside locations are discarded
  27. ! 4. if there close profiles (in the same grid cell), the best
  28. ! one (with most data or the most recent) is retained
  29. !
  30. ! Modifications: 17/08/2010 PS: skip discarding close profiles
  31. !
  32. module m_read_ifremer_argo
  33. implicit none
  34. integer, parameter, private :: STRLEN = 512
  35. real, parameter, private :: SAL_MIN = 32.0
  36. real, parameter, private :: SAL_MAX = 37.5
  37. real, parameter, private :: DENS_DIFF_MIN = -0.02
  38. logical, parameter, private :: DISCARD_CLOSE = .false.
  39. public read_ifremer_argo
  40. private data_inquire
  41. private data_readfile
  42. private potential_density
  43. private grid_readxyz
  44. contains
  45. subroutine read_ifremer_argo(fnames, obstype, variance, nx, ny, data)
  46. use mod_measurement
  47. use m_oldtonew
  48. use m_confmap
  49. use m_bilincoeff
  50. use m_pivotp
  51. use nfw_mod
  52. character(*), intent(in) :: fnames
  53. character(*), intent(in) :: obstype
  54. real(8), intent(in) :: variance
  55. integer, intent(in) :: nx, ny
  56. type(measurement), allocatable, intent(out) :: data(:)
  57. character(STRLEN) :: fname
  58. integer :: nfile, nprof, nlev
  59. real(8), allocatable :: juld(:)
  60. character, allocatable :: juld_qc(:)
  61. real(8), allocatable :: lat(:), lon(:)
  62. character, allocatable :: pos_qc(:)
  63. real(8), allocatable :: pres(:,:)
  64. character, allocatable :: pres_qc(:,:)
  65. real(8), allocatable :: temp(:,:), salt(:, :)
  66. character, allocatable :: temp_qc(:,:), salt_qc(:, :)
  67. integer, allocatable :: ipiv(:), jpiv(:)
  68. real(8), dimension(nx, ny) :: modlat, modlon
  69. real(8), dimension(nx, ny) :: depths
  70. integer :: f, l, p, np
  71. integer, allocatable :: mask(:)
  72. integer, allocatable :: mask2(:, :)
  73. integer, allocatable :: fid(:);
  74. integer, allocatable :: profid(:)
  75. integer, allocatable :: done(:)
  76. real(8) :: zmax, Q, Qbest, rho, rho_prev, rho_inc
  77. integer :: best
  78. integer :: p1
  79. integer ngood, ndata
  80. real(8) :: latnew, lonnew
  81. print *, 'BEGIN read_ifremer_argo()'
  82. call data_inquire(fnames, nfile, nprof, nlev)
  83. print *, ' overall: nprof =', nprof, ', nlev =', nlev
  84. allocate(juld(nprof))
  85. allocate(juld_qc(nprof))
  86. allocate(lat(nprof))
  87. allocate(lon(nprof))
  88. allocate(pos_qc(nprof))
  89. allocate(fid(nprof))
  90. allocate(profid(nprof))
  91. allocate(pres(nlev, nprof))
  92. allocate(pres_qc(nlev, nprof))
  93. allocate(temp(nlev, nprof))
  94. allocate(salt(nlev, nprof))
  95. allocate(temp_qc(nlev, nprof))
  96. allocate(salt_qc(nlev, nprof))
  97. p = 1
  98. do f = 1, nfile
  99. call data_readfile(f, trim(obstype), np, juld(p : nprof),&
  100. juld_qc(p : nprof), lat(p : nprof),&
  101. lon(p : nprof), pos_qc(p : nprof), pres(1 : nlev, p : nprof),&
  102. pres_qc(1 : nlev, p : nprof), temp(1 : nlev, p : nprof),&
  103. temp_qc(1 : nlev, p : nprof), salt(1 : nlev, p : nprof),&
  104. salt_qc(1 : nlev, p : nprof))
  105. fid(p : p + np - 1) = f
  106. do l = 1, np
  107. profid(p + l - 1) = l
  108. end do
  109. p = p + np
  110. end do
  111. ! mask <- juld_qc, pos_qc, pres_qc, v_qc
  112. !
  113. allocate(mask(nprof))
  114. mask(:) = 1
  115. allocate(mask2(nlev, nprof))
  116. mask2(:, :) = 1
  117. where (juld_qc /= '1' .and. juld_qc /= '2') mask = 0
  118. do p = 1, nprof
  119. if (mask(p) == 0) then
  120. mask2(:, p) = 0
  121. end if
  122. end do
  123. print *, ' after examining JULD_QC:'
  124. print *, ' ', count(mask == 1), ' good profiles'
  125. print *, ' ', count(mask2 == 1), ' good obs'
  126. where (pos_qc /= '1' .and. pos_qc /= '2') mask = 0
  127. do p = 1, nprof
  128. if (mask(p) == 0) then
  129. mask2(:, p) = 0
  130. end if
  131. end do
  132. print *, ' after examining POS_QC:'
  133. print *, ' ', count(mask == 1), ' good profiles'
  134. print *, ' ', count(mask2 == 1), ' good obs'
  135. ! ipiv, jpiv
  136. !
  137. allocate(ipiv(nprof))
  138. allocate(jpiv(nprof))
  139. ipiv(:) = -999
  140. jpiv(:) = -999
  141. call confmap_init(nx, ny)
  142. do p = 1, nprof
  143. if (mask(p) == 0) then
  144. cycle
  145. end if
  146. call oldtonew(lat(p), lon(p), latnew, lonnew)
  147. call pivotp(lonnew, latnew, ipiv(p), jpiv(p))
  148. end do
  149. where (ipiv < 1 .or. jpiv < 1 .or. ipiv > nx - 1 .or. jpiv > ny - 1) mask = 0
  150. do p = 1, nprof
  151. if (mask(p) == 0) then
  152. mask2(:, p) = 0
  153. end if
  154. end do
  155. print *, ' after calculaling pivot points:'
  156. print *, ' ', count(mask == 1), ' good profiles'
  157. print *, ' ', count(mask2 == 1), ' good obs'
  158. !
  159. ! Now examine 3D quality flags; set the mask for a profile to 0 if there
  160. ! are no good samples in this profile
  161. !
  162. ! pres_qc
  163. !
  164. do p = 1, nprof
  165. do l = 1, nlev
  166. if (pres_qc(l, p) /= '1' .and. pres_qc(l, p) /= '2') then
  167. mask2(l, p) = 0
  168. end if
  169. end do
  170. if (count(mask2(:, p) == 1) == 0) then
  171. mask(p) = 0
  172. end if
  173. end do
  174. print *, ' after examining PRES_QC:'
  175. print *, ' ', count(mask == 1), ' good profiles'
  176. print *, ' ', count(mask2 == 1), ' good obs'
  177. ! <data>_qc
  178. !
  179. if (trim(obstype) == 'SAL') then
  180. do p = 1, nprof
  181. do l = 1, nlev
  182. if (salt_qc(l, p) /= '1' .and. salt_qc(l, p) /= '2') then
  183. mask2(l, p) = 0
  184. end if
  185. end do
  186. if (count(mask2(:, p) == 1) == 0) then
  187. mask(p) = 0
  188. end if
  189. end do
  190. else if (trim(obstype) == 'TEM') then
  191. do p = 1, nprof
  192. do l = 1, nlev
  193. if (temp_qc(l, p) /= '1' .and. temp_qc(l, p) /= '2') then
  194. mask2(l, p) = 0
  195. end if
  196. end do
  197. if (count(mask2(:, p) == 1) == 0) then
  198. mask(p) = 0
  199. end if
  200. end do
  201. end if
  202. print *, ' after examining <data>_QC:'
  203. print *, ' ', count(mask == 1), ' good profiles'
  204. print *, ' ', count(mask2 == 1), ' good obs'
  205. ! Check for the observation being wet
  206. !
  207. call grid_readxyz(nx, ny, modlat, modlon, depths)
  208. do p = 1, nprof
  209. if (mask(p) == 0) then
  210. cycle
  211. end if
  212. do l = 1, nlev
  213. if (mask2(l, p) == 0) then
  214. cycle
  215. end if
  216. if (pres(l, p) > depths(ipiv(p), jpiv(p)) .or.&
  217. pres(l, p) > depths(ipiv(p) + 1, jpiv(p)) .or.&
  218. pres(l, p) > depths(ipiv(p), jpiv(p) + 1) .or.&
  219. pres(l, p) > depths(ipiv(p) + 1, jpiv(p) + 1)) then
  220. mask2(l, p) = 0
  221. end if
  222. end do
  223. if (count(mask2(:, p) == 1) == 0) then
  224. mask(p) = 0
  225. end if
  226. end do
  227. print *, ' after examining for wet cells:'
  228. print *, ' ', count(mask == 1), ' good profiles'
  229. print *, ' ', count(mask2 == 1), ' good obs'
  230. ! For salinity, allow SAL_MIN < S < SAL_MAX only in a profile
  231. !
  232. do p = 1, nprof
  233. if (mask(p) == 0) then
  234. cycle
  235. end if
  236. do l = 1, nlev
  237. if (mask2(l, p) == 0) then
  238. cycle
  239. end if
  240. if ((trim(obstype) == 'SAL' .and.&
  241. (salt_qc(l, p) == '1' .or. salt_qc(l, p) == '2')) .and.&
  242. (salt(l, p) < SAL_MIN .or. salt(l, p) > SAL_MAX)) then
  243. mask(p) = 0 ! discard the profile
  244. mask2(:, p) = 0
  245. exit
  246. end if
  247. end do
  248. end do
  249. print *, ' after keeping only profiles with salinity within',&
  250. SAL_MIN, '<= S <=', SAL_MAX, ":"
  251. print *, ' ', count(mask == 1), ' good profiles'
  252. print *, ' ', count(mask2 == 1), ' good obs'
  253. print *, ' discarding convectionally unstable profiles:'
  254. do p = 1, nprof
  255. if (mask(p) == 0) then
  256. cycle
  257. end if
  258. rho_prev = -999.0
  259. do l = 1, nlev
  260. if (mask2(l, p) == 0 .or.&
  261. (temp_qc(l, p) /= '1' .and. temp_qc(l, p) /= '2') .or.&
  262. (salt_qc(l, p) /= '1' .and. salt_qc(l, p) /= '2')) then
  263. cycle
  264. end if
  265. if (rho_prev == -999.0) then
  266. rho_prev = potential_density(temp(l, p), salt(l, p))
  267. cycle
  268. else
  269. rho = potential_density(temp(l, p), salt(l, p))
  270. rho_inc = rho - rho_prev
  271. if (rho_inc < DENS_DIFF_MIN) then
  272. open(10, file = 'infiles.txt')
  273. do f = 1, fid(p)
  274. read(10, fmt = '(a)') fname
  275. end do
  276. close(10)
  277. print *, ' ', trim(fname), ':'
  278. print *, ' profile #', profid(p), '( #', p, ')'
  279. print *, ' level #', l
  280. print *, ' rho increment =', rho_inc
  281. mask(p) = 0 ! discard the profile
  282. mask2(:, p) = 0
  283. exit
  284. end if
  285. rho_prev = rho
  286. end if
  287. end do
  288. end do
  289. print *, ' after discarding unstable profiles:'
  290. print *, ' ', count(mask == 1), ' good profiles'
  291. print *, ' ', count(mask2 == 1), ' good obs'
  292. ! Finally, discard redundant observations
  293. ! This is a O(n^2) search, which can become a bit long when the number of
  294. ! examined profiles becomes really large (say, 10^4)
  295. !
  296. if (DISCARD_CLOSE) then
  297. allocate(done(nprof))
  298. done = 0
  299. do p = 1, nprof
  300. if (mask(p) == 0 .or. done(p) == 1) then
  301. cycle
  302. end if
  303. np = 1
  304. profid(np) = p
  305. do p1 = p + 1, nprof
  306. if (ipiv(p1) == ipiv(p) .and. jpiv(p1) == jpiv(p)) then
  307. np = np + 1
  308. profid(np) = p1
  309. done(p1) = 1
  310. end if
  311. end do
  312. if (np > 1) then
  313. ! for each of close profiles find the depth range, number of points
  314. ! and the age
  315. Qbest = 0.0
  316. do p1 = 1, np
  317. zmax = 0.0
  318. ndata = 0
  319. do l = 1, nlev
  320. if (mask2(l, p1) == 1) then
  321. ndata = ndata + 1
  322. if (pres(l, profid(p1)) > zmax) then
  323. zmax = pres(l, profid(p1))
  324. end if
  325. end if
  326. end do
  327. Q = min(zmax, 400.0) / 400.0 + min(ndata, 10) / 10
  328. if (Q > Qbest) then
  329. best = p1
  330. end if
  331. end do
  332. do p1 = 1, np
  333. if (p1 == best) then
  334. cycle
  335. end if
  336. mask(profid(p1)) = 0
  337. mask2(:, profid(p1)) = 0
  338. end do
  339. end if
  340. end do
  341. deallocate(done)
  342. print *, ' after discarding close profiles:'
  343. print *, ' ', count(mask == 1), ' good profiles'
  344. print *, ' ', count(mask2 == 1), ' good obs'
  345. end if ! DISCARD_CLOSE
  346. ngood = count(mask2 == 1)
  347. allocate(data(ngood))
  348. ndata = 0
  349. do p = 1, nprof
  350. if (mask(p) == 0) then
  351. cycle
  352. end if
  353. do l = 1, nlev
  354. if (mask2(l, p) == 0) then
  355. cycle
  356. end if
  357. ndata = ndata + 1
  358. if (ndata > ngood) then
  359. print *, 'ERROR: read_ifremer_argo(): programming error'
  360. print *, ' p =', p, ', l =', l
  361. print *, ' # data =', ndata, ', ngood =', ngood
  362. stop
  363. end if
  364. ! PS: I guess we should not bother about the cost of the
  365. ! comparisons below.
  366. !
  367. if (trim(obstype) == 'SAL') then
  368. data(ndata) % d = salt(l, p)
  369. else if (trim(obstype) == 'TEM') then
  370. data(ndata) % d = temp(l, p)
  371. else
  372. data(ndata) % d = -999.0
  373. end if
  374. data(ndata) % var = variance
  375. data(ndata) % id = obstype
  376. data(ndata) % lon = lon(p)
  377. data(ndata) % lat = lat(p)
  378. data(ndata) % depth = max(0.0, pres(l, p))
  379. data(ndata) % ipiv = ipiv(p)
  380. data(ndata) % jpiv = jpiv(p)
  381. data(ndata) % ns = 0 ! for a point (not gridded) measurement
  382. data(ndata) % date = 0 ! assimilate synchronously
  383. call bilincoeff(modlon, modlat, nx, ny, lon(p), lat(p), ipiv(p),&
  384. jpiv(p), data(ndata) % a1, data(ndata) % a2, data(ndata) % a3,&
  385. data(ndata) % a4)
  386. data(ndata) % status = .true. ! (active)
  387. data(ndata) % i_orig_grid = p
  388. data(ndata) % j_orig_grid = l
  389. end do
  390. end do
  391. if (ndata /= ngood) then
  392. print *, 'ERROR: read_ifremer_argo(): programming error'
  393. print *, ' ndata =', ndata, ', ngood =', ngood
  394. stop
  395. end if
  396. deallocate(juld)
  397. deallocate(juld_qc)
  398. deallocate(lat)
  399. deallocate(lon)
  400. deallocate(pos_qc)
  401. deallocate(profid)
  402. deallocate(pres)
  403. deallocate(pres_qc)
  404. deallocate(temp)
  405. deallocate(salt)
  406. deallocate(temp_qc)
  407. deallocate(salt_qc)
  408. deallocate(mask)
  409. deallocate(mask2)
  410. deallocate(ipiv)
  411. deallocate(jpiv)
  412. print *, 'END read_ifremer_argo()'
  413. end subroutine read_ifremer_argo
  414. subroutine data_inquire(fnames, nfile, nprof, nlev)
  415. use nfw_mod
  416. character(*), intent(in) :: fnames
  417. integer, intent(inout) :: nfile, nprof, nlev
  418. character(STRLEN) :: command ! (there may be a limit of 80 on some systems)
  419. character(STRLEN) :: fname
  420. integer :: ios
  421. integer :: ncid
  422. integer :: id
  423. integer :: nprof_this, nlev_this
  424. nfile = 0
  425. nprof = 0
  426. nlev = 0
  427. command = 'ls '//trim(fnames)//' > infiles.txt'
  428. call system(command);
  429. nfile = 0
  430. open(10, file = 'infiles.txt')
  431. do while (.true.)
  432. read(10, fmt = '(a)', iostat = ios) fname
  433. if (ios /= 0) then
  434. exit
  435. end if
  436. nfile = nfile + 1
  437. print *, ' file #', nfile, ' = "', trim(fname), '"'
  438. call nfw_open(fname, nf_nowrite, ncid)
  439. ! nprof
  440. !
  441. call nfw_inq_dimid(fname, ncid, 'N_PROF', id)
  442. call nfw_inq_dimlen(fname, ncid, id, nprof_this)
  443. print *, ' nprof = ', nprof_this
  444. ! nlev
  445. !
  446. call nfw_inq_dimid(fname, ncid, 'N_LEVELS', id)
  447. call nfw_inq_dimlen(fname, ncid, id, nlev_this)
  448. print *, ' nlev = ', nlev_this
  449. nprof = nprof + nprof_this
  450. if (nlev_this > nlev) then
  451. nlev = nlev_this
  452. end if
  453. call nfw_close(fname, ncid)
  454. end do
  455. close(10)
  456. end subroutine data_inquire
  457. subroutine data_readfile(fid, obstype, nprof, juld_all, juld_qc_all,&
  458. lat_all, lon_all, pos_qc_all, pres_all, pres_qc_all, temp_all, temp_qc_all, salt_all, salt_qc_all)
  459. use nfw_mod
  460. integer, intent(in) :: fid
  461. character(*), intent(in) :: obstype
  462. integer, intent(inout) :: nprof
  463. real(8), intent(inout), dimension(:) :: juld_all
  464. character, intent(inout), dimension(:) :: juld_qc_all
  465. real(8), intent(inout), dimension(:) :: lat_all, lon_all
  466. character, intent(inout), dimension(:) :: pos_qc_all
  467. real(8), intent(inout), dimension(:,:) :: pres_all
  468. character, intent(inout), dimension(:,:) :: pres_qc_all
  469. real(8), intent(inout), dimension(:,:) :: temp_all
  470. character, intent(inout), dimension(:,:) :: temp_qc_all
  471. real(8), intent(inout), dimension(:,:) :: salt_all
  472. character, intent(inout), dimension(:,:) :: salt_qc_all
  473. character(STRLEN) :: fname
  474. integer :: f
  475. integer :: ncid
  476. integer :: id
  477. integer :: nlev
  478. open(10, file = 'infiles.txt')
  479. do f = 1, fid
  480. read(10, fmt = '(a)') fname
  481. end do
  482. close(10)
  483. print *, ' reading "', trim(fname), '"'
  484. call nfw_open(fname, nf_nowrite, ncid)
  485. ! nprof
  486. !
  487. call nfw_inq_dimid(fname, ncid, 'N_PROF', id)
  488. call nfw_inq_dimlen(fname, ncid, id, nprof)
  489. ! nlev
  490. !
  491. call nfw_inq_dimid(fname, ncid, 'N_LEVELS', id)
  492. call nfw_inq_dimlen(fname, ncid, id, nlev)
  493. ! juld
  494. !
  495. call nfw_inq_varid(fname, ncid, 'JULD', id)
  496. call nfw_get_var_double(fname, ncid, id, juld_all(1 : nprof))
  497. ! juld_qc
  498. !
  499. call nfw_inq_varid(fname, ncid, 'JULD_QC', id)
  500. call nfw_get_var_text(fname, ncid, id, juld_qc_all(1 : nprof))
  501. ! lat
  502. !
  503. call nfw_inq_varid(fname, ncid, 'LATITUDE', id)
  504. call nfw_get_var_double(fname, ncid, id, lat_all(1 : nprof))
  505. ! lon
  506. !
  507. call nfw_inq_varid(fname, ncid, 'LONGITUDE', id)
  508. call nfw_get_var_double(fname, ncid, id, lon_all(1 : nprof))
  509. ! pos_qc
  510. !
  511. call nfw_inq_varid(fname, ncid, 'POSITION_QC', id)
  512. call nfw_get_var_text(fname, ncid, id, pos_qc_all(1 : nprof))
  513. ! pres
  514. !
  515. call nfw_inq_varid(fname, ncid, 'PRES', id)
  516. call nfw_get_var_double(fname, ncid, id, pres_all(1 : nlev, 1 : nprof))
  517. ! pres_qc
  518. !
  519. call nfw_inq_varid(fname, ncid, 'PRES_QC', id)
  520. call nfw_get_var_text(fname, ncid, id, pres_qc_all(1 : nlev, 1 : nprof))
  521. ! temp
  522. !
  523. call nfw_inq_varid(fname, ncid, 'TEMP', id)
  524. call nfw_get_var_double(fname, ncid, id, temp_all(1 : nlev, 1 : nprof))
  525. ! temp_qc
  526. !
  527. call nfw_inq_varid(fname, ncid, 'TEMP_QC', id)
  528. call nfw_get_var_text(fname, ncid, id, temp_qc_all(1 : nlev, 1 : nprof))
  529. if (nfw_var_exists(ncid, 'PSAL')) then
  530. ! psal
  531. !
  532. call nfw_inq_varid(fname, ncid, 'PSAL', id)
  533. call nfw_get_var_double(fname, ncid, id, salt_all(1 : nlev, 1 : nprof))
  534. ! psal_qc
  535. !
  536. call nfw_inq_varid(fname, ncid, 'PSAL_QC', id)
  537. call nfw_get_var_text(fname, ncid, id, salt_qc_all(1 : nlev, 1 : nprof))
  538. else
  539. salt_qc_all = 'E';
  540. end if
  541. call nfw_close(fname, ncid)
  542. end subroutine data_readfile
  543. subroutine grid_readxyz(nx, ny, lat, lon, depth)
  544. integer, intent(in) :: nx, ny
  545. real(8), dimension(nx, ny), intent(inout) :: lat, lon, depth
  546. logical :: exists
  547. character(len = 128) :: fname
  548. fname = 'newpos.uf'
  549. inquire(file = fname, exist = exists)
  550. if (.not. exists) then
  551. print *, 'grid_readxyz(): ERROR: "', trim(fname), '" does not exist'
  552. stop
  553. end if
  554. open(10, file = fname, form = 'unformatted', status = 'old')
  555. print *, ' grid_readxyz(): reading "', trim(fname), '"...'
  556. read(10) lat, lon
  557. close(10)
  558. write(fname, '(a, i3.3, a, i3.3, a)') 'depths', nx, 'x', ny, '.uf'
  559. inquire(file = fname, exist = exists)
  560. if (.not. exists) then
  561. print*, 'grid_readxyz(): ERROR: "', trim(fname), '" does not exist'
  562. stop
  563. end if
  564. open (unit = 10, file = fname, status = 'old', form = 'unformatted')
  565. print *, ' grid_readxyz(): reading "', trim(fname), '"...'
  566. read(10) depth
  567. close(10)
  568. end subroutine grid_readxyz
  569. real(8) function potential_density(T, S)
  570. real(8), intent(in) :: T, S
  571. if (T < -2.0d0 .or. T > 40.0d0 .or. S < 0.0d0 .or. S > 42.0d0) then
  572. potential_density = -999.0d0
  573. return
  574. end if
  575. potential_density =&
  576. -9.20601d-2&
  577. + T * (5.10768d-2 + S * (- 3.01036d-3)&
  578. + T * (- 7.40849d-3 + T * 3.32367d-5 + S * 3.21931d-5))&
  579. + 8.05999d-1 * S
  580. end function potential_density
  581. end module m_read_ifremer_argo