scripgrid_mod.F90 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759
  1. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  2. !
  3. ! This module creates grid description files for input to the SCRIP code
  4. !
  5. !-----------------------------------------------------------------------
  6. MODULE scripgrid_mod
  7. USE kinds_mod
  8. USE constants
  9. USE iounits
  10. USE netcdf
  11. USE netcdf_mod
  12. IMPLICIT NONE
  13. !-----------------------------------------------------------------------
  14. ! module variables that describe the grid
  15. INTEGER (kind=int_kind), parameter :: &
  16. grid_rank = 2, &
  17. grid_corners = 4
  18. INTEGER (kind=int_kind) :: nx, ny, grid_size
  19. INTEGER (kind=int_kind), dimension(2) :: &
  20. grid_dims, & ! size of x, y dimensions
  21. grid_dim_ids ! ids of the x, y dimensions
  22. INTEGER (kind=int_kind), ALLOCATABLE, DIMENSION(:) :: &
  23. grid_imask ! land-sea mask
  24. REAL (kind=int_kind), ALLOCATABLE, DIMENSION(:) :: &
  25. grid_center_lat, & ! lat/lon coordinates for
  26. grid_center_lon ! each grid center in degrees
  27. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:,:) :: &
  28. grid_corner_lat, & ! lat/lon coordinates for
  29. grid_corner_lon ! each grid corner in degrees
  30. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:,:,:) :: &
  31. corner_lon, &
  32. corner_lat
  33. REAL (kind=dbl_kind), PARAMETER :: circle = 360.0
  34. !-----------------------------------------------------------------------
  35. ! module variables that describe the netcdf file
  36. INTEGER (kind=int_kind) :: &
  37. ncstat, & ! general netCDF status variable
  38. ncid_in
  39. CONTAINS
  40. ! ==============================================================================
  41. SUBROUTINE convert(nm_in)
  42. ! -----------------------------------------------------------------------------
  43. ! - input variables
  44. CHARACTER(char_len), INTENT(in) :: &
  45. nm_in
  46. ! -----------------------------------------------------------------------------
  47. ! - local variables
  48. CHARACTER(char_len) :: &
  49. nemo_file, input_file, method, input_lon, input_lat, datagrid_file, &
  50. nemogrid_file, nemo_lon, nemo_lat, corn_lon, corn_lat, nemo_mask, input_mask
  51. INTEGER (kind=int_kind), dimension(2) :: &
  52. offset
  53. INTEGER (kind=int_kind) :: &
  54. iunit, nemo_mask_value, input_mask_value
  55. namelist /grid_inputs/ nemo_file, input_file, datagrid_file, nemogrid_file, &
  56. method, input_lon, input_lat, nemo_lon, nemo_lat, &
  57. nemo_mask, nemo_mask_value, input_mask, input_mask_value
  58. !-----------------------------------------------------------------------
  59. ! - namelist describing the processing
  60. ! note that mask_value is the minimum good value,
  61. ! so that where the mask is less than the value is masked
  62. nemo_file = "coordinates.nc"
  63. nemo_lon = "glamt"
  64. nemo_lat = "gphit"
  65. input_lon = "lon"
  66. input_lat = "lat"
  67. input_mask = "none"
  68. input_mask_value = 0
  69. datagrid_file = 'remap_data_grid.nc'
  70. nemogrid_file = 'remap_nemo_grid.nc'
  71. call get_unit(iunit)
  72. open(iunit, file=nm_in, status='old', form='formatted')
  73. read(iunit, nml=grid_inputs)
  74. call release_unit(iunit)
  75. if (nemo_lon(1:4) .ne. 'glam' .or. nemo_lat(1:4) .ne. 'gphi') then
  76. write(6,*) 'lon name does not start with "glam" or lat name does not start with "gphi"'
  77. stop
  78. endif
  79. ! set up the names of the corner variables for a given input
  80. ! the offset represents what needs to be added to (i,j) to get to the correct
  81. ! element in the corner arrays to correspond to the point northeast of the center
  82. if (nemo_lon(5:5) == "t") then
  83. corn_lon = "glamf"
  84. corn_lat = "gphif"
  85. offset = (/ 0,0 /)
  86. else if (nemo_lon(5:5) == "u") then
  87. corn_lon = "glamv"
  88. corn_lat = "gphiv"
  89. offset = (/ 1,0 /)
  90. else if (nemo_lon(5:5) == "v") then
  91. corn_lon = "glamu"
  92. corn_lat = "gphiu"
  93. offset = (/ 0,1 /)
  94. else
  95. write(6,*) 'unknown nemo_lon name'
  96. stop
  97. endif
  98. write(6,*) "processing " // trim(nemo_file)
  99. call convertNEMO(nemo_file, nemo_lon, nemo_lat, corn_lon, corn_lat, &
  100. offset, nemogrid_file)
  101. write(6,*) "processing regular grid"
  102. call convertFLUX(input_file, input_lon, input_lat, &
  103. input_mask, input_mask_value, datagrid_file)
  104. END SUBROUTINE convert
  105. ! ==============================================================================
  106. SUBROUTINE convertNEMO(grid_file_in, cent_lon, cent_lat, corn_lon, corn_lat, &
  107. off, grid_file_out)
  108. !-----------------------------------------------------------------------
  109. !
  110. ! This routine converts a NEMO coordinates.nc file to a remapping grid file.
  111. !
  112. CHARACTER(char_len), INTENT(in) :: cent_lon, cent_lat, corn_lon, corn_lat
  113. INTEGER (kind=int_kind), INTENT(in), DIMENSION(2) :: off
  114. CHARACTER(char_len), INTENT(in) :: grid_file_out
  115. CHARACTER(char_len), INTENT(in) :: grid_file_in
  116. !-----------------------------------------------------------------------
  117. ! module variables that describe the grid
  118. CHARACTER(char_len), parameter :: &
  119. grid_name = 'Remapped NEMO grid for SCRIP'
  120. !-----------------------------------------------------------------------
  121. ! grid coordinates and masks
  122. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:,:) :: &
  123. clon, clat, & ! expanded corner arrays
  124. glam, & ! center longitude
  125. gphi, & ! center latitude
  126. glamc, & ! corner longitude
  127. gphic ! corner latitude
  128. !-----------------------------------------------------------------------
  129. ! other local variables
  130. INTEGER (kind=int_kind) :: i, j, n, iunit, im1, jm1, imid, isame, ic, jc
  131. INTEGER (kind=int_kind) :: varid_lam, varid_phi, varid_lamc, varid_phic
  132. INTEGER (kind=int_kind) :: jdim
  133. INTEGER (kind=int_kind), dimension(4) :: grid_dimids ! input fields have 4 dims
  134. REAL (kind=dbl_kind) :: tmplon, dxt, dyt
  135. !-----------------------------------------------------------------------
  136. ! read in grid info
  137. !
  138. ! For NEMO input grids, assume that variable names are glam, glamc etc.
  139. ! Assume that 1st 2 dimensions of these variables are x and y directions.
  140. ! These assumptions are made by NEMO, so should be valid for coordinates.nc.
  141. !
  142. ! write in nf90 calls (without error handling) and then think about
  143. ! making more readable by taking chunks into ncutil
  144. !
  145. ncstat = nf90_open( grid_file_in, NF90_NOWRITE, ncid_in )
  146. call netcdf_error_handler(ncstat)
  147. ! find dimids for 'glam'
  148. ! use dimids to get dimlengths
  149. ! allocate glam array
  150. ! get glam from file
  151. ncstat = nf90_inq_varid( ncid_in, cent_lon, varid_lam )
  152. call netcdf_error_handler(ncstat)
  153. ncstat = nf90_inq_varid( ncid_in, corn_lon, varid_lamc )
  154. call netcdf_error_handler(ncstat)
  155. ncstat = nf90_inq_varid( ncid_in, cent_lat, varid_phi )
  156. call netcdf_error_handler(ncstat)
  157. ncstat = nf90_inq_varid( ncid_in, corn_lat, varid_phic )
  158. call netcdf_error_handler(ncstat)
  159. ncstat = nf90_inquire_variable( ncid_in, varid_lam, dimids=grid_dimids(:) )
  160. call netcdf_error_handler(ncstat)
  161. DO jdim = 1, SIZE(grid_dims)
  162. ncstat = nf90_inquire_dimension( ncid_in, grid_dimids(jdim), &
  163. len=grid_dims(jdim) )
  164. call netcdf_error_handler(ncstat)
  165. END DO
  166. nx = grid_dims(1)
  167. ny = grid_dims(2)
  168. grid_size = nx * ny
  169. WRITE(*,FMT='("Input grid dimensions are:",2i6)') nx, ny
  170. ! assume that dimensions are all the same as glam
  171. ALLOCATE( glam(nx,ny), glamc(nx,ny), gphi(nx,ny), gphic(nx,ny) )
  172. ncstat = nf90_get_var( ncid_in, varid_lam, glam(:,:) )
  173. call netcdf_error_handler(ncstat)
  174. ncstat = nf90_get_var( ncid_in, varid_lamc, glamc(:,:) )
  175. call netcdf_error_handler(ncstat)
  176. ncstat = nf90_get_var( ncid_in, varid_phi, gphi(:,:) )
  177. call netcdf_error_handler(ncstat)
  178. ncstat = nf90_get_var( ncid_in, varid_phic, gphic(:,:) )
  179. call netcdf_error_handler(ncstat)
  180. !-----------------------------------------------------------------------
  181. ! - Mask is all ocean for now
  182. ALLOCATE( grid_imask(grid_size) )
  183. grid_imask(:) = 1
  184. !-----------------------------------------------------------------------
  185. ! corners are arranged as follows: 4 3
  186. ! 1 2
  187. !
  188. ! Assume that cyclic grids have 2 wrap columns in coordinates.nc
  189. ! (this is the case for ORCA grids)
  190. !
  191. ! -----------------------------------------------------------------------------
  192. ! create a single pair of arrays for the corners where clon(1,1) corresponds
  193. ! to the south west corner of a box containing glam(1,1)
  194. ! various special cases then apply
  195. ! bottom row: assume clon(:,j) = clon(:,j+1)
  196. ALLOCATE ( clon(nx+1,ny+1), clat(nx+1,ny+1) )
  197. ! first the easy internal points
  198. DO j = 2,ny
  199. DO i = 2,nx
  200. ic = i + off(1) - 1
  201. jc = j + off(2) - 1
  202. clon(i,j) = glamc(ic,jc)
  203. clat(i,j) = gphic(ic,jc)
  204. ENDDO
  205. ENDDO
  206. ! then the tricky boundary points
  207. imid = (nx-1)/2 + 1
  208. DO j = 1,ny+1,ny
  209. DO i = 1,nx+1,nx
  210. ic = i + off(1) - 1
  211. jc = j + off(2) - 1
  212. if (ic == 0 .and. jc == 0) then
  213. clon(i,j) = glamc(nx,1)
  214. clat(i,j) = gphic(nx,1) - (gphic(nx,2)-gphic(nx,1))
  215. else if (ic == nx+1 .and. jc == 0) then
  216. clon(i,j) = glamc(1,1)
  217. clat(i,j) = gphic(1,1) - (gphic(1,2)-gphic(1,1))
  218. else if (ic == 0 .and. jc == ny+1) then
  219. isame = 2*imid - nx + 1
  220. clon(i,j) = glamc(isame,jc-1)
  221. clat(i,j) = gphic(isame,jc-1)
  222. else if (ic == nx+1 .and. jc == ny+1) then
  223. isame = 2*imid
  224. clon(i,j) = glamc(isame,jc-1)
  225. clat(i,j) = gphic(isame,jc-1)
  226. else if (ic == 0) then
  227. clon(i,j) = glamc(nx,jc)
  228. clat(i,j) = gphic(nx,jc)
  229. else if (jc == 0) then
  230. clon(i,j) = glamc(ic,1)
  231. clat(i,j) = gphic(ic,1) - (gphic(ic,2)-gphic(ic,1))
  232. else if (ic == nx+1) then
  233. clon(i,j) = glamc(1,jc)
  234. clat(i,j) = gphic(1,jc)
  235. else if (jc == ny+1) then
  236. isame = 2*imid - ic + 1
  237. clon(i,j) = glamc(isame,jc-1)
  238. clat(i,j) = gphic(isame,jc-1)
  239. endif
  240. ENDDO
  241. ENDDO
  242. ALLOCATE ( corner_lon(4,nx,ny), corner_lat(4,nx,ny) )
  243. ! top-right corner
  244. corner_lon(3,:,:) = clon(2:nx+1,2:ny+1)
  245. corner_lat(3,:,:) = clat(2:nx+1,2:ny+1)
  246. ! top-left corner
  247. corner_lon(4,:,:) = clon(1:nx,2:ny+1)
  248. corner_lat(4,:,:) = clat(1:nx,2:ny+1)
  249. ! bottom-right corner
  250. corner_lon(2,:,:) = clon(2:nx+1,1:ny)
  251. corner_lat(2,:,:) = clat(2:nx+1,1:ny)
  252. ! bottom-left corner
  253. corner_lon(1,:,:) = clon(1:nx,1:ny)
  254. corner_lat(1,:,:) = clat(1:nx,1:ny)
  255. ! For [N, E, W]-ward extrapolation near the poles, should we use stereographic (or
  256. ! similar) projection? This issue will come for V,F interpolation, and for all
  257. ! grids with non-cyclic grids.
  258. ! -----------------------------------------------------------------------------
  259. ! correct for 0,2pi longitude crossings
  260. ! (In practice this means putting all corners into 0,2pi range
  261. ! and ensuring that no box corners are miles from each other.
  262. ! 3pi/2 is used as threshold - I think this is quite arbitrary.)
  263. corner_lon(:,:,:) = MODULO( corner_lon(:,:,:), circle )
  264. DO n = 2, grid_corners
  265. WHERE ( corner_lon(n,:,:) - corner_lon(n-1,:,:) < -three*circle*0.25 )
  266. corner_lon(n,:,:) = corner_lon(n,:,:) + circle
  267. ELSEWHERE( corner_lon(n,:,:) - corner_lon(n-1,:,:) > three*circle*0.25 )
  268. corner_lon(n,:,:) = corner_lon(n,:,:) - circle
  269. END WHERE
  270. END DO
  271. ! -----------------------------------------------------------------------------
  272. ! - put longitudes on smooth grid
  273. ! call mouldlon(glam,nx,ny)
  274. ! call mouldlon(corner_lon(1,:,:),nx,ny)
  275. ! call mouldlon(corner_lon(2,:,:),nx,ny)
  276. ! call mouldlon(corner_lon(3,:,:),nx,ny)
  277. ! call mouldlon(corner_lon(4,:,:),nx,ny)
  278. ! -----------------------------------------------------------------------------
  279. ! - reshape for SCRIP input format
  280. ALLOCATE( grid_center_lon(grid_size), grid_center_lat(grid_size) )
  281. grid_center_lon(:) = RESHAPE( glam(:,:), (/ grid_size /) )
  282. grid_center_lat(:) = RESHAPE( gphi(:,:), (/ grid_size /) )
  283. DEALLOCATE( glam, gphi, glamc, gphic )
  284. ALLOCATE( grid_corner_lon(4, grid_size), grid_corner_lat(4, grid_size) )
  285. grid_corner_lon(:,:) = RESHAPE( corner_lon(:,:,:), (/ 4, grid_size /) )
  286. grid_corner_lat(:,:) = RESHAPE( corner_lat(:,:,:), (/ 4, grid_size /) )
  287. DEALLOCATE( corner_lon, corner_lat )
  288. CALL createSCRIPgrid(grid_file_out, grid_name)
  289. END SUBROUTINE convertNEMO
  290. ! ==============================================================================
  291. SUBROUTINE convertFLUX(grid_file_in, name_lon, name_lat, &
  292. name_mask, value_mask, grid_file_out)
  293. !-----------------------------------------------------------------------
  294. !
  295. ! This routine creates a remapping grid file from an input grid.
  296. !
  297. !-----------------------------------------------------------------------
  298. CHARACTER(char_len), INTENT(in) :: &
  299. grid_file_in, name_lon, name_lat, name_mask, grid_file_out
  300. INTEGER (kind=int_kind) :: value_mask
  301. !-----------------------------------------------------------------------
  302. ! variables that describe the grid
  303. CHARACTER(char_len), parameter :: &
  304. grid_name = 'Remapped regular grid for SCRIP'
  305. !-----------------------------------------------------------------------
  306. ! grid coordinates (note that a flux file just has lon and lat)
  307. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:) :: &
  308. lam, phi
  309. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:,:) :: &
  310. glam, & ! longitude
  311. gphi, & ! latitude
  312. glamc, &
  313. gphic
  314. REAL (kind=dbl_kind), ALLOCATABLE, DIMENSION(:,:) :: mask
  315. !-----------------------------------------------------------------------
  316. ! other local variables
  317. INTEGER (kind=int_kind) :: i, j, n, iunit, im1, jm1
  318. INTEGER (kind=int_kind) :: varid_lam, varid_phi, varid_mask
  319. INTEGER (kind=int_kind) :: jdim, nspace
  320. INTEGER (kind=int_kind), dimension(4) :: grid_dimids ! input fields have 4 dims
  321. REAL (kind=dbl_kind) :: tmplon, dxt, dyt
  322. !-----------------------------------------------------------------------
  323. ! read in grid info
  324. !
  325. ! For NEMO input grids, assume that variable names are glam, glamc etc.
  326. ! Assume that 1st 2 dimensions of these variables are x and y directions.
  327. ! These assumptions are made by NEMO, so should be valid for coordinates.nc.
  328. !
  329. ! write in nf90 calls (without error handling) and then think about
  330. ! making more readable by taking chunks into ncutil
  331. ncstat = nf90_open( grid_file_in, NF90_NOWRITE, ncid_in )
  332. call netcdf_error_handler(ncstat)
  333. ! find dimids for 'glamt'
  334. ! use dimids to get dimlengths
  335. ! allocate glam array
  336. ! get glam from file
  337. ncstat = nf90_inq_varid( ncid_in, name_lat, varid_phi )
  338. call netcdf_error_handler(ncstat)
  339. ncstat = nf90_inq_varid( ncid_in, name_lon, varid_lam )
  340. call netcdf_error_handler(ncstat)
  341. ncstat = nf90_inquire_variable( ncid_in, varid_lam, ndims=nspace )
  342. call netcdf_error_handler(ncstat)
  343. if (nspace == 1) then
  344. ncstat = nf90_inquire_variable( ncid_in, varid_lam, dimids=grid_dimids(:1) )
  345. call netcdf_error_handler(ncstat)
  346. ncstat = nf90_inquire_variable( ncid_in, varid_phi, dimids=grid_dimids(2:) )
  347. call netcdf_error_handler(ncstat)
  348. ncstat = nf90_inquire_dimension( ncid_in, grid_dimids(1), len=grid_dims(1) )
  349. call netcdf_error_handler(ncstat)
  350. ncstat = nf90_inquire_dimension( ncid_in, grid_dimids(2), len=grid_dims(2) )
  351. call netcdf_error_handler(ncstat)
  352. nx = grid_dims(1)
  353. ny = grid_dims(2)
  354. grid_size = nx * ny
  355. WRITE(*,FMT='("Input grid dimensions are:",2i6)') nx, ny
  356. ALLOCATE( lam(nx), phi(ny) )
  357. write(6,*) 'double'
  358. ncstat = nf90_get_var( ncid_in, varid_lam, lam )
  359. call netcdf_error_handler(ncstat)
  360. ncstat = nf90_get_var( ncid_in, varid_phi, phi )
  361. call netcdf_error_handler(ncstat)
  362. ALLOCATE( glam(nx,ny), gphi(nx,ny))
  363. write(6,*) shape(lam),shape(phi)
  364. glam(:,:) = SPREAD(lam,2,ny)
  365. gphi(:,:) = SPREAD(phi,1,nx)
  366. else
  367. ncstat = nf90_inquire_variable( ncid_in, varid_lam, dimids=grid_dimids(:2) )
  368. call netcdf_error_handler(ncstat)
  369. ncstat = nf90_inquire_dimension( ncid_in, grid_dimids(1), len=grid_dims(1) )
  370. call netcdf_error_handler(ncstat)
  371. ncstat = nf90_inquire_dimension( ncid_in, grid_dimids(2), len=grid_dims(2) )
  372. call netcdf_error_handler(ncstat)
  373. nx = grid_dims(1)
  374. ny = grid_dims(2)
  375. grid_size = nx * ny
  376. WRITE(*,FMT='("Input grid dimensions are:",2i6)') nx, ny
  377. ALLOCATE( glam(nx,ny), gphi(nx,ny))
  378. ncstat = nf90_get_var( ncid_in, varid_lam, glam )
  379. call netcdf_error_handler(ncstat)
  380. ncstat = nf90_get_var( ncid_in, varid_phi, gphi )
  381. call netcdf_error_handler(ncstat)
  382. endif
  383. write(6,*) grid_size,nx,ny
  384. ALLOCATE(glamc(0:nx,0:ny), gphic(0:nx,0:ny) )
  385. ! - for now a simple average to get top right box corners
  386. ! - glamc(i,j), gphic(i,j) are top right coordinates of box containing
  387. ! - glam(i,j),gphi(i,j)
  388. write(6,*) 'averaging'
  389. write(6,*) size(gphic),size(gphi)
  390. gphic(1:nx,1:ny-1) = 0.5*(gphi(:,1:ny-1)+gphi(:,2:ny))
  391. write(6,*) size(glamc),size(glam)
  392. glamc(1:nx-1,1:ny) = 0.5*(glam(1:nx-1,:)+glam(2:nx,:))
  393. ! - left and right column of longitudes
  394. write(6,*) 'columns'
  395. glamc(nx,1:ny) = 1.5*glam(nx,:)-0.5*glam(nx-1,:)
  396. glamc( 0,1:ny) = 1.5*glam(1,:)-0.5*glam(2,:)
  397. glamc(nx, 0) = glamc(nx,1)
  398. glamc( 0, 0) = glamc( 0,1)
  399. ! - top and bottom row of latitudes by extrapolation
  400. write(6,*) 'rows'
  401. gphic(1:nx,ny) = 1.5*gphi(:,ny)-0.5*gphi(:,ny-1)
  402. gphic(1:nx, 0) = 1.5*gphi(:,1)-0.5*gphi(:,2)
  403. gphic( 0,ny) = gphic(1,ny)
  404. gphic( 0, 0) = gphic(1, 0)
  405. !-----------------------------------------------------------------------
  406. write(6,*) 'allocating'
  407. ALLOCATE( grid_imask(grid_size) )
  408. grid_imask(:) = 1
  409. write(6,*) name_mask
  410. if (trim(name_mask) /= "none") then
  411. write(6,*) 'masking'
  412. ncstat = nf90_inq_varid( ncid_in, name_mask, varid_mask )
  413. call netcdf_error_handler(ncstat)
  414. ALLOCATE( mask(nx,ny) )
  415. write(6,*) 'reading mask'
  416. ncstat = nf90_get_var( ncid_in, varid_mask, mask )
  417. call netcdf_error_handler(ncstat)
  418. write(6,*) 'setting mask'
  419. WHERE ( RESHAPE(mask(:,:),(/ grid_size /)) < value_mask)
  420. grid_imask = 0
  421. END WHERE
  422. write(6,*) 'masked'
  423. END IF
  424. !-----------------------------------------------------------------------
  425. ! corners are arranged as follows: 4 3
  426. ! 1 2
  427. ALLOCATE ( corner_lon(4,nx,ny), corner_lat(4,nx,ny) )
  428. ! - bottom-left corner
  429. corner_lon(1,:,:) = glamc(0:nx-1, 0:ny-1 )
  430. corner_lat(1,:,:) = gphic(0:nx-1, 0:ny-1 )
  431. ! - bottom-right corner
  432. corner_lon(2,:,:) = glamc(1:nx, 0:ny-1 )
  433. corner_lat(2,:,:) = gphic(1:nx, 0:ny-1 )
  434. ! - top-right corner
  435. corner_lon(3,:,:) = glamc(1:nx,1:ny)
  436. corner_lat(3,:,:) = gphic(1:nx,1:ny)
  437. write(6,*) corner_lat(3,nx-2:nx,ny)
  438. ! - top-left corner
  439. corner_lon(4,:,:) = glamc(0:nx-1, 1:ny )
  440. corner_lat(4,:,:) = gphic(0:nx-1, 1:ny )
  441. ! For [N, E, W]-ward extrapolation near the poles, should we use stereographic (or
  442. ! similar) projection? This issue will come for V,F interpolation, and for all
  443. ! grids with non-cyclic grids.
  444. ! -----------------------------------------------------------------------------
  445. ! correct for 0,2pi longitude crossings
  446. ! (In practice this means putting all corners into 0,2pi range
  447. ! and ensuring that no box corners are miles from each other.
  448. ! 3pi/2 is used as threshold - I think this is quite arbitrary.)
  449. ! corner_lon(:,:,:) = MODULO( corner_lon(:,:,:), circle )
  450. ! DO n = 2, grid_corners
  451. ! WHERE ( corner_lon(n,:,:) - corner_lon(n-1,:,:) < -three*circle*0.25 )
  452. ! corner_lon(n,:,:) = corner_lon(n,:,:) + circle
  453. ! ELSEWHERE( corner_lon(n,:,:) - corner_lon(n-1,:,:) > three*circle*0.25 )
  454. ! corner_lon(n,:,:) = corner_lon(n,:,:) - circle
  455. ! END WHERE
  456. ! END DO
  457. ! -----------------------------------------------------------------------------
  458. ! - reshape for SCRIP input format
  459. ALLOCATE( grid_center_lon(grid_size), grid_center_lat(grid_size) )
  460. grid_center_lon(:) = RESHAPE( glam(:,:), (/ grid_size /) )
  461. grid_center_lat(:) = RESHAPE( gphi(:,:), (/ grid_size /) )
  462. DEALLOCATE( glam, gphi, glamc, gphic )
  463. ALLOCATE( grid_corner_lon(4, grid_size), grid_corner_lat(4, grid_size) )
  464. grid_corner_lon(:,:) = RESHAPE( corner_lon(:,:,:), (/ 4, grid_size /) )
  465. grid_corner_lat(:,:) = RESHAPE( corner_lat(:,:,:), (/ 4, grid_size /) )
  466. DEALLOCATE( corner_lon, corner_lat )
  467. CALL createSCRIPgrid(grid_file_out, grid_name)
  468. END SUBROUTINE convertFLUX
  469. ! ==============================================================================
  470. SUBROUTINE mouldlon(lon_grid, nx, ny)
  471. ! -----------------------------------------------------------------------------
  472. ! - input variables
  473. INTEGER, INTENT(in) :: nx, ny
  474. REAL (kind=dbl_kind), INTENT(inout), DIMENSION(nx,ny) :: &
  475. lon_grid
  476. ! -----------------------------------------------------------------------------
  477. ! - local variables
  478. INTEGER :: ix, iy
  479. REAL (kind=dbl_kind), DIMENSION(:,:), ALLOCATABLE :: &
  480. dlon
  481. REAL :: step
  482. ! -----------------------------------------------------------------------------
  483. ! - try to eliminate any 360 degree steps in a grid of longitudes
  484. ALLOCATE(dlon(nx,ny))
  485. step = 0.75*circle
  486. dlon(:,:) = 0
  487. dlon(2:,:) = lon_grid(2:,:) - lon_grid(:nx-1,:)
  488. WHERE (dlon > -step .AND. dlon < step)
  489. dlon = 0.0
  490. ELSEWHERE
  491. dlon = -SIGN(circle,dlon)
  492. END WHERE
  493. ! - close your eyes this is nasty
  494. DO ix = 2,nx
  495. dlon(ix,:) = dlon(ix,:) + dlon(ix-1,:)
  496. END DO
  497. lon_grid = lon_grid + dlon
  498. END SUBROUTINE mouldlon
  499. ! ==============================================================================
  500. SUBROUTINE createSCRIPgrid(grid_file_out, grid_name)
  501. ! -----------------------------------------------------------------------------
  502. ! - input variables
  503. CHARACTER(char_len), INTENT(in) :: &
  504. grid_name, grid_file_out
  505. ! -----------------------------------------------------------------------------
  506. ! - local variables that describe the netcdf file
  507. INTEGER (kind=int_kind) :: &
  508. nc_grid_id, & ! netCDF grid dataset id
  509. nc_gridsize_id, & ! netCDF grid size dim id
  510. nc_gridcorn_id, & ! netCDF grid corner dim id
  511. nc_gridrank_id, & ! netCDF grid rank dim id
  512. nc_griddims_id, & ! netCDF grid dimensions id
  513. nc_grdcntrlat_id, & ! netCDF grid center lat id
  514. nc_grdcntrlon_id, & ! netCDF grid center lon id
  515. nc_grdimask_id, & ! netCDF grid mask id
  516. nc_gridarea_id, & ! netCDF grid area id
  517. nc_grdcrnrlat_id, & ! netCDF grid corner lat id
  518. nc_grdcrnrlon_id ! netCDF grid corner lon id
  519. ! -----------------------------------------------------------------------------
  520. ! - create netCDF dataset for this grid
  521. ! - rewrite in nf90
  522. ! - (bring out functional blocks into ncclear for readability)
  523. ncstat = nf90_create (grid_file_out, NF90_CLOBBER, nc_grid_id)
  524. call netcdf_error_handler(ncstat)
  525. ncstat = nf90_put_att (nc_grid_id, NF90_GLOBAL, 'title', grid_name)
  526. call netcdf_error_handler(ncstat)
  527. ! -----------------------------------------------------------------------------
  528. ! - define grid size dimension
  529. ncstat = nf90_def_dim (nc_grid_id, 'grid_size', grid_size, nc_gridsize_id)
  530. call netcdf_error_handler(ncstat)
  531. ! -----------------------------------------------------------------------------
  532. ! - define grid rank dimension
  533. ncstat = nf90_def_dim (nc_grid_id, 'grid_rank', grid_rank, nc_gridrank_id)
  534. call netcdf_error_handler(ncstat)
  535. ! -----------------------------------------------------------------------------
  536. ! - define grid corner dimension
  537. ncstat = nf90_def_dim (nc_grid_id, 'grid_corners', grid_corners, nc_gridcorn_id)
  538. call netcdf_error_handler(ncstat)
  539. ! -----------------------------------------------------------------------------
  540. ! - define grid dim size array
  541. ncstat = nf90_def_var(nc_grid_id, 'grid_dims', NF90_INT, nc_gridrank_id, nc_griddims_id)
  542. call netcdf_error_handler(ncstat)
  543. ! -----------------------------------------------------------------------------
  544. ! - define grid mask
  545. ncstat = nf90_def_var(nc_grid_id, 'grid_imask', NF90_INT, &
  546. nc_gridsize_id, nc_grdimask_id)
  547. call netcdf_error_handler(ncstat)
  548. ncstat = nf90_put_att(nc_grid_id, nc_grdimask_id, 'units', 'unitless')
  549. call netcdf_error_handler(ncstat)
  550. ! -----------------------------------------------------------------------------
  551. ! - define grid center latitude array
  552. ncstat = nf90_def_var(nc_grid_id, 'grid_center_lat', NF90_DOUBLE, &
  553. nc_gridsize_id, nc_grdcntrlat_id)
  554. call netcdf_error_handler(ncstat)
  555. ncstat = nf90_put_att(nc_grid_id, nc_grdcntrlat_id, 'units', 'degrees')
  556. call netcdf_error_handler(ncstat)
  557. ! -----------------------------------------------------------------------------
  558. ! - define grid center longitude array
  559. ncstat = nf90_def_var(nc_grid_id, 'grid_center_lon', NF90_DOUBLE, &
  560. nc_gridsize_id, nc_grdcntrlon_id)
  561. call netcdf_error_handler(ncstat)
  562. ncstat = nf90_put_att(nc_grid_id, nc_grdcntrlon_id, 'units', 'degrees')
  563. call netcdf_error_handler(ncstat)
  564. ! -----------------------------------------------------------------------------
  565. ! - define grid corner latitude array
  566. grid_dim_ids = (/ nc_gridcorn_id, nc_gridsize_id /)
  567. ncstat = nf90_def_var(nc_grid_id, 'grid_corner_lat', NF90_DOUBLE, &
  568. grid_dim_ids, nc_grdcrnrlat_id)
  569. call netcdf_error_handler(ncstat)
  570. ncstat = nf90_put_att(nc_grid_id, nc_grdcrnrlat_id, 'units', 'degrees')
  571. call netcdf_error_handler(ncstat)
  572. ! -----------------------------------------------------------------------------
  573. ! - define grid corner longitude array
  574. ncstat = nf90_def_var(nc_grid_id, 'grid_corner_lon', NF90_DOUBLE, &
  575. grid_dim_ids, nc_grdcrnrlon_id)
  576. call netcdf_error_handler(ncstat)
  577. ncstat = nf90_put_att(nc_grid_id, nc_grdcrnrlon_id, 'units', 'degrees')
  578. call netcdf_error_handler(ncstat)
  579. ! -----------------------------------------------------------------------------
  580. ! end definition stage
  581. ncstat = nf90_enddef(nc_grid_id)
  582. call netcdf_error_handler(ncstat)
  583. ! -----------------------------------------------------------------------------
  584. ! write grid data
  585. ncstat = nf90_put_var(nc_grid_id, nc_griddims_id, grid_dims)
  586. call netcdf_error_handler(ncstat)
  587. ncstat = nf90_put_var(nc_grid_id, nc_grdimask_id, grid_imask)
  588. call netcdf_error_handler(ncstat)
  589. ncstat = nf90_put_var(nc_grid_id, nc_grdcntrlat_id, grid_center_lat)
  590. call netcdf_error_handler(ncstat)
  591. ncstat = nf90_put_var(nc_grid_id, nc_grdcntrlon_id, grid_center_lon)
  592. call netcdf_error_handler(ncstat)
  593. ncstat = nf90_put_var(nc_grid_id, nc_grdcrnrlat_id, grid_corner_lat)
  594. call netcdf_error_handler(ncstat)
  595. ncstat = nf90_put_var(nc_grid_id, nc_grdcrnrlon_id, grid_corner_lon)
  596. call netcdf_error_handler(ncstat)
  597. ncstat = nf90_close(nc_grid_id)
  598. call netcdf_error_handler(ncstat)
  599. DEALLOCATE( grid_imask, grid_center_lon, grid_center_lat, &
  600. grid_corner_lon, grid_corner_lat )
  601. END SUBROUTINE createSCRIPgrid
  602. END MODULE scripgrid_mod