crsdomwri.F90 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. MODULE crsdomwri
  2. !!======================================================================
  3. !! Coarse Ocean initialization : write the coarse ocean domain mesh and mask files
  4. !!======================================================================
  5. !! History : OPA ! 1997-02 (G. Madec) Original code
  6. !! 8.1 ! 1999-11 (M. Imbard) NetCDF FORMAT with IOIPSL
  7. !! NEMO 1.0 ! 2002-08 (G. Madec) F90 and several file
  8. !! 3.0 ! 2008-01 (S. Masson) add dom_uniq_crs
  9. !! 4.0 ! 2011-01 (A. R. Porter, STFC Daresbury) dynamical allocation
  10. !! ! 2012-06 (J. Simeon, C. Calone, C Ethe ) Reduced and modified for coarse grid
  11. !!----------------------------------------------------------------------
  12. !!----------------------------------------------------------------------
  13. !! crs_dom_wri : create and write mesh and mask file(s)
  14. !!----------------------------------------------------------------------
  15. USE timing ! Timing
  16. USE dom_oce ! ocean space and time domain
  17. USE in_out_manager ! I/O manager
  18. USE par_kind, ONLY: wp
  19. USE lib_mpp ! MPP library
  20. USE iom_def
  21. USE iom
  22. USE crs ! coarse grid domain
  23. USE crsdom ! coarse grid domain
  24. USE crslbclnk ! crs mediator to lbclnk
  25. USE wrk_nemo ! Working array
  26. IMPLICIT NONE
  27. PRIVATE
  28. PUBLIC crs_dom_wri ! routine called by crsini.F90
  29. !! $Id: crsdomwri.F90 2355 2015-05-20 07:11:50Z ufla $
  30. CONTAINS
  31. SUBROUTINE crs_dom_wri
  32. !!----------------------------------------------------------------------
  33. !! *** ROUTINE crs_dom_wri ***
  34. !!
  35. !! ** Purpose : Create the NetCDF file(s) which contain(s) all the
  36. !! ocean domain informations (mesh and mask arrays). This (these)
  37. !! file(s) is (are) used for visualisation (SAXO software) and
  38. !! diagnostic computation.
  39. !!
  40. !! ** Method : Write in a file all the arrays generated in routines
  41. !! crsini for meshes and mask. In three separate files:
  42. !! domain size, horizontal grid-point position,
  43. !! masks, depth and vertical scale factors
  44. !!
  45. !! ** Output files : mesh_hgr_crs.nc, mesh_zgr_crs.nc, mesh_mask.nc
  46. !!----------------------------------------------------------------------
  47. !!
  48. INTEGER :: inum0 ! temprary units for 'mesh_mask.nc' file
  49. INTEGER :: inum1 ! temprary units for 'mesh.nc' file
  50. INTEGER :: inum2 ! temprary units for 'mask.nc' file
  51. INTEGER :: inum3 ! temprary units for 'mesh_hgr.nc' file
  52. INTEGER :: inum4 ! temprary units for 'mesh_zgr.nc' file
  53. INTEGER :: iif, iil, ijf, ijl
  54. CHARACTER(len=21) :: clnam0 ! filename (mesh and mask informations)
  55. CHARACTER(len=21) :: clnam1 ! filename (mesh informations)
  56. CHARACTER(len=21) :: clnam2 ! filename (mask informations)
  57. CHARACTER(len=21) :: clnam3 ! filename (horizontal mesh informations)
  58. CHARACTER(len=21) :: clnam4 ! filename (vertical mesh informations)
  59. INTEGER :: ji, jj, jk ! dummy loop indices
  60. ! ! workspaces
  61. REAL(wp), POINTER, DIMENSION(:,: ) :: zprt, zprw
  62. REAL(wp), POINTER, DIMENSION(:,:,:) :: zdepu, zdepv
  63. REAL(wp), POINTER, DIMENSION(:,: ) :: ze3tp, ze3wp
  64. !!----------------------------------------------------------------------
  65. !
  66. IF( nn_timing == 1 ) CALL timing_start('crs_dom_wri')
  67. !
  68. CALL wrk_alloc( jpi_crs, jpj_crs, zprt , zprw )
  69. CALL wrk_alloc( jpi_crs, jpj_crs, ze3tp, ze3wp )
  70. CALL wrk_alloc( jpi_crs, jpj_crs, jpk, zdepu, zdepv )
  71. ze3tp(:,:) = 0.0
  72. ze3wp(:,:) = 0.0
  73. !
  74. IF(lwp) WRITE(numout,*)
  75. IF(lwp) WRITE(numout,*) 'crs_dom_wri : create NetCDF mesh and mask information file(s)'
  76. IF(lwp) WRITE(numout,*) '~~~~~~~'
  77. clnam0 = 'mesh_mask_crs' ! filename (mesh and mask informations)
  78. clnam1 = 'mesh_crs' ! filename (mesh informations)
  79. clnam2 = 'mask_crs' ! filename (mask informations)
  80. clnam3 = 'mesh_hgr_crs' ! filename (horizontal mesh informations)
  81. clnam4 = 'mesh_zgr_crs' ! filename (vertical mesh informations)
  82. SELECT CASE ( MOD(nn_msh_crs, 3) )
  83. ! ! ============================
  84. CASE ( 1 ) ! create 'mesh_mask.nc' file
  85. ! ! ============================
  86. CALL iom_open( TRIM(clnam0), inum0, ldwrt = .TRUE., kiolib = jprstlib )
  87. inum2 = inum0 ! put all the informations
  88. inum3 = inum0 ! in unit inum0
  89. inum4 = inum0
  90. ! ! ============================
  91. CASE ( 2 ) ! create 'mesh.nc' and
  92. ! ! 'mask.nc' files
  93. ! ! ============================
  94. CALL iom_open( TRIM(clnam1), inum1, ldwrt = .TRUE., kiolib = jprstlib )
  95. CALL iom_open( TRIM(clnam2), inum2, ldwrt = .TRUE., kiolib = jprstlib )
  96. inum3 = inum1 ! put mesh informations
  97. inum4 = inum1 ! in unit inum1
  98. ! ! ============================
  99. CASE ( 0 ) ! create 'mesh_hgr.nc'
  100. ! ! 'mesh_zgr.nc' and
  101. ! ! 'mask.nc' files
  102. ! ! ============================
  103. CALL iom_open( TRIM(clnam2), inum2, ldwrt = .TRUE., kiolib = jprstlib )
  104. CALL iom_open( TRIM(clnam3), inum3, ldwrt = .TRUE., kiolib = jprstlib )
  105. CALL iom_open( TRIM(clnam4), inum4, ldwrt = .TRUE., kiolib = jprstlib )
  106. !
  107. END SELECT
  108. !========================================================
  109. ! ! masks (inum2)
  110. CALL iom_rstput( 0, 0, inum2, 'tmask', tmask_crs, ktype = jp_i1 ) ! ! land-sea mask
  111. CALL iom_rstput( 0, 0, inum2, 'umask', umask_crs, ktype = jp_i1 )
  112. CALL iom_rstput( 0, 0, inum2, 'vmask', vmask_crs, ktype = jp_i1 )
  113. CALL iom_rstput( 0, 0, inum2, 'fmask', fmask_crs, ktype = jp_i1 )
  114. tmask_i_crs(:,:) = tmask_crs(:,:,1)
  115. iif = jpreci
  116. iil = nlci_crs - jpreci + 1
  117. ijf = jpreci
  118. ijl = nlcj_crs - jprecj + 1
  119. tmask_i_crs( 1:iif , : ) = 0._wp
  120. tmask_i_crs(iil:jpi_crs, : ) = 0._wp
  121. tmask_i_crs( : , 1:ijf ) = 0._wp
  122. tmask_i_crs( : ,ijl:jpj_crs) = 0._wp
  123. tpol_crs(1:jpiglo_crs,:) = 1._wp
  124. fpol_crs(1:jpiglo_crs,:) = 1._wp
  125. IF( jperio == 3 .OR. jperio == 4 ) THEN
  126. tpol_crs(jpiglo_crs/2+1:jpiglo_crs,:) = 0._wp
  127. fpol_crs( 1 :jpiglo_crs,:) = 0._wp
  128. IF( mjg_crs(nlej_crs) == jpiglo_crs ) THEN
  129. DO ji = iif+1, iil-1
  130. tmask_i_crs(ji,nlej_crs-1) = tmask_i_crs(ji,nlej_crs-1) &
  131. & * tpol_crs(mig_crs(ji),1)
  132. ENDDO
  133. ENDIF
  134. ENDIF
  135. IF( jperio == 5 .OR. jperio == 6 ) THEN
  136. tpol_crs( 1 :jpiglo_crs,:)=0._wp
  137. fpol_crs(jpiglo_crs/2+1:jpiglo_crs,:)=0._wp
  138. ENDIF
  139. CALL iom_rstput( 0, 0, inum2, 'tmaskutil', tmask_i_crs, ktype = jp_i1 )
  140. ! ! unique point mask
  141. CALL dom_uniq_crs( zprw, 'U' )
  142. zprt = umask_crs(:,:,1) * zprw
  143. CALL iom_rstput( 0, 0, inum2, 'umaskutil', zprt, ktype = jp_i1 )
  144. CALL dom_uniq_crs( zprw, 'V' )
  145. zprt = vmask_crs(:,:,1) * zprw
  146. CALL iom_rstput( 0, 0, inum2, 'vmaskutil', zprt, ktype = jp_i1 )
  147. CALL dom_uniq_crs( zprw, 'F' )
  148. zprt = fmask_crs(:,:,1) * zprw
  149. CALL iom_rstput( 0, 0, inum2, 'fmaskutil', zprt, ktype = jp_i1 )
  150. !========================================================
  151. ! ! horizontal mesh (inum3)
  152. CALL iom_rstput( 0, 0, inum3, 'glamt', glamt_crs, ktype = jp_r4 ) ! ! latitude
  153. CALL iom_rstput( 0, 0, inum3, 'glamu', glamu_crs, ktype = jp_r4 )
  154. CALL iom_rstput( 0, 0, inum3, 'glamv', glamv_crs, ktype = jp_r4 )
  155. CALL iom_rstput( 0, 0, inum3, 'glamf', glamf_crs, ktype = jp_r4 )
  156. CALL iom_rstput( 0, 0, inum3, 'gphit', gphit_crs, ktype = jp_r4 ) ! ! longitude
  157. CALL iom_rstput( 0, 0, inum3, 'gphiu', gphiu_crs, ktype = jp_r4 )
  158. CALL iom_rstput( 0, 0, inum3, 'gphiv', gphiv_crs, ktype = jp_r4 )
  159. CALL iom_rstput( 0, 0, inum3, 'gphif', gphif_crs, ktype = jp_r4 )
  160. CALL iom_rstput( 0, 0, inum3, 'e1t', e1t_crs, ktype = jp_r8 ) ! ! e1 scale factors
  161. CALL iom_rstput( 0, 0, inum3, 'e1u', e1u_crs, ktype = jp_r8 )
  162. CALL iom_rstput( 0, 0, inum3, 'e1v', e1v_crs, ktype = jp_r8 )
  163. CALL iom_rstput( 0, 0, inum3, 'e1f', e1f_crs, ktype = jp_r8 )
  164. CALL iom_rstput( 0, 0, inum3, 'e2t', e2t_crs, ktype = jp_r8 ) ! ! e2 scale factors
  165. CALL iom_rstput( 0, 0, inum3, 'e2u', e2u_crs, ktype = jp_r8 )
  166. CALL iom_rstput( 0, 0, inum3, 'e2v', e2v_crs, ktype = jp_r8 )
  167. CALL iom_rstput( 0, 0, inum3, 'e2f', e2f_crs, ktype = jp_r8 )
  168. CALL iom_rstput( 0, 0, inum3, 'ff', ff_crs, ktype = jp_r8 ) ! ! coriolis factor
  169. !========================================================
  170. ! ! vertical mesh (inum4)
  171. ! ! note that mbkt is set to 1 over land ==> use surface tmask_crs
  172. zprt(:,:) = tmask_crs(:,:,1) * REAL( mbkt_crs(:,:) , wp )
  173. CALL iom_rstput( 0, 0, inum4, 'mbathy', zprt, ktype = jp_i2 ) ! ! nb of ocean T-points
  174. IF( ln_zps ) THEN ! z-coordinate - partial steps
  175. IF ( nn_msh_crs <= 6 ) THEN
  176. CALL iom_rstput( 0, 0, inum4, 'e3t', e3t_crs )
  177. CALL iom_rstput( 0, 0, inum4, 'e3w', e3w_crs )
  178. CALL iom_rstput( 0, 0, inum4, 'e3u', e3u_crs )
  179. CALL iom_rstput( 0, 0, inum4, 'e3v', e3v_crs )
  180. ELSE
  181. DO jj = 1,jpj_crs
  182. DO ji = 1,jpi_crs
  183. ze3tp(ji,jj) = e3t_crs(ji,jj,mbkt_crs(ji,jj)) * tmask_crs(ji,jj,1)
  184. ze3wp(ji,jj) = e3w_crs(ji,jj,mbkt_crs(ji,jj)) * tmask_crs(ji,jj,1)
  185. END DO
  186. END DO
  187. CALL crs_lbc_lnk( ze3tp,'T', 1.0 )
  188. CALL crs_lbc_lnk( ze3wp,'W', 1.0 )
  189. CALL iom_rstput( 0, 0, inum4, 'e3t_ps', ze3tp )
  190. CALL iom_rstput( 0, 0, inum4, 'e3w_ps', ze3wp )
  191. ENDIF
  192. IF ( nn_msh_crs <= 3 ) THEN
  193. CALL iom_rstput( 0, 0, inum4, 'gdept', gdept_crs, ktype = jp_r4 )
  194. DO jk = 1,jpk
  195. DO jj = 1, jpj_crsm1
  196. DO ji = 1, jpi_crsm1 ! jes what to do for fs_jpim1??vector opt.
  197. zdepu(ji,jj,jk) = MIN( gdept_crs(ji,jj,jk) , gdept_crs(ji+1,jj ,jk) ) * umask_crs(ji,jj,jk)
  198. zdepv(ji,jj,jk) = MIN( gdept_crs(ji,jj,jk) , gdept_crs(ji ,jj+1,jk) ) * vmask_crs(ji,jj,jk)
  199. END DO
  200. END DO
  201. END DO
  202. CALL crs_lbc_lnk( zdepu,'U', 1. ) ; CALL crs_lbc_lnk( zdepv,'V', 1. )
  203. CALL iom_rstput( 0, 0, inum4, 'gdepu', zdepu, ktype = jp_r4 )
  204. CALL iom_rstput( 0, 0, inum4, 'gdepv', zdepv, ktype = jp_r4 )
  205. CALL iom_rstput( 0, 0, inum4, 'gdepw', gdepw_crs, ktype = jp_r4 )
  206. ELSE
  207. DO jj = 1,jpj_crs
  208. DO ji = 1,jpi_crs
  209. zprt(ji,jj) = gdept_0(ji,jj,mbkt(ji,jj) ) * tmask(ji,jj,1)
  210. zprw(ji,jj) = gdepw_0(ji,jj,mbkt(ji,jj)+1) * tmask(ji,jj,1)
  211. END DO
  212. END DO
  213. CALL iom_rstput( 0, 0, inum4, 'hdept', zprt, ktype = jp_r4 )
  214. CALL iom_rstput( 0, 0, inum4, 'hdepw', zprw, ktype = jp_r4 )
  215. ENDIF
  216. CALL iom_rstput( 0, 0, inum4, 'gdept_1d', gdept_1d ) ! ! reference z-coord.
  217. CALL iom_rstput( 0, 0, inum4, 'gdepw_1d', gdepw_1d )
  218. CALL iom_rstput( 0, 0, inum4, 'e3t_1d' , e3t_1d )
  219. CALL iom_rstput( 0, 0, inum4, 'e3w_1d' , e3w_1d )
  220. CALL iom_rstput( 0, 0, inum4, 'ocean_volume_t', ocean_volume_crs_t )
  221. CALL iom_rstput( 0, 0, inum4, 'facvol_t' , facvol_t )
  222. CALL iom_rstput( 0, 0, inum4, 'facvol_w' , facvol_w )
  223. CALL iom_rstput( 0, 0, inum4, 'facsurfu' , facsurfu )
  224. CALL iom_rstput( 0, 0, inum4, 'facsurfv' , facsurfv )
  225. CALL iom_rstput( 0, 0, inum4, 'e1e2w_msk', e1e2w_msk )
  226. CALL iom_rstput( 0, 0, inum4, 'e2e3u_msk', e2e3u_msk )
  227. CALL iom_rstput( 0, 0, inum4, 'e1e3v_msk', e1e3v_msk )
  228. CALL iom_rstput( 0, 0, inum4, 'e1e2w' , e1e2w_crs )
  229. CALL iom_rstput( 0, 0, inum4, 'e2e3u' , e2e3u_crs )
  230. CALL iom_rstput( 0, 0, inum4, 'e1e3v' , e1e3v_crs )
  231. CALL iom_rstput( 0, 0, inum4, 'bt' , bt_crs )
  232. CALL iom_rstput( 0, 0, inum4, 'r1_bt' , r1_bt_crs )
  233. CALL iom_rstput( 0, 0, inum4, 'crs_surfu_wgt', crs_surfu_wgt )
  234. CALL iom_rstput( 0, 0, inum4, 'crs_surfv_wgt', crs_surfv_wgt )
  235. CALL iom_rstput( 0, 0, inum4, 'crs_volt_wgt' , crs_volt_wgt )
  236. ENDIF
  237. IF( ln_zco ) THEN
  238. ! ! z-coordinate - full steps
  239. CALL iom_rstput( 0, 0, inum4, 'gdept_1d', gdept_1d ) ! ! depth
  240. CALL iom_rstput( 0, 0, inum4, 'gdepw_1d', gdepw_1d )
  241. CALL iom_rstput( 0, 0, inum4, 'e3t_1d' , e3t_1d ) ! ! scale factors
  242. CALL iom_rstput( 0, 0, inum4, 'e3w_1d' , e3w_1d )
  243. ENDIF
  244. ! ! ============================
  245. ! ! close the files
  246. ! ! ============================
  247. SELECT CASE ( MOD(nn_msh_crs, 3) )
  248. CASE ( 1 )
  249. CALL iom_close( inum0 )
  250. CASE ( 2 )
  251. CALL iom_close( inum1 )
  252. CALL iom_close( inum2 )
  253. CASE ( 0 )
  254. CALL iom_close( inum2 )
  255. CALL iom_close( inum3 )
  256. CALL iom_close( inum4 )
  257. END SELECT
  258. !
  259. CALL wrk_dealloc( jpi_crs, jpj_crs, zprt , zprw )
  260. CALL wrk_dealloc( jpi_crs, jpj_crs, ze3tp, ze3wp )
  261. CALL wrk_dealloc( jpi_crs, jpj_crs, jpk, zdepu, zdepv )
  262. !
  263. IF( nn_timing == 1 ) CALL timing_stop('crs_dom_wri')
  264. !
  265. END SUBROUTINE crs_dom_wri
  266. SUBROUTINE dom_uniq_crs( puniq, cdgrd )
  267. !!----------------------------------------------------------------------
  268. !! *** ROUTINE crs_dom_uniq_crs ***
  269. !!
  270. !! ** Purpose : identify unique point of a grid (TUVF)
  271. !!
  272. !! ** Method : 1) apply crs_lbc_lnk on an array with different values for each element
  273. !! 2) check which elements have been changed
  274. !!----------------------------------------------------------------------
  275. !
  276. CHARACTER(len=1) , INTENT(in ) :: cdgrd !
  277. REAL(wp), DIMENSION(:,:), INTENT(inout) :: puniq !
  278. !
  279. REAL(wp) :: zshift ! shift value link to the process number
  280. INTEGER :: ji ! dummy loop indices
  281. LOGICAL, DIMENSION(SIZE(puniq,1),SIZE(puniq,2),1) :: lldbl ! store whether each point is unique or not
  282. REAL(wp), POINTER, DIMENSION(:,:) :: ztstref
  283. !!----------------------------------------------------------------------
  284. !
  285. IF( nn_timing == 1 ) CALL timing_start('crs_dom_uniq_crs')
  286. !
  287. CALL wrk_alloc( jpi_crs, jpj_crs, ztstref )
  288. !
  289. ! build an array with different values for each element
  290. ! in mpp: make sure that these values are different even between process
  291. ! -> apply a shift value according to the process number
  292. zshift = jpi_crs * jpj_crs * ( narea - 1 )
  293. ztstref(:,:) = RESHAPE( (/ (zshift + REAL(ji,wp), ji = 1, jpi_crs*jpj_crs) /), (/ jpi_crs, jpj_crs /) )
  294. !
  295. puniq(:,:) = ztstref(:,:) ! default definition
  296. CALL crs_lbc_lnk( puniq,cdgrd, 1. ) ! apply boundary conditions
  297. lldbl(:,:,1) = puniq(:,:) == ztstref(:,:) ! check which values have been changed
  298. !
  299. puniq(:,:) = 1. ! default definition
  300. ! fill only the inner part of the cpu with llbl converted into real
  301. puniq(nldi_crs:nlei_crs,nldj_crs:nlej_crs) = REAL( COUNT( lldbl(nldi_crs:nlei_crs,nldj_crs:nlej_crs,:), dim = 3 ) , wp )
  302. !
  303. CALL wrk_dealloc( jpi_crs, jpj_crs, ztstref )
  304. !
  305. IF( nn_timing == 1 ) CALL timing_stop('crs_dom_uniq_crs')
  306. !
  307. END SUBROUTINE dom_uniq_crs
  308. !!======================================================================
  309. END MODULE crsdomwri