iom_nf90.F90 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. MODULE iom_nf90
  2. !!=====================================================================
  3. !! *** MODULE iom_nf90 ***
  4. !! Input/Output manager : Library to read input files with NF90 (only fliocom module)
  5. !!====================================================================
  6. !! History : 9.0 ! 05 12 (J. Belier) Original code
  7. !! 9.0 ! 06 02 (S. Masson) Adaptation to NEMO
  8. !! " ! 07 07 (D. Storkey) Changes to iom_nf90_gettime
  9. !!--------------------------------------------------------------------
  10. !!gm caution add !DIR nec: improved performance to be checked as well as no result changes
  11. !!--------------------------------------------------------------------
  12. !! iom_open : open a file read only
  13. !! iom_close : close a file or all files opened by iom
  14. !! iom_get : read a field (interfaced to several routines)
  15. !! iom_gettime : read the time axis kvid in the file
  16. !! iom_varid : get the id of a variable in a file
  17. !! iom_rstput : write a field in a restart file (interfaced to several routines)
  18. !!--------------------------------------------------------------------
  19. USE dom_oce ! ocean space and time domain
  20. USE lbclnk ! lateal boundary condition / mpp exchanges
  21. USE iom_def ! iom variables definitions
  22. USE netcdf ! NetCDF library
  23. USE in_out_manager ! I/O manager
  24. USE lib_mpp ! MPP library
  25. IMPLICIT NONE
  26. PRIVATE
  27. PUBLIC iom_nf90_open, iom_nf90_close, iom_nf90_varid, iom_nf90_get, iom_nf90_gettime, iom_nf90_rstput
  28. PUBLIC iom_nf90_getatt
  29. INTERFACE iom_nf90_get
  30. MODULE PROCEDURE iom_nf90_g0d, iom_nf90_g123d
  31. END INTERFACE
  32. INTERFACE iom_nf90_getatt
  33. MODULE PROCEDURE iom_nf90_intatt
  34. END INTERFACE
  35. INTERFACE iom_nf90_rstput
  36. MODULE PROCEDURE iom_nf90_rp0123d
  37. END INTERFACE
  38. !!----------------------------------------------------------------------
  39. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  40. !! $Id: iom_nf90.F90 4689 2014-06-24 23:40:18Z clem $
  41. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  42. !!----------------------------------------------------------------------
  43. CONTAINS
  44. SUBROUTINE iom_nf90_open( cdname, kiomid, ldwrt, ldok, kdompar )
  45. !!---------------------------------------------------------------------
  46. !! *** SUBROUTINE iom_open ***
  47. !!
  48. !! ** Purpose : open an input file with NF90
  49. !!---------------------------------------------------------------------
  50. CHARACTER(len=*) , INTENT(inout) :: cdname ! File name
  51. INTEGER , INTENT( out) :: kiomid ! nf90 identifier of the opened file
  52. LOGICAL , INTENT(in ) :: ldwrt ! read or write the file?
  53. LOGICAL , INTENT(in ) :: ldok ! check the existence
  54. INTEGER, DIMENSION(2,5), INTENT(in ), OPTIONAL :: kdompar ! domain parameters:
  55. CHARACTER(LEN=256) :: clinfo ! info character
  56. CHARACTER(LEN=256) :: cltmp ! temporary character
  57. INTEGER :: iln ! lengths of character
  58. INTEGER :: istop ! temporary storage of nstop
  59. INTEGER :: if90id ! nf90 identifier of the opened file
  60. INTEGER :: idmy ! dummy variable
  61. INTEGER :: jl ! loop variable
  62. INTEGER :: ichunk ! temporary storage of nn_chunksz
  63. INTEGER :: imode ! creation mode flag: NF90_CLOBBER or NF90_NOCLOBBER or NF90_HDF5
  64. INTEGER :: ihdf5 ! local variable for retrieval of value for NF90_HDF5
  65. LOGICAL :: llclobber ! local definition of ln_clobber
  66. !---------------------------------------------------------------------
  67. clinfo = ' iom_nf90_open ~~~ '
  68. istop = nstop ! store the actual value of nstop
  69. IF( nn_chunksz > 0 ) THEN ; ichunk = nn_chunksz
  70. ELSE ; ichunk = NF90_SIZEHINT_DEFAULT
  71. ENDIF
  72. !
  73. llclobber = ldwrt .AND. ln_clobber
  74. IF( ldok .AND. .NOT. llclobber ) THEN ! Open existing file...
  75. ! ! =============
  76. IF( ldwrt ) THEN ! ... in write mode
  77. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' open existing file: '//TRIM(cdname)//' in WRITE mode'
  78. IF( snc4set%luse ) THEN
  79. CALL iom_nf90_check(NF90_OPEN( TRIM(cdname), NF90_WRITE , if90id ), clinfo)
  80. ELSE
  81. CALL iom_nf90_check(NF90_OPEN( TRIM(cdname), NF90_WRITE , if90id, chunksize = ichunk ), clinfo)
  82. ENDIF
  83. CALL iom_nf90_check(NF90_SET_FILL( if90id, NF90_NOFILL, idmy ), clinfo)
  84. ELSE ! ... in read mode
  85. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' open existing file: '//TRIM(cdname)//' in READ mode'
  86. CALL iom_nf90_check(NF90_OPEN( TRIM(cdname), NF90_NOWRITE, if90id, chunksize = ichunk ), clinfo)
  87. ENDIF
  88. ELSE ! the file does not exist (or we overwrite it)
  89. ! ! =============
  90. iln = INDEX( cdname, '.nc' )
  91. IF( ldwrt ) THEN ! the file should be open in write mode so we create it...
  92. IF( jpnij > 1 ) THEN
  93. WRITE(cltmp,'(a,a,i4.4,a)') cdname(1:iln-1), '_', narea-1, '.nc'
  94. cdname = TRIM(cltmp)
  95. ENDIF
  96. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' create new file: '//TRIM(cdname)//' in WRITE mode'
  97. IF( llclobber ) THEN ; imode = IOR( NF90_64BIT_OFFSET, NF90_CLOBBER )
  98. ELSE ; imode = IOR( NF90_64BIT_OFFSET, NF90_NOCLOBBER )
  99. ENDIF
  100. IF( snc4set%luse ) THEN
  101. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' creating file: '//TRIM(cdname)//' in hdf5 (netcdf4) mode'
  102. CALL GET_NF90_SYMBOL("NF90_HDF5", ihdf5)
  103. IF( llclobber ) THEN ; imode = IOR(ihdf5, NF90_CLOBBER)
  104. ELSE ; imode = IOR(ihdf5, NF90_NOCLOBBER)
  105. ENDIF
  106. CALL iom_nf90_check(NF90_CREATE( TRIM(cdname), imode, if90id ), clinfo)
  107. ELSE
  108. CALL iom_nf90_check(NF90_CREATE( TRIM(cdname), imode, if90id, chunksize = ichunk ), clinfo)
  109. ENDIF
  110. CALL iom_nf90_check(NF90_SET_FILL( if90id, NF90_NOFILL, idmy ), clinfo)
  111. ! define dimensions
  112. CALL iom_nf90_check(NF90_DEF_DIM( if90id, 'x', kdompar(1,1) , idmy ), clinfo)
  113. CALL iom_nf90_check(NF90_DEF_DIM( if90id, 'y', kdompar(2,1) , idmy ), clinfo)
  114. CALL iom_nf90_check(NF90_DEF_DIM( if90id, 'z', jpk , idmy ), clinfo)
  115. CALL iom_nf90_check(NF90_DEF_DIM( if90id, 't', NF90_UNLIMITED, idmy ), clinfo)
  116. ! global attributes
  117. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_number_total' , jpnij ), clinfo)
  118. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_number' , narea-1 ), clinfo)
  119. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_dimensions_ids' , (/1 , 2 /) ), clinfo)
  120. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_size_global' , (/jpiglo, jpjglo/) ), clinfo)
  121. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_size_local' , kdompar(:,1) ), clinfo)
  122. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_position_first' , kdompar(:,2) ), clinfo)
  123. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_position_last' , kdompar(:,3) ), clinfo)
  124. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_halo_size_start', kdompar(:,4) ), clinfo)
  125. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_halo_size_end' , kdompar(:,5) ), clinfo)
  126. CALL iom_nf90_check(NF90_PUT_ATT( if90id, NF90_GLOBAL, 'DOMAIN_type' , 'BOX' ), clinfo)
  127. ELSE ! the file should be open for read mode so it must exist...
  128. CALL ctl_stop( TRIM(clinfo), ' should be impossible case...' )
  129. ENDIF
  130. ENDIF
  131. ! start to fill file informations
  132. ! =============
  133. IF( istop == nstop ) THEN ! no error within this routine
  134. !does not work with some compilers kiomid = MINLOC(iom_file(:)%nfid, dim = 1)
  135. kiomid = 0
  136. DO jl = jpmax_files, 1, -1
  137. IF( iom_file(jl)%nfid == 0 ) kiomid = jl
  138. ENDDO
  139. iom_file(kiomid)%name = TRIM(cdname)
  140. iom_file(kiomid)%nfid = if90id
  141. iom_file(kiomid)%iolib = jpnf90
  142. iom_file(kiomid)%nvars = 0
  143. iom_file(kiomid)%irec = -1 ! useless for NetCDF files, used to know if the file is in define mode
  144. CALL iom_nf90_check(NF90_Inquire(if90id, unlimitedDimId = iom_file(kiomid)%iduld), clinfo)
  145. IF ( iom_file(kiomid)%iduld .GE. 0 ) THEN
  146. CALL iom_nf90_check(NF90_Inquire_Dimension(if90id, iom_file(kiomid)%iduld, &
  147. & name = iom_file(kiomid)%uldname), clinfo)
  148. ENDIF
  149. IF(lwp) WRITE(numout,*) ' ---> '//TRIM(cdname)//' OK'
  150. ELSE
  151. kiomid = 0 ! return error flag
  152. ENDIF
  153. !
  154. END SUBROUTINE iom_nf90_open
  155. SUBROUTINE iom_nf90_close( kiomid )
  156. !!--------------------------------------------------------------------
  157. !! *** SUBROUTINE iom_nf90_close ***
  158. !!
  159. !! ** Purpose : close an input file with NF90
  160. !!--------------------------------------------------------------------
  161. INTEGER, INTENT(in) :: kiomid ! iom identifier of the file to be closed
  162. CHARACTER(LEN=100) :: clinfo ! info character
  163. !---------------------------------------------------------------------
  164. !
  165. clinfo = ' iom_nf90_close , file: '//TRIM(iom_file(kiomid)%name)
  166. CALL iom_nf90_check(NF90_CLOSE(iom_file(kiomid)%nfid), clinfo)
  167. !
  168. END SUBROUTINE iom_nf90_close
  169. FUNCTION iom_nf90_varid ( kiomid, cdvar, kiv, kdimsz, kndims )
  170. !!-----------------------------------------------------------------------
  171. !! *** FUNCTION iom_varid ***
  172. !!
  173. !! ** Purpose : get the id of a variable in a file with NF90
  174. !!-----------------------------------------------------------------------
  175. INTEGER , INTENT(in ) :: kiomid ! file Identifier
  176. CHARACTER(len=*) , INTENT(in ) :: cdvar ! name of the variable
  177. INTEGER , INTENT(in ) :: kiv !
  178. INTEGER, DIMENSION(:), INTENT( out), OPTIONAL :: kdimsz ! size of the dimensions
  179. INTEGER, INTENT( out), OPTIONAL :: kndims ! size of the dimensions
  180. !
  181. INTEGER :: iom_nf90_varid ! iom variable Id
  182. INTEGER :: if90id ! nf90 file identifier
  183. INTEGER :: ji ! dummy loop index
  184. INTEGER :: ivarid ! NetCDF variable Id
  185. INTEGER :: i_nvd ! number of dimension of the variable
  186. INTEGER, DIMENSION(jpmax_dims) :: idimid ! dimension ids of the variable
  187. LOGICAL :: llok ! ok test
  188. CHARACTER(LEN=100) :: clinfo ! info character
  189. !!-----------------------------------------------------------------------
  190. clinfo = ' iom_nf90_varid, file: '//TRIM(iom_file(kiomid)%name)//', var: '//TRIM(cdvar)
  191. iom_nf90_varid = 0 ! default definition
  192. IF( PRESENT(kdimsz) ) kdimsz(:) = 0 ! default definition
  193. if90id = iom_file(kiomid)%nfid ! get back NetCDF file id
  194. !
  195. llok = NF90_INQ_VARID( if90id, TRIM(cdvar), ivarid ) == nf90_noerr ! does the variable exist in the file
  196. IF( llok ) THEN
  197. iom_nf90_varid = kiv
  198. iom_file(kiomid)%nvars = kiv
  199. iom_file(kiomid)%nvid(kiv) = ivarid
  200. iom_file(kiomid)%cn_var(kiv) = TRIM(cdvar)
  201. CALL iom_nf90_check(NF90_Inquire_Variable(if90id, ivarid, ndims = i_nvd), clinfo) ! number of dimensions
  202. iom_file(kiomid)%ndims(kiv) = i_nvd
  203. CALL iom_nf90_check(NF90_Inquire_Variable(if90id, ivarid, dimids = idimid(1:i_nvd)), clinfo) ! dimensions ids
  204. iom_file(kiomid)%luld(kiv) = .FALSE. ! default value
  205. iom_file(kiomid)%dimsz(:,kiv) = 0 ! reset dimsz in case previously used
  206. DO ji = 1, i_nvd ! dimensions size
  207. CALL iom_nf90_check(NF90_Inquire_Dimension(if90id, idimid(ji), len = iom_file(kiomid)%dimsz(ji,kiv)), clinfo)
  208. IF( idimid(ji) == iom_file(kiomid)%iduld ) iom_file(kiomid)%luld(kiv) = .TRUE. ! unlimited dimension?
  209. END DO
  210. !---------- Deal with scale_factor and add_offset
  211. llok = NF90_Inquire_attribute(if90id, ivarid, 'scale_factor') == nf90_noerr
  212. IF( llok) THEN
  213. CALL iom_nf90_check(NF90_GET_ATT(if90id, ivarid, 'scale_factor', iom_file(kiomid)%scf(kiv)), clinfo)
  214. ELSE
  215. iom_file(kiomid)%scf(kiv) = 1.
  216. END IF
  217. llok = NF90_Inquire_attribute(if90id, ivarid, 'add_offset') == nf90_noerr
  218. IF( llok ) THEN
  219. CALL iom_nf90_check(NF90_GET_ATT(if90id, ivarid, 'add_offset', iom_file(kiomid)%ofs(kiv)), clinfo)
  220. ELSE
  221. iom_file(kiomid)%ofs(kiv) = 0.
  222. END IF
  223. ! return the simension size
  224. IF( PRESENT(kdimsz) ) THEN
  225. IF( i_nvd == SIZE(kdimsz) ) THEN
  226. kdimsz(:) = iom_file(kiomid)%dimsz(1:i_nvd,kiv)
  227. ELSE
  228. WRITE(ctmp1,*) i_nvd, SIZE(kdimsz)
  229. CALL ctl_stop( TRIM(clinfo), 'error in kdimsz size'//TRIM(ctmp1) )
  230. ENDIF
  231. ENDIF
  232. IF( PRESENT(kndims) ) kndims = iom_file(kiomid)%ndims(kiv)
  233. ELSE
  234. iom_nf90_varid = -1 ! variable not found, return error code: -1
  235. ENDIF
  236. !
  237. END FUNCTION iom_nf90_varid
  238. SUBROUTINE iom_nf90_g0d( kiomid, kvid, pvar, kstart )
  239. !!-----------------------------------------------------------------------
  240. !! *** ROUTINE iom_nf90_g0d ***
  241. !!
  242. !! ** Purpose : read a scalar with NF90
  243. !!-----------------------------------------------------------------------
  244. INTEGER , INTENT(in ) :: kiomid ! Identifier of the file
  245. INTEGER , INTENT(in ) :: kvid ! variable id
  246. REAL(wp), INTENT( out) :: pvar ! read field
  247. INTEGER , DIMENSION(1), INTENT(in ), OPTIONAL :: kstart ! start position of the reading in each axis
  248. !
  249. CHARACTER(LEN=100) :: clinfo ! info character
  250. !---------------------------------------------------------------------
  251. clinfo = 'iom_nf90_g0d , file: '//TRIM(iom_file(kiomid)%name)//', var: '//TRIM(iom_file(kiomid)%cn_var(kvid))
  252. CALL iom_nf90_check(NF90_GET_VAR(iom_file(kiomid)%nfid, iom_file(kiomid)%nvid(kvid), pvar, start = kstart), clinfo )
  253. !
  254. END SUBROUTINE iom_nf90_g0d
  255. SUBROUTINE iom_nf90_g123d( kiomid, kvid, knbdim, kstart, kcount, kx1, kx2, ky1, ky2, &
  256. & pv_r1d, pv_r2d, pv_r3d )
  257. !!-----------------------------------------------------------------------
  258. !! *** ROUTINE iom_nf90_g123d ***
  259. !!
  260. !! ** Purpose : read a 1D/2D/3D variable with NF90
  261. !!
  262. !! ** Method : read ONE record at each CALL
  263. !!-----------------------------------------------------------------------
  264. INTEGER , INTENT(in ) :: kiomid ! iom identifier of the file
  265. INTEGER , INTENT(in ) :: kvid ! Name of the variable
  266. INTEGER , INTENT(in ) :: knbdim ! number of dimensions of the variable
  267. INTEGER , DIMENSION(:) , INTENT(in ) :: kstart ! start position of the reading in each axis
  268. INTEGER , DIMENSION(:) , INTENT(in ) :: kcount ! number of points to be read in each axis
  269. INTEGER , INTENT(in ) :: kx1, kx2, ky1, ky2 ! subdomain indexes
  270. REAL(wp), DIMENSION(:) , INTENT( out), OPTIONAL :: pv_r1d ! read field (1D case)
  271. REAL(wp), DIMENSION(:,:) , INTENT( out), OPTIONAL :: pv_r2d ! read field (2D case)
  272. REAL(wp), DIMENSION(:,:,:) , INTENT( out), OPTIONAL :: pv_r3d ! read field (3D case)
  273. !
  274. CHARACTER(LEN=100) :: clinfo ! info character
  275. INTEGER :: if90id ! nf90 identifier of the opened file
  276. INTEGER :: ivid ! nf90 variable id
  277. !---------------------------------------------------------------------
  278. clinfo = 'iom_nf90_g123d , file: '//TRIM(iom_file(kiomid)%name)//', var: '//TRIM(iom_file(kiomid)%cn_var(kvid))
  279. if90id = iom_file(kiomid)%nfid ! get back NetCDF file id
  280. ivid = iom_file(kiomid)%nvid(kvid) ! get back NetCDF var id
  281. !
  282. IF( PRESENT(pv_r1d) ) THEN
  283. CALL iom_nf90_check( NF90_GET_VAR(if90id, ivid, pv_r1d(: ), start = kstart(1:knbdim), &
  284. & count = kcount(1:knbdim)), clinfo )
  285. ELSEIF( PRESENT(pv_r2d) ) THEN
  286. CALL iom_nf90_check( NF90_GET_VAR(if90id, ivid, pv_r2d(kx1:kx2,ky1:ky2 ), start = kstart(1:knbdim), &
  287. & count = kcount(1:knbdim)), clinfo )
  288. ELSEIF( PRESENT(pv_r3d) ) THEN
  289. CALL iom_nf90_check( NF90_GET_VAR(if90id, ivid, pv_r3d(kx1:kx2,ky1:ky2,:), start = kstart(1:knbdim), &
  290. & count = kcount(1:knbdim)), clinfo )
  291. ENDIF
  292. !
  293. END SUBROUTINE iom_nf90_g123d
  294. SUBROUTINE iom_nf90_intatt( kiomid, cdatt, pvar )
  295. !!-----------------------------------------------------------------------
  296. !! *** ROUTINE iom_nf90_intatt ***
  297. !!
  298. !! ** Purpose : read an integer attribute with NF90
  299. !!-----------------------------------------------------------------------
  300. INTEGER , INTENT(in ) :: kiomid ! Identifier of the file
  301. CHARACTER(len=*), INTENT(in ) :: cdatt ! attribute name
  302. INTEGER , INTENT( out) :: pvar ! read field
  303. !
  304. INTEGER :: if90id ! temporary integer
  305. LOGICAL :: llok ! temporary logical
  306. CHARACTER(LEN=100) :: clinfo ! info character
  307. !---------------------------------------------------------------------
  308. !
  309. if90id = iom_file(kiomid)%nfid
  310. llok = NF90_Inquire_attribute(if90id, NF90_GLOBAL, cdatt) == nf90_noerr
  311. IF( llok) THEN
  312. clinfo = 'iom_nf90_getatt, file: '//TRIM(iom_file(kiomid)%name)//', att: '//TRIM(cdatt)
  313. CALL iom_nf90_check(NF90_GET_ATT(if90id, NF90_GLOBAL, cdatt, values=pvar), clinfo)
  314. ELSE
  315. CALL ctl_warn('iom_nf90_getatt: no attribute '//cdatt//' found')
  316. pvar = -999
  317. ENDIF
  318. !
  319. END SUBROUTINE iom_nf90_intatt
  320. SUBROUTINE iom_nf90_gettime( kiomid, kvid, ptime, cdunits, cdcalendar )
  321. !!--------------------------------------------------------------------
  322. !! *** SUBROUTINE iom_gettime ***
  323. !!
  324. !! ** Purpose : read the time axis kvid in the file with NF90
  325. !!--------------------------------------------------------------------
  326. INTEGER , INTENT(in ) :: kiomid ! file Identifier
  327. INTEGER , INTENT(in ) :: kvid ! variable id
  328. REAL(wp), DIMENSION(:) , INTENT( out) :: ptime ! the time axis
  329. CHARACTER(len=*), OPTIONAL, INTENT( out) :: cdunits ! units attribute
  330. CHARACTER(len=*), OPTIONAL, INTENT( out) :: cdcalendar ! calendar attribute
  331. !
  332. CHARACTER(LEN=100) :: clinfo ! info character
  333. !---------------------------------------------------------------------
  334. clinfo = 'iom_nf90_gettime, file: '//TRIM(iom_file(kiomid)%name)//', var: '//TRIM(iom_file(kiomid)%cn_var(kvid))
  335. CALL iom_nf90_check(NF90_GET_VAR(iom_file(kiomid)%nfid, iom_file(kiomid)%nvid(kvid), ptime(:), &
  336. & start=(/ 1 /), count=(/ iom_file(kiomid)%dimsz(1, kvid) /)), clinfo)
  337. IF ( PRESENT(cdunits) ) THEN
  338. CALL iom_nf90_check(NF90_GET_ATT(iom_file(kiomid)%nfid, iom_file(kiomid)%nvid(kvid), "units", &
  339. & values=cdunits), clinfo)
  340. ENDIF
  341. IF ( PRESENT(cdcalendar) ) THEN
  342. CALL iom_nf90_check(NF90_GET_ATT(iom_file(kiomid)%nfid, iom_file(kiomid)%nvid(kvid), "calendar", &
  343. & values=cdcalendar), clinfo)
  344. ENDIF
  345. !
  346. END SUBROUTINE iom_nf90_gettime
  347. SUBROUTINE iom_nf90_rp0123d( kt, kwrite, kiomid, cdvar , kvid , ktype, &
  348. & pv_r0d, pv_r1d, pv_r2d, pv_r3d )
  349. !!--------------------------------------------------------------------
  350. !! *** SUBROUTINE iom_nf90_rstput ***
  351. !!
  352. !! ** Purpose : read the time axis cdvar in the file
  353. !!--------------------------------------------------------------------
  354. INTEGER , INTENT(in) :: kt ! ocean time-step
  355. INTEGER , INTENT(in) :: kwrite ! writing time-step
  356. INTEGER , INTENT(in) :: kiomid ! Identifier of the file
  357. CHARACTER(len=*) , INTENT(in) :: cdvar ! variable name
  358. INTEGER , INTENT(in) :: kvid ! variable id
  359. INTEGER , INTENT(in), OPTIONAL :: ktype ! variable type (default R8)
  360. REAL(wp) , INTENT(in), OPTIONAL :: pv_r0d ! written Od field
  361. REAL(wp), DIMENSION( :), INTENT(in), OPTIONAL :: pv_r1d ! written 1d field
  362. REAL(wp), DIMENSION(:, : ), INTENT(in), OPTIONAL :: pv_r2d ! written 2d field
  363. REAL(wp), DIMENSION(:, :, :), INTENT(in), OPTIONAL :: pv_r3d ! written 3d field
  364. !
  365. INTEGER :: idims ! number of dimension
  366. INTEGER :: idvar ! variable id
  367. INTEGER :: jd ! dimension loop counter
  368. INTEGER :: ix1, ix2, iy1, iy2 ! subdomain indexes
  369. INTEGER, DIMENSION(4) :: idimsz ! dimensions size
  370. INTEGER, DIMENSION(4) :: idimid ! dimensions id
  371. CHARACTER(LEN=256) :: clinfo ! info character
  372. CHARACTER(LEN= 12), DIMENSION(4) :: cltmp ! temporary character
  373. INTEGER :: if90id ! nf90 file identifier
  374. INTEGER :: idmy ! dummy variable
  375. INTEGER :: itype ! variable type
  376. INTEGER, DIMENSION(4) :: ichunksz ! NetCDF4 chunk sizes. Will be computed using
  377. ! nn_nchunks_[i,j,k,t] namelist parameters
  378. INTEGER :: ichunkalg, ishuffle,&
  379. ideflate, ideflate_level
  380. ! NetCDF4 internally fixed parameters
  381. LOGICAL :: lchunk ! logical switch to activate chunking and compression
  382. ! when appropriate (currently chunking is applied to 4d fields only)
  383. !---------------------------------------------------------------------
  384. !
  385. clinfo = ' iom_nf90_rp0123d, file: '//TRIM(iom_file(kiomid)%name)//', var: '//TRIM(cdvar)
  386. if90id = iom_file(kiomid)%nfid
  387. !
  388. ! define dimension variables if it is not already done
  389. ! ==========================
  390. IF( iom_file(kiomid)%nvars == 0 ) THEN
  391. ! are we in define mode?
  392. IF( iom_file(kiomid)%irec /= -1 ) THEN ! trick: irec used to know if the file is in define mode or not
  393. CALL iom_nf90_check(NF90_REDEF( if90id ), clinfo) ; iom_file(kiomid)%irec = -1
  394. ENDIF
  395. ! define the dimension variables if it is not already done
  396. cltmp = (/ 'nav_lon ', 'nav_lat ', 'nav_lev ', 'time_counter' /)
  397. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cltmp(1)), NF90_FLOAT , (/ 1, 2 /), iom_file(kiomid)%nvid(1) ), clinfo)
  398. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cltmp(2)), NF90_FLOAT , (/ 1, 2 /), iom_file(kiomid)%nvid(2) ), clinfo)
  399. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cltmp(3)), NF90_FLOAT , (/ 3 /), iom_file(kiomid)%nvid(3) ), clinfo)
  400. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cltmp(4)), NF90_DOUBLE, (/ 4 /), iom_file(kiomid)%nvid(4) ), clinfo)
  401. ! update informations structure related the dimension variable we just added...
  402. iom_file(kiomid)%nvars = 4
  403. iom_file(kiomid)%luld(1:4) = (/ .FALSE., .FALSE., .FALSE., .TRUE. /)
  404. iom_file(kiomid)%cn_var(1:4) = cltmp
  405. iom_file(kiomid)%ndims(1:4) = (/ 2, 2, 1, 1 /)
  406. ! trick: defined to 0 to say that dimension variables are defined but not yet written
  407. iom_file(kiomid)%dimsz(1, 1) = 0
  408. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' define dimension variables done'
  409. ENDIF
  410. ! define the data if it is not already done
  411. ! ===============
  412. IF( kvid <= 0 ) THEN
  413. !
  414. ! NetCDF4 chunking and compression fixed settings
  415. ichunkalg = 0
  416. ishuffle = 1
  417. ideflate = 1
  418. ideflate_level = 1
  419. !
  420. idvar = iom_file(kiomid)%nvars + 1
  421. ! are we in define mode?
  422. IF( iom_file(kiomid)%irec /= -1 ) THEN ! trick: irec used to know if the file is in define mode or not
  423. CALL iom_nf90_check(NF90_REDEF( if90id ), clinfo) ; iom_file(kiomid)%irec = -1
  424. ENDIF
  425. ! variable definition
  426. IF( PRESENT(pv_r0d) ) THEN ; idims = 0
  427. ELSEIF( PRESENT(pv_r1d) ) THEN ; idims = 2 ; idimid(1:idims) = (/ 3,4/)
  428. ELSEIF( PRESENT(pv_r2d) ) THEN ; idims = 3 ; idimid(1:idims) = (/1,2 ,4/)
  429. ELSEIF( PRESENT(pv_r3d) ) THEN ; idims = 4 ; idimid(1:idims) = (/1,2,3,4/)
  430. ENDIF
  431. IF( PRESENT(ktype) ) THEN ! variable external type
  432. SELECT CASE (ktype)
  433. CASE (jp_r8) ; itype = NF90_DOUBLE
  434. CASE (jp_r4) ; itype = NF90_FLOAT
  435. CASE (jp_i4) ; itype = NF90_INT
  436. CASE (jp_i2) ; itype = NF90_SHORT
  437. CASE (jp_i1) ; itype = NF90_BYTE
  438. CASE DEFAULT ; CALL ctl_stop( TRIM(clinfo)//' unknown variable type' )
  439. END SELECT
  440. ELSE
  441. itype = NF90_DOUBLE
  442. ENDIF
  443. IF( PRESENT(pv_r0d) ) THEN
  444. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cdvar), itype, &
  445. & iom_file(kiomid)%nvid(idvar) ), clinfo)
  446. ELSE
  447. CALL iom_nf90_check(NF90_DEF_VAR( if90id, TRIM(cdvar), itype, idimid(1:idims), &
  448. & iom_file(kiomid)%nvid(idvar) ), clinfo)
  449. ENDIF
  450. lchunk = .false.
  451. IF( snc4set%luse .AND. idims.eq.4 ) lchunk = .true.
  452. ! update informations structure related the new variable we want to add...
  453. iom_file(kiomid)%nvars = idvar
  454. iom_file(kiomid)%cn_var(idvar) = TRIM(cdvar)
  455. iom_file(kiomid)%scf(idvar) = 1.
  456. iom_file(kiomid)%ofs(idvar) = 0.
  457. iom_file(kiomid)%ndims(idvar) = idims
  458. IF( .NOT. PRESENT(pv_r0d) ) THEN ; iom_file(kiomid)%luld(idvar) = .TRUE.
  459. ELSE ; iom_file(kiomid)%luld(idvar) = .FALSE.
  460. ENDIF
  461. DO jd = 1, idims
  462. CALL iom_nf90_check(NF90_INQUIRE_DIMENSION( if90id, idimid(jd), len = iom_file(kiomid)%dimsz(jd,idvar) ), clinfo)
  463. IF ( lchunk ) ichunksz(jd) = iom_file(kiomid)%dimsz(jd,idvar)
  464. END DO
  465. IF ( lchunk ) THEN
  466. ! Calculate chunk sizes by partitioning each dimension as requested in namnc4 namelist
  467. ! Disallow very small chunk sizes and prevent chunk sizes larger than each individual dimension
  468. ichunksz(1) = MIN( ichunksz(1),MAX( (ichunksz(1)-1)/snc4set%ni + 1 ,16 ) ) ! Suggested default nc4set%ni=4
  469. ichunksz(2) = MIN( ichunksz(2),MAX( (ichunksz(2)-1)/snc4set%nj + 1 ,16 ) ) ! Suggested default nc4set%nj=2
  470. ichunksz(3) = MIN( ichunksz(3),MAX( (ichunksz(3)-1)/snc4set%nk + 1 , 1 ) ) ! Suggested default nc4set%nk=6
  471. ichunksz(4) = 1 ! Do not allow chunks to span the
  472. ! unlimited dimension
  473. CALL iom_nf90_check(SET_NF90_DEF_VAR_CHUNKING(if90id, idvar, ichunkalg, ichunksz), clinfo)
  474. CALL iom_nf90_check(SET_NF90_DEF_VAR_DEFLATE(if90id, idvar, ishuffle, ideflate, ideflate_level), clinfo)
  475. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' chunked ok. Chunks sizes: ', ichunksz
  476. ENDIF
  477. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' defined ok'
  478. ELSE
  479. idvar = kvid
  480. ENDIF
  481. ! time step kwrite : write the variable
  482. IF( kt == kwrite ) THEN
  483. ! are we in write mode?
  484. IF( iom_file(kiomid)%irec == -1 ) THEN ! trick: irec used to know if the file is in define mode or not
  485. CALL iom_nf90_check(NF90_ENDDEF( if90id ), clinfo) ; iom_file(kiomid)%irec = 0
  486. ENDIF
  487. ! on what kind of domain must the data be written?
  488. IF( PRESENT(pv_r2d) .OR. PRESENT(pv_r3d) ) THEN
  489. idimsz(1:2) = iom_file(kiomid)%dimsz(1:2,idvar)
  490. IF( idimsz(1) == (nlei - nldi + 1) .AND. idimsz(2) == (nlej - nldj + 1) ) THEN
  491. ix1 = nldi ; ix2 = nlei ; iy1 = nldj ; iy2 = nlej
  492. ELSEIF( idimsz(1) == nlci .AND. idimsz(2) == nlcj ) THEN
  493. ix1 = 1 ; ix2 = nlci ; iy1 = 1 ; iy2 = nlcj
  494. ELSEIF( idimsz(1) == jpi .AND. idimsz(2) == jpj ) THEN
  495. ix1 = 1 ; ix2 = jpi ; iy1 = 1 ; iy2 = jpj
  496. ELSE
  497. CALL ctl_stop( 'iom_nf90_rp0123d: should have been an impossible case...' )
  498. ENDIF
  499. ! write dimension variables if it is not already done
  500. ! =============
  501. ! trick: is defined to 0 => dimension variable are defined but not yet written
  502. IF( iom_file(kiomid)%dimsz(1, 1) == 0 ) THEN
  503. CALL iom_nf90_check(NF90_INQ_VARID( if90id, 'nav_lon' , idmy ), clinfo)
  504. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idmy, glamt(ix1:ix2, iy1:iy2) ), clinfo)
  505. CALL iom_nf90_check(NF90_INQ_VARID( if90id, 'nav_lat' , idmy ), clinfo)
  506. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idmy, gphit(ix1:ix2, iy1:iy2) ), clinfo)
  507. CALL iom_nf90_check(NF90_INQ_VARID( if90id, 'nav_lev' , idmy ), clinfo)
  508. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idmy, gdept_1d ), clinfo)
  509. ! +++ WRONG VALUE: to be improved but not really useful...
  510. CALL iom_nf90_check(NF90_INQ_VARID( if90id, 'time_counter', idmy ), clinfo)
  511. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idmy, kt ), clinfo)
  512. ! update the values of the variables dimensions size
  513. CALL iom_nf90_check(NF90_INQUIRE_DIMENSION( if90id, 1, len = iom_file(kiomid)%dimsz(1,1) ), clinfo)
  514. CALL iom_nf90_check(NF90_INQUIRE_DIMENSION( if90id, 2, len = iom_file(kiomid)%dimsz(2,1) ), clinfo)
  515. iom_file(kiomid)%dimsz(1:2, 2) = iom_file(kiomid)%dimsz(1:2, 1)
  516. CALL iom_nf90_check(NF90_INQUIRE_DIMENSION( if90id, 3, len = iom_file(kiomid)%dimsz(1,3) ), clinfo)
  517. iom_file(kiomid)%dimsz(1 , 4) = 1 ! unlimited dimension
  518. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' write dimension variables done'
  519. ENDIF
  520. ENDIF
  521. ! write the data
  522. ! =============
  523. IF( PRESENT(pv_r0d) ) THEN
  524. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idvar, pv_r0d ), clinfo)
  525. ELSEIF( PRESENT(pv_r1d) ) THEN
  526. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idvar, pv_r1d( :) ), clinfo)
  527. ELSEIF( PRESENT(pv_r2d) ) THEN
  528. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idvar, pv_r2d(ix1:ix2, iy1:iy2 ) ), clinfo)
  529. ELSEIF( PRESENT(pv_r3d) ) THEN
  530. CALL iom_nf90_check(NF90_PUT_VAR( if90id, idvar, pv_r3d(ix1:ix2, iy1:iy2, :) ), clinfo)
  531. ENDIF
  532. ! add 1 to the size of the temporal dimension (not really useful...)
  533. IF( iom_file(kiomid)%luld(idvar) ) iom_file(kiomid)%dimsz(iom_file(kiomid)%ndims(idvar), idvar) &
  534. & = iom_file(kiomid)%dimsz(iom_file(kiomid)%ndims(idvar), idvar) + 1
  535. IF(lwp) WRITE(numout,*) TRIM(clinfo)//' written ok'
  536. ENDIF
  537. !
  538. END SUBROUTINE iom_nf90_rp0123d
  539. SUBROUTINE iom_nf90_check( kstatus, cdinfo )
  540. !!--------------------------------------------------------------------
  541. !! *** SUBROUTINE iom_nf90_check ***
  542. !!
  543. !! ** Purpose : check nf90 errors
  544. !!--------------------------------------------------------------------
  545. INTEGER, INTENT(in) :: kstatus
  546. CHARACTER(LEN=*), INTENT(in) :: cdinfo
  547. !---------------------------------------------------------------------
  548. IF(kstatus /= nf90_noerr) CALL ctl_stop( 'iom_nf90_check : '//TRIM(nf90_strerror(kstatus)), TRIM(cdinfo) )
  549. END SUBROUTINE iom_nf90_check
  550. !!======================================================================
  551. END MODULE iom_nf90