domwri.F90 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. MODULE domwri
  2. !!======================================================================
  3. !! *** MODULE domwri ***
  4. !! Ocean initialization : write the ocean domain mesh file(s)
  5. !!======================================================================
  6. !! History : OPA ! 1997-02 (G. Madec) Original code
  7. !! 8.1 ! 1999-11 (M. Imbard) NetCDF FORMAT with IOIPSL
  8. !! NEMO 1.0 ! 2002-08 (G. Madec) F90 and several file
  9. !! 3.0 ! 2008-01 (S. Masson) add dom_uniq
  10. !! 4.0 ! 2011-01 (A. R. Porter, STFC Daresbury) dynamical allocation
  11. !!----------------------------------------------------------------------
  12. !!----------------------------------------------------------------------
  13. !! dom_wri : create and write mesh and mask file(s)
  14. !! dom_uniq :
  15. !!----------------------------------------------------------------------
  16. USE dom_oce ! ocean space and time domain
  17. USE in_out_manager ! I/O manager
  18. USE iom ! I/O library
  19. USE lbclnk ! lateral boundary conditions - mpp exchanges
  20. USE lib_mpp ! MPP library
  21. USE wrk_nemo ! Memory allocation
  22. USE timing ! Timing
  23. IMPLICIT NONE
  24. PRIVATE
  25. PUBLIC dom_wri ! routine called by inidom.F90
  26. !! * Substitutions
  27. # include "vectopt_loop_substitute.h90"
  28. !!----------------------------------------------------------------------
  29. !! NEMO/OPA 3.3 , NEMO Consortium (2010)
  30. !! $Id: domwri.F90 5604 2015-07-16 12:31:49Z timgraham $
  31. !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
  32. !!----------------------------------------------------------------------
  33. CONTAINS
  34. SUBROUTINE dom_wri
  35. !!----------------------------------------------------------------------
  36. !! *** ROUTINE dom_wri ***
  37. !!
  38. !! ** Purpose : Create the NetCDF file(s) which contain(s) all the
  39. !! ocean domain informations (mesh and mask arrays). This (these)
  40. !! file(s) is (are) used for visualisation (SAXO software) and
  41. !! diagnostic computation.
  42. !!
  43. !! ** Method : Write in a file all the arrays generated in routines
  44. !! domhgr, domzgr, and dommsk. Note: the file contain depends on
  45. !! the vertical coord. used (z-coord, partial steps, s-coord)
  46. !! MOD(nmsh, 3) = 1 : 'mesh_mask.nc' file
  47. !! = 2 : 'mesh.nc' and mask.nc' files
  48. !! = 0 : 'mesh_hgr.nc', 'mesh_zgr.nc' and
  49. !! 'mask.nc' files
  50. !! For huge size domain, use option 2 or 3 depending on your
  51. !! vertical coordinate.
  52. !!
  53. !! if nmsh <= 3: write full 3D arrays for e3[tuvw] and gdep[tuvw]
  54. !! if 3 < nmsh <= 6: write full 3D arrays for e3[tuvw] and 2D arrays
  55. !! corresponding to the depth of the bottom t- and w-points
  56. !! if 6 < nmsh <= 9: write 2D arrays corresponding to the depth and the
  57. !! thickness (e3[tw]_ps) of the bottom points
  58. !!
  59. !! ** output file : meshmask.nc : domain size, horizontal grid-point position,
  60. !! masks, depth and vertical scale factors
  61. !!----------------------------------------------------------------------
  62. !!
  63. INTEGER :: inum0 ! temprary units for 'mesh_mask.nc' file
  64. INTEGER :: inum1 ! temprary units for 'mesh.nc' file
  65. INTEGER :: inum2 ! temprary units for 'mask.nc' file
  66. INTEGER :: inum3 ! temprary units for 'mesh_hgr.nc' file
  67. INTEGER :: inum4 ! temprary units for 'mesh_zgr.nc' file
  68. CHARACTER(len=21) :: clnam0 ! filename (mesh and mask informations)
  69. CHARACTER(len=21) :: clnam1 ! filename (mesh informations)
  70. CHARACTER(len=21) :: clnam2 ! filename (mask informations)
  71. CHARACTER(len=21) :: clnam3 ! filename (horizontal mesh informations)
  72. CHARACTER(len=21) :: clnam4 ! filename (vertical mesh informations)
  73. INTEGER :: ji, jj, jk ! dummy loop indices
  74. ! ! workspaces
  75. REAL(wp), POINTER, DIMENSION(:,: ) :: zprt, zprw
  76. REAL(wp), POINTER, DIMENSION(:,:,:) :: zdepu, zdepv
  77. !!----------------------------------------------------------------------
  78. !
  79. IF( nn_timing == 1 ) CALL timing_start('dom_wri')
  80. !
  81. CALL wrk_alloc( jpi, jpj, zprt, zprw )
  82. CALL wrk_alloc( jpi, jpj, jpk, zdepu, zdepv )
  83. !
  84. IF(lwp) WRITE(numout,*)
  85. IF(lwp) WRITE(numout,*) 'dom_wri : create NetCDF mesh and mask information file(s)'
  86. IF(lwp) WRITE(numout,*) '~~~~~~~'
  87. clnam0 = 'mesh_mask' ! filename (mesh and mask informations)
  88. clnam1 = 'mesh' ! filename (mesh informations)
  89. clnam2 = 'mask' ! filename (mask informations)
  90. clnam3 = 'mesh_hgr' ! filename (horizontal mesh informations)
  91. clnam4 = 'mesh_zgr' ! filename (vertical mesh informations)
  92. SELECT CASE ( MOD(nmsh, 3) )
  93. ! ! ============================
  94. CASE ( 1 ) ! create 'mesh_mask.nc' file
  95. ! ! ============================
  96. CALL iom_open( TRIM(clnam0), inum0, ldwrt = .TRUE., kiolib = jprstlib )
  97. inum2 = inum0 ! put all the informations
  98. inum3 = inum0 ! in unit inum0
  99. inum4 = inum0
  100. ! ! ============================
  101. CASE ( 2 ) ! create 'mesh.nc' and
  102. ! ! 'mask.nc' files
  103. ! ! ============================
  104. CALL iom_open( TRIM(clnam1), inum1, ldwrt = .TRUE., kiolib = jprstlib )
  105. CALL iom_open( TRIM(clnam2), inum2, ldwrt = .TRUE., kiolib = jprstlib )
  106. inum3 = inum1 ! put mesh informations
  107. inum4 = inum1 ! in unit inum1
  108. ! ! ============================
  109. CASE ( 0 ) ! create 'mesh_hgr.nc'
  110. ! ! 'mesh_zgr.nc' and
  111. ! ! 'mask.nc' files
  112. ! ! ============================
  113. CALL iom_open( TRIM(clnam2), inum2, ldwrt = .TRUE., kiolib = jprstlib )
  114. CALL iom_open( TRIM(clnam3), inum3, ldwrt = .TRUE., kiolib = jprstlib )
  115. CALL iom_open( TRIM(clnam4), inum4, ldwrt = .TRUE., kiolib = jprstlib )
  116. !
  117. END SELECT
  118. ! ! masks (inum2)
  119. CALL iom_rstput( 0, 0, inum2, 'tmask', tmask, ktype = jp_i1 ) ! ! land-sea mask
  120. CALL iom_rstput( 0, 0, inum2, 'umask', umask, ktype = jp_i1 )
  121. CALL iom_rstput( 0, 0, inum2, 'vmask', vmask, ktype = jp_i1 )
  122. CALL iom_rstput( 0, 0, inum2, 'fmask', fmask, ktype = jp_i1 )
  123. CALL dom_uniq( zprw, 'T' )
  124. DO jj = 1, jpj
  125. DO ji = 1, jpi
  126. jk=mikt(ji,jj)
  127. zprt(ji,jj) = tmask(ji,jj,jk) * zprw(ji,jj) ! ! unique point mask
  128. END DO
  129. END DO ! ! unique point mask
  130. CALL iom_rstput( 0, 0, inum2, 'tmaskutil', zprt, ktype = jp_i1 )
  131. CALL dom_uniq( zprw, 'U' )
  132. DO jj = 1, jpj
  133. DO ji = 1, jpi
  134. jk=miku(ji,jj)
  135. zprt(ji,jj) = umask(ji,jj,jk) * zprw(ji,jj) ! ! unique point mask
  136. END DO
  137. END DO
  138. CALL iom_rstput( 0, 0, inum2, 'umaskutil', zprt, ktype = jp_i1 )
  139. CALL dom_uniq( zprw, 'V' )
  140. DO jj = 1, jpj
  141. DO ji = 1, jpi
  142. jk=mikv(ji,jj)
  143. zprt(ji,jj) = vmask(ji,jj,jk) * zprw(ji,jj) ! ! unique point mask
  144. END DO
  145. END DO
  146. CALL iom_rstput( 0, 0, inum2, 'vmaskutil', zprt, ktype = jp_i1 )
  147. CALL dom_uniq( zprw, 'F' )
  148. DO jj = 1, jpj
  149. DO ji = 1, jpi
  150. jk=mikf(ji,jj)
  151. zprt(ji,jj) = fmask(ji,jj,jk) * zprw(ji,jj) ! ! unique point mask
  152. END DO
  153. END DO
  154. CALL iom_rstput( 0, 0, inum2, 'fmaskutil', zprt, ktype = jp_i1 )
  155. ! ! horizontal mesh (inum3)
  156. CALL iom_rstput( 0, 0, inum3, 'glamt', glamt, ktype = jp_r4 ) ! ! latitude
  157. CALL iom_rstput( 0, 0, inum3, 'glamu', glamu, ktype = jp_r4 )
  158. CALL iom_rstput( 0, 0, inum3, 'glamv', glamv, ktype = jp_r4 )
  159. CALL iom_rstput( 0, 0, inum3, 'glamf', glamf, ktype = jp_r4 )
  160. CALL iom_rstput( 0, 0, inum3, 'gphit', gphit, ktype = jp_r4 ) ! ! longitude
  161. CALL iom_rstput( 0, 0, inum3, 'gphiu', gphiu, ktype = jp_r4 )
  162. CALL iom_rstput( 0, 0, inum3, 'gphiv', gphiv, ktype = jp_r4 )
  163. CALL iom_rstput( 0, 0, inum3, 'gphif', gphif, ktype = jp_r4 )
  164. CALL iom_rstput( 0, 0, inum3, 'e1t', e1t, ktype = jp_r8 ) ! ! e1 scale factors
  165. CALL iom_rstput( 0, 0, inum3, 'e1u', e1u, ktype = jp_r8 )
  166. CALL iom_rstput( 0, 0, inum3, 'e1v', e1v, ktype = jp_r8 )
  167. CALL iom_rstput( 0, 0, inum3, 'e1f', e1f, ktype = jp_r8 )
  168. CALL iom_rstput( 0, 0, inum3, 'e2t', e2t, ktype = jp_r8 ) ! ! e2 scale factors
  169. CALL iom_rstput( 0, 0, inum3, 'e2u', e2u, ktype = jp_r8 )
  170. CALL iom_rstput( 0, 0, inum3, 'e2v', e2v, ktype = jp_r8 )
  171. CALL iom_rstput( 0, 0, inum3, 'e2f', e2f, ktype = jp_r8 )
  172. CALL iom_rstput( 0, 0, inum3, 'ff', ff, ktype = jp_r8 ) ! ! coriolis factor
  173. ! note that mbkt is set to 1 over land ==> use surface tmask
  174. zprt(:,:) = ssmask(:,:) * REAL( mbkt(:,:) , wp )
  175. CALL iom_rstput( 0, 0, inum4, 'mbathy', zprt, ktype = jp_i2 ) ! ! nb of ocean T-points
  176. zprt(:,:) = ssmask(:,:) * REAL( mikt(:,:) , wp )
  177. CALL iom_rstput( 0, 0, inum4, 'misf', zprt, ktype = jp_i2 ) ! ! nb of ocean T-points
  178. zprt(:,:) = ssmask(:,:) * REAL( risfdep(:,:) , wp )
  179. CALL iom_rstput( 0, 0, inum4, 'isfdraft', zprt, ktype = jp_r4 ) ! ! nb of ocean T-points
  180. IF( ln_sco ) THEN ! s-coordinate
  181. CALL iom_rstput( 0, 0, inum4, 'hbatt', hbatt )
  182. CALL iom_rstput( 0, 0, inum4, 'hbatu', hbatu )
  183. CALL iom_rstput( 0, 0, inum4, 'hbatv', hbatv )
  184. CALL iom_rstput( 0, 0, inum4, 'hbatf', hbatf )
  185. !
  186. CALL iom_rstput( 0, 0, inum4, 'gsigt', gsigt ) ! ! scaling coef.
  187. CALL iom_rstput( 0, 0, inum4, 'gsigw', gsigw )
  188. CALL iom_rstput( 0, 0, inum4, 'gsi3w', gsi3w )
  189. CALL iom_rstput( 0, 0, inum4, 'esigt', esigt )
  190. CALL iom_rstput( 0, 0, inum4, 'esigw', esigw )
  191. !
  192. CALL iom_rstput( 0, 0, inum4, 'e3t_0', e3t_0 ) ! ! scale factors
  193. CALL iom_rstput( 0, 0, inum4, 'e3u_0', e3u_0 )
  194. CALL iom_rstput( 0, 0, inum4, 'e3v_0', e3v_0 )
  195. CALL iom_rstput( 0, 0, inum4, 'e3w_0', e3w_0 )
  196. CALL iom_rstput( 0, 0, inum4, 'rx1', rx1 ) ! ! Max. grid stiffness ratio
  197. !
  198. CALL iom_rstput( 0, 0, inum4, 'gdept_1d' , gdept_1d ) ! ! stretched system
  199. CALL iom_rstput( 0, 0, inum4, 'gdepw_1d' , gdepw_1d )
  200. CALL iom_rstput( 0, 0, inum4, 'gdept_0', gdept_0, ktype = jp_r4 )
  201. CALL iom_rstput( 0, 0, inum4, 'gdepw_0', gdepw_0, ktype = jp_r4 )
  202. ENDIF
  203. IF( ln_zps ) THEN ! z-coordinate - partial steps
  204. !
  205. IF( nmsh <= 6 ) THEN ! ! 3D vertical scale factors
  206. CALL iom_rstput( 0, 0, inum4, 'e3t_0', e3t_0 )
  207. CALL iom_rstput( 0, 0, inum4, 'e3u_0', e3u_0 )
  208. CALL iom_rstput( 0, 0, inum4, 'e3v_0', e3v_0 )
  209. CALL iom_rstput( 0, 0, inum4, 'e3w_0', e3w_0 )
  210. ELSE ! ! 2D masked bottom ocean scale factors
  211. DO jj = 1,jpj
  212. DO ji = 1,jpi
  213. e3tp(ji,jj) = e3t_0(ji,jj,mbkt(ji,jj)) * ssmask(ji,jj)
  214. e3wp(ji,jj) = e3w_0(ji,jj,mbkt(ji,jj)) * ssmask(ji,jj)
  215. END DO
  216. END DO
  217. CALL iom_rstput( 0, 0, inum4, 'e3t_ps', e3tp )
  218. CALL iom_rstput( 0, 0, inum4, 'e3w_ps', e3wp )
  219. END IF
  220. !
  221. IF( nmsh <= 3 ) THEN ! ! 3D depth
  222. CALL iom_rstput( 0, 0, inum4, 'gdept_0', gdept_0, ktype = jp_r4 )
  223. DO jk = 1,jpk
  224. DO jj = 1, jpjm1
  225. DO ji = 1, fs_jpim1 ! vector opt.
  226. zdepu(ji,jj,jk) = MIN( gdept_0(ji,jj,jk) , gdept_0(ji+1,jj ,jk) )
  227. zdepv(ji,jj,jk) = MIN( gdept_0(ji,jj,jk) , gdept_0(ji ,jj+1,jk) )
  228. END DO
  229. END DO
  230. END DO
  231. CALL lbc_lnk( zdepu, 'U', 1. ) ; CALL lbc_lnk( zdepv, 'V', 1. )
  232. CALL iom_rstput( 0, 0, inum4, 'gdepu', zdepu, ktype = jp_r4 )
  233. CALL iom_rstput( 0, 0, inum4, 'gdepv', zdepv, ktype = jp_r4 )
  234. CALL iom_rstput( 0, 0, inum4, 'gdepw_0', gdepw_0, ktype = jp_r4 )
  235. ELSE ! ! 2D bottom depth
  236. DO jj = 1,jpj
  237. DO ji = 1,jpi
  238. zprt(ji,jj) = gdept_0(ji,jj,mbkt(ji,jj) ) * ssmask(ji,jj)
  239. zprw(ji,jj) = gdepw_0(ji,jj,mbkt(ji,jj)+1) * ssmask(ji,jj)
  240. END DO
  241. END DO
  242. CALL iom_rstput( 0, 0, inum4, 'hdept', zprt, ktype = jp_r4 )
  243. CALL iom_rstput( 0, 0, inum4, 'hdepw', zprw, ktype = jp_r4 )
  244. ENDIF
  245. !
  246. CALL iom_rstput( 0, 0, inum4, 'gdept_1d', gdept_1d ) ! ! reference z-coord.
  247. CALL iom_rstput( 0, 0, inum4, 'gdepw_1d', gdepw_1d )
  248. CALL iom_rstput( 0, 0, inum4, 'e3t_1d' , e3t_1d )
  249. CALL iom_rstput( 0, 0, inum4, 'e3w_1d' , e3w_1d )
  250. ENDIF
  251. IF( ln_zco ) THEN
  252. ! ! z-coordinate - full steps
  253. CALL iom_rstput( 0, 0, inum4, 'gdept_1d', gdept_1d ) ! ! depth
  254. CALL iom_rstput( 0, 0, inum4, 'gdepw_1d', gdepw_1d )
  255. CALL iom_rstput( 0, 0, inum4, 'e3t_1d' , e3t_1d ) ! ! scale factors
  256. CALL iom_rstput( 0, 0, inum4, 'e3w_1d' , e3w_1d )
  257. ENDIF
  258. ! ! ============================
  259. ! ! close the files
  260. ! ! ============================
  261. SELECT CASE ( MOD(nmsh, 3) )
  262. CASE ( 1 )
  263. CALL iom_close( inum0 )
  264. CASE ( 2 )
  265. CALL iom_close( inum1 )
  266. CALL iom_close( inum2 )
  267. CASE ( 0 )
  268. CALL iom_close( inum2 )
  269. CALL iom_close( inum3 )
  270. CALL iom_close( inum4 )
  271. END SELECT
  272. !
  273. CALL wrk_dealloc( jpi, jpj, zprt, zprw )
  274. CALL wrk_dealloc( jpi, jpj, jpk, zdepu, zdepv )
  275. !
  276. IF( nn_timing == 1 ) CALL timing_stop('dom_wri')
  277. !
  278. END SUBROUTINE dom_wri
  279. SUBROUTINE dom_uniq( puniq, cdgrd )
  280. !!----------------------------------------------------------------------
  281. !! *** ROUTINE dom_uniq ***
  282. !!
  283. !! ** Purpose : identify unique point of a grid (TUVF)
  284. !!
  285. !! ** Method : 1) aplly lbc_lnk on an array with different values for each element
  286. !! 2) check which elements have been changed
  287. !!----------------------------------------------------------------------
  288. !
  289. CHARACTER(len=1) , INTENT(in ) :: cdgrd !
  290. REAL(wp), DIMENSION(:,:), INTENT(inout) :: puniq !
  291. !
  292. REAL(wp) :: zshift ! shift value link to the process number
  293. INTEGER :: ji ! dummy loop indices
  294. LOGICAL, DIMENSION(SIZE(puniq,1),SIZE(puniq,2),1) :: lldbl ! store whether each point is unique or not
  295. REAL(wp), POINTER, DIMENSION(:,:) :: ztstref
  296. !!----------------------------------------------------------------------
  297. !
  298. IF( nn_timing == 1 ) CALL timing_start('dom_uniq')
  299. !
  300. CALL wrk_alloc( jpi, jpj, ztstref )
  301. !
  302. ! build an array with different values for each element
  303. ! in mpp: make sure that these values are different even between process
  304. ! -> apply a shift value according to the process number
  305. zshift = jpi * jpj * ( narea - 1 )
  306. ztstref(:,:) = RESHAPE( (/ (zshift + REAL(ji,wp), ji = 1, jpi*jpj) /), (/ jpi, jpj /) )
  307. !
  308. puniq(:,:) = ztstref(:,:) ! default definition
  309. CALL lbc_lnk( puniq, cdgrd, 1. ) ! apply boundary conditions
  310. lldbl(:,:,1) = puniq(:,:) == ztstref(:,:) ! check which values have been changed
  311. !
  312. puniq(:,:) = 1. ! default definition
  313. ! fill only the inner part of the cpu with llbl converted into real
  314. puniq(nldi:nlei,nldj:nlej) = REAL( COUNT( lldbl(nldi:nlei,nldj:nlej,:), dim = 3 ) , wp )
  315. !
  316. CALL wrk_dealloc( jpi, jpj, ztstref )
  317. !
  318. IF( nn_timing == 1 ) CALL timing_stop('dom_uniq')
  319. !
  320. END SUBROUTINE dom_uniq
  321. !!======================================================================
  322. END MODULE domwri