get_bisicles_corners.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. import sys
  2. import numpy as np
  3. from netCDF4 import Dataset
  4. import os
  5. import time
  6. from pyproj import CRS, Transformer
  7. # C. Pelletier july 2021.
  8. # Example of using PYPROJ to manage projections.
  9. # I highly recommend using this tool, as you're then relying on something documented from projecting (i.e. from lat/lon to stereographic)
  10. # This is pretty useful for ice sheet / ocean coupling and pre/post processing. since most ice sheet models are defined on polar stereographic grids.
  11. # This script just gets the grid corners of the BISICLE grid.
  12. # But it's an illustration of how to use PYPROJ.
  13. # <https://pyproj4.github.io/pyproj/stable/>
  14. # <https://proj.org/>
  15. grid_bisicles = "/afast/pelletie/totten/BISICLES-smaller_grid.nc"
  16. output_file = "/afast/pelletie/totten/BISICLES-smaller_grid_corners.nc"
  17. # description of the projection.
  18. proj_polster = "+proj=stere +lat_0=-90.0 +lat_ts=-71. +lon_0=-90."
  19. # The projection python object
  20. crs_polster = CRS.from_proj4(proj_polster)
  21. tmpdat = Dataset(grid_bisicles, mode='r')
  22. # Center of cells in stereographic projection. No idea why X and Y are interverted.
  23. x_ctn = tmpdat.variables['Y'][:]
  24. y_ctn = tmpdat.variables['X'][:]
  25. mask = tmpdat.variables['MASK'][:].astype(int)
  26. tmpdat.close()
  27. nx = np.size(x_ctn)
  28. ny = np.size(y_ctn)
  29. # Edges of cell in stereographics projection. This is just the middle of two consecutive cells. And a bit of symmetry for the edges.
  30. x_stg = np.ndarray(shape=[nx+1], dtype=float)
  31. y_stg = np.ndarray(shape=[ny+1], dtype=float)
  32. x_stg[1:-1] = .5 * ( x_ctn[:-1] + x_ctn[1:] )
  33. x_stg[0] = 2 * x_ctn[0] - x_stg[1]
  34. x_stg[-1] = 2 * x_ctn[-1] - x_stg[-2]
  35. y_stg[1:-1] = .5 * ( y_ctn[:-1] + y_ctn[1:] )
  36. y_stg[0] = 2 * y_ctn[0] - y_stg[1]
  37. y_stg[-1] = 2 * y_ctn[-1] - y_stg[-2]
  38. # PYPROJ transformation object, polster -> latlon
  39. # <crs_something>.geodetic_crs is always the latlon projection, regardless of <crs_something>
  40. polster_to_latlon = Transformer.from_crs(crs_polster, crs_polster.geodetic_crs)
  41. # Get lon, lat of centers from x,y (which are broadcasted with [None,:] etc.)
  42. lon_ctn, lat_ctn = polster_to_latlon.transform(x_ctn[None,:] * (np.ones(shape=[ny], dtype=float))[:,None], \
  43. y_ctn[:,None] * (np.ones(shape=[nx], dtype=float))[None,:])
  44. # No idea why I'm doing this. I guess everything's corked and dirty.
  45. lon_ctn = - lon_ctn
  46. # Reformat corners in (y,x,4) instead of (y+1,x+1).
  47. x_crn = np.ndarray(shape=[ny, nx, 4], dtype=float)
  48. y_crn = np.ndarray(shape=[ny, nx, 4], dtype=float)
  49. x_crn[:,:,0] = (x_stg[1:])[None,:] * (np.ones(shape=[ny], dtype=float))[:,None]
  50. y_crn[:,:,0] = (y_stg[1:])[:,None] * (np.ones(shape=[nx], dtype=float))[None,:]
  51. x_crn[:,:,1] = (x_stg[1:])[None,:] * (np.ones(shape=[ny], dtype=float))[:,None]
  52. y_crn[:,:,1] = (y_stg[:-1])[:,None] * (np.ones(shape=[nx], dtype=float))[None,:]
  53. x_crn[:,:,2] = (x_stg[:-1])[None,:] * (np.ones(shape=[ny], dtype=float))[:,None]
  54. y_crn[:,:,2] = (y_stg[:-1])[:,None] * (np.ones(shape=[nx], dtype=float))[None,:]
  55. x_crn[:,:,3] = (x_stg[:-1])[None,:] * (np.ones(shape=[ny], dtype=float))[:,None]
  56. y_crn[:,:,3] = (y_stg[1:])[:,None] * (np.ones(shape=[nx], dtype=float))[None,:]
  57. lon_crn = np.ndarray(shape=[ny, nx, 4], dtype=float)
  58. lat_crn = np.ndarray(shape=[ny, nx, 4], dtype=float)
  59. for m in range(0,4):
  60. lon_crn[:,:,m], lat_crn[:,:,m] = polster_to_latlon.transform(x_crn[:,:,m], y_crn[:,:,m])
  61. lon_crn = - lon_crn
  62. out_nc = Dataset(output_file, mode='w')
  63. out_nc.createDimension('y', ny)
  64. out_nc.createDimension('x', nx)
  65. out_nc.createDimension('crn', 4)
  66. tmp = out_nc.createVariable('lat', datatype='f8', dimensions=['y', 'x'])
  67. tmp[:] = lat_ctn
  68. tmp.standard_name = 'latitude'
  69. tmp.units = 'degrees North'
  70. tmp.bounds = 'lat_corn'
  71. tmp = out_nc.createVariable('lat_corn', datatype='f8', dimensions=['y', 'x','crn'])
  72. tmp[:] = lat_crn
  73. tmp = out_nc.createVariable('lon', datatype='f8', dimensions=['y', 'x'])
  74. tmp[:] = lon_ctn
  75. tmp.standard_name = 'longitude'
  76. tmp.units = 'degrees East'
  77. tmp.bounds = 'lon_corn'
  78. tmp = out_nc.createVariable('lon_corn', datatype='f8', dimensions=['y', 'x','crn'])
  79. tmp[:] = lon_crn
  80. tmp = out_nc.createVariable('mask', datatype='i2', dimensions=['y', 'x'])
  81. tmp[:] = mask
  82. tmp.coordinates = 'lat lon'
  83. out_nc.close()