Skip to content

Commit

Permalink
initial checkin of scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
hgoelzer committed May 24, 2024
1 parent 761bc4e commit 53349e5
Show file tree
Hide file tree
Showing 7 changed files with 578 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.nc
__pycache__/

98 changes: 98 additions & 0 deletions ISMIP7_AIS_multigrid_generator_nc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Write ISMIP7 grid files in CDO format

import numpy as np
from generate_CDO_files_nc import generate_CDO_files

# for checking
def isaninteger(x):
return np.mod(x, 1) == 0

##### Typically the only part a user needs to modify
# Specify various ISM grids at different resolution
rk = [16]
#rk = [32, 16, 8, 4, 2, 1]
#rk = [0.5]

# Choose which output file to write
flag_nc = True
flag_xy = True
flag_af2 = True
#####

# Output angle type (degrees or radians)
output_data_type = 'degrees'

# Write additional g0 grid files
flag_g0 = False

# Mapping information. This is EPSG 3031 for AIS
proj_info = {}
proj_info['earthradius'] = 6378137.0
proj_info['eccentricity'] = 0.081819190842621
proj_info['standard_parallel'] = 71.
proj_info['longitude_rot'] = 0.
proj_info['hemisphere'] = 'south'
# Offset of grid node centers. Lower left corner coordinates.
# Note sign change compared to matlab version!
proj_info['falseeasting'] = -3040000
proj_info['falsenorthing'] = -3040000

# Grid dimensions of 1 km base grid
nx_base = 6081
ny_base = 6081


# g1 grid where ice thickness and SMB are defined
grids1 = []
for r in rk:
# For any resolution but check integer grid numbers
nx = ((nx_base-1)/r)+1
ny = ((ny_base-1)/r)+1
if isaninteger(nx) and isaninteger(ny):
agrid = {}
agrid['dx'] = r*1000.
agrid['dy'] = r*1000.
agrid['nx'] = int(nx)
agrid['ny'] = int(ny)
agrid['offsetx'] = 0.
agrid['offsety'] = 0.
agrid['LatLonOutputFileName'] = 'grid_ISMIP7_g1_AIS_{:05d}m.nc'.format(int(r*1000))
agrid['xyOutputFileName'] = 'xy_ISMIP7_g1_AIS_{:05d}m.nc'.format(int(r*1000))
agrid['af2OutputFileName'] = 'af2_ISMIP7_g1_AIS_{:05d}m.nc'.format(int(r*1000))
grids1.append(agrid)
else:
print('Warning: resolution {} km is not comensurable, skipped.'.format(r))

# Create grids and write out
for agrid in grids1:
#print(agrid)
success = generate_CDO_files(agrid, proj_info, output_data_type, flag_nc, flag_xy, flag_af2)


if flag_g0:
# g0 grid where horizontal velocities are defined e.g. for CISM
grids0 = []
for r in rk:
# For any resolution but check integer grid numbers
nx = ((nx_base-1)/r)
ny = ((ny_base-1)/r)
if isaninteger(nx) and isaninteger(ny):
agrid = {}
agrid['dx'] = r*1000.
agrid['dy'] = r*1000.
agrid['nx'] = int(nx)
agrid['ny'] = int(ny)
# g0 grid is offset by half a grid size
agrid['offsetx'] = r*1000./2.
agrid['offsety'] = r*1000./2.
agrid['LatLonOutputFileName'] = 'grid_ISMIP7_g0_AIS_{:05d}m.nc'.format(int(r*1000))
agrid['xyOutputFileName'] = 'xy_ISMIP7_g0_AIS_{:05d}m.nc'.format(int(r*1000))
agrid['af2OutputFileName'] = 'af2_ISMIP7_g0_AIS_{:05d}m.nc'.format(int(r*1000))
grids0.append(agrid)
else:
print('Warning: resolution {} km is not comensurable, skipped.'.format(r))

# Create grids and write out
for agrid in grids0:
#print(agrid)
success = generate_CDO_files(agrid, proj_info, output_data_type, flag_nc, flag_xy, flag_af2)
98 changes: 98 additions & 0 deletions ISMIP7_GrIS_multigrid_generat0r_nc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Write ISMIP7 grid files in CDO format

import numpy as np
from generate_CDO_files_nc import generate_CDO_files

# for checking
def isaninteger(x):
return np.mod(x, 1) == 0

##### Typically the only part a user needs to modify
# Specify various ISM grids at different resolution
rk = [16]
#rk = [16, 8, 4, 2, 1]
#rk = [0.5]

# Choose which output file to write
flag_nc = True
flag_xy = True
flag_af2 = True
#####

# Output angle type (degrees or radians)
output_data_type = 'degrees'

# Write additional g0 grid files
flag_g0 = False

# Mapping information. This is EPSG 3413 for GrIS
proj_info = {}
proj_info['earthradius'] = 6378137.0
proj_info['eccentricity'] = 0.081819190842621
proj_info['standard_parallel'] = 70.
proj_info['longitude_rot'] = 315.
proj_info['hemisphere'] = 'north'
# Offset of grid node centers. Lower left corner coordinates.
# Note sign change compared to matlab version!
proj_info['falseeasting'] = -720000
proj_info['falsenorthing'] = -3450000

# Grid dimensions of 1 km base grid
nx_base = 1681
ny_base = 2881


# g1 grid where ice thickness and SMB are defined
grids1 = []
for r in rk:
# For any resolution but check integer grid numbers
nx = ((nx_base-1)/r)+1
ny = ((ny_base-1)/r)+1
if isaninteger(nx) and isaninteger(ny):
agrid = {}
agrid['dx'] = r*1000.
agrid['dy'] = r*1000.
agrid['nx'] = int(nx)
agrid['ny'] = int(ny)
agrid['offsetx'] = 0.
agrid['offsety'] = 0.
agrid['LatLonOutputFileName'] = 'grid_ISMIP7_g1_GrIS_{:05d}m.nc'.format(int(r*1000))
agrid['xyOutputFileName'] = 'xy_ISMIP7_g1_GrIS_{:05d}m.nc'.format(int(r*1000))
agrid['af2OutputFileName'] = 'af2_ISMIP7_g1_GrIS_{:05d}m.nc'.format(int(r*1000))
grids1.append(agrid)
else:
print('Warning: resolution {} km is not comensurable, skipped.'.format(r))

# Create grids and write out
for agrid in grids1:
#print(agrid)
success = generate_CDO_files(agrid, proj_info, output_data_type, flag_nc, flag_xy, flag_af2)


if flag_g0:
# g0 grid where horizontal velocities are defined e.g. for CISM
grids0 = []
for r in rk:
# For any resolution but check integer grid numbers
nx = ((nx_base-1)/r)
ny = ((ny_base-1)/r)
if isaninteger(nx) and isaninteger(ny):
agrid = {}
agrid['dx'] = r*1000.
agrid['dy'] = r*1000.
agrid['nx'] = int(nx)
agrid['ny'] = int(ny)
# g0 grid is offset by half a grid size
agrid['offsetx'] = r*1000./2.
agrid['offsety'] = r*1000./2.
agrid['LatLonOutputFileName'] = 'grid_ISMIP7_g0_GrIS_{:05d}m.nc'.format(int(r*1000))
agrid['xyOutputFileName'] = 'xy_ISMIP7_g0_GrIS_{:05d}m.nc'.format(int(r*1000))
agrid['af2OutputFileName'] = 'af2_ISMIP7_g0_GrIS_{:05d}m.nc'.format(int(r*1000))
grids0.append(agrid)
else:
print('Warning: resolution {} km is not comensurable, skipped.'.format(r))

# Create grids and write out
for agrid in grids0:
#print(agrid)
success = generate_CDO_files(agrid, proj_info, output_data_type, flag_nc, flag_xy, flag_af2)
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,25 @@
# generate-ismip7-grid-files-py
Python scripts to generate ISMIP7 grid description files used for CDO regridding.

## Setup
Needs a python3 environment with
numpy, netCDF4, os

The scripts can generate 3 different types of files for Greenland and Antarctica

### grid description files (needed for CDO regridding)
grid_ISMIP7_g?_IS_res.nc
### xy coordinates
xy_ISMIP7_g?_IS_res.nc
### area factors
af2_ISMIP7_g?_IS_res.nc

All files are produced for the diagnostic grid g1 (ice thickness, SMB, ..)
The scripts can also generate files for a staggered grid g0, where e.g. CISM defines horizontal velocities.
ISMIP7_AIS_multigrid_generator_nc.py
ISMIP7_GrIS_multigrid_generator_nc.py

using

polar_stereo.py
wnc.py
134 changes: 134 additions & 0 deletions generate_CDO_files_nc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# generate CDO lat-lon grid file from xy and mapping information
import numpy as np
import os
from wnc import wnc, wncatts
from polar_stereo import polar_xy_to_lonlat, polar_xy_scale_factor2

def generate_CDO_files(agrid, proj_info, output_data_type, flag_nc, flag_xy, flag_af2):

# Grid parameters
dx = agrid['dx']
dy = agrid['dy']
nx = agrid['nx']
ny = agrid['ny']
offsetx = agrid['offsetx']
offsety = agrid['offsety']

# Create gridded x and y. Dimension order is y,x!
ycenters, xcenters = np.meshgrid((np.arange(ny)*dy), (np.arange(nx)*dx), indexing='ij')
#print(xcenters.shape)

# Generate xy corner coordinates. CDO needs bounds to rotate counterclockwise
ycorners, xcorners = np.meshgrid((np.arange(ny+1)*dy-dy/2), (np.arange(nx+1)*dx-dx/2), indexing='ij')

ybounds = np.zeros([ycenters.shape[0], ycenters.shape[1], 4])

SEcorner= ycorners[:-1, 1:]
ybounds[:,:,0] = SEcorner
NEcorner= ycorners[1:, 1:]
ybounds[:,:,1] = NEcorner
NWcorner= ycorners[1:, :-1]
ybounds[:,:,2] = NWcorner
SWcorner= ycorners[:-1, :-1]
ybounds[:,:,3] = SWcorner

xbounds = np.zeros([xcenters.shape[0], xcenters.shape[1], 4])

SEcorner= xcorners[:-1, 1:]
xbounds[:,:,0] = SEcorner
NEcorner= xcorners[1:, 1:]
xbounds[:,:,1] = NEcorner
NWcorner= xcorners[1:, :-1]
xbounds[:,:,2] = NWcorner
SWcorner= xcorners[:-1, :-1]
xbounds[:,:,3] = SWcorner

# Write 2d xy netcdf file
if flag_xy:
print(f"Generating {agrid['xyOutputFileName']}")

try:
os.remove(agrid['xyOutputFileName'])
except OSError:
pass

# write 2D and 1D x,y
wnc(xcenters+proj_info['falseeasting']+offsetx, agrid['xyOutputFileName'], 'x2', 'm', 'grid center x-coordinate', ['y', 'x'], 0, 'NETCDF4')
wnc(ycenters+proj_info['falsenorthing']+offsety, agrid['xyOutputFileName'], 'y2', 'm', 'grid center y-coordinate', ['y', 'x'], 0, 'NETCDF4')

wnc(xcenters[0, :]+proj_info['falseeasting']+offsetx, agrid['xyOutputFileName'], 'x1', 'm', 'grid center x-coordinate', 'x', 0, 'NETCDF4')
wnc(ycenters[:, 0]+proj_info['falsenorthing']+offsety, agrid['xyOutputFileName'], 'y1', 'm', 'grid center y-coordinate', 'y', 0, 'NETCDF4')

# write bounds
wnc(xbounds+proj_info['falseeasting']+offsetx, agrid['xyOutputFileName'], 'x_bnds', 'm', 'grid corner x-coordinate', ['y', 'x', 'nv4'], 0, 'NETCDF4')
wnc(ybounds+proj_info['falsenorthing']+offsety, agrid['xyOutputFileName'], 'y_bnds', 'm', 'grid corner y-coordinate', ['y', 'x', 'nv4'], 0, 'NETCDF4')


## Write CDO grid netcdf file
if flag_nc:

# Create lat,lon centers
LI_grid_center_lon, LI_grid_center_lat, _ = polar_xy_to_lonlat(xcenters+proj_info['falseeasting']+offsetx, ycenters+proj_info['falsenorthing']+offsety, proj_info['standard_parallel'], proj_info['longitude_rot'], proj_info['earthradius'], proj_info['eccentricity'], proj_info['hemisphere'] )

# Create lat,lon bounds
LI_grid_corner_lon, LI_grid_corner_lat, _ = polar_xy_to_lonlat(xbounds+proj_info['falseeasting']+offsetx, ybounds+proj_info['falsenorthing']+offsety, proj_info['standard_parallel'], proj_info['longitude_rot'], proj_info['earthradius'], proj_info['eccentricity'], proj_info['hemisphere'] )

# Map to 360 range
LI_grid_center_lon = LI_grid_center_lon % 360.
LI_grid_corner_lon = LI_grid_corner_lon % 360.

# Map to -180 to 180 range, nicer for Greenland
LI_grid_center_lon = np.where(LI_grid_center_lon < 180., LI_grid_center_lon, LI_grid_center_lon - 360.)
LI_grid_corner_lon = np.where(LI_grid_corner_lon < 180., LI_grid_corner_lon, LI_grid_corner_lon - 360.)

# Convert to radians if requested
if output_data_type == 'radians':
LI_grid_center_lat = np.deg2rad(LI_grid_center_lat)
LI_grid_center_lon = np.deg2rad(LI_grid_center_lon)
LI_grid_corner_lat = np.deg2rad(LI_grid_corner_lat)
LI_grid_corner_lon = np.deg2rad(LI_grid_corner_lon)

print(f"Generating {agrid['LatLonOutputFileName']}")

try:
os.remove(agrid['LatLonOutputFileName'])
except OSError:
pass

# grid centers
wnc(LI_grid_center_lat, agrid['LatLonOutputFileName'], 'lat', 'degrees_north', 'grid center latitude', ['y', 'x'], 0, 'NETCDF4')
wncatts(agrid['LatLonOutputFileName'],'lat','standard_name', 'latitude')
wncatts(agrid['LatLonOutputFileName'],'lat','bounds', 'lat_bnds')

wnc(LI_grid_center_lon, agrid['LatLonOutputFileName'], 'lon', 'degrees_east', 'grid center longitude', ['y', 'x'], 0, 'NETCDF4')
wncatts(agrid['LatLonOutputFileName'],'lon','standard_name', 'longitude')
wncatts(agrid['LatLonOutputFileName'],'lon','bounds', 'lon_bnds')

# bounds
wnc(LI_grid_corner_lat, agrid['LatLonOutputFileName'], 'lat_bnds', 'degrees_north', 'grid corner latitude', ['y', 'x', 'nv4'], 0, 'NETCDF4')
wnc(LI_grid_corner_lon, agrid['LatLonOutputFileName'], 'lon_bnds', 'degrees_east', 'grid corner longitude', ['y', 'x', 'nv4'], 0, 'NETCDF4')

# dummy needed for mapping
wnc(np.int8(LI_grid_center_lon*0+1), agrid['LatLonOutputFileName'], 'dummy', '1', 'dummy variable', ['y', 'x'], 0, 'NETCDF4')
# add lat,lon mapping
wncatts(agrid['LatLonOutputFileName'],'dummy', 'coordinates', 'lon lat')

## Write af2 netcdf file
if flag_af2:

# Create af2, lat,lon centers
LI_grid_center_af2 = polar_xy_scale_factor2(xcenters+proj_info['falseeasting']+offsetx, ycenters+proj_info['falsenorthing']+offsety, proj_info['standard_parallel'], proj_info['longitude_rot'], proj_info['earthradius'], proj_info['eccentricity'], proj_info['hemisphere'])

print(f"Generating {agrid['af2OutputFileName']}")

try:
os.remove(agrid['af2OutputFileName'])
except OSError:
pass

# grid centers
wnc(LI_grid_center_af2, agrid['af2OutputFileName'], 'af2', 'scale_factor2', 'squared map scale factor', ['y', 'x'], 0, 'NETCDF4')


successfully_completed = True

Loading

0 comments on commit 53349e5

Please sign in to comment.